]> mj.ucw.cz Git - paperjam.git/blob - pdf-tools.h
Rudimentary reading and writing PDFs
[paperjam.git] / pdf-tools.h
1 /*
2  *      Auxiliary functions for processing PDF files
3  *
4  *      (c) 2018 Martin Mares <mj@ucw.cz>
5  */
6
7 #ifndef _PDF_TOOLS_H
8 #define _PDF_TOOLS_H
9
10 #include <cmath>
11 #include <string>
12
13 #include <qpdf/QPDF.hh>
14
15 /*** Basic macros and constants ***/
16
17 #define UNUSED __attribute__((unused))
18 #define FORMAT_CHECK(x,y,z) __attribute__((format(x,y,z)))
19 #define NONRET __attribute__((noreturn))
20
21 #define A4_WIDTH 595
22 #define A4_HEIGHT 842
23 static const double mm = 72/25.4;
24
25 /*** Messages ***/
26
27 void debug(const char *msg, ...) FORMAT_CHECK(printf, 1, 2);
28 void warn(const char *msg, ...) FORMAT_CHECK(printf, 1, 2);
29 void die(const char *msg, ...) FORMAT_CHECK(printf, 1, 2) NONRET;
30 void bad(const char *msg, ...) FORMAT_CHECK(printf, 1, 2) NONRET;
31
32 extern int debug_mode;
33
34 /*** Transformation matrices ***/
35
36 struct pdf_matrix {
37         /*
38          *  A transformation matrix corresponds to the linear transform
39          *
40          *            (a b 0)
41          *  (x y 1) * (c d 0) = (ax+cy+e bx+dy+f 1)
42          *            (e f 1)
43          *
44          *  We represent the non-trivial coefficients of the matrix by
45          *  an array {a,b,c,d,e,f}.
46          */
47         double m[6];
48
49         pdf_matrix() {
50                 m[0] = 1;
51                 m[1] = 0;
52                 m[2] = 0;
53                 m[3] = 1;
54                 m[4] = m[5] = 0;
55         }
56
57         pdf_matrix(double a, double b, double c, double d, double e, double f)
58         {
59                 m[0] = a;
60                 m[1] = b;
61                 m[2] = c;
62                 m[3] = d;
63                 m[4] = e;
64                 m[5] = f;
65         }
66
67         // A*B is a matrix which transforms first by A and then by B
68         pdf_matrix operator *(pdf_matrix y)
69         {
70                 return pdf_matrix(
71                         m[0]*y.m[0] + m[1]*y.m[2],
72                         m[0]*y.m[1] + m[1]*y.m[3],
73                         m[2]*y.m[0] + m[3]*y.m[2],
74                         m[2]*y.m[1] + m[3]*y.m[3],
75                         m[4]*y.m[0] + m[5]*y.m[2] + y.m[4],
76                         m[4]*y.m[1] + m[5]*y.m[3] + y.m[5]
77                 );
78         }
79
80         void concat(pdf_matrix y)
81         {
82                 pdf_matrix t = *this * y;
83                 for (int i=0; i<6; i++)
84                         m[i] = t.m[i];
85         }
86
87         void shift(double dx, double dy)
88         {
89                 m[4] += dx;
90                 m[5] += dy;
91         }
92
93         void scale(double s)
94         {
95                 concat(pdf_matrix(s, 0, 0, s, 0, 0));
96         }
97
98         void scale(double sx, double sy)
99         {
100                 concat(pdf_matrix(sx, 0, 0, sy, 0, 0));
101         }
102
103         void rotate_rad(double angle)
104         {
105                 double c = std::cos(angle), s = std::sin(angle);
106                 concat(pdf_matrix(c, s, -s, c, 0, 0));
107         }
108
109         void rotate_deg(double angle)
110         {
111                 rotate_rad(angle/180. * M_PI);
112         }
113
114         std::string to_string();
115 };
116
117 /*** Bounding boxes ***/
118
119 struct BBox {
120         double x_min, x_max, y_min, y_max;
121         BBox() {
122                 x_min = y_min = x_max = y_max = 0;
123         }
124         BBox(double xmin, double ymin, double xmax, double ymax) {
125                 x_min = xmin, x_max = xmax;
126                 y_min = ymin, y_max = ymax;
127         }
128         BBox(double x, double y) {
129                 x_min = 0, x_max = x;
130                 y_min = 0, y_max = y;
131         }
132         BBox(QPDFObjectHandle box) {
133                 if (!parse(box)) {
134                         warn("Invalid bounding box, falling back to A4");
135                         x_min = 0, x_max = A4_WIDTH;
136                         y_min = 0, y_max = A4_HEIGHT;
137                 }
138         }
139         QPDFObjectHandle to_array();
140         double width() { return x_max - x_min; }
141         double height() { return y_max - y_min; }
142 private:
143         bool parse(QPDFObjectHandle h);
144 };
145
146 /*** Miscellaneous ***/
147
148 QPDFObjectHandle unicode_string(std::string s);
149 QPDFObjectHandle page_to_xobject(QPDF *out, QPDFObjectHandle page);
150
151 #endif
152