mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-13 22:44:26 +02:00
Compare commits
23 Commits
294f5e07c5
...
v1.4.0
Author | SHA1 | Date | |
---|---|---|---|
6d65a609e5 | |||
e96f9bfa6b | |||
10c15fc281 | |||
fd8427d68a | |||
ed1421287f | |||
aa91b141a8 | |||
5dc68f3285 | |||
52b508bdd2 | |||
41ebe39f3b | |||
62df5f5c78 | |||
a1237db52c | |||
a24fdee335 | |||
e4081f2ba3 | |||
5bc7ebee2c | |||
b872df5a1e | |||
53967552df | |||
f8639fbd64 | |||
9020e92928 | |||
48e6597337 | |||
d4e3bbcf16 | |||
2c8a996875 | |||
3d6d9e3e3e | |||
62fdf48ff9 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -12,14 +12,16 @@
|
||||
/configure~
|
||||
/doc/pdfio.epub
|
||||
/examples/code128
|
||||
/examples/image2pdf
|
||||
/examples/md2pdf
|
||||
/examples/pdf2text
|
||||
/examples/pdfioinfo
|
||||
/Makefile
|
||||
/packages
|
||||
/pdfio.pc
|
||||
/pdfio.xcodeproj/xcshareddata
|
||||
/pdfio-*.tar.gz*
|
||||
/pdfio-*.zip*
|
||||
/pdfiototext
|
||||
/testpdfio
|
||||
/testpdfio-*.pdf
|
||||
/testttf
|
||||
|
@ -14,6 +14,7 @@ v1.4.0 - YYYY-MM-DD
|
||||
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)
|
||||
- Fixed validation of date/time values (Issue #83)
|
||||
|
||||
|
||||
v1.3.2 - 2024-08-15
|
||||
|
37
Makefile.in
37
Makefile.in
@ -103,15 +103,33 @@ LIBOBJS = \
|
||||
ttf.o
|
||||
OBJS = \
|
||||
$(LIBOBJS) \
|
||||
pdfiototext.o \
|
||||
testpdfio.o \
|
||||
testttf.o
|
||||
TARGETS = \
|
||||
$(LIBPDFIO) \
|
||||
$(LIBPDFIO_STATIC) \
|
||||
pdfiototext \
|
||||
testpdfio \
|
||||
testttf
|
||||
DOCFILES = \
|
||||
doc/pdfio.html \
|
||||
doc/pdfio-512.png \
|
||||
LICENSE \
|
||||
NOTICE
|
||||
EXAMPLES = \
|
||||
examples/Makefile \
|
||||
examples/Roboto-Bold.ttf \
|
||||
examples/Roboto-Italic.ttf \
|
||||
examples/Roboto-Regular.ttf \
|
||||
examples/RobotoMono-Regular.ttf \
|
||||
examples/code128.c \
|
||||
examples/code128.ttf \
|
||||
examples/image2pdf.c \
|
||||
examples/md2pdf.c \
|
||||
examples/md2pdf.md \
|
||||
examples/mmd.c \
|
||||
examples/mmd.h \
|
||||
examples/pdf2text.c \
|
||||
examples/pdfioinfo.c
|
||||
|
||||
|
||||
# Make everything
|
||||
@ -152,8 +170,13 @@ install: $(TARGETS)
|
||||
$(INSTALL) -c -m 644 pdfio.pc $(BUILDROOT)$(libdir)/pkgconfig
|
||||
echo Installing documentation to $(BUILDROOT)$(datadir)/doc/pdfio...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(datadir)/doc/pdfio
|
||||
for file in doc/pdfio.html doc/pdfio-512.png LICENSE NOTICE; do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio; \
|
||||
for file in $(DOCFILES); do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio; \
|
||||
done
|
||||
echo Installing examples to $(BUILDROOT)$(datadir)/doc/pdfio/examples...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(datadir)/doc/pdfio/examples
|
||||
for file in $(EXAMPLES); do \
|
||||
$(INSTALL) -c -m 644 $$file $(BUILDROOT)$(datadir)/doc/pdfio/examples; \
|
||||
done
|
||||
echo Installing man page to $(BUILDROOT)$(mandir)/man3...
|
||||
$(INSTALL) -d -m 755 $(BUILDROOT)$(mandir)/man3
|
||||
@ -201,12 +224,6 @@ pdfio1.def: $(LIBOBJS) Makefile
|
||||
grep -v '^_ttf' | sed -e '1,$$s/^_//' | sort >>$@
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdfiototext: pdfiototext.o libpdfio.a
|
||||
echo Linking $@...
|
||||
$(CC) $(LDFLAGS) -o $@ pdfiototext.o libpdfio.a $(LIBS)
|
||||
|
||||
|
||||
# pdfio test program
|
||||
testpdfio: testpdfio.o libpdfio.a
|
||||
echo Linking $@...
|
||||
|
1214
doc/pdfio.3
1214
doc/pdfio.3
File diff suppressed because it is too large
Load Diff
1066
doc/pdfio.html
1066
doc/pdfio.html
File diff suppressed because it is too large
Load Diff
1218
doc/pdfio.md
1218
doc/pdfio.md
File diff suppressed because it is too large
Load Diff
@ -13,14 +13,18 @@
|
||||
|
||||
# Common options
|
||||
CFLAGS = -g $(CPPFLAGS)
|
||||
CPPFLAGS = -I..
|
||||
LIBS = -L.. -lpdfio -lz
|
||||
#CFLAGS = -g -fsanitize=address $(CPPFLAGS)
|
||||
CPPFLAGS = -I.. -I/usr/local/include
|
||||
LIBS = -L.. -L/usr/local/lib -lpdfio -lz
|
||||
|
||||
|
||||
# Targets
|
||||
TARGETS = \
|
||||
code128 \
|
||||
md2pdf
|
||||
image2pdf \
|
||||
md2pdf \
|
||||
pdf2text \
|
||||
pdfioinfo
|
||||
|
||||
|
||||
# Make everything
|
||||
@ -37,10 +41,25 @@ code128: code128.c
|
||||
$(CC) $(CFLAGS) -o $@ code128.c $(LIBS)
|
||||
|
||||
|
||||
# image2pdf
|
||||
image2pdf: image2pdf.c
|
||||
$(CC) $(CFLAGS) -o $@ image2pdf.c $(LIBS)
|
||||
|
||||
|
||||
# md2pdf
|
||||
md2pdf: md2pdf.c mmd.c mmd.h
|
||||
$(CC) $(CFLAGS) -o $@ md2pdf.c mmd.c $(LIBS)
|
||||
|
||||
|
||||
# pdfio text extraction (demo, doesn't handle a lot of things yet)
|
||||
pdf2text: pdf2text.c
|
||||
$(CC) $(CFLAGS) -o $@ pdf2text.c $(LIBS)
|
||||
|
||||
|
||||
# pdfioinfo
|
||||
pdfioinfo: pdfioinfo.c
|
||||
$(CC) $(CFLAGS) -o $@ pdfioinfo.c $(LIBS)
|
||||
|
||||
|
||||
# Common dependencies...
|
||||
$(TARGETS): Makefile ../pdfio.h ../pdfio-content.h
|
||||
|
@ -23,7 +23,6 @@
|
||||
// extended characters are ignored in the source string.
|
||||
//
|
||||
|
||||
|
||||
static char * // O - Output string
|
||||
make_code128(char *dst, // I - Destination buffer
|
||||
const char *src, // I - Source string
|
||||
@ -54,9 +53,9 @@ make_code128(char *dst, // I - Destination buffer
|
||||
static const char code128_start_code_a = '\313';
|
||||
// Start code A
|
||||
static const char code128_start_code_b = '\314';
|
||||
// Start code A
|
||||
// Start code B
|
||||
static const char code128_start_code_c = '\315';
|
||||
// Start code A
|
||||
// Start code C
|
||||
static const char code128_stop = '\316';
|
||||
// Stop pattern
|
||||
|
||||
@ -149,7 +148,7 @@ main(int argc, // I - Number of command-line arguments
|
||||
// Load fonts...
|
||||
barcode_font = pdfioFileCreateFontObjFromFile(pdf, "code128.ttf", /*unicode*/false);
|
||||
if (text)
|
||||
text_font = pdfioFileCreateFontObjFromFile(pdf, "../testfiles/OpenSans-Regular.ttf", /*unicode*/true);
|
||||
text_font = pdfioFileCreateFontObjFromBase(pdf, "Helvetica");
|
||||
|
||||
// Generate Code128 characters for the desired barcode...
|
||||
if (!(barcode[0] & 0x80))
|
||||
@ -182,7 +181,7 @@ main(int argc, // I - Number of command-line arguments
|
||||
page_st = pdfioFileCreatePage(pdf, page_dict);
|
||||
|
||||
// Draw the page...
|
||||
pdfioContentSetStrokeColorGray(page_st, 0.0);
|
||||
pdfioContentSetFillColorGray(page_st, 0.0);
|
||||
|
||||
pdfioContentSetTextFont(page_st, "B128", barcode_height);
|
||||
pdfioContentTextBegin(page_st);
|
||||
@ -195,7 +194,7 @@ main(int argc, // I - Number of command-line arguments
|
||||
pdfioContentSetTextFont(page_st, "TEXT", text_height);
|
||||
pdfioContentTextBegin(page_st);
|
||||
pdfioContentTextMoveTo(page_st, 0.5 * (media_box.x2 - text_width), 9.0);
|
||||
pdfioContentTextShow(page_st, /*unicode*/true, text);
|
||||
pdfioContentTextShow(page_st, /*unicode*/false, text);
|
||||
pdfioContentTextEnd(page_st);
|
||||
}
|
||||
|
||||
|
139
examples/image2pdf.c
Normal file
139
examples/image2pdf.c
Normal file
@ -0,0 +1,139 @@
|
||||
//
|
||||
// Image example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./image2pdf FILENAME.{jpg,png} FILENAME.pdf ["TEXT"]
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <pdfio-content.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//
|
||||
// 'create_pdf_image_file()' - Create a PDF file of an image with optional caption.
|
||||
//
|
||||
|
||||
bool // O - True on success, false on failure
|
||||
create_pdf_image_file(
|
||||
const char *pdfname, // I - PDF filename
|
||||
const char *imagename, // I - Image filename
|
||||
const char *caption) // I - Caption filename
|
||||
{
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_obj_t *font; // Caption font
|
||||
pdfio_obj_t *image; // Image
|
||||
pdfio_dict_t *dict; // Page dictionary
|
||||
pdfio_stream_t *page; // Page stream
|
||||
double width, height; // Width and height of image
|
||||
double swidth, sheight; // Scaled width and height on page
|
||||
double tx, ty; // Position on page
|
||||
|
||||
|
||||
// Create the PDF file...
|
||||
pdf = pdfioFileCreate(pdfname, /*version*/NULL, /*media_box*/NULL,
|
||||
/*crop_box*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (!pdf)
|
||||
return (false);
|
||||
|
||||
// Create a Courier base font for the caption
|
||||
font = pdfioFileCreateFontObjFromBase(pdf, "Courier");
|
||||
|
||||
if (!font)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create an image object from the JPEG/PNG image file...
|
||||
image = pdfioFileCreateImageObjFromFile(pdf, imagename, true);
|
||||
|
||||
if (!image)
|
||||
{
|
||||
pdfioFileClose(pdf);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create a page dictionary with the font and image...
|
||||
dict = pdfioDictCreate(pdf);
|
||||
pdfioPageDictAddFont(dict, "F1", font);
|
||||
pdfioPageDictAddImage(dict, "IM1", image);
|
||||
|
||||
// Create the page and its content stream...
|
||||
page = pdfioFileCreatePage(pdf, dict);
|
||||
|
||||
// Position and scale the image on the page...
|
||||
width = pdfioImageGetWidth(image);
|
||||
height = pdfioImageGetHeight(image);
|
||||
|
||||
// Default media_box is "universal" 595.28x792 points (8.27x11in or
|
||||
// 210x279mm). Use margins of 36 points (0.5in or 12.7mm) with another
|
||||
// 36 points for the caption underneath...
|
||||
swidth = 595.28 - 72.0;
|
||||
sheight = swidth * height / width;
|
||||
if (sheight > (792.0 - 36.0 - 72.0))
|
||||
{
|
||||
sheight = 792.0 - 36.0 - 72.0;
|
||||
swidth = sheight * width / height;
|
||||
}
|
||||
|
||||
tx = 0.5 * (595.28 - swidth);
|
||||
ty = 0.5 * (792 - 36 - sheight);
|
||||
|
||||
pdfioContentDrawImage(page, "IM1", tx, ty + 36.0, swidth, sheight);
|
||||
|
||||
// Draw the caption in black...
|
||||
pdfioContentSetFillColorDeviceGray(page, 0.0);
|
||||
|
||||
// Compute the starting point for the text - Courier is monospaced
|
||||
// with a nominal width of 0.6 times the text height...
|
||||
tx = 0.5 * (595.28 - 18.0 * 0.6 * strlen(caption));
|
||||
|
||||
// Position and draw the caption underneath...
|
||||
pdfioContentTextBegin(page);
|
||||
pdfioContentSetTextFont(page, "F1", 18.0);
|
||||
pdfioContentTextMoveTo(page, tx, ty);
|
||||
pdfioContentTextShow(page, /*unicode*/false, caption);
|
||||
pdfioContentTextEnd(page);
|
||||
|
||||
// Close the page stream and the PDF file...
|
||||
pdfioStreamClose(page);
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Produce a single-page file from an image.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // I - Command-line arguments
|
||||
{
|
||||
const char *imagefile, // Image filename
|
||||
*pdffile, // PDF filename
|
||||
*caption; // Caption text
|
||||
|
||||
|
||||
// Get the image file, PDF file, and optional caption text from the command-line...
|
||||
if (argc < 3 || argc > 4)
|
||||
{
|
||||
fputs("Usage: image2pdf FILENAME.{jpg,png} FILENAME.pdf [\"TEXT\"]\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
imagefile = argv[1];
|
||||
pdffile = argv[2];
|
||||
caption = argv[3];
|
||||
|
||||
return (create_pdf_image_file(imagefile, pdffile, caption) ? 0 : 1);
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./md2pdf FILENAME.md FILENAME.pdf
|
||||
// ./md2pdf FILENAME.md >FILENAME.pdf
|
||||
//
|
||||
// The generated PDF file is formatted for a "universal" paper size (8.27x11",
|
||||
@ -40,7 +41,7 @@ typedef enum doccolor_e // Document color enumeration
|
||||
{
|
||||
DOCCOLOR_BLACK, // #000
|
||||
DOCCOLOR_RED, // #900
|
||||
DOCCOLOR_GREEN, // #090
|
||||
DOCCOLOR_ORANGE, // #CC0
|
||||
DOCCOLOR_BLUE, // #00C
|
||||
DOCCOLOR_LTGRAY, // #EEE
|
||||
DOCCOLOR_GRAY // #555
|
||||
@ -88,17 +89,37 @@ typedef struct doctarget_s // Document target info
|
||||
|
||||
#define DOCTARGET_MAX 1000 // Maximum number of targets per document
|
||||
|
||||
typedef struct doctoc_s // Document table-of-contents entry
|
||||
{
|
||||
int level; // Level
|
||||
int count; // Total number of child entries
|
||||
pdfio_obj_t *obj; // Dictionary object
|
||||
pdfio_dict_t *dict; // Dictionary value
|
||||
} doctoc_t;
|
||||
|
||||
#define DOCTOC_MAX 1000 // Maximum number of TOC entries
|
||||
|
||||
typedef struct docdata_s // Document formatting data
|
||||
{
|
||||
// State for the whole document
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
pdfio_rect_t media_box; // Media (page) box
|
||||
pdfio_rect_t crop_box; // Crop box (for margins)
|
||||
pdfio_rect_t art_box; // Art box (for markdown content)
|
||||
pdfio_obj_t *fonts[DOCFONT_MAX]; // Embedded fonts
|
||||
double font_space; // Unit width of a space
|
||||
size_t num_images; // Number of embedded images
|
||||
docimage_t images[DOCIMAGE_MAX]; // Embedded images
|
||||
const char *title; // Document title
|
||||
char *heading; // Current document heading
|
||||
size_t num_actions; // Number of actions for this document
|
||||
docaction_t actions[DOCACTION_MAX]; // Actions for this document
|
||||
size_t num_targets; // Number of targets for this document
|
||||
doctarget_t targets[DOCTARGET_MAX]; // Targets for this document
|
||||
size_t num_toc; // Number of table-of-contents entries
|
||||
doctoc_t toc[DOCTOC_MAX]; // Table-of-contents entries
|
||||
|
||||
// State for the current page
|
||||
pdfio_stream_t *st; // Current page stream
|
||||
double y; // Current position on page
|
||||
docfont_t font; // Current font
|
||||
@ -108,10 +129,6 @@ typedef struct docdata_s // Document formatting data
|
||||
pdfio_obj_t *annots_obj; // Annotations object (for links)
|
||||
size_t num_links; // Number of links for this page
|
||||
doclink_t links[DOCLINK_MAX]; // Links for this page
|
||||
size_t num_actions; // Number of actions for this document
|
||||
docaction_t actions[DOCACTION_MAX]; // Actions for this document
|
||||
size_t num_targets; // Number of targets for this document
|
||||
doctarget_t targets[DOCTARGET_MAX]; // Targets for this document
|
||||
} docdata_t;
|
||||
|
||||
typedef struct linefrag_s // Line fragment
|
||||
@ -192,10 +209,17 @@ static const char * const docfont_names[] =
|
||||
"FM"
|
||||
};
|
||||
|
||||
#define BQ_PADDING 18.0 // Padding for block quotes
|
||||
#define BQ_THICKNESS 3.0 // Thickness of block quote bar
|
||||
|
||||
#define CODE_PADDING 4.5 // Padding for code blocks
|
||||
|
||||
#define IMAGE_PPI 100.0 // Pixels per inch for images
|
||||
|
||||
#define LINE_HEIGHT 1.4 // Multiplier for line height
|
||||
|
||||
#define LIST_PADDING 36.0 // Padding/indentation for lists
|
||||
|
||||
#define SIZE_BODY 11.0 // Size of body text (points)
|
||||
#define SIZE_CODEBLOCK 10.0 // Size of code block text (points)
|
||||
#define SIZE_HEADFOOT 9.0 // Size of header/footer text (points)
|
||||
@ -231,18 +255,19 @@ static void add_links(docdata_t *dd);
|
||||
static pdfio_obj_t *find_image(docdata_t *dd, const char *url, size_t *imagenum);
|
||||
static void format_block(docdata_t *dd, mmd_t *block, docfont_t deffont, double fsize, double left, double right, const char *leader);
|
||||
static void format_code(docdata_t *dd, mmd_t *block, double left, double right);
|
||||
static void format_doc(docdata_t *dd, mmd_t *doc, double left, double right);
|
||||
static void format_doc(docdata_t *dd, mmd_t *doc, docfont_t deffont, double left, double right);
|
||||
static void format_table(docdata_t *dd, mmd_t *table, double left, double right);
|
||||
static void make_target_name(char *dst, const char *src, size_t dstsize);
|
||||
static double measure_cell(docdata_t *dd, mmd_t *cell, tablecol_t *col);
|
||||
static mmd_t *mmd_walk_next(mmd_t *top, mmd_t *node);
|
||||
static void new_page(docdata_t *dd);
|
||||
static ssize_t output_cb(void *output_cbdata, const void *buffer, size_t bytes);
|
||||
static void render_line(docdata_t *dd, double margin_left, double margin_top, double lineheight, size_t num_frags, linefrag_t *frags);
|
||||
static void render_line(docdata_t *dd, double margin_left, double need_bottom, double lineheight, size_t num_frags, linefrag_t *frags);
|
||||
static void render_row(docdata_t *dd, size_t num_cols, tablecol_t *cols, tablerow_t *row);
|
||||
static void set_color(docdata_t *dd, doccolor_t color);
|
||||
static void set_font(docdata_t *dd, docfont_t font, double fsize);
|
||||
static void write_actions(docdata_t *dd);
|
||||
static void write_toc(docdata_t *dd);
|
||||
|
||||
|
||||
//
|
||||
@ -262,9 +287,10 @@ main(int argc, // I - Number of command-line arguments
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
// Get the markdown file from the command-line...
|
||||
if (argc != 2)
|
||||
if (argc < 2 || argc > 3)
|
||||
{
|
||||
fputs("Usage: md2pdf FILENANE.md >FILENAME.pdf\n", stderr);
|
||||
fputs("Usage: md2pdf FILENANE.md [FILENAME.pdf]\n", stderr);
|
||||
fputs(" md2pdf FILENANE.md >FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -287,15 +313,23 @@ main(int argc, // I - Number of command-line arguments
|
||||
dd.art_box.x2 = PAGE_RIGHT;
|
||||
dd.art_box.y2 = PAGE_TOP;
|
||||
|
||||
dd.title = mmdGetMetadata(doc, "title");
|
||||
if ((dd.title = mmdGetMetadata(doc, "title")) == NULL)
|
||||
dd.art_box.y2 = PAGE_HEADER; // No header if there is no title
|
||||
|
||||
// Output a PDF file to the standard output...
|
||||
if (argc == 2)
|
||||
{
|
||||
// Output a PDF file to the standard output...
|
||||
#ifdef _WIN32
|
||||
setmode(1, O_BINARY); // Force binary output on Windows
|
||||
setmode(1, O_BINARY); // Force binary output on Windows
|
||||
#endif // _WIN32
|
||||
|
||||
if ((dd.pdf = pdfioFileCreateOutput(output_cb, /*output_cbdata*/NULL, /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
if ((dd.pdf = pdfioFileCreateOutput(output_cb, /*output_cbdata*/NULL, /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
}
|
||||
else if ((dd.pdf = pdfioFileCreate(argv[2], /*version*/NULL, /*media_box*/NULL, /*crop_box*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
if ((value = mmdGetMetadata(doc, "author")) != NULL)
|
||||
pdfioFileSetAuthor(dd.pdf, value);
|
||||
@ -323,11 +357,13 @@ main(int argc, // I - Number of command-line arguments
|
||||
#endif // USE_TRUETYPE
|
||||
}
|
||||
|
||||
dd.font_space = pdfioContentTextMeasure(dd.fonts[DOCFONT_REGULAR], " ", 1.0);
|
||||
|
||||
// Add images...
|
||||
add_images(&dd, doc);
|
||||
|
||||
// Parse the markdown document...
|
||||
format_doc(&dd, doc, dd.art_box.x1, dd.art_box.x2);
|
||||
format_doc(&dd, doc, DOCFONT_REGULAR, dd.art_box.x1, dd.art_box.x2);
|
||||
|
||||
// Close the PDF and return...
|
||||
if (dd.st)
|
||||
@ -335,7 +371,12 @@ main(int argc, // I - Number of command-line arguments
|
||||
pdfioStreamClose(dd.st);
|
||||
add_links(&dd);
|
||||
}
|
||||
|
||||
write_actions(&dd);
|
||||
|
||||
if (dd.num_toc > 0)
|
||||
write_toc(&dd);
|
||||
|
||||
pdfioFileClose(dd.pdf);
|
||||
|
||||
mmdFree(doc);
|
||||
@ -539,27 +580,31 @@ format_block(docdata_t *dd, // I - Document data
|
||||
width, // Width of current fragment
|
||||
wswidth, // Width of whitespace
|
||||
margin_left, // Left margin
|
||||
margin_top, // Top margin
|
||||
need_bottom, // Space needed after this block
|
||||
height, // Height of current fragment
|
||||
lineheight; // Height of current line
|
||||
|
||||
|
||||
blocktype = mmdGetType(block);
|
||||
|
||||
if ((blocktype >= MMD_TYPE_TABLE_HEADER_CELL && blocktype <= MMD_TYPE_TABLE_BODY_CELL_RIGHT) || blocktype == MMD_TYPE_LIST_ITEM)
|
||||
margin_top = 0.0;
|
||||
if (mmdGetNextSibling(block))
|
||||
need_bottom = 3.0 * SIZE_BODY * LINE_HEIGHT;
|
||||
else
|
||||
margin_top = fsize * LINE_HEIGHT;
|
||||
need_bottom = 0.0;
|
||||
|
||||
if (leader)
|
||||
{
|
||||
// Add leader text on first line...
|
||||
frags[0].width = pdfioContentTextMeasure(dd->fonts[deffont], leader, fsize);
|
||||
frags[0].height = fsize;
|
||||
frags[0].x = left - frags[0].width;
|
||||
frags[0].text = leader;
|
||||
frags[0].font = deffont;
|
||||
frags[0].color = DOCCOLOR_BLACK;
|
||||
frags[0].type = MMD_TYPE_NORMAL_TEXT;
|
||||
frags[0].width = pdfioContentTextMeasure(dd->fonts[deffont], leader, fsize);
|
||||
frags[0].height = fsize;
|
||||
frags[0].x = left - frags[0].width;
|
||||
frags[0].imagenum = 0;
|
||||
frags[0].text = leader;
|
||||
frags[0].url = NULL;
|
||||
frags[0].ws = false;
|
||||
frags[0].font = deffont;
|
||||
frags[0].color = DOCCOLOR_BLACK;
|
||||
|
||||
num_frags = 1;
|
||||
lineheight = fsize * LINE_HEIGHT;
|
||||
@ -583,7 +628,7 @@ format_block(docdata_t *dd, // I - Document data
|
||||
imagenum = 0;
|
||||
url = mmdGetURL(current);
|
||||
ws = mmdGetWhitespace(current);
|
||||
wswidth = 0.0;
|
||||
wswidth = ws ? dd->font_space * fsize : 0.0;
|
||||
next = mmd_walk_next(block, current);
|
||||
|
||||
// Process the node...
|
||||
@ -620,13 +665,21 @@ format_block(docdata_t *dd, // I - Document data
|
||||
else
|
||||
margin_left = 0.0;
|
||||
|
||||
render_line(dd, margin_left, margin_top, lineheight, num_frags, frags);
|
||||
render_line(dd, margin_left, need_bottom, lineheight, num_frags, frags);
|
||||
|
||||
num_frags = 0;
|
||||
frag = frags;
|
||||
x = left;
|
||||
lineheight = 0.0;
|
||||
margin_top = 0.0;
|
||||
if (deffont == DOCFONT_ITALIC)
|
||||
{
|
||||
// Add an orange bar to the left of block quotes...
|
||||
set_color(dd, DOCCOLOR_ORANGE);
|
||||
pdfioContentPathRect(dd->st, left - BQ_PADDING, dd->y - (LINE_HEIGHT - 1.0) * fsize - BQ_THICKNESS, BQ_THICKNESS, lineheight + 2.0 * BQ_THICKNESS);
|
||||
pdfioContentFill(dd->st, /*even_odd*/false);
|
||||
}
|
||||
|
||||
num_frags = 0;
|
||||
frag = frags;
|
||||
x = left;
|
||||
lineheight = 0.0;
|
||||
need_bottom = 0.0;
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -660,9 +713,6 @@ format_block(docdata_t *dd, // I - Document data
|
||||
|
||||
width = pdfioContentTextMeasure(dd->fonts[font], text, fsize);
|
||||
height = fsize * LINE_HEIGHT;
|
||||
|
||||
if (ws)
|
||||
wswidth = pdfioContentTextMeasure(dd->fonts[font], " ", fsize);
|
||||
}
|
||||
|
||||
// See if this node will fit on the current line...
|
||||
@ -676,18 +726,31 @@ format_block(docdata_t *dd, // I - Document data
|
||||
else
|
||||
margin_left = 0.0;
|
||||
|
||||
render_line(dd, margin_left, margin_top, lineheight, num_frags, frags);
|
||||
render_line(dd, margin_left, need_bottom, lineheight, num_frags, frags);
|
||||
|
||||
num_frags = 0;
|
||||
frag = frags;
|
||||
x = left;
|
||||
lineheight = 0.0;
|
||||
margin_top = 0.0;
|
||||
num_frags = 0;
|
||||
frag = frags;
|
||||
x = left;
|
||||
lineheight = 0.0;
|
||||
need_bottom = 0.0;
|
||||
|
||||
if (deffont == DOCFONT_ITALIC)
|
||||
{
|
||||
// Add an orange bar to the left of block quotes...
|
||||
set_color(dd, DOCCOLOR_ORANGE);
|
||||
pdfioContentSave(dd->st);
|
||||
pdfioContentSetLineWidth(dd->st, 3.0);
|
||||
pdfioContentPathMoveTo(dd->st, left - 6.0, dd->y - (LINE_HEIGHT - 1.0) * fsize);
|
||||
pdfioContentPathLineTo(dd->st, left - 6.0, dd->y + fsize);
|
||||
pdfioContentStroke(dd->st);
|
||||
pdfioContentRestore(dd->st);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the current node to the fragment list
|
||||
if (num_frags == 0)
|
||||
{
|
||||
// No leading whitespace at the start of the line
|
||||
ws = false;
|
||||
wswidth = 0.0;
|
||||
}
|
||||
@ -719,7 +782,19 @@ format_block(docdata_t *dd, // I - Document data
|
||||
else
|
||||
margin_left = 0.0;
|
||||
|
||||
render_line(dd, margin_left, margin_top, lineheight, num_frags, frags);
|
||||
render_line(dd, margin_left, need_bottom, lineheight, num_frags, frags);
|
||||
|
||||
if (deffont == DOCFONT_ITALIC)
|
||||
{
|
||||
// Add an orange bar to the left of block quotes...
|
||||
set_color(dd, DOCCOLOR_ORANGE);
|
||||
pdfioContentSave(dd->st);
|
||||
pdfioContentSetLineWidth(dd->st, 3.0);
|
||||
pdfioContentPathMoveTo(dd->st, left - 6.0, dd->y - (LINE_HEIGHT - 1.0) * fsize);
|
||||
pdfioContentPathLineTo(dd->st, left - 6.0, dd->y + fsize);
|
||||
pdfioContentStroke(dd->st);
|
||||
pdfioContentRestore(dd->st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -738,19 +813,27 @@ format_code(docdata_t *dd, // I - Document data
|
||||
double lineheight; // Line height
|
||||
|
||||
|
||||
// Compute line height...
|
||||
lineheight = SIZE_CODEBLOCK * LINE_HEIGHT;
|
||||
|
||||
// Start a new page as needed...
|
||||
if (!dd->st)
|
||||
new_page(dd);
|
||||
|
||||
lineheight = SIZE_CODEBLOCK * LINE_HEIGHT;
|
||||
dd->y -= 2.0 * lineheight;
|
||||
if (dd->y < dd->art_box.y1)
|
||||
dd->y -= lineheight + CODE_PADDING;
|
||||
|
||||
if ((dd->y - lineheight) < dd->art_box.y1)
|
||||
{
|
||||
new_page(dd);
|
||||
|
||||
dd->y -= lineheight;
|
||||
dd->y -= lineheight + CODE_PADDING;
|
||||
}
|
||||
|
||||
// Draw the top padding...
|
||||
set_color(dd, DOCCOLOR_LTGRAY);
|
||||
pdfioContentPathRect(dd->st, left - CODE_PADDING, dd->y + SIZE_CODEBLOCK, right - left + 2.0 * CODE_PADDING, CODE_PADDING);
|
||||
pdfioContentFillAndStroke(dd->st, false);
|
||||
|
||||
// Start a code text block...
|
||||
set_font(dd, DOCFONT_MONOSPACE, SIZE_CODEBLOCK);
|
||||
pdfioContentTextBegin(dd->st);
|
||||
@ -759,7 +842,7 @@ format_code(docdata_t *dd, // I - Document data
|
||||
for (code = mmdGetFirstChild(block); code; code = mmdGetNextSibling(code))
|
||||
{
|
||||
set_color(dd, DOCCOLOR_LTGRAY);
|
||||
pdfioContentPathRect(dd->st, left - 3.0, dd->y - (LINE_HEIGHT - 1.0) * SIZE_CODEBLOCK, right - left + 3.0, lineheight);
|
||||
pdfioContentPathRect(dd->st, left - CODE_PADDING, dd->y - (LINE_HEIGHT - 1.0) * SIZE_CODEBLOCK, right - left + 2.0 * CODE_PADDING, lineheight);
|
||||
pdfioContentFillAndStroke(dd->st, false);
|
||||
|
||||
set_color(dd, DOCCOLOR_RED);
|
||||
@ -784,6 +867,12 @@ format_code(docdata_t *dd, // I - Document data
|
||||
|
||||
// End the current text block...
|
||||
pdfioContentTextEnd(dd->st);
|
||||
dd->y += lineheight;
|
||||
|
||||
// Draw the bottom padding...
|
||||
set_color(dd, DOCCOLOR_LTGRAY);
|
||||
pdfioContentPathRect(dd->st, left - CODE_PADDING, dd->y - CODE_PADDING - (LINE_HEIGHT - 1.0) * SIZE_CODEBLOCK, right - left + 2.0 * CODE_PADDING, CODE_PADDING);
|
||||
pdfioContentFillAndStroke(dd->st, false);
|
||||
}
|
||||
|
||||
|
||||
@ -794,6 +883,7 @@ format_code(docdata_t *dd, // I - Document data
|
||||
static void
|
||||
format_doc(docdata_t *dd, // I - Document data
|
||||
mmd_t *doc, // I - Document node to format
|
||||
docfont_t deffont, // I - Default font
|
||||
double left, // I - Left margin
|
||||
double right) // I - Right margin
|
||||
{
|
||||
@ -822,27 +912,31 @@ format_doc(docdata_t *dd, // I - Document data
|
||||
default :
|
||||
break;
|
||||
|
||||
case MMD_TYPE_THEMATIC_BREAK :
|
||||
// Force a page break
|
||||
dd->y = dd->art_box.y1;
|
||||
break;
|
||||
|
||||
case MMD_TYPE_BLOCK_QUOTE :
|
||||
format_doc(dd, current, left + 36.0, right - 36.0);
|
||||
format_doc(dd, current, DOCFONT_ITALIC, left + BQ_PADDING, right - BQ_PADDING);
|
||||
break;
|
||||
|
||||
case MMD_TYPE_ORDERED_LIST :
|
||||
case MMD_TYPE_UNORDERED_LIST :
|
||||
if (dd->st)
|
||||
dd->y -= SIZE_BODY * LINE_HEIGHT;
|
||||
dd->y -= SIZE_BODY * LINE_HEIGHT;
|
||||
|
||||
format_doc(dd, current, left + 36.0, right);
|
||||
format_doc(dd, current, deffont, left + LIST_PADDING, right);
|
||||
break;
|
||||
|
||||
case MMD_TYPE_LIST_ITEM :
|
||||
if (doctype == MMD_TYPE_ORDERED_LIST)
|
||||
{
|
||||
snprintf(leader, sizeof(leader), "%d. ", i);
|
||||
format_block(dd, current, DOCFONT_REGULAR, SIZE_BODY, left, right, leader);
|
||||
format_block(dd, current, deffont, SIZE_BODY, left, right, leader);
|
||||
}
|
||||
else
|
||||
{
|
||||
format_block(dd, current, DOCFONT_REGULAR, SIZE_BODY, left, right, /*leader*/"• ");
|
||||
format_block(dd, current, deffont, SIZE_BODY, left, right, /*leader*/"• ");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -852,13 +946,41 @@ format_doc(docdata_t *dd, // I - Document data
|
||||
case MMD_TYPE_HEADING_4 :
|
||||
case MMD_TYPE_HEADING_5 :
|
||||
case MMD_TYPE_HEADING_6 :
|
||||
if (dd->heading)
|
||||
free(dd->heading);
|
||||
|
||||
// Update the current heading
|
||||
free(dd->heading);
|
||||
dd->heading = mmdCopyAllText(current);
|
||||
|
||||
// Add a blank line before the heading...
|
||||
dd->y -= heading_sizes[curtype - MMD_TYPE_HEADING_1] * LINE_HEIGHT;
|
||||
|
||||
// Format the heading...
|
||||
format_block(dd, current, DOCFONT_BOLD, heading_sizes[curtype - MMD_TYPE_HEADING_1], left, right, /*leader*/NULL);
|
||||
|
||||
// Add the heading to the table-of-contents...
|
||||
if (dd->num_toc < DOCTOC_MAX)
|
||||
{
|
||||
doctoc_t *t = dd->toc + dd->num_toc;
|
||||
// New TOC
|
||||
pdfio_array_t *dest; // Destination array
|
||||
|
||||
t->level = curtype - MMD_TYPE_HEADING_1;
|
||||
t->dict = pdfioDictCreate(dd->pdf);
|
||||
t->obj = pdfioFileCreateObj(dd->pdf, t->dict);
|
||||
dest = pdfioArrayCreate(dd->pdf);
|
||||
|
||||
pdfioArrayAppendObj(dest, pdfioFileGetPage(dd->pdf, pdfioFileGetNumPages(dd->pdf) - 1));
|
||||
pdfioArrayAppendName(dest, "XYZ");
|
||||
pdfioArrayAppendNumber(dest, PAGE_LEFT);
|
||||
pdfioArrayAppendNumber(dest, dd->y + heading_sizes[curtype - MMD_TYPE_HEADING_1] * LINE_HEIGHT);
|
||||
pdfioArrayAppendNumber(dest, 0.0);
|
||||
|
||||
pdfioDictSetArray(t->dict, "Dest", dest);
|
||||
pdfioDictSetString(t->dict, "Title", pdfioStringCreate(dd->pdf, dd->heading));
|
||||
|
||||
dd->num_toc ++;
|
||||
}
|
||||
|
||||
// Add the heading to the list of link targets...
|
||||
if (dd->num_targets < DOCTARGET_MAX)
|
||||
{
|
||||
doctarget_t *t = dd->targets + dd->num_targets;
|
||||
@ -873,15 +995,27 @@ format_doc(docdata_t *dd, // I - Document data
|
||||
break;
|
||||
|
||||
case MMD_TYPE_PARAGRAPH :
|
||||
format_block(dd, current, DOCFONT_REGULAR, SIZE_BODY, left, right, /*leader*/NULL);
|
||||
// Add a blank line before the paragraph...
|
||||
dd->y -= SIZE_BODY * LINE_HEIGHT;
|
||||
|
||||
// Format the paragraph...
|
||||
format_block(dd, current, deffont, SIZE_BODY, left, right, /*leader*/NULL);
|
||||
break;
|
||||
|
||||
case MMD_TYPE_TABLE :
|
||||
// Add a blank line before the paragraph...
|
||||
dd->y -= SIZE_BODY * LINE_HEIGHT;
|
||||
|
||||
// Format the table...
|
||||
format_table(dd, current, left, right);
|
||||
break;
|
||||
|
||||
case MMD_TYPE_CODE_BLOCK :
|
||||
format_code(dd, current, left + 36.0, right - 36.0);
|
||||
// Add a blank line before the code block...
|
||||
dd->y -= SIZE_BODY * LINE_HEIGHT;
|
||||
|
||||
// Format the code block...
|
||||
format_code(dd, current, left + CODE_PADDING, right - CODE_PADDING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -915,14 +1049,10 @@ format_table(docdata_t *dd, // I - Document data
|
||||
|
||||
|
||||
// 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)
|
||||
for (num_cols = 0, num_rows = 0, rowptr = rows, current = mmdGetFirstChild(table); current && num_rows < TABLEROW_MAX; current = next)
|
||||
{
|
||||
next = mmd_walk_next(table, current);
|
||||
type = mmdGetType(current);
|
||||
@ -1014,9 +1144,6 @@ format_table(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
@ -1238,15 +1365,15 @@ new_page(docdata_t *dd) // I - Document data
|
||||
|
||||
// Prep the new page...
|
||||
page_dict = pdfioDictCreate(dd->pdf);
|
||||
|
||||
dd->annots_array = pdfioArrayCreate(dd->pdf);
|
||||
dd->annots_obj = pdfioFileCreateArrayObj(dd->pdf, dd->annots_array);
|
||||
pdfioDictSetObj(page_dict, "Annots", dd->annots_obj);
|
||||
|
||||
pdfioDictSetRect(page_dict, "MediaBox", &dd->media_box);
|
||||
// pdfioDictSetRect(page_dict, "CropBox", &dd->crop_box);
|
||||
pdfioDictSetRect(page_dict, "ArtBox", &dd->art_box);
|
||||
|
||||
pdfioDictSetObj(page_dict, "Annots", dd->annots_obj);
|
||||
|
||||
for (fontface = DOCFONT_REGULAR; fontface < DOCFONT_MAX; fontface ++)
|
||||
pdfioPageDictAddFont(page_dict, docfont_names[fontface], dd->fonts[fontface]);
|
||||
|
||||
@ -1343,7 +1470,7 @@ output_cb(void *output_cbdata, // I - Callback data (not used)
|
||||
static void
|
||||
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
|
||||
@ -1354,13 +1481,10 @@ render_line(docdata_t *dd, // I - Document data
|
||||
|
||||
|
||||
if (!dd->st)
|
||||
{
|
||||
new_page(dd);
|
||||
margin_top = 0.0;
|
||||
}
|
||||
|
||||
dd->y -= margin_top + lineheight;
|
||||
if (dd->y < dd->art_box.y1)
|
||||
dd->y -= lineheight;
|
||||
if ((dd->y - need_bottom) < dd->art_box.y1)
|
||||
{
|
||||
new_page(dd);
|
||||
|
||||
@ -1398,9 +1522,6 @@ render_line(docdata_t *dd, // I - Document data
|
||||
else if (frag->text)
|
||||
{
|
||||
// Draw text
|
||||
set_color(dd, frag->color);
|
||||
set_font(dd, frag->font, frag->height);
|
||||
|
||||
if (!in_text)
|
||||
{
|
||||
pdfioContentTextBegin(dd->st);
|
||||
@ -1409,12 +1530,21 @@ render_line(docdata_t *dd, // I - Document data
|
||||
in_text = true;
|
||||
}
|
||||
|
||||
if (frag->ws)
|
||||
pdfioContentTextShowf(dd->st, UNICODE_VALUE, " %s", frag->text);
|
||||
else
|
||||
pdfioContentTextShow(dd->st, UNICODE_VALUE, frag->text);
|
||||
if (frag->ws && frag->font == DOCFONT_MONOSPACE)
|
||||
{
|
||||
set_font(dd, DOCFONT_REGULAR, frag->height);
|
||||
pdfioContentTextShow(dd->st, UNICODE_VALUE, " ");
|
||||
}
|
||||
|
||||
if (frag->type == MMD_TYPE_LINKED_TEXT && frag->url && dd->num_links < DOCLINK_MAX)
|
||||
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
|
||||
@ -1545,9 +1675,9 @@ set_color(docdata_t *dd, // I - Document data
|
||||
pdfioContentSetFillColorDeviceRGB(dd->st, 0.6, 0.0, 0.0);
|
||||
pdfioContentSetStrokeColorDeviceRGB(dd->st, 0.6, 0.0, 0.0);
|
||||
break;
|
||||
case DOCCOLOR_GREEN :
|
||||
pdfioContentSetFillColorDeviceRGB(dd->st, 0.0, 0.6, 0.0);
|
||||
pdfioContentSetStrokeColorDeviceRGB(dd->st, 0.0, 0.6, 0.0);
|
||||
case DOCCOLOR_ORANGE :
|
||||
pdfioContentSetFillColorDeviceRGB(dd->st, 1.0, 0.5, 0.0);
|
||||
pdfioContentSetStrokeColorDeviceRGB(dd->st, 1.0, 0.5, 0.0);
|
||||
break;
|
||||
case DOCCOLOR_BLUE :
|
||||
pdfioContentSetFillColorDeviceRGB(dd->st, 0.0, 0.0, 0.8);
|
||||
@ -1629,3 +1759,107 @@ write_actions(docdata_t *dd) // I - Document data
|
||||
pdfioObjClose(a->obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'write_toc()' - Write the table-of-contents outline.
|
||||
//
|
||||
|
||||
static void
|
||||
write_toc(docdata_t *dd) // I - Document data
|
||||
{
|
||||
size_t i, j; // Looping vars
|
||||
doctoc_t *t, // Table-of-contents entry
|
||||
*nt, // Next entry
|
||||
*levels[6]; // Current entries for each level
|
||||
int level; // Current level
|
||||
pdfio_dict_t *dict; // Outline dictionary
|
||||
pdfio_obj_t *obj; // Outline object
|
||||
|
||||
|
||||
// Initialize the various TOC levels...
|
||||
levels[0] = levels[1] = levels[2] = levels[3] = levels[4] = levels[5] = NULL;
|
||||
|
||||
// Scan the table of contents and finalize the dictionaries...
|
||||
for (i = 0, t = dd->toc; i < dd->num_toc; i ++, t ++)
|
||||
{
|
||||
// Set parent, previous, and next entries...
|
||||
if (t->level > 0 && levels[t->level - 1])
|
||||
pdfioDictSetObj(t->dict, "Parent", levels[t->level - 1]->obj);
|
||||
|
||||
if (levels[t->level])
|
||||
pdfioDictSetObj(t->dict, "Prev", levels[t->level]->obj);
|
||||
|
||||
for (j = i + 1, nt = t + 1; j < dd->num_toc; j ++, nt ++)
|
||||
{
|
||||
if (nt->level == t->level)
|
||||
{
|
||||
pdfioDictSetObj(t->dict, "Next", nt->obj);
|
||||
break;
|
||||
}
|
||||
else if (nt->level < t->level)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// First, last, and count...
|
||||
for (level = 0; level < t->level; level ++)
|
||||
levels[level]->count ++;
|
||||
|
||||
levels[t->level] = t;
|
||||
|
||||
if ((i + 1) < dd->num_toc && t[1].level > t->level)
|
||||
pdfioDictSetObj(t->dict, "First", t[1].obj);
|
||||
|
||||
if ((i + 1) >= dd->num_toc)
|
||||
{
|
||||
// Close out all levels...
|
||||
for (level = t->level; level > 0; level --)
|
||||
{
|
||||
pdfioDictSetObj(levels[level - 1]->dict, "Last", levels[level]->obj);
|
||||
levels[level] = NULL;
|
||||
}
|
||||
}
|
||||
else if (t->level > t[1].level)
|
||||
{
|
||||
// Close out N levels...
|
||||
for (level = t->level; level > t[1].level; level --)
|
||||
{
|
||||
pdfioDictSetObj(levels[level - 1]->dict, "Last", levels[level]->obj);
|
||||
levels[level] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the top-level outline object...
|
||||
dict = pdfioDictCreate(dd->pdf);
|
||||
obj = pdfioFileCreateObj(dd->pdf, dict);
|
||||
|
||||
pdfioDictSetName(dict, "Type", "Outline");
|
||||
pdfioDictSetNumber(dict, "Count", dd->num_toc);
|
||||
pdfioDictSetObj(dict, "First", dd->toc[0].obj);
|
||||
|
||||
// Close the objects for the entries...
|
||||
for (i = 0, t = dd->toc; i < dd->num_toc; i ++, t ++)
|
||||
{
|
||||
if (t->level == 0)
|
||||
pdfioDictSetObj(dict, "Last", t->obj);
|
||||
|
||||
if (t->count)
|
||||
{
|
||||
// Set Count value...
|
||||
if (t->level == 0)
|
||||
pdfioDictSetNumber(t->dict, "Count", t->count);
|
||||
else
|
||||
pdfioDictSetNumber(t->dict, "Count", -t->count);
|
||||
}
|
||||
|
||||
pdfioObjClose(t->obj);
|
||||
}
|
||||
|
||||
// Close the outline object and add it to the document catalog...
|
||||
pdfioObjClose(obj);
|
||||
|
||||
pdfioDictSetObj(pdfioFileGetCatalog(dd->pdf), "Outlines", obj);
|
||||
}
|
||||
|
@ -1,22 +1,10 @@
|
||||
---
|
||||
title: Markdown to PDF Converter Example
|
||||
title: Markdown to PDF Converter Test File
|
||||
...
|
||||
|
||||
Markdown to PDF Converter Example
|
||||
=================================
|
||||
|
||||
The `md2pdf` example program reads a markdown file and formats the content onto
|
||||
pages in a PDF file. It demonstrates how to:
|
||||
|
||||
- Embed base and TrueType fonts,
|
||||
- Format text,
|
||||
- Embed JPEG and PNG images,
|
||||
- Add headers and footers, and
|
||||
- Add hyperlinks.
|
||||
|
||||
|
||||
Source Files
|
||||
------------
|
||||
Markdown to PDF Converter Test File
|
||||
===================================
|
||||
|
||||
The `md2pdf` program is organized into three source files: `md2pdf.c` which
|
||||
contains the code to format the markdown content and `mmd.h` and `mmd.c` (from
|
||||
@ -24,4 +12,73 @@ the [Miniature Markdown Library][MMD] project) which load the markdown content.
|
||||
|
||||
[MMD]: https://www.msweet.org/mmd/
|
||||
|
||||
This is a test file for `md2pdf`. Here is a bullet list:
|
||||
|
||||
- Embed base and TrueType fonts,
|
||||
- Format text with embedded JPEG and PNG images and check boxes, with support
|
||||
for wrapping, alignment in table cells, leader text (as used for lists), and
|
||||
variable line height,
|
||||
- Add headers and footers, and
|
||||
- Add hyperlinks and document platform.
|
||||
|
||||
And here is an ordered list:
|
||||
|
||||
1. Embed base and TrueType fonts,
|
||||
2. Format text with embedded JPEG and PNG images and check boxes, with support
|
||||
for wrapping, alignment in table cells, leader text (as used for lists), and
|
||||
variable line height,
|
||||
3. Add headers and footers, and
|
||||
4. Add hyperlinks and document platform.
|
||||
|
||||
|
||||
Code Blocks
|
||||
-----------
|
||||
|
||||
```
|
||||
0 1 2 3 4 5 6 7 8
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
```
|
||||
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
PDFio book cover image:
|
||||
|
||||

|
||||
|
||||
|
||||
Tables
|
||||
------
|
||||
|
||||
Table with leading/trailing pipes:
|
||||
|
||||
| Heading 1 | Heading 2 | Heading 3 |
|
||||
| --------- | --------- | --------- |
|
||||
| Cell 1,1 | Cell 1,2 | Cell 1,3 |
|
||||
| Cell 2,1 | Cell 2,2 | Cell 2,3 |
|
||||
| Cell 3,1 | Cell 3,2 | Cell 3,3 |
|
||||
|
||||
Table without leading/trailing pipes:
|
||||
|
||||
Heading 1 | Heading 2 | Heading 3
|
||||
--------- | --------- | ---------
|
||||
Cell 1,1 | Cell 1,2 | Cell 1,3
|
||||
Cell 2,1 | Cell 2,2 | Cell 2,3
|
||||
Cell 3,1 | Cell 3,2 | Cell 3,3
|
||||
|
||||
Table with alignment:
|
||||
|
||||
Left Alignment | Center Alignment | Right Alignment
|
||||
:-------- | :-------: | --------:
|
||||
Cell 1,1 | Cell 1,2 | 1
|
||||
Cell 2,1 | Cell 2,2 | 12
|
||||
Cell 3,1 | Cell 3,2 | 123
|
||||
|
||||
Table in block quote:
|
||||
|
||||
> Heading 1 | Heading 2 | Heading 3
|
||||
> --------- | --------- | ---------
|
||||
> Cell 1,1 | Cell 1,2 | Cell 1,3
|
||||
> Cell 2,1 | Cell 2,2 | Cell 2,3
|
||||
> Cell 3,1 | Cell 3,2 | Cell 3,3
|
||||
|
@ -166,7 +166,7 @@ mmdCopyAllText(mmd_t *node) // I - Parent node
|
||||
char *all = NULL, // String buffer
|
||||
*allptr = NULL, // Pointer into string buffer
|
||||
*temp; // Temporary pointer
|
||||
size_t allsize = 0, // Size of "all" buffer
|
||||
size_t allsize = 1, // Size of "all" buffer
|
||||
textlen; // Length of "text" string
|
||||
mmd_t *current, // Current node
|
||||
*next; // Next node
|
||||
|
@ -1,17 +1,17 @@
|
||||
//
|
||||
// PDF to text program for PDFio.
|
||||
//
|
||||
// Copyright © 2022 by Michael R Sweet.
|
||||
// Copyright © 2022-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfiototext FILENAME.pdf > FILENAME.txt
|
||||
// ./pdf2text FILENAME.pdf > FILENAME.txt
|
||||
//
|
||||
|
||||
#include "pdfio.h"
|
||||
#include <pdfio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@ -36,16 +36,14 @@ main(int argc, // I - Number of command-line arguments
|
||||
// Verify command-line arguments...
|
||||
if (argc != 2)
|
||||
{
|
||||
puts("Usage: pdfiototext FILENAME.pdf > FILENAME.txt");
|
||||
puts("Usage: pdf2text FILENAME.pdf > FILENAME.txt");
|
||||
return (1);
|
||||
}
|
||||
|
||||
// Open the PDF file...
|
||||
if ((file = pdfioFileOpen(argv[1], NULL, NULL, NULL, NULL)) == NULL)
|
||||
if ((file = pdfioFileOpen(argv[1], /*password_cb*/NULL, /*password_data*/NULL, /*error_cb*/NULL, /*error_data*/NULL)) == NULL)
|
||||
return (1);
|
||||
|
||||
// printf("%s: %u pages\n", argv[1], (unsigned)pdfioFileGetNumPages(file));
|
||||
|
||||
// Try grabbing content from all of the pages...
|
||||
for (i = 0, num_pages = pdfioFileGetNumPages(file); i < num_pages; i ++)
|
||||
{
|
||||
@ -54,29 +52,28 @@ main(int argc, // I - Number of command-line arguments
|
||||
|
||||
num_streams = pdfioPageGetNumStreams(obj);
|
||||
|
||||
// printf("%s: page%u=%p, num_streams=%u\n", argv[1], (unsigned)i, obj, (unsigned)num_streams);
|
||||
|
||||
for (j = 0; j < num_streams; j ++)
|
||||
{
|
||||
if ((st = pdfioPageOpenStream(obj, j, true)) == NULL)
|
||||
continue;
|
||||
|
||||
// printf("%s: page%u st%u=%p\n", argv[1], (unsigned)i, (unsigned)j, st);
|
||||
|
||||
// Read PDF tokens from the page stream...
|
||||
first = true;
|
||||
while (pdfioStreamGetToken(st, buffer, sizeof(buffer)))
|
||||
{
|
||||
if (buffer[0] == '(')
|
||||
{
|
||||
// Text string using an 8-bit encoding
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
else if (buffer[1] != ' ')
|
||||
putchar(' ');
|
||||
|
||||
fputs(buffer + 1, stdout);
|
||||
}
|
||||
else if (!strcmp(buffer, "Td") || !strcmp(buffer, "TD") || !strcmp(buffer, "T*") || !strcmp(buffer, "\'") || !strcmp(buffer, "\""))
|
||||
{
|
||||
// Text operators that advance to the next line in the block
|
||||
putchar('\n');
|
||||
first = true;
|
||||
}
|
65
examples/pdfioinfo.c
Normal file
65
examples/pdfioinfo.c
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// PDF metadata example for PDFio.
|
||||
//
|
||||
// Copyright © 2023-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ./pdfioinfo FILENAME.pdf
|
||||
//
|
||||
|
||||
#include <pdfio.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
//
|
||||
// 'main()' - Open a PDF file and show its metadata.
|
||||
//
|
||||
|
||||
int // O - Exit status
|
||||
main(int argc, // I - Number of command-line arguments
|
||||
char *argv[]) // Command-line arguments
|
||||
{
|
||||
const char *filename; // PDF filename
|
||||
pdfio_file_t *pdf; // PDF file
|
||||
time_t creation_date; // Creation date
|
||||
struct tm *creation_tm; // Creation date/time information
|
||||
char creation_text[256]; // Creation date/time as a string
|
||||
|
||||
|
||||
// Get the filename from the command-line...
|
||||
if (argc != 2)
|
||||
{
|
||||
fputs("Usage: ./pdfioinfo FILENAME.pdf\n", stderr);
|
||||
return (1);
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
// Open the PDF file with the default callbacks...
|
||||
pdf = pdfioFileOpen(filename, /*password_cb*/NULL,
|
||||
/*password_cbdata*/NULL, /*error_cb*/NULL,
|
||||
/*error_cbdata*/NULL);
|
||||
if (pdf == NULL)
|
||||
return (1);
|
||||
|
||||
// Get the creation date and convert to a string...
|
||||
creation_date = pdfioFileGetCreationDate(pdf);
|
||||
creation_tm = localtime(&creation_date);
|
||||
strftime(creation_text, sizeof(creation_text), "%c", creation_tm);
|
||||
|
||||
// Print file information to stdout...
|
||||
printf("%s:\n", filename);
|
||||
printf(" Title: %s\n", pdfioFileGetTitle(pdf));
|
||||
printf(" Author: %s\n", pdfioFileGetAuthor(pdf));
|
||||
printf(" Created On: %s\n", creation_text);
|
||||
printf(" Number Pages: %u\n", (unsigned)pdfioFileGetNumPages(pdf));
|
||||
|
||||
// Close the PDF file...
|
||||
pdfioFileClose(pdf);
|
||||
|
||||
return (0);
|
||||
}
|
@ -284,7 +284,7 @@ static short times_roman_widths[256] =
|
||||
};
|
||||
|
||||
|
||||
static short zapf_dingbats_widths[256] =
|
||||
static short zapfdingbats_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,
|
||||
|
@ -1132,7 +1132,7 @@ pdfioContentTextMeasure(
|
||||
}
|
||||
|
||||
if (i < (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])))
|
||||
ch = i + 0x80; // Extra characters from 0x80 to 0x9f
|
||||
ch = (int)(i + 0x80); // Extra characters from 0x80 to 0x9f
|
||||
else
|
||||
ch = '?'; // Unsupported chars map to ?
|
||||
}
|
||||
@ -1171,8 +1171,8 @@ pdfioContentTextMeasure(
|
||||
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 if (!strcmp(basefont, "ZapfDingbats"))
|
||||
widths = zapfdingbats_widths;
|
||||
else
|
||||
return (0.0);
|
||||
|
||||
|
@ -755,6 +755,8 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
int offset; // Date offset
|
||||
|
||||
|
||||
PDFIO_DEBUG("get_date_time(s=\"%s\")\n", s);
|
||||
|
||||
// Possible date value of the form:
|
||||
//
|
||||
// (D:YYYYMMDDhhmmssZ)
|
||||
@ -772,10 +774,12 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
{
|
||||
if (s[i] == 'Z')
|
||||
{
|
||||
// UTC...
|
||||
i ++;
|
||||
}
|
||||
else if (s[i] == '-' || s[i] == '+')
|
||||
{
|
||||
// Timezone offset from UTC...
|
||||
if (isdigit(s[i + 1] & 255) && isdigit(s[i + 2] & 255) && s[i + 3] == '\'' && isdigit(s[i + 4] & 255) && isdigit(s[i + 5] & 255))
|
||||
{
|
||||
i += 6;
|
||||
@ -783,6 +787,11 @@ get_date_time(const char *s) // I - PDF date/time value
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
else if (!s[i])
|
||||
{
|
||||
// Missing zone info, invalid date string...
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (s[i])
|
||||
|
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -31,6 +31,7 @@
|
||||
27F2F0612710BE92008ECD36 /* pdfio-rc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */; };
|
||||
27F2F0622710BE92008ECD36 /* pdfio-crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */; };
|
||||
27F2F0642711243D008ECD36 /* pdfio-sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = 27F2F0632711243D008ECD36 /* pdfio-sha256.c */; };
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */ = {isa = PBXBuildFile; fileRef = 27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -89,6 +90,7 @@
|
||||
27F2F05E2710BE92008ECD36 /* pdfio-rc4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-rc4.c"; sourceTree = "<group>"; };
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-crypto.c"; sourceTree = "<group>"; };
|
||||
27F2F0632711243D008ECD36 /* pdfio-sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "pdfio-sha256.c"; sourceTree = "<group>"; };
|
||||
27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "pdfio-base-font-widths.h"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -162,6 +164,7 @@
|
||||
children = (
|
||||
27CF90432711DFFE00E50FE4 /* pdfio-aes.c */,
|
||||
273440BA263D727800FBFD63 /* pdfio-array.c */,
|
||||
27FCBDE32D19F9B300485EEE /* pdfio-base-font-widths.h */,
|
||||
273440BB263D727800FBFD63 /* pdfio-common.c */,
|
||||
271EA703265B2B1000ACDD39 /* pdfio-content.c */,
|
||||
27F2F05F2710BE92008ECD36 /* pdfio-crypto.c */,
|
||||
@ -205,6 +208,7 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
27FCBDE42D19F9B300485EEE /* pdfio-base-font-widths.h in Headers */,
|
||||
273440CC263D727800FBFD63 /* pdfio.h in Headers */,
|
||||
271EA706265B2B1000ACDD39 /* pdfio-content.h in Headers */,
|
||||
273440C3263D727800FBFD63 /* pdfio-private.h in Headers */,
|
||||
@ -256,7 +260,8 @@
|
||||
273440A8263D6FE200FBFD63 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1600;
|
||||
TargetAttributes = {
|
||||
273440AF263D6FE200FBFD63 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@ -373,9 +378,11 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@ -450,15 +457,15 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1.1.2;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
@ -486,6 +493,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -497,6 +505,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RU58A2256H;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -509,6 +518,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@ -525,6 +535,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
@ -16,7 +16,7 @@
|
||||
<copyright>Copyright © 2019-2024 by Michael R Sweet</copyright>
|
||||
<tags>pdf file native</tags>
|
||||
<dependencies>
|
||||
<dependency id="pdfio_native.redist" version="1.3.2" />
|
||||
<dependency id="pdfio_native.redist" version="1.4.0" />
|
||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>pdfio_native.redist</id>
|
||||
<title>PDFio Library for VS2019+</title>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.0</version>
|
||||
<authors>Michael R Sweet</authors>
|
||||
<owners>michaelrsweet</owners>
|
||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||
|
Reference in New Issue
Block a user