Example usage for org.apache.pdfbox.pdmodel.font PDFont getFontMatrix

List of usage examples for org.apache.pdfbox.pdmodel.font PDFont getFontMatrix

Introduction

In this page you can find the example usage for org.apache.pdfbox.pdmodel.font PDFont getFontMatrix.

Prototype

@Override
    public Matrix getFontMatrix() 

Source Link

Usage

From source file:com.repeatability.pdf.PDFTextStreamEngine.java

License:Apache License

/**
 * This method was originally written by Ben Litchfield for PDFStreamEngine.
 *//* w w w.  java 2s.  c  o m*/
@Override
protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode, Vector displacement)
        throws IOException {
    //
    // legacy calculations which were previously in PDFStreamEngine
    //

    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 (capHeight != 0 && capHeight < glyphHeight) {
            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();
    // the sorting algorithm is based on the width of the character. As the displacement
    // for vertical characters doesn't provide any suitable value for it, we have to 
    // 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();
        }
    }
    // (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
    Matrix nextTextRenderingMatrix = td.multiply(textMatrix).multiply(ctm); // text space -> device space
    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 (Throwable exception) {
        LOG.warn(exception, exception);
    }

    if (spaceWidthText == 0) {
        spaceWidthText = font.getAverageFontWidth() * glyphSpaceToTextSpaceFactor;
        // the average space width appears to be higher than necessary so make it smaller
        spaceWidthText *= .80f;
    }
    if (spaceWidthText == 0) {
        spaceWidthText = 1.0f; // if could not find font, use a generic value
    }

    // 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);

    // when there is no Unicode mapping available, Acrobat simply coerces the character code
    // into Unicode, so we do the same. Subclasses of PDFStreamEngine don't necessarily want
    // 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 {
            // Acrobat doesn't seem to coerce composite font's character codes, instead it
            // 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, dyDisplay, dxDisplay, spaceWidthDisplay, unicode,
            new int[] { code }, font, fontSize, (int) (fontSize * textMatrix.getScalingFactorX())));
}

From source file:com.trollworks.gcs.pdfview.PdfRenderer.java

License:Open Source License

@Override
protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
    text = text.toLowerCase();/*w w  w  .  j  a va  2  s .  c o m*/
    int index = text.indexOf(mTextToHighlight);
    if (index != -1) {
        PDPage currentPage = getCurrentPage();
        PDRectangle pageBoundingBox = currentPage.getBBox();
        AffineTransform flip = new AffineTransform();
        flip.translate(0, pageBoundingBox.getHeight());
        flip.scale(1, -1);
        PDRectangle mediaBox = currentPage.getMediaBox();
        float mediaHeight = mediaBox.getHeight();
        float mediaWidth = mediaBox.getWidth();
        int size = textPositions.size();
        while (index != -1) {
            int last = index + mTextToHighlight.length() - 1;
            for (int i = index; i <= last; i++) {
                TextPosition pos = textPositions.get(i);
                PDFont font = pos.getFont();
                BoundingBox bbox = font.getBoundingBox();
                Rectangle2D.Float rect = new Rectangle2D.Float(0, bbox.getLowerLeftY(),
                        font.getWidth(pos.getCharacterCodes()[0]), bbox.getHeight());
                AffineTransform at = pos.getTextMatrix().createAffineTransform();
                if (font instanceof PDType3Font) {
                    at.concatenate(font.getFontMatrix().createAffineTransform());
                } else {
                    at.scale(1 / 1000f, 1 / 1000f);
                }
                Shape shape = flip.createTransformedShape(at.createTransformedShape(rect));
                AffineTransform transform = mGC.getTransform();
                int rotation = currentPage.getRotation();
                if (rotation != 0) {
                    switch (rotation) {
                    case 90:
                        mGC.translate(mediaHeight, 0);
                        break;
                    case 270:
                        mGC.translate(0, mediaWidth);
                        break;
                    case 180:
                        mGC.translate(mediaWidth, mediaHeight);
                        break;
                    default:
                        break;
                    }
                    mGC.rotate(Math.toRadians(rotation));
                }
                mGC.fill(shape);
                if (rotation != 0) {
                    mGC.setTransform(transform);
                }
            }
            index = last < size - 1 ? text.indexOf(mTextToHighlight, last + 1) : -1;
        }
    }
}

From source file:com.yiyihealth.tools.test.DrawPrintTextLocations.java

License:Apache License

