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());
}
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())));
}
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;
}
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);
}
}
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;
}
Aggregations