]> mj.ucw.cz Git - paperjam.git/blob - pdf-tools.h
a4004d3d8c2e03dccdf9beed4a42bc4202d15875
[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         // A*B is a matrix which transforms first by A and then by B
69         pdf_matrix operator *(pdf_matrix y)
70         {
71                 return pdf_matrix(
72                         m[0]*y.m[0] + m[1]*y.m[2],
73                         m[0]*y.m[1] + m[1]*y.m[3],
74                         m[2]*y.m[0] + m[3]*y.m[2],
75                         m[2]*y.m[1] + m[3]*y.m[3],
76                         m[4]*y.m[0] + m[5]*y.m[2] + y.m[4],
77                         m[4]*y.m[1] + m[5]*y.m[3] + y.m[5]
78                 );
79         }
80
81         void concat(pdf_matrix y)
82         {
83                 pdf_matrix t = *this * y;
84                 for (int i=0; i<6; i++)
85                         m[i] = t.m[i];
86         }
87
88         void shift(double dx, double dy)
89         {
90                 m[4] += dx;
91                 m[5] += dy;
92         }
93
94         void scale(double s)
95         {
96                 concat(pdf_matrix(s, 0, 0, s, 0, 0));
97         }
98
99         void scale(double sx, double sy)
100         {
101                 concat(pdf_matrix(sx, 0, 0, sy, 0, 0));
102         }
103
104         void rotate_rad(double angle)
105         {
106                 double c = std::cos(angle), s = std::sin(angle);
107                 concat(pdf_matrix(c, s, -s, c, 0, 0));
108         }
109
110         void rotate_deg(double angle)
111         {
112                 rotate_rad(angle/180. * M_PI);
113         }
114
115         std::string to_string();
116 };
117
118 /*** Bounding boxes ***/
119
120 struct BBox {
121         double x_min, x_max, y_min, y_max;
122         BBox() {
123                 x_min = y_min = x_max = y_max = 0;
124         }
125         BBox(double xmin, double ymin, double xmax, double ymax) {
126                 x_min = xmin, x_max = xmax;
127                 y_min = ymin, y_max = ymax;
128         }
129         BBox(double x, double y) {
130                 x_min = 0, x_max = x;
131                 y_min = 0, y_max = y;
132         }
133         BBox(QPDFObjectHandle box) {
134                 if (!parse(box)) {
135                         warn("Invalid bounding box, falling back to A4");
136                         x_min = 0, x_max = A4_WIDTH;
137                         y_min = 0, y_max = A4_HEIGHT;
138                 }
139         }
140         QPDFObjectHandle to_array();
141         double width() { return x_max - x_min; }
142         double height() { return y_max - y_min; }
143 private:
144         bool parse(QPDFObjectHandle h);
145 };
146
147 /*** Miscellaneous ***/
148
149 QPDFObjectHandle unicode_string(std::string s);
150 QPDFObjectHandle page_to_xobject(QPDF *out, QPDFObjectHandle page);
151
152 #endif
153