Search in sources :

Example 1 with BoundingBox

use of org.apache.fontbox.util.BoundingBox in project pdfbox by apache.

the class PDType3Font method generateBoundingBox.

private BoundingBox generateBoundingBox() {
    PDRectangle rect = getFontBBox();
    if (!isNonZeroBoundingBox(rect)) {
        // Plan B: get the max bounding box of the glyphs
        COSDictionary cp = getCharProcs();
        for (COSName name : cp.keySet()) {
            COSBase base = cp.getDictionaryObject(name);
            if (base instanceof COSStream) {
                PDType3CharProc charProc = new PDType3CharProc(this, (COSStream) base);
                try {
                    PDRectangle glyphBBox = charProc.getGlyphBBox();
                    if (glyphBBox == null) {
                        continue;
                    }
                    rect.setLowerLeftX(Math.min(rect.getLowerLeftX(), glyphBBox.getLowerLeftX()));
                    rect.setLowerLeftY(Math.min(rect.getLowerLeftY(), glyphBBox.getLowerLeftY()));
                    rect.setUpperRightX(Math.max(rect.getUpperRightX(), glyphBBox.getUpperRightX()));
                    rect.setUpperRightY(Math.max(rect.getUpperRightY(), glyphBBox.getUpperRightY()));
                } catch (IOException ex) {
                    // ignore
                    LOG.debug("error getting the glyph bounding box - font bounding box will be used", ex);
                }
            }
        }
    }
    return new BoundingBox(rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getUpperRightX(), rect.getUpperRightY());
}
Also used : COSStream(org.apache.pdfbox.cos.COSStream) COSDictionary(org.apache.pdfbox.cos.COSDictionary) COSName(org.apache.pdfbox.cos.COSName) BoundingBox(org.apache.fontbox.util.BoundingBox) COSBase(org.apache.pdfbox.cos.COSBase) PDRectangle(org.apache.pdfbox.pdmodel.common.PDRectangle) IOException(java.io.IOException)

Example 2 with BoundingBox

use of org.apache.fontbox.util.BoundingBox 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())));
}
Also used : PDTrueTypeFont(org.apache.pdfbox.pdmodel.font.PDTrueTypeFont) TrueTypeFont(org.apache.fontbox.ttf.TrueTypeFont) PDType0Font(org.apache.pdfbox.pdmodel.font.PDType0Font) PDFontDescriptor(org.apache.pdfbox.pdmodel.font.PDFontDescriptor) IOException(java.io.IOException) PDSimpleFont(org.apache.pdfbox.pdmodel.font.PDSimpleFont) SetMatrix(org.apache.pdfbox.contentstream.operator.state.SetMatrix) Matrix(org.apache.pdfbox.util.Matrix) PDType3Font(org.apache.pdfbox.pdmodel.font.PDType3Font) BoundingBox(org.apache.fontbox.util.BoundingBox) PDTrueTypeFont(org.apache.pdfbox.pdmodel.font.PDTrueTypeFont) PDCIDFontType2(org.apache.pdfbox.pdmodel.font.PDCIDFontType2) PDCIDFont(org.apache.pdfbox.pdmodel.font.PDCIDFont) PDGraphicsState(org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState)

Example 3 with BoundingBox

use of org.apache.fontbox.util.BoundingBox in project pdfbox by apache.

the class PreflightType3Stream method processOperator.

/**
 * This is used to handle an operation.
 *
 * @param operator
 *            The operation to perform.
 * @param operands
 *            The list of arguments.
 *
 * @throws IOException
 *             If there is an error processing the operation.
 */
