#include #include #include #include "pdf.h" static int failures; static void check(int cond, const char *what) { if (!cond) { printf("FAIL %s\n", what); failures++; } else { printf("ok %s\n", what); } } static void near(const char *what, double got, double want) { double d = got - want; if (d < 0) d = -d; if (d > 0.001) { printf("FAIL %s: got %.4f want %.4f\n", what, got, want); failures++; } else { printf("ok %s: %.4f\n", what, got); } } static int contains(const unsigned char *data, size_t len, const char *needle) { size_t n = strlen(needle); if (n > len) return 0; for (size_t i = 0; i + n <= len; i++) if (memcmp(data + i, needle, n) == 0) return 1; return 0; } static void put_text(struct pdf *p, const char *text, double x, double base, const char *font, double size, const char *rgb) { double w = pdf_text_width(font, size, text); pdf_text(p, x, base, font, size, rgb, text); printf("@@%s x=%.3f y=%.3f w=%.3f\n", text, x, base, w); } int main(int argc, char **argv) { struct pdf *p = pdf_new(); unsigned char *data; size_t len = 0; near("width H 10 Hello", pdf_text_width("H", 10, "Hello"), 22.78); near("width HB 12 Hello", pdf_text_width("HB", 12, "Hello"), 29.34); near("width H 12 aao", pdf_text_width("H", 12, "\xc3\xa5\xc3\xa4\xc3\xb6"), 20.016); near("width H 12 latin", pdf_text_width("H", 12, "\xc3\x85\xc3\x84\xc3\x96\xc3\xa5\xc3\xa4" "\xc3\xb6\xc3\xa9\xc3\xa1\xe2\x80\x93\xe2\x80" "\x99\xe2\x82\xac"), 74.712); near("width H 10 unmappable", pdf_text_width("H", 10, "Unmappable \xe2\x98\x83"), 65.03); near("ascent H 10", pdf_font_ascent("H", 10), 7.18); near("ascent HB 14", pdf_font_ascent("HB", 14), 10.052); near("width default font", pdf_text_width(NULL, 10, "Hello"), 22.78); near("width invalid utf8", pdf_text_width("H", 10, "\xff"), 5.56); near("width 4-byte codepoint", pdf_text_width("H", 10, "\xf0\x9f\x98\x80"), 5.56); check(pdf_text_width("H", 0, "Hello") == 0.0, "width size 0"); check(pdf_text_width("H", 10, NULL) == 0.0, "width NULL text"); check(pdf_page(p) == 0, "pdf_page"); check(pdf_page(p) == -1, "pdf_page twice rejected"); pdf_fill_rect(p, 0, 48, 595, 32, "#314c59"); pdf_fill_rect(p, 300, 300, 60, 40, "#ffffff"); pdf_line(p, 0, 80, 595, 80, 0.5, "#314c59"); pdf_line(p, 20, 100, 575, 100, 0.25, "#314c59"); put_text(p, "MAKANDRA", 20, 70, "HB", 16, "#ffffff"); put_text(p, "FAKTURA", 575 - pdf_text_width("H", 16, "FAKTURA"), 70, "H", 16, "#ffffff"); put_text(p, "Left", 20, 120, "H", 10, "#314c59"); put_text(p, "Right", 575 - pdf_text_width("H", 10, "Right"), 120, "H", 10, "#314c59"); put_text(p, "V\xc3\xa4nster", 20, 140, "H", 10, "#314c59"); put_text(p, "H\xc3\xb6ger", 575 - pdf_text_width("HB", 10, "H\xc3\xb6ger"), 140, "HB", 10, "#314c59"); put_text(p, "\xc3\x85\xc3\x84\xc3\x96\xc3\xa5\xc3\xa4\xc3\xb6\xc3\xa9" "\xc3\xa1\xe2\x80\x93\xe2\x80\x99\xe2\x82\xac", 20, 160, "H", 12, "#314c59"); put_text(p, "Col", 300, 160, "H", 10, "#314c59"); put_text(p, "Col2", 300, 180, "H", 10, "#314c59"); put_text(p, "A(B)C\\D", 20, 180, "H", 10, "#314c59"); put_text(p, "((((((((((((((((((((((((((((((((", 20, 200, "H", 8, "#314c59"); near("width 32 parens", pdf_text_width("H", 8, "(((((((((((((((((((((((((((((((("), 85.248); pdf_path(p, "M 10 10 L 90 10 C 100 10 100 60 90 60 L 10 60 Z", 450, 300, "#314c59"); pdf_path(p, "M.5.5L20 20Z", 100, 400, "#314c59"); data = pdf_finish(p, &len); check(data != NULL && len > 500, "pdf_finish bytes"); if (!data) { printf("FAIL: no data\n"); return 1; } check(memcmp(data, "%PDF-1.4", 8) == 0, "header"); check(memcmp(data + len - 6, "%%EOF\n", 6) == 0, "trailer eof"); check(memchr(data, '\0', len) == NULL, "no NUL bytes"); check(contains(data, len, "/MediaBox [0 0 595 842]"), "MediaBox"); check(contains(data, len, "/Count 1"), "page count"); check(contains(data, len, "/BaseFont /Helvetica "), "Helvetica font"); check(contains(data, len, "/BaseFont /Helvetica-Bold"), "Helvetica-Bold"); check(contains(data, len, "/Encoding /WinAnsiEncoding"), "WinAnsi"); check(contains(data, len, "/Length "), "stream length"); check(contains(data, len, "1 0 obj"), "object 1"); check(contains(data, len, "6 0 obj"), "object 6"); check(!contains(data, len, "\r"), "no CR"); if (argc > 1) { FILE *f = fopen(argv[1], "wb"); if (!f) { printf("FAIL: cannot write %s\n", argv[1]); failures++; } else { fwrite(data, 1, len, f); fclose(f); printf("wrote %s (%zu bytes)\n", argv[1], len); } } free(data); { struct pdf *e = pdf_new(); unsigned char *d; size_t n = 1; put_text(e, "no explicit pdf_page", 20, 100, "H", 10, "#000000"); d = pdf_finish(e, &n); check(d != NULL && n > 0 && memcmp(d, "%PDF-1.4", 8) == 0, "implicit page document"); check(d != NULL && memcmp(d + n - 6, "%%EOF\n", 6) == 0, "implicit page eof"); free(d); } check(pdf_finish(NULL, &len) == NULL && len == 0, "finish NULL"); if (failures) printf("%d failures\n", failures); else puts("all ok"); return failures ? 1 : 0; }