private Shape calculateGlyphBounds(Matrix textRenderingMatrix, PDFont font, int code) throws IOException {
    GeneralPath path = null;//from   w w  w .  j a va  2  s  . c  o m
    AffineTransform at = textRenderingMatrix.createAffineTransform();
    at.concatenate(font.getFontMatrix().createAffineTransform());
    if (font instanceof PDType3Font) {
        PDType3Font t3Font = (PDType3Font) font;
        PDType3CharProc charProc = t3Font.getCharProc(code);
        if (charProc != null) {
            PDRectangle glyphBBox = charProc.getGlyphBBox();
            if (glyphBBox != null) {
                path = glyphBBox.toGeneralPath();
            }
        }
    } else if (font instanceof PDVectorFont) {
        PDVectorFont vectorFont = (PDVectorFont) font;
        path = vectorFont.getPath(code);

        if (font instanceof PDTrueTypeFont) {
            PDTrueTypeFont ttFont = (PDTrueTypeFont) font;
            int unitsPerEm = ttFont.getTrueTypeFont().getHeader().getUnitsPerEm();
            at.scale(1000d / unitsPerEm, 1000d / unitsPerEm);
        }
        if (font instanceof PDType0Font) {
            PDType0Font t0font = (PDType0Font) font;
            if (t0font.getDescendantFont() instanceof PDCIDFontType2) {
                int unitsPerEm = ((PDCIDFontType2) t0font.getDescendantFont()).getTrueTypeFont().getHeader()
                        .getUnitsPerEm();
                at.scale(1000d / unitsPerEm, 1000d / unitsPerEm);
            }
        }
    } else if (font instanceof PDSimpleFont) {
        PDSimpleFont simpleFont = (PDSimpleFont) font;

        // these two lines do not always work, e.g. for the TT fonts in file 032431.pdf
        // which is why PDVectorFont is tried first.
        String name = simpleFont.getEncoding().getName(code);
        path = simpleFont.getPath(name);
    } else {
        // shouldn't happen, please open issue in JIRA
        System.out.println("Unknown font class: " + font.getClass());
    }
    if (path == null) {
        return null;
    }
    return at.createTransformedShape(path.getBounds2D());
}

From source file:com.yiyihealth.tools.test.DrawPrintTextLocations.java

License:Apache License

/**
 * Override the default functionality of PDFTextStripper.
 *//*from w  w w  .  j a  v  a  2  s .  c  o m*/
@Override
protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
    for (TextPosition text : textPositions) {
        System.out.println("String[" + text.getXDirAdj() + "," + text.getYDirAdj() + " fs=" + text.getFontSize()
                + " xscale=" + text.getXScale() + " height=" + text.getHeightDir() + " space="
                + text.getWidthOfSpace() + " width=" + text.getWidthDirAdj() + "]" + text.getUnicode());

        // in red:
        // show rectangles with the "height" (not a real height, but used for text extraction 
        // heuristics, it is 1/2 of the bounding box height and starts at y=0)
        Rectangle2D.Float rect = new Rectangle2D.Float(text.getXDirAdj(),
                (text.getYDirAdj() - text.getHeightDir()), text.getWidthDirAdj(), text.getHeightDir());
        g2d.setColor(Color.red);
        g2d.draw(rect);

        // in blue:
        // show rectangle with the real vertical bounds, based on the font bounding box y values
        // usually, the height is identical to what you see when marking text in Adobe Reader
        PDFont font = text.getFont();
        BoundingBox bbox = font.getBoundingBox();

        // advance width, bbox height (glyph space)
        float xadvance = font.getWidth(text.getCharacterCodes()[0]); // todo: should iterate all chars
        rect = new Rectangle2D.Float(0, bbox.getLowerLeftY(), xadvance, bbox.getHeight());

        // glyph space -> user space
        // note: text.getTextMatrix() is *not* the Text Matrix, it's the Text Rendering Matrix
        AffineTransform at = text.getTextMatrix().createAffineTransform();
        if (font instanceof PDType3Font) {
            // bbox and font matrix are unscaled
            at.concatenate(font.getFontMatrix().createAffineTransform());
        } else {
            // bbox and font matrix are already scaled to 1000
            at.scale(1 / 1000f, 1 / 1000f);
        }
        Shape s = at.createTransformedShape(rect);

        s = flipAT.createTransformedShape(s);
        s = rotateAT.createTransformedShape(s);

        g2d.setColor(Color.blue);
        g2d.draw(s);
    }
}

From source file:edu.ist.psu.sagnik.research.pdfbox2playground.javatest.DrawPrintTextLocations.java

License:Apache License

/**
 * Override the default functionality of PDFTextStripper.
 *///from   www .  j ava2 s.c o m
