Skip to content

Commit

Permalink
Add some documentation on the code128 example.
Browse files Browse the repository at this point in the history
Clean up the code128 code a bit and use the Helvetica font for the text.

Add support for writing to a PDF file on the command-line vs. just doing
redirection.
  • Loading branch information
michaelrsweet committed Dec 16, 2024
1 parent f8639fb commit 5396755
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 14 deletions.
174 changes: 171 additions & 3 deletions doc/pdfio.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PDFio requires the following to build the software:
IDE files for Xcode (macOS/iOS) and Visual Studio (Windows) are also provided.


Installing pdfio
Installing PDFio
----------------

PDFio comes with a configure script that creates a portable makefile that will
Expand Down Expand Up @@ -315,8 +315,9 @@ Reading PDF Files
You open an existing PDF file using the [`pdfioFileOpen`](@@) function:

```c
pdfio_file_t *pdf = pdfioFileOpen("myinputfile.pdf", password_cb, password_data,
error_cb, error_data);
pdfio_file_t *pdf =
pdfioFileOpen("myinputfile.pdf", password_cb, password_data,
error_cb, error_data);

```
Expand Down Expand Up @@ -865,6 +866,7 @@ escaping, as needed:
Examples
========


Read PDF Metadata
-----------------

Expand Down Expand Up @@ -995,3 +997,169 @@ create_pdf_image_file(const char *pdfname, const char *imagename,
pdfioFileClose(pdf);
}
```


Generate a Code 128 Barcode
---------------------------

One-dimensional barcodes are often rendered using special fonts that map ASCII
characters to sequences of bars that can be read. The "examples" directory
contains such a font to create "Code 128" barcodes, with an accompanying bit of
example code.

The first thing you need to do is prepare the barcode string to use with the
font. Each barcode begins with a start pattern followed by the characters or
digits you want to encode, a weighted sum digit, and a stop pattern. The
`make_code128` function creates this string:

```c
static char * // O - Output string
make_code128(char *dst, // I - Destination buffer
const char *src, // I - Source string
size_t dstsize) // I - Size of destination buffer
{
char *dstptr, // Pointer into destination buffer
*dstend; // End of destination buffer
int sum; // Weighted sum
static const char *code128_chars = // Code 128 characters
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~\303"
"\304\305\306\307\310\311\312";
static const char code128_start_code_b = '\314';
// Start code B
static const char code128_stop = '\316';
// Stop pattern


// Start a Code B barcode...
dstptr = dst;
dstend = dst + dstsize - 3;

*dstptr++ = code128_start_code_b;
sum = code128_start_code_b - 100;

while (*src && dstptr < dstend)
{
if (*src >= ' ' && *src < 0x7f)
{
sum += (dstptr - dst) * (*src - ' ');
*dstptr++ = *src;
}

src ++;
}

// Add the weighted sum modulo 103
*dstptr++ = code128_chars[sum % 103];

// Add the stop pattern and return...
*dstptr++ = code128_stop;
*dstptr = '\0';

return (dst);
}
```
The `main` function does the rest of the work. The barcode font is imported
using the [`pdfioFileCreateFontObjFromFile`](@@) function. We pass `false`
for the "unicode" argument since we just want the (default) ASCII encoding:
```c
barcode_font = pdfioFileCreateFontObjFromFile(pdf, "code128.ttf",
/*unicode*/false);
```

Since barcodes usually have the number or text represented by the barcode
printed underneath it, we also need a regular text font, for which we can choose
one of the standard 14 PostScript base fonts using the
[`pdfioFIleCreateFontObjFromBase`](@@) function:

```c
text_font = pdfioFileCreateFontObjFromBase(pdf, "Helvetica");
```

Once we have these fonts we can measure the barcode and regular text labels
using the [`pdfioContentTextMeasure`](@@) function to determine how large the
PDF page needs to be to hold the barcode and text:

```c
// Compute sizes of the text...
const char *barcode = argv[1];
char barcode_temp[256];

if (!(barcode[0] & 0x80))
barcode = make_code128(barcode_temp, barcode, sizeof(barcode_temp));

double barcode_height = 36.0;
double barcode_width =
pdfioContentTextMeasure(barcode_font, barcode, barcode_height);

const char *text = argv[2];
double text_height = 0.0;
double text_width = 0.0;

if (text && text_font)
{
text_height = 9.0;
text_width = pdfioContentTextMeasure(text_font, text,
text_height);
}

// Compute the size of the PDF page...
pdfio_rect_t media_box;

media_box.x1 = 0.0;
media_box.y1 = 0.0;
media_box.x2 = (barcode_width > text_width ?
barcode_width : text_width) + 18.0;
media_box.y2 = barcode_height + text_height + 18.0;
```
Finally, we just need to create a page of the specified size that references the
two fonts:
```c
// Start a page for the barcode...
page_dict = pdfioDictCreate(pdf);
pdfioDictSetRect(page_dict, "MediaBox", &media_box);
pdfioDictSetRect(page_dict, "CropBox", &media_box);
pdfioPageDictAddFont(page_dict, "B128", barcode_font);
if (text_font)
pdfioPageDictAddFont(page_dict, "TEXT", text_font);
page_st = pdfioFileCreatePage(pdf, page_dict);
```

With the barcode font called "B128" and the text font called "TEXT", we can
use them to draw two strings:

```c
// Draw the page...
pdfioContentSetFillColorGray(page_st, 0.0);

pdfioContentSetTextFont(page_st, "B128", barcode_height);
pdfioContentTextBegin(page_st);
pdfioContentTextMoveTo(page_st, 0.5 * (media_box.x2 - barcode_width),
9.0 + text_height);
pdfioContentTextShow(page_st, /*unicode*/false, barcode);
pdfioContentTextEnd(page_st);

if (text && text_font)
{
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*/false, text);
pdfioContentTextEnd(page_st);
}

pdfioStreamClose(page_st);
```
Convert Markdown to PDF
-----------------------
11 changes: 5 additions & 6 deletions examples/code128.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
19 changes: 14 additions & 5 deletions examples/md2pdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -262,9 +263,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);
}

Expand All @@ -289,13 +291,20 @@ main(int argc, // I - Number of command-line arguments

dd.title = mmdGetMetadata(doc, "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);
Expand Down

0 comments on commit 5396755

Please sign in to comment.