@Override
protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
    super.processOperator(operator, operands);
    String operation = operator.getName();
    if (operation.equals("BI")) {
        image = new PDInlineImage(operator.getImageParameters(), operator.getImageData(), getResources());
        validateInlineImageFilter(operator);
        validateInlineImageColorSpace(operator);
    }
    if (operation.equals("d0")) {
        checkType3FirstOperator(operands);
    } else if (operation.equals("d1")) {
        COSNumber llx = (COSNumber) operands.get(2);
        COSNumber lly = (COSNumber) operands.get(3);
        COSNumber urx = (COSNumber) operands.get(4);
        COSNumber ury = (COSNumber) operands.get(5);
        box = new BoundingBox();
        box.setLowerLeftX(llx.floatValue());
        box.setLowerLeftY(lly.floatValue());
        box.setUpperRightX(urx.floatValue());
        box.setUpperRightY(ury.floatValue());
        checkType3FirstOperator(operands);
    }
    checkColorOperators(operation);
    validateRenderingIntent(operator, operands);
    checkSetColorSpaceOperators(operator, operands);
    validateNumberOfGraphicStates(operator);
    firstOperator = false;
}
Also used : BoundingBox(org.apache.fontbox.util.BoundingBox) COSNumber(org.apache.pdfbox.cos.COSNumber) PDInlineImage(org.apache.pdfbox.pdmodel.graphics.image.PDInlineImage)

Example 4 with BoundingBox

use of org.apache.fontbox.util.BoundingBox in project pdfbox by apache.

the class DrawPrintTextLocations method writeString.

/**
 * Override the default functionality of PDFTextStripper.
 */
@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());
        // glyph space -> user space
        // note: text.getTextMatrix() is *not* the Text Matrix, it's the Text Rendering Matrix
        AffineTransform at = text.getTextMatrix().createAffineTransform();
        // 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(0, 0, text.getWidthDirAdj() / text.getTextMatrix().getScalingFactorX(), text.getHeightDir() / text.getTextMatrix().getScalingFactorY());
        Shape s = at.createTransformedShape(rect);
        s = flipAT.createTransformedShape(s);
        s = rotateAT.createTransformedShape(s);
        g2d.setColor(Color.red);
        g2d.draw(s);
        // 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)
        // todo: should iterate all chars
        float xadvance = font.getWidth(text.getCharacterCodes()[0]);
        rect = new Rectangle2D.Float(0, bbox.getLowerLeftY(), xadvance, bbox.getHeight());
        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);
        }
        s = at.createTransformedShape(rect);
        s = flipAT.createTransformedShape(s);
        s = rotateAT.createTransformedShape(s);
        g2d.setColor(Color.blue);
        g2d.draw(s);
    }
}
Also used : PDFont(org.apache.pdfbox.pdmodel.font.PDFont) Shape(java.awt.Shape) PDType3Font(org.apache.pdfbox.pdmodel.font.PDType3Font) TextPosition(org.apache.pdfbox.text.TextPosition) BoundingBox(org.apache.fontbox.util.BoundingBox) Rectangle2D(java.awt.geom.Rectangle2D) AffineTransform(java.awt.geom.AffineTransform)

Example 5 with BoundingBox

use of org.apache.fontbox.util.BoundingBox in project pdfbox by apache.

the class AFMParser method parseCharMetric.

/**
 * This will parse a single CharMetric object from the stream.
 *
 * @return The next char metric in the stream.
 *
 * @throws IOException If there is an error reading from the stream.
 */
