]> mj.ucw.cz Git - paperjam.git/blob - pdf-tools.h
9563ec024ceb132c7a1fb457b83f04c8b61bada6
[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 extern int debug_indent;
34
35 /*** Transformation matrices ***/
36
37 struct pdf_matrix {
38         /*
39          *  A transformation matrix corresponds to the linear transform
40          *
41          *            (a b 0)
42          *  (x y 1) * (c d 0) = (ax+cy+e bx+dy+f 1)
43          *            (e f 1)
44          *
45          *  We represent the non-trivial coefficients of the matrix by
46          *  an array {a,b,c,d,e,f}.
47          */
48         double m[6];
49
50         pdf_matrix() {
51                 m[0] = 1;
52                 m[1] = 0;
53                 m[2] = 0;
54                 m[3] = 1;
55                 m[4] = m[5] = 0;
56         }
57
58         pdf_matrix(double a, double b, double c, double d, double e, double f)
59         {
60                 m[0] = a;
61                 m[1] = b;
62                 m[2] = c;
63                 m[3] = d;
64                 m[4] = e;
65                 m[5] = f;
66         }
67
68         void apply(double *px, double *py)
69         {
70                 double x=*px, y=*py;
71                 *px = m[0]*x + m[2]*y + m[4];
72                 *py = m[1]*x + m[3]*y + m[5];
73         }
74
75         // A*B is a matrix which transforms first by A and then by B
76         pdf_matrix operator *(pdf_matrix y)
77         {
78                 return pdf_matrix(
79                         m[0]*y.m[0] + m[1]*y.m[2],
80                         m[0]*y.m[1] + m[1]*y.m[3],
81                         m[2]*y.m[0] + m[3]*y.m[2],
82                         m[2]*y.m[1] + m[3]*y.m[3],
83                         m[4]*y.m[0] + m[5]*y.m[2] + y.m[4],
84                         m[4]*y.m[1] + m[5]*y.m[3] + y.m[5]
85                 );
86         }
87
88         void concat(pdf_matrix y)
89         {
90                 pdf_matrix t = *this * y;
91                 for (int i=0; i<6; i++)
92                         m[i] = t.m[i];
93         }
94
95         void shift(double dx, double dy)
96         {
97                 m[4] += dx;
98                 m[5] += dy;
99         }
100
101         void scale(double s)
102         {
103                 concat(pdf_matrix(s, 0, 0, s, 0, 0));
104         }
105
106         void scale(double sx, double sy)
107         {
108                 concat(pdf_matrix(sx, 0, 0, sy, 0, 0));
109         }
110
111         void rotate_rad(double angle)
112         {
113                 double c = std::cos(angle), s = std::sin(angle);
114                 concat(pdf_matrix(c, s, -s, c, 0, 0));
115         }
116
117         void rotate_deg(double angle)
118         {
119                 rotate_rad(angle/180. * M_PI);
120         }
121
122         std::string to_string();
123 };
124
125 /*** Bounding boxes ***/
126
127 struct BBox {
128         double x_min, x_max, y_min, y_max;
129         BBox() {
130                 x_min = y_min = x_max = y_max = 0;
131         }
132         BBox(double xmin, double ymin, double xmax, double ymax) {
133                 x_min = xmin, x_max = xmax;
134                 y_min = ymin, y_max = ymax;
135         }
136         BBox(double x, double y) {
137                 x_min = 0, x_max = x;
138                 y_min = 0, y_max = y;
139         }
140         BBox(QPDFObjectHandle box) {
141                 if (!parse(box)) {
142                         warn("Invalid bounding box, falling back to A4");
143                         x_min = 0, x_max = A4_WIDTH;
144                         y_min = 0, y_max = A4_HEIGHT;
145                 }
146         }
147         QPDFObjectHandle to_array();
148         string to_rect();
149         double width() { return x_max - x_min; }
150         double height() { return y_max - y_min; }
151         void transform(pdf_matrix &m);
152 private:
153         bool parse(QPDFObjectHandle h);
154 };
155
156 /*** Miscellaneous ***/
157
158 QPDFObjectHandle unicode_string(std::string s);
159 QPDFObjectHandle page_to_xobject(QPDF *out, QPDFObjectHandle page);
160
161 #endif
162