Spaces:
Running
Running
//======================================================================== | |
// | |
// BBoxOutputDev.cc | |
// | |
// This file is licensed under the GPLv2 or later | |
// | |
// Copyright 2020 sgerwk <[email protected]> | |
// Copyright 2022 Oliver Sander <[email protected]> | |
// | |
//======================================================================== | |
BBoxOutputDev::BBoxOutputDev() : BBoxOutputDev(true, true, true) { } | |
BBoxOutputDev::BBoxOutputDev(bool textA, bool vectorA, bool rasterA) : BBoxOutputDev(textA, vectorA, rasterA, true) { } | |
BBoxOutputDev::BBoxOutputDev(bool textA, bool vectorA, bool rasterA, bool lwidthA) | |
{ | |
hasGraphics = false; | |
text = textA; | |
vector = vectorA; | |
raster = rasterA; | |
lwidth = lwidthA; | |
} | |
double BBoxOutputDev::getX1() const | |
{ | |
return bb.x1; | |
} | |
double BBoxOutputDev::getY1() const | |
{ | |
return bb.y1; | |
} | |
double BBoxOutputDev::getX2() const | |
{ | |
return bb.x2; | |
} | |
double BBoxOutputDev::getY2() const | |
{ | |
return bb.y2; | |
} | |
double BBoxOutputDev::getHasGraphics() const | |
{ | |
return hasGraphics; | |
} | |
void BBoxOutputDev::endPage() { } | |
void BBoxOutputDev::stroke(GfxState *state) | |
{ | |
updatePath(&bb, state->getPath(), state); | |
} | |
void BBoxOutputDev::fill(GfxState *state) | |
{ | |
updatePath(&bb, state->getPath(), state); | |
} | |
void BBoxOutputDev::eoFill(GfxState *state) | |
{ | |
updatePath(&bb, state->getPath(), state); | |
} | |
void BBoxOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) | |
{ | |
updateImage(&bb, state); | |
} | |
void BBoxOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) | |
{ | |
updateImage(&bb, state); | |
} | |
void 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) | |
{ | |
updateImage(&bb, state); | |
} | |
void BBoxOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap, | |
bool maskInterpolate) | |
{ | |
updateImage(&bb, state); | |
} | |
void 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) | |
{ | |
double leftent, rightent, ascent, descent; | |
const double *fm, *fb; | |
double fontSize, w, adjust; | |
double fx, fy; | |
if (!text) { | |
return; | |
} | |
const GfxFont *const font = state->getFont().get(); | |
if (!font) { | |
return; | |
} | |
if (code == (CharCode)0x20) { | |
return; | |
} | |
fontSize = state->getFontSize(); | |
fb = font->getFontBBox(); | |
if (font->getWMode() == writingModeHorizontal) { | |
leftent = 0; | |
rightent = 0; | |
ascent = font->getAscent(); | |
descent = font->getDescent(); | |
} else { | |
if (fb[0] == 0 && fb[1] == 0 && fb[2] == 0 && fb[3] == 0) { | |
leftent = -0.5; | |
rightent = 0.5; | |
} else { | |
leftent = fb[1]; | |
rightent = fb[3]; | |
} | |
ascent = 0; | |
descent = 0; | |
} | |
if (font->getType() != fontType3) { | |
adjust = 1; | |
} else { | |
// adjust font size for type3 fonts, | |
// similar to TextPage::updateFont() | |
w = ((Gfx8BitFont *)font)->getWidth(code); | |
adjust = w / 0.5; | |
fm = font->getFontMatrix(); | |
if (fm[0] != 0) { | |
adjust *= fabs(fm[3] / fm[0]); | |
} | |
} | |
ascent *= adjust * fontSize; | |
descent *= adjust * fontSize; | |
leftent *= adjust * fontSize; | |
rightent *= adjust * fontSize; | |
state->textTransformDelta(leftent, descent, &fx, &fy); | |
updatePoint(&bb, fx + x, fy + y, state); | |
state->textTransformDelta(rightent, ascent, &fx, &fy); | |
updatePoint(&bb, fx + x, fy + y, state); | |
state->textTransformDelta(leftent, descent, &fx, &fy); | |
updatePoint(&bb, fx + x + dx, fy + y + dy, state); | |
state->textTransformDelta(rightent, ascent, &fx, &fy); | |
updatePoint(&bb, fx + x + dx, fy + y + dy, state); | |
} | |
/* update the bounding box with a new point */ | |
void BBoxOutputDev::updatePoint(PDFRectangle *bbA, double x, double y, const GfxState *state) | |
{ | |
Matrix o = { 1, 0, 0, 1, 0, 0 }; | |
double tx, ty; | |
double xMin, yMin, xMax, yMax; | |
state->getClipBBox(&xMin, &yMin, &xMax, &yMax); | |
o.scale(1, -1); | |
o.translate(0, -state->getPageHeight()); | |
state->transform(x, y, &tx, &ty); | |
tx = tx < xMin ? xMin : tx > xMax ? xMax : tx; | |
ty = ty < yMin ? yMin : ty > yMax ? yMax : ty; | |
o.transform(tx, ty, &x, &y); | |
if (!hasGraphics || bbA->x1 > x) { | |
bbA->x1 = x; | |
} | |
if (!hasGraphics || bbA->y1 > y) { | |
bbA->y1 = y; | |
} | |
if (!hasGraphics || bbA->x2 < x) { | |
bbA->x2 = x; | |
} | |
if (!hasGraphics || bbA->y2 < y) { | |
bbA->y2 = y; | |
} | |
hasGraphics = true; | |
} | |
/* update the bounding box with a new path */ | |
void BBoxOutputDev::updatePath(PDFRectangle *bbA, const GfxPath *path, const GfxState *state) | |
{ | |
int i, j; | |
const GfxSubpath *subpath; | |
double x, y; | |
double w; | |
if (!vector) { | |
return; | |
} | |
w = lwidth ? state->getLineWidth() : 0; | |
for (i = 0; i < path->getNumSubpaths(); i++) { | |
subpath = path->getSubpath(i); | |
for (j = 0; j < subpath->getNumPoints(); j++) { | |
x = subpath->getX(j); | |
y = subpath->getY(j); | |
updatePoint(bbA, x - w / 2, y - w / 2, state); | |
updatePoint(bbA, x + w / 2, y + w / 2, state); | |
} | |
} | |
} | |
/* update the bounding box with a new image */ | |
void BBoxOutputDev::updateImage(PDFRectangle *bbA, const GfxState *state) | |
{ | |
if (!raster) { | |
return; | |
} | |
updatePoint(bbA, 0, 1, state); | |
updatePoint(bbA, 1, 0, state); | |
} | |