private CharMetric parseCharMetric() throws IOException {
    CharMetric charMetric = new CharMetric();
    String metrics = readLine();
    StringTokenizer metricsTokenizer = new StringTokenizer(metrics);
    try {
        while (metricsTokenizer.hasMoreTokens()) {
            String nextCommand = metricsTokenizer.nextToken();
            switch(nextCommand) {
                case CHARMETRICS_C:
                    String charCodeC = metricsTokenizer.nextToken();
                    charMetric.setCharacterCode(Integer.parseInt(charCodeC));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_CH:
                    // Is the hex string <FF> or FF, the spec is a little
                    // unclear, wait and see if it breaks anything.
                    String charCodeCH = metricsTokenizer.nextToken();
                    charMetric.setCharacterCode(Integer.parseInt(charCodeCH, BITS_IN_HEX));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_WX:
                    charMetric.setWx(Float.parseFloat(metricsTokenizer.nextToken()));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W0X:
                    charMetric.setW0x(Float.parseFloat(metricsTokenizer.nextToken()));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W1X:
                    charMetric.setW1x(Float.parseFloat(metricsTokenizer.nextToken()));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_WY:
                    charMetric.setWy(Float.parseFloat(metricsTokenizer.nextToken()));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W0Y:
                    charMetric.setW0y(Float.parseFloat(metricsTokenizer.nextToken()));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W1Y:
                    charMetric.setW1y(Float.parseFloat(metricsTokenizer.nextToken()));
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W:
                    float[] w = new float[2];
                    w[0] = Float.parseFloat(metricsTokenizer.nextToken());
                    w[1] = Float.parseFloat(metricsTokenizer.nextToken());
                    charMetric.setW(w);
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W0:
                    float[] w0 = new float[2];
                    w0[0] = Float.parseFloat(metricsTokenizer.nextToken());
                    w0[1] = Float.parseFloat(metricsTokenizer.nextToken());
                    charMetric.setW0(w0);
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_W1:
                    float[] w1 = new float[2];
                    w1[0] = Float.parseFloat(metricsTokenizer.nextToken());
                    w1[1] = Float.parseFloat(metricsTokenizer.nextToken());
                    charMetric.setW1(w1);
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_VV:
                    float[] vv = new float[2];
                    vv[0] = Float.parseFloat(metricsTokenizer.nextToken());
                    vv[1] = Float.parseFloat(metricsTokenizer.nextToken());
                    charMetric.setVv(vv);
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_N:
                    charMetric.setName(metricsTokenizer.nextToken());
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_B:
                    BoundingBox box = new BoundingBox();
                    box.setLowerLeftX(Float.parseFloat(metricsTokenizer.nextToken()));
                    box.setLowerLeftY(Float.parseFloat(metricsTokenizer.nextToken()));
                    box.setUpperRightX(Float.parseFloat(metricsTokenizer.nextToken()));
                    box.setUpperRightY(Float.parseFloat(metricsTokenizer.nextToken()));
                    charMetric.setBoundingBox(box);
                    verifySemicolon(metricsTokenizer);
                    break;
                case CHARMETRICS_L:
                    Ligature lig = new Ligature();
                    lig.setSuccessor(metricsTokenizer.nextToken());
                    lig.setLigature(metricsTokenizer.nextToken());
                    charMetric.addLigature(lig);
                    verifySemicolon(metricsTokenizer);
                    break;
                default:
                    throw new IOException("Unknown CharMetrics command '" + nextCommand + "'");
            }
        }
    } catch (NumberFormatException e) {
        throw new IOException("Error: Corrupt AFM document:" + e);
    }
    return charMetric;
}
Also used : StringTokenizer(java.util.StringTokenizer) BoundingBox(org.apache.fontbox.util.BoundingBox) IOException(java.io.IOException)

Aggregations

BoundingBox (org.apache.fontbox.util.BoundingBox)9 IOException (java.io.IOException)4 AffineTransform (java.awt.geom.AffineTransform)3 PDRectangle (org.apache.pdfbox.pdmodel.common.PDRectangle)3 PDType3Font (org.apache.pdfbox.pdmodel.font.PDType3Font)3 PDCIDFontType2 (org.apache.pdfbox.pdmodel.font.PDCIDFontType2)2 PDSimpleFont (org.apache.pdfbox.pdmodel.font.PDSimpleFont)2 PDTrueTypeFont (org.apache.pdfbox.pdmodel.font.PDTrueTypeFont)2 PDType0Font (org.apache.pdfbox.pdmodel.font.PDType0Font)2 Matrix (org.apache.pdfbox.util.Matrix)2 Shape (java.awt.Shape)1 GeneralPath (java.awt.geom.GeneralPath)1 Rectangle2D (java.awt.geom.Rectangle2D)1 ArrayList (java.util.ArrayList)1 StringTokenizer (java.util.StringTokenizer)1 TrueTypeFont (org.apache.fontbox.ttf.TrueTypeFont)1 SetMatrix (org.apache.pdfbox.contentstream.operator.state.SetMatrix)1 COSBase (org.apache.pdfbox.cos.COSBase)1 COSDictionary (org.apache.pdfbox.cos.COSDictionary)1 COSName (org.apache.pdfbox.cos.COSName)1