1//========================================================================
2//
3// BBoxOutputDev.cc
4//
5// This file is licensed under the GPLv2 or later
6//
7// Copyright 2020 sgerwk <sgerwk@aol.com>
8// Copyright 2022 Oliver Sander <oliver.sander@tu-dresden.de>
9//
10//========================================================================
11
12#include <cmath>
13#include <BBoxOutputDev.h>
14#include <GfxFont.h>
15
16#define writingModeHorizontal 0
17#define writingModeVertical 1
18
19BBoxOutputDev::BBoxOutputDev() : BBoxOutputDev(true, true, true) { }
20
21BBoxOutputDev::BBoxOutputDev(bool textA, bool vectorA, bool rasterA) : BBoxOutputDev(textA, vectorA, rasterA, true) { }
22
23BBoxOutputDev::BBoxOutputDev(bool textA, bool vectorA, bool rasterA, bool lwidthA)
24{
25 hasGraphics = false;
26 text = textA;
27 vector = vectorA;
28 raster = rasterA;
29 lwidth = lwidthA;
30}
31
32double BBoxOutputDev::getX1() const
33{
34 return bb.x1;
35}
36
37double BBoxOutputDev::getY1() const
38{
39 return bb.y1;
40}
41
42double BBoxOutputDev::getX2() const
43{
44 return bb.x2;
45}
46
47double BBoxOutputDev::getY2() const
48{
49 return bb.y2;
50}
51
52double BBoxOutputDev::getHasGraphics() const
53{
54 return hasGraphics;
55}
56
57void BBoxOutputDev::endPage() { }
58
59void BBoxOutputDev::stroke(GfxState *state)
60{
61 updatePath(bbA: &bb, path: state->getPath(), state);
62}
63
64void BBoxOutputDev::fill(GfxState *state)
65{
66 updatePath(bbA: &bb, path: state->getPath(), state);
67}
68
69void BBoxOutputDev::eoFill(GfxState *state)
70{
71 updatePath(bbA: &bb, path: state->getPath(), state);
72}
73
74void BBoxOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg)
75{
76 updateImage(bbA: &bb, state);
77}
78
79void BBoxOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg)
80{
81 updateImage(bbA: &bb, state);
82}
83
84void BBoxOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, bool maskInvert, bool maskInterpolate)
85{
86 updateImage(bbA: &bb, state);
87}
88
89void BBoxOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap,
90 bool maskInterpolate)
91{
92 updateImage(bbA: &bb, state);
93}
94
95void BBoxOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, const Unicode *u, int uLen)
96{
97 double leftent, rightent, ascent, descent;
98 const double *fm, *fb;
99 double fontSize, w, adjust;
100 double fx, fy;
101
102 if (!text) {
103 return;
104 }
105
106 const GfxFont *const font = state->getFont().get();
107 if (!font) {
108 return;
109 }
110
111 if (code == (CharCode)0x20) {
112 return;
113 }
114
115 fontSize = state->getFontSize();
116
117 fb = font->getFontBBox();
118 if (font->getWMode() == writingModeHorizontal) {
119 leftent = 0;
120 rightent = 0;
121 ascent = font->getAscent();
122 descent = font->getDescent();
123 } else {
124 if (fb[0] == 0 && fb[1] == 0 && fb[2] == 0 && fb[3] == 0) {
125 leftent = -0.5;
126 rightent = 0.5;
127 } else {
128 leftent = fb[1];
129 rightent = fb[3];
130 }
131 ascent = 0;
132 descent = 0;
133 }
134
135 if (font->getType() != fontType3) {
136 adjust = 1;
137 } else {
138 // adjust font size for type3 fonts,
139 // similar to TextPage::updateFont()
140 w = ((Gfx8BitFont *)font)->getWidth(c: code);
141 adjust = w / 0.5;
142 fm = font->getFontMatrix();
143 if (fm[0] != 0) {
144 adjust *= fabs(x: fm[3] / fm[0]);
145 }
146 }
147
148 ascent *= adjust * fontSize;
149 descent *= adjust * fontSize;
150 leftent *= adjust * fontSize;
151 rightent *= adjust * fontSize;
152
153 state->textTransformDelta(x1: leftent, y1: descent, x2: &fx, y2: &fy);
154 updatePoint(bbA: &bb, x: fx + x, y: fy + y, state);
155
156 state->textTransformDelta(x1: rightent, y1: ascent, x2: &fx, y2: &fy);
157 updatePoint(bbA: &bb, x: fx + x, y: fy + y, state);
158
159 state->textTransformDelta(x1: leftent, y1: descent, x2: &fx, y2: &fy);
160 updatePoint(bbA: &bb, x: fx + x + dx, y: fy + y + dy, state);
161
162 state->textTransformDelta(x1: rightent, y1: ascent, x2: &fx, y2: &fy);
163 updatePoint(bbA: &bb, x: fx + x + dx, y: fy + y + dy, state);
164}
165
166/* update the bounding box with a new point */
167void BBoxOutputDev::updatePoint(PDFRectangle *bbA, double x, double y, const GfxState *state)
168{
169 Matrix o = { 1, 0, 0, 1, 0, 0 };
170 double tx, ty;
171 double xMin, yMin, xMax, yMax;
172
173 state->getClipBBox(xMin: &xMin, yMin: &yMin, xMax: &xMax, yMax: &yMax);
174
175 o.scale(sx: 1, sy: -1);
176 o.translate(tx: 0, ty: -state->getPageHeight());
177
178 state->transform(x1: x, y1: y, x2: &tx, y2: &ty);
179 tx = tx < xMin ? xMin : tx > xMax ? xMax : tx;
180 ty = ty < yMin ? yMin : ty > yMax ? yMax : ty;
181 o.transform(x: tx, y: ty, tx: &x, ty: &y);
182
183 if (!hasGraphics || bbA->x1 > x) {
184 bbA->x1 = x;
185 }
186 if (!hasGraphics || bbA->y1 > y) {
187 bbA->y1 = y;
188 }
189 if (!hasGraphics || bbA->x2 < x) {
190 bbA->x2 = x;
191 }
192 if (!hasGraphics || bbA->y2 < y) {
193 bbA->y2 = y;
194 }
195 hasGraphics = true;
196}
197
198/* update the bounding box with a new path */
199void BBoxOutputDev::updatePath(PDFRectangle *bbA, const GfxPath *path, const GfxState *state)
200{
201 int i, j;
202 const GfxSubpath *subpath;
203 double x, y;
204 double w;
205 if (!vector) {
206 return;
207 }
208 w = lwidth ? state->getLineWidth() : 0;
209 for (i = 0; i < path->getNumSubpaths(); i++) {
210 subpath = path->getSubpath(i);
211 for (j = 0; j < subpath->getNumPoints(); j++) {
212 x = subpath->getX(i: j);
213 y = subpath->getY(i: j);
214 updatePoint(bbA, x: x - w / 2, y: y - w / 2, state);
215 updatePoint(bbA, x: x + w / 2, y: y + w / 2, state);
216 }
217 }
218}
219
220/* update the bounding box with a new image */
221void BBoxOutputDev::updateImage(PDFRectangle *bbA, const GfxState *state)
222{
223 if (!raster) {
224 return;
225 }
226 updatePoint(bbA, x: 0, y: 1, state);
227 updatePoint(bbA, x: 1, y: 0, state);
228}
229

source code of poppler/poppler/BBoxOutputDev.cc