@Override
protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
    for (TextPosition text : textPositions) {
        System.out.println("String[" + text.getXDirAdj() + "," + text.getYDirAdj() + " fs=" + text.getFontSize()
                + " xscale=" + text.getXScale() + " height=" + text.getHeightDir() + " space="
                + text.getWidthOfSpace() + " width=" + text.getWidthDirAdj() + "]" + text.getUnicode());

        // in red:
        // show rectangles with the "height" (not a real height, but used for text extraction
        // heuristics, it is 1/2 of the bounding box height and starts at y=0)
        Rectangle2D.Float rect = new Rectangle2D.Float(text.getXDirAdj(),
                (text.getYDirAdj() - text.getHeightDir()), text.getWidthDirAdj(), text.getHeightDir());
        g2d.setColor(Color.red);
        g2d.draw(rect);

        // in blue:
        // show rectangle with the real vertical bounds, based on the font bounding box y values
        // usually, the height is identical to what you see when marking text in Adobe Reader
        PDFont font = text.getFont();
        BoundingBox bbox = font.getBoundingBox();

        // advance width, bbox height (glyph space)
        float xadvance = font.getWidth(text.getCharacterCodes()[0]); // todo: should iterate all chars
        rect = new Rectangle2D.Float(0, bbox.getLowerLeftY(), xadvance, bbox.getHeight());

        // glyph space -> user space
        // note: text.getTextMatrix() is *not* the Text Matrix, it's the Text Rendering Matrix
        AffineTransform at = text.getTextMatrix().createAffineTransform();
        if (font instanceof PDType3Font) {
            // bbox and font matrix are unscaled
            at.concatenate(font.getFontMatrix().createAffineTransform());
        } else {
            // bbox and font matrix are already scaled to 1000
            at.scale(1 / 1000f, 1 / 1000f);
        }
        Shape s = at.createTransformedShape(rect);

        s = flipAT.createTransformedShape(s);
        s = rotateAT.createTransformedShape(s);

        g2d.setColor(Color.blue);
        g2d.draw(s);
    }
}

From source file:org.elacin.pdfextract.datasource.pdfbox.PDFBoxIntegration.java

License:Apache License

/**
 * Old version/*from w  w w. j av a  2s  .c  o m*/
 */
