use of org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState in project pdfbox by apache.
the class PageDrawer method endTextClip.
/**
* End buffering the text clipping path, if any.
*/
private void endTextClip() {
PDGraphicsState state = getGraphicsState();
RenderingMode renderingMode = state.getTextState().getRenderingMode();
// apply the buffered clip as one area
if (renderingMode.isClip() && !textClippings.isEmpty()) {
// PDFBOX-4150: this is much faster than using textClippingArea.add(new Area(glyph))
// https://stackoverflow.com/questions/21519007/fast-union-of-shapes-in-java
GeneralPath path = new GeneralPath();
for (Shape shape : textClippings) {
path.append(shape, false);
}
state.intersectClippingPath(path);
textClippings = new ArrayList<>();
// PDFBOX-3681: lastClip needs to be reset, because after intersection it is still the same
// object, thus setClip() would believe that it is cached.
lastClip = null;
}
}
use of org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState in project pdfbox by apache.
the class LegacyPDFStreamEngine method showGlyph.
/**
* This method was originally written by Ben Litchfield for PDFStreamEngine.
*/
@Override
protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode, Vector displacement) throws IOException {
//
// legacy calculations which were previously in PDFStreamEngine
//
// DO NOT USE THIS CODE UNLESS YOU ARE WORKING WITH PDFTextStripper.
// THIS CODE IS DELIBERATELY INCORRECT
//
PDGraphicsState state = getGraphicsState();
Matrix ctm = state.getCurrentTransformationMatrix();
float fontSize = state.getTextState().getFontSize();
float horizontalScaling = state.getTextState().getHorizontalScaling() / 100f;
Matrix textMatrix = getTextMatrix();
BoundingBox bbox = font.getBoundingBox();
if (bbox.getLowerLeftY() < Short.MIN_VALUE) {
// PDFBOX-2158 and PDFBOX-3130
// files by Salmat eSolutions / ClibPDF Library
bbox.setLowerLeftY(-(bbox.getLowerLeftY() + 65536));
}
// 1/2 the bbox is used as the height todo: why?
float glyphHeight = bbox.getHeight() / 2;
// sometimes the bbox has very high values, but CapHeight is OK
PDFontDescriptor fontDescriptor = font.getFontDescriptor();
if (fontDescriptor != null) {
float capHeight = fontDescriptor.getCapHeight();
if (Float.compare(capHeight, 0) != 0 && (capHeight < glyphHeight || Float.compare(glyphHeight, 0) == 0)) {
glyphHeight = capHeight;
}
}
// transformPoint from glyph space -> text space
float height;
if (font instanceof PDType3Font) {
height = font.getFontMatrix().transformPoint(0, glyphHeight).y;
} else {
height = glyphHeight / 1000;
}
float displacementX = displacement.getX();
// calculate our own
if (font.isVertical()) {
displacementX = font.getWidth(code) / 1000;
// there may be an additional scaling factor for true type fonts
TrueTypeFont ttf = null;
if (font instanceof PDTrueTypeFont) {
ttf = ((PDTrueTypeFont) font).getTrueTypeFont();
} else if (font instanceof PDType0Font) {
PDCIDFont cidFont = ((PDType0Font) font).getDescendantFont();
if (cidFont instanceof PDCIDFontType2) {
ttf = ((PDCIDFontType2) cidFont).getTrueTypeFont();
}
}
if (ttf != null && ttf.getUnitsPerEm() != 1000) {
displacementX *= 1000f / ttf.getUnitsPerEm();
}
}
//
// legacy calculations which were previously in PDFStreamEngine
//
// DO NOT USE THIS CODE UNLESS YOU ARE WORKING WITH PDFTextStripper.
// THIS CODE IS DELIBERATELY INCORRECT
//
// (modified) combined displacement, this is calculated *without* taking the character
// spacing and word spacing into account, due to legacy code in TextStripper
float tx = displacementX * fontSize * horizontalScaling;
float ty = displacement.getY() * fontSize;
// (modified) combined displacement matrix
Matrix td = Matrix.getTranslateInstance(tx, ty);
// (modified) text rendering matrix
// text space -> device space
Matrix nextTextRenderingMatrix = td.multiply(textMatrix).multiply(ctm);
float nextX = nextTextRenderingMatrix.getTranslateX();
float nextY = nextTextRenderingMatrix.getTranslateY();
// (modified) width and height calculations
float dxDisplay = nextX - textRenderingMatrix.getTranslateX();
float dyDisplay = height * textRenderingMatrix.getScalingFactorY();
//
// start of the original method
//
// Note on variable names. There are three different units being used in this code.
// Character sizes are given in glyph units, text locations are initially given in text
// units, and we want to save the data in display units. The variable names should end with
// Text or Disp to represent if the values are in text or disp units (no glyph units are
// saved).
float glyphSpaceToTextSpaceFactor = 1 / 1000f;
if (font instanceof PDType3Font) {
glyphSpaceToTextSpaceFactor = font.getFontMatrix().getScaleX();
}
float spaceWidthText = 0;
try {
// to avoid crash as described in PDFBOX-614, see what the space displacement should be
spaceWidthText = font.getSpaceWidth() * glyphSpaceToTextSpaceFactor;
} catch (Exception exception) {
LOG.warn(exception, exception);
}
if (Float.compare(spaceWidthText, 0) == 0) {
spaceWidthText = font.getAverageFontWidth() * glyphSpaceToTextSpaceFactor;
// the average space width appears to be higher than necessary so make it smaller
spaceWidthText *= .80f;
}
if (Float.compare(spaceWidthText, 0) == 0) {
// if could not find font, use a generic value
spaceWidthText = 1.0f;
}
// the space width has to be transformed into display units
float spaceWidthDisplay = spaceWidthText * textRenderingMatrix.getScalingFactorX();
// use our additional glyph list for Unicode mapping
unicode = font.toUnicode(code, glyphList);
// this, which is why we leave it until this point in PDFTextStreamEngine.
if (unicode == null) {
if (font instanceof PDSimpleFont) {
char c = (char) code;
unicode = new String(new char[] { c });
} else {
// skips them. See the "allah2.pdf" TestTextStripper file.
return;
}
}
// adjust for cropbox if needed
Matrix translatedTextRenderingMatrix;
if (translateMatrix == null) {
translatedTextRenderingMatrix = textRenderingMatrix;
} else {
translatedTextRenderingMatrix = Matrix.concatenate(translateMatrix, textRenderingMatrix);
nextX -= pageSize.getLowerLeftX();
nextY -= pageSize.getLowerLeftY();
}
processTextPosition(new TextPosition(pageRotation, pageSize.getWidth(), pageSize.getHeight(), translatedTextRenderingMatrix, nextX, nextY, Math.abs(dyDisplay), dxDisplay, Math.abs(spaceWidthDisplay), unicode, new int[] { code }, font, fontSize, (int) (fontSize * textMatrix.getScalingFactorX())));
}
use of org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState in project pdfbox by apache.
the class PDFStreamEngine method processAnnotation.
/**
* Process the given annotation with the specified appearance stream.
*
* @param annotation The annotation containing the appearance stream to process.
* @param appearance The appearance stream to process.
* @throws IOException If there is an error reading or parsing the appearance content stream.
*/
protected void processAnnotation(PDAnnotation annotation, PDAppearanceStream appearance) throws IOException {
PDResources parent = pushResources(appearance);
Stack<PDGraphicsState> savedStack = saveGraphicsStack();
PDRectangle bbox = appearance.getBBox();
PDRectangle rect = annotation.getRectangle();
Matrix matrix = appearance.getMatrix();
// zero-sized rectangles are not valid
if (rect != null && rect.getWidth() > 0 && rect.getHeight() > 0 && bbox != null) {
// transformed appearance box fixme: may be an arbitrary shape
Rectangle2D transformedBox = bbox.transform(matrix).getBounds2D();
// compute a matrix which scales and translates the transformed appearance box to align
// with the edges of the annotation's rectangle
Matrix a = Matrix.getTranslateInstance(rect.getLowerLeftX(), rect.getLowerLeftY());
a.concatenate(Matrix.getScaleInstance((float) (rect.getWidth() / transformedBox.getWidth()), (float) (rect.getHeight() / transformedBox.getHeight())));
a.concatenate(Matrix.getTranslateInstance((float) -transformedBox.getX(), (float) -transformedBox.getY()));
// Matrix shall be concatenated with A to form a matrix AA that maps from the appearance's
// coordinate system to the annotation's rectangle in default user space
//
// HOWEVER only the opposite order works for rotated pages with
// filled fields / annotations that have a matrix in the appearance stream, see PDFBOX-3083
Matrix aa = Matrix.concatenate(a, matrix);
// make matrix AA the CTM
getGraphicsState().setCurrentTransformationMatrix(aa);
// clip to bounding box
clipToRect(bbox);
// needed for patterns in appearance streams, e.g. PDFBOX-2182
initialMatrix = aa.clone();
processStreamOperators(appearance);
}
restoreGraphicsStack(savedStack);
popResources(parent);
}
use of org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState in project pdfbox by apache.
the class PDFStreamEngine method processTransparencyGroup.
/**
* Processes a transparency group stream.
* @param group
* @throws IOException
*/
protected void processTransparencyGroup(PDTransparencyGroup group) throws IOException {
if (currentPage == null) {
throw new IllegalStateException("No current page, call " + "#processChildStream(PDContentStream, PDPage) instead");
}
PDResources parent = pushResources(group);
Stack<PDGraphicsState> savedStack = saveGraphicsStack();
Matrix parentMatrix = initialMatrix;
// the stream's initial matrix includes the parent CTM, e.g. this allows a scaled form
initialMatrix = getGraphicsState().getCurrentTransformationMatrix().clone();
// transform the CTM using the stream's matrix
getGraphicsState().getCurrentTransformationMatrix().concatenate(group.getMatrix());
// Before execution of the transparency group XObject’s content stream,
// the current blend mode in the graphics state shall be initialized to Normal,
// the current stroking and nonstroking alpha constants to 1.0, and the current soft mask to None.
getGraphicsState().setBlendMode(BlendMode.NORMAL);
getGraphicsState().setAlphaConstant(1);
getGraphicsState().setNonStrokeAlphaConstant(1);
getGraphicsState().setSoftMask(null);
// clip to bounding box
clipToRect(group.getBBox());
processStreamOperators(group);
initialMatrix = parentMatrix;
restoreGraphicsStack(savedStack);
popResources(parent);
}
use of org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState in project pdfbox by apache.
the class PDFStreamEngine method processType3Stream.
/**
* Processes a Type 3 character stream.
*
* @param charProc Type 3 character procedure
* @param textRenderingMatrix the Text Rendering Matrix
* @throws IOException if there is an error reading or parsing the character content stream.
*/
protected void processType3Stream(PDType3CharProc charProc, Matrix textRenderingMatrix) throws IOException {
if (currentPage == null) {
throw new IllegalStateException("No current page, call " + "#processChildStream(PDContentStream, PDPage) instead");
}
PDResources parent = pushResources(charProc);
Stack<PDGraphicsState> savedStack = saveGraphicsStack();
// replace the CTM with the TRM
getGraphicsState().setCurrentTransformationMatrix(textRenderingMatrix);
// transform the CTM using the stream's matrix (this is the FontMatrix)
getGraphicsState().getCurrentTransformationMatrix().concatenate(charProc.getMatrix());
// note: we don't clip to the BBox as it is often wrong, see PDFBOX-1917
// save text matrices (Type 3 stream may contain BT/ET, see PDFBOX-2137)
Matrix textMatrixOld = textMatrix;
textMatrix = new Matrix();
Matrix textLineMatrixOld = textLineMatrix;
textLineMatrix = new Matrix();
processStreamOperators(charProc);
// restore text matrices
textMatrix = textMatrixOld;
textLineMatrix = textLineMatrixOld;
restoreGraphicsStack(savedStack);
popResources(parent);
}
Aggregations