use of com.tom_roush.fontbox.util.BoundingBox in project PdfBox-Android by TomRoush.
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();
if (nextCommand.equals(CHARMETRICS_C)) {
String charCode = metricsTokenizer.nextToken();
charMetric.setCharacterCode(Integer.parseInt(charCode));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_CH)) {
// Is the hex string <FF> or FF, the spec is a little
// unclear, wait and see if it breaks anything.
String charCode = metricsTokenizer.nextToken();
charMetric.setCharacterCode(Integer.parseInt(charCode, BITS_IN_HEX));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_WX)) {
charMetric.setWx(Float.parseFloat(metricsTokenizer.nextToken()));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W0X)) {
charMetric.setW0x(Float.parseFloat(metricsTokenizer.nextToken()));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W1X)) {
charMetric.setW1x(Float.parseFloat(metricsTokenizer.nextToken()));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_WY)) {
charMetric.setWy(Float.parseFloat(metricsTokenizer.nextToken()));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W0Y)) {
charMetric.setW0y(Float.parseFloat(metricsTokenizer.nextToken()));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W1Y)) {
charMetric.setW1y(Float.parseFloat(metricsTokenizer.nextToken()));
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W)) {
float[] w = new float[2];
w[0] = Float.parseFloat(metricsTokenizer.nextToken());
w[1] = Float.parseFloat(metricsTokenizer.nextToken());
charMetric.setW(w);
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W0)) {
float[] w0 = new float[2];
w0[0] = Float.parseFloat(metricsTokenizer.nextToken());
w0[1] = Float.parseFloat(metricsTokenizer.nextToken());
charMetric.setW0(w0);
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_W1)) {
float[] w1 = new float[2];
w1[0] = Float.parseFloat(metricsTokenizer.nextToken());
w1[1] = Float.parseFloat(metricsTokenizer.nextToken());
charMetric.setW1(w1);
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_VV)) {
float[] vv = new float[2];
vv[0] = Float.parseFloat(metricsTokenizer.nextToken());
vv[1] = Float.parseFloat(metricsTokenizer.nextToken());
charMetric.setVv(vv);
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(CHARMETRICS_N)) {
charMetric.setName(metricsTokenizer.nextToken());
verifySemicolon(metricsTokenizer);
} else if (nextCommand.equals(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);
} else if (nextCommand.equals(CHARMETRICS_L)) {
Ligature lig = new Ligature();
lig.setSuccessor(metricsTokenizer.nextToken());
lig.setLigature(metricsTokenizer.nextToken());
charMetric.addLigature(lig);
verifySemicolon(metricsTokenizer);
} else {
throw new IOException("Unknown CharMetrics command '" + nextCommand + "'");
}
}
} catch (NumberFormatException e) {
throw new IOException("Error: Corrupt AFM document:" + e);
}
return charMetric;
}
use of com.tom_roush.fontbox.util.BoundingBox in project PdfBox-Android by TomRoush.
the class GlyphData method initData.
/**
* This will read the required data from the stream.
*
* @param glyphTable The glyph table this glyph belongs to.
* @param data The stream to read the data from.
* @param leftSideBearing The left side bearing for this glyph.
* @throws IOException If there is an error reading the data.
*/
void initData(GlyphTable glyphTable, TTFDataStream data, int leftSideBearing) throws IOException {
numberOfContours = data.readSignedShort();
xMin = data.readSignedShort();
yMin = data.readSignedShort();
xMax = data.readSignedShort();
yMax = data.readSignedShort();
boundingBox = new BoundingBox(xMin, yMin, xMax, yMax);
if (numberOfContours >= 0) {
// create a simple glyph
short x0 = (short) (leftSideBearing - xMin);
glyphDescription = new GlyfSimpleDescript(numberOfContours, data, x0);
} else {
// create a composite glyph
glyphDescription = new GlyfCompositeDescript(data, glyphTable);
}
}
use of com.tom_roush.fontbox.util.BoundingBox in project PdfBox-Android by TomRoush.
the class AFMParser method parseFontMetric.
/**
* This will parse a font metrics item.
*
* @return The parse font metrics item.
*
* @throws IOException If there is an error reading the AFM file.
*/
private FontMetrics parseFontMetric(boolean reducedDataset) throws IOException {
FontMetrics fontMetrics = new FontMetrics();
String startFontMetrics = readString();
if (!START_FONT_METRICS.equals(startFontMetrics)) {
throw new IOException("Error: The AFM file should start with " + START_FONT_METRICS + " and not '" + startFontMetrics + "'");
}
fontMetrics.setAFMVersion(readFloat());
String nextCommand;
boolean charMetricsRead = false;
while (!END_FONT_METRICS.equals((nextCommand = readString()))) {
if (FONT_NAME.equals(nextCommand)) {
fontMetrics.setFontName(readLine());
} else if (FULL_NAME.equals(nextCommand)) {
fontMetrics.setFullName(readLine());
} else if (FAMILY_NAME.equals(nextCommand)) {
fontMetrics.setFamilyName(readLine());
} else if (WEIGHT.equals(nextCommand)) {
fontMetrics.setWeight(readLine());
} else if (FONT_BBOX.equals(nextCommand)) {
BoundingBox bBox = new BoundingBox();
bBox.setLowerLeftX(readFloat());
bBox.setLowerLeftY(readFloat());
bBox.setUpperRightX(readFloat());
bBox.setUpperRightY(readFloat());
fontMetrics.setFontBBox(bBox);
} else if (VERSION.equals(nextCommand)) {
fontMetrics.setFontVersion(readLine());
} else if (NOTICE.equals(nextCommand)) {
fontMetrics.setNotice(readLine());
} else if (ENCODING_SCHEME.equals(nextCommand)) {
fontMetrics.setEncodingScheme(readLine());
} else if (MAPPING_SCHEME.equals(nextCommand)) {
fontMetrics.setMappingScheme(readInt());
} else if (ESC_CHAR.equals(nextCommand)) {
fontMetrics.setEscChar(readInt());
} else if (CHARACTER_SET.equals(nextCommand)) {
fontMetrics.setCharacterSet(readLine());
} else if (CHARACTERS.equals(nextCommand)) {
fontMetrics.setCharacters(readInt());
} else if (IS_BASE_FONT.equals(nextCommand)) {
fontMetrics.setIsBaseFont(readBoolean());
} else if (V_VECTOR.equals(nextCommand)) {
float[] vector = new float[2];
vector[0] = readFloat();
vector[1] = readFloat();
fontMetrics.setVVector(vector);
} else if (IS_FIXED_V.equals(nextCommand)) {
fontMetrics.setIsFixedV(readBoolean());
} else if (CAP_HEIGHT.equals(nextCommand)) {
fontMetrics.setCapHeight(readFloat());
} else if (X_HEIGHT.equals(nextCommand)) {
fontMetrics.setXHeight(readFloat());
} else if (ASCENDER.equals(nextCommand)) {
fontMetrics.setAscender(readFloat());
} else if (DESCENDER.equals(nextCommand)) {
fontMetrics.setDescender(readFloat());
} else if (STD_HW.equals(nextCommand)) {
fontMetrics.setStandardHorizontalWidth(readFloat());
} else if (STD_VW.equals(nextCommand)) {
fontMetrics.setStandardVerticalWidth(readFloat());
} else if (COMMENT.equals(nextCommand)) {
fontMetrics.addComment(readLine());
} else if (UNDERLINE_POSITION.equals(nextCommand)) {
fontMetrics.setUnderlinePosition(readFloat());
} else if (UNDERLINE_THICKNESS.equals(nextCommand)) {
fontMetrics.setUnderlineThickness(readFloat());
} else if (ITALIC_ANGLE.equals(nextCommand)) {
fontMetrics.setItalicAngle(readFloat());
} else if (CHAR_WIDTH.equals(nextCommand)) {
float[] widths = new float[2];
widths[0] = readFloat();
widths[1] = readFloat();
fontMetrics.setCharWidth(widths);
} else if (IS_FIXED_PITCH.equals(nextCommand)) {
fontMetrics.setFixedPitch(readBoolean());
} else if (START_CHAR_METRICS.equals(nextCommand)) {
int count = readInt();
List<CharMetric> charMetrics = new ArrayList<CharMetric>(count);
for (int i = 0; i < count; i++) {
CharMetric charMetric = parseCharMetric();
charMetrics.add(charMetric);
}
String end = readString();
if (!end.equals(END_CHAR_METRICS)) {
throw new IOException("Error: Expected '" + END_CHAR_METRICS + "' actual '" + end + "'");
}
charMetricsRead = true;
fontMetrics.setCharMetrics(charMetrics);
} else if (!reducedDataset && START_COMPOSITES.equals(nextCommand)) {
int count = readInt();
for (int i = 0; i < count; i++) {
Composite part = parseComposite();
fontMetrics.addComposite(part);
}
String end = readString();
if (!end.equals(END_COMPOSITES)) {
throw new IOException("Error: Expected '" + END_COMPOSITES + "' actual '" + end + "'");
}
} else if (!reducedDataset && START_KERN_DATA.equals(nextCommand)) {
parseKernData(fontMetrics);
} else {
if (reducedDataset && charMetricsRead) {
break;
}
throw new IOException("Unknown AFM key '" + nextCommand + "'");
}
}
return fontMetrics;
}
use of com.tom_roush.fontbox.util.BoundingBox in project PdfBox-Android by TomRoush.
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;
}
// PDFBOX-3464, PDFBOX-4480, PDFBOX-4553:
// sometimes even CapHeight has very high value, but Ascent and Descent are ok
float ascent = fontDescriptor.getAscent();
float descent = fontDescriptor.getDescent();
if (capHeight > ascent && ascent > 0 && descent < 0 && ((ascent - descent) / 2 < glyphHeight || Float.compare(glyphHeight, 0) == 0)) {
glyphHeight = (ascent - descent) / 2;
}
}
// 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 (Throwable exception) {
Log.w("PdfBox-Android", exception.getMessage(), 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) {
// 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 com.tom_roush.fontbox.util.BoundingBox in project PdfBox-Android by TomRoush.
the class LayerUtility method importPageAsForm.
/**
* Imports a page from some PDF file as a Form XObject so it can be placed on another page
* in the target document.
* <p>
* You may want to call {@link #wrapInSaveRestore(PDPage) wrapInSaveRestore(PDPage)} before invoking the Form XObject to
* make sure that the graphics state is reset.
*
* @param sourceDoc the source PDF document that contains the page to be copied
* @param page the page in the source PDF document to be copied
* @return a Form XObject containing the original page's content
* @throws IOException if an I/O error occurs
*/
public PDFormXObject importPageAsForm(PDDocument sourceDoc, PDPage page) throws IOException {
importOcProperties(sourceDoc);
PDStream newStream = new PDStream(targetDoc, page.getContents(), COSName.FLATE_DECODE);
PDFormXObject form = new PDFormXObject(newStream);
// Copy resources
PDResources pageRes = page.getResources();
PDResources formRes = new PDResources();
cloner.cloneMerge(pageRes, formRes);
form.setResources(formRes);
// Transfer some values from page to form
transferDict(page.getCOSObject(), form.getCOSObject(), PAGE_TO_FORM_FILTER, true);
Matrix matrix = form.getMatrix();
AffineTransform at = matrix.createAffineTransform();
PDRectangle mediaBox = page.getMediaBox();
PDRectangle cropBox = page.getCropBox();
PDRectangle viewBox = (cropBox != null ? cropBox : mediaBox);
// Handle the /Rotation entry on the page dict
int rotation = page.getRotation();
// Transform to FOP's user space
// at.scale(1 / viewBox.getWidth(), 1 / viewBox.getHeight());
at.translate(mediaBox.getLowerLeftX() - viewBox.getLowerLeftX(), mediaBox.getLowerLeftY() - viewBox.getLowerLeftY());
switch(rotation) {
case 90:
at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth());
at.translate(0, viewBox.getWidth());
at.rotate(-Math.PI / 2.0);
break;
case 180:
at.translate(viewBox.getWidth(), viewBox.getHeight());
at.rotate(-Math.PI);
break;
case 270:
at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth());
at.translate(viewBox.getHeight(), 0);
at.rotate(-Math.PI * 1.5);
break;
default:
}
// Compensate for Crop Boxes not starting at 0,0
at.translate(-viewBox.getLowerLeftX(), -viewBox.getLowerLeftY());
if (!at.isIdentity()) {
form.setMatrix(at);
}
BoundingBox bbox = new BoundingBox();
bbox.setLowerLeftX(viewBox.getLowerLeftX());
bbox.setLowerLeftY(viewBox.getLowerLeftY());
bbox.setUpperRightX(viewBox.getUpperRightX());
bbox.setUpperRightY(viewBox.getUpperRightY());
form.setBBox(new PDRectangle(bbox));
return form;
}
Aggregations