public void processEncodedText(@NotNull byte[] string) throws IOException {

    /*
     *  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).
     */
    final float fontSizeText = getGraphicsState().getTextState().getFontSize();
    final float horizontalScalingText = getGraphicsState().getTextState().getHorizontalScalingPercent() / 100f;

    // float verticalScalingText = horizontalScaling;//not sure if this is right but what else to
    // do???
    final float riseText = getGraphicsState().getTextState().getRise();
    final float wordSpacingText = getGraphicsState().getTextState().getWordSpacing();
    final float characterSpacingText = getGraphicsState().getTextState().getCharacterSpacing();

    /*
     *  We won't know the actual number of characters until
     * we process the byte data(could be two bytes each) but
     * it won't ever be more than string.length*2(there are some cases
     * were a single byte will result in two output characters "fi"
     */
    final PDFont font = getGraphicsState().getTextState().getFont();

    /*
     *  This will typically be 1000 but in the case of a type3 font this might be a different
     * number
     */
    final float glyphSpaceToTextSpaceFactor;

    if (font instanceof PDType3Font) {
        PDMatrix fontMatrix = font.getFontMatrix();
        float fontMatrixXScaling = fontMatrix.getValue(0, 0);

        glyphSpaceToTextSpaceFactor = 1.0f / fontMatrixXScaling;
    } else {
        glyphSpaceToTextSpaceFactor = /* 1.0f / */ 1000f;
    }

    float spaceWidthText = 0.0F;

    try {
        spaceWidthText = (font.getFontWidth(SPACE_BYTES, 0, 1) / glyphSpaceToTextSpaceFactor);
    } catch (Throwable exception) {
        log.warn(exception, exception);
    }

    if (spaceWidthText == 0.0F) {
        spaceWidthText = (font.getAverageFontWidth() / glyphSpaceToTextSpaceFactor);
        spaceWidthText *= .80f;
    }

    /* Convert textMatrix to display units */
    final Matrix initialMatrix = new Matrix();

    initialMatrix.setValue(0, 0, 1.0F);
    initialMatrix.setValue(0, 1, 0.0F);
    initialMatrix.setValue(0, 2, 0.0F);
    initialMatrix.setValue(1, 0, 0.0F);
    initialMatrix.setValue(1, 1, 1.0F);
    initialMatrix.setValue(1, 2, 0.0F);
    initialMatrix.setValue(2, 0, 0.0F);
    initialMatrix.setValue(2, 1, riseText);
    initialMatrix.setValue(2, 2, 1.0F);

    final Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
    final Matrix dispMatrix = initialMatrix.multiply(ctm);
    Matrix textMatrixStDisp = getTextMatrix().multiply(dispMatrix);
    final float xScaleDisp = textMatrixStDisp.getXScale();
    final float yScaleDisp = textMatrixStDisp.getYScale();
    final float spaceWidthDisp = spaceWidthText * xScaleDisp * fontSizeText;
    final float wordSpacingDisp = wordSpacingText * xScaleDisp * fontSizeText;
    float maxVerticalDisplacementText = 0.0F;
    StringBuilder characterBuffer = new StringBuilder(string.length);
    int codeLength = 1;

    for (int i = 0; i < string.length; i += codeLength) {

        // Decode the value to a Unicode character
        codeLength = 1;

        String c = font.encode(string, i, codeLength);

        if ((c == null) && (i + 1 < string.length)) {

            // maybe a multibyte encoding
            codeLength++;
            c = font.encode(string, i, codeLength);
        }

        c = inspectFontEncoding(c);

        // todo, handle horizontal displacement
        // get the width and height of this character in text units
        float fontWidth = font.getFontWidth(string, i, codeLength) * 0.95f;

        if (fontWidth == 0.0f) {
            fontWidth = spaceWidthDisp;
        }

        float characterHorizontalDisplacementText = (fontWidth / glyphSpaceToTextSpaceFactor);

        maxVerticalDisplacementText = Math.max(maxVerticalDisplacementText,
                font.getFontHeight(string, i, codeLength) / glyphSpaceToTextSpaceFactor);

        if (maxVerticalDisplacementText <= 0.0f) {
            maxVerticalDisplacementText = font.getFontBoundingBox().getHeight() / glyphSpaceToTextSpaceFactor;
        }

        /**
         * PDF Spec - 5.5.2 Word Spacing
         *
         * Word spacing works the same was as character spacing, but applies
         * only to the space character, code 32.
         *
         * Note: Word spacing is applied to every occurrence of the single-byte
         * character code 32 in a string.  This can occur when using a simple
         * font or a composite font that defines code 32 as a single-byte code.
         * It does not apply to occurrences of the byte value 32 in multiple-byte
         * codes.
         *
         * RDD - My interpretation of this is that only character code 32's that
         * encode to spaces should have word spacing applied.  Cases have been
         * observed where a font has a space character with a character code
         * other than 32, and where word spacing (Tw) was used.  In these cases,
         * applying word spacing to either the non-32 space or to the character
         * code 32 non-space resulted in errors consistent with this interpretation.
         */
        float spacingText = characterSpacingText;

        if ((string[i] == (byte) 0x20) && (codeLength == 1)) {
            spacingText += wordSpacingText;
        }

        /*
         *  The text matrix gets updated after each glyph is placed.  The updated
         *          version will have the X and Y coordinates for the next glyph.
         */
        Matrix glyphMatrixStDisp = getTextMatrix().multiply(dispMatrix);

        // The adjustment will always be zero.  The adjustment as shown in the
        // TJ operator will be handled separately.
        float adjustment = 0.0F;

        // TODO : tx should be set for horizontal text and ty for vertical text
        // which seems to be specified in the font (not the direction in the matrix).
        float tx = ((characterHorizontalDisplacementText - adjustment / glyphSpaceToTextSpaceFactor)
                * fontSizeText) * horizontalScalingText;
        Matrix td = new Matrix();

        td.setValue(2, 0, tx);

        float ty = 0.0F;

        td.setValue(2, 1, ty);
        setTextMatrix(td.multiply(getTextMatrix()));

        Matrix glyphMatrixEndDisp = getTextMatrix().multiply(dispMatrix);
        float sx = spacingText * horizontalScalingText;
        Matrix sd = new Matrix();

        sd.setValue(2, 0, sx);

        float sy = 0.0F;

        sd.setValue(2, 1, sy);
        setTextMatrix(sd.multiply(getTextMatrix()));

        float widthText = glyphMatrixEndDisp.getXPosition() - glyphMatrixStDisp.getXPosition();

        characterBuffer.append(c);

        Matrix textMatrixEndDisp = glyphMatrixEndDisp;
        float totalVerticalDisplacementDisp = maxVerticalDisplacementText * fontSizeText * yScaleDisp;

        try {
            final ETextPosition text = new ETextPosition(page, textMatrixStDisp, textMatrixEndDisp,
                    totalVerticalDisplacementDisp, new float[] { widthText }, spaceWidthDisp,
                    characterBuffer.toString(), font, fontSizeText,
                    (int) (fontSizeText * getTextMatrix().getXScale()), wordSpacingDisp);

            correctPosition(font, string, i, c, fontSizeText, glyphSpaceToTextSpaceFactor,
                    horizontalScalingText, codeLength, text);
            processTextPosition(text);
        } catch (Exception e) {
            log.warn("LOG00570:Error adding '" + characterBuffer + "': " + e.getMessage());
        }

        textMatrixStDisp = getTextMatrix().multiply(dispMatrix);
        characterBuffer.setLength(0);
    }
}