private ArrayList<Shape> getSelectedTextBounds() { Page currentPage = pageViewComponent.getPage(); ArrayList<Shape> highlightBounds = null; if (currentPage != null && currentPage.isInitiated()) { try { PageText pageText = currentPage.getViewText(); if (pageText != null) { // get page transformation AffineTransform pageTransform = currentPage.getPageTransform( documentViewModel.getPageBoundary(), documentViewModel.getViewRotation(), documentViewModel.getViewZoom()); // paint the sprites GeneralPath textPath; ArrayList<LineText> pageLines = pageText.getPageLines(); if (pageLines != null) { for (LineText lineText : pageLines) { java.util.List<WordText> words = lineText.getWords(); if (words != null) { for (WordText wordText : words) { // paint whole word if (wordText.isSelected() || wordText.isHighlighted()) { textPath = new GeneralPath(wordText.getBounds()); textPath.transform(pageTransform); // paint highlight over any selected if (wordText.isSelected()) { if (highlightBounds == null) { highlightBounds = new ArrayList<Shape>(); } highlightBounds.add(textPath.getBounds2D()); } } // check children else { for (GlyphText glyph : wordText.getGlyphs()) { if (glyph.isSelected()) { textPath = new GeneralPath(glyph.getBounds()); textPath.transform(pageTransform); if (highlightBounds == null) { highlightBounds = new ArrayList<Shape>(); } highlightBounds.add(textPath.getBounds2D()); } } } } } } } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.fine("HighLightAnnotation selected text bounds calculation interrupted."); } } return highlightBounds; }
/** Render a compound glyf */ protected GeneralPath renderCompoundGlyph(GlyfTable glyf, GlyfCompound g) { GeneralPath gp = new GeneralPath(); for (int i = 0; i < g.getNumComponents(); i++) { // find and render the component glyf Glyf gl = glyf.getGlyph(g.getGlyphIndex(i)); GeneralPath path = null; if (gl instanceof GlyfSimple) { path = renderSimpleGlyph((GlyfSimple) gl); } else if (gl instanceof GlyfCompound) { path = renderCompoundGlyph(glyf, (GlyfCompound) gl); } else { throw new RuntimeException("Unsupported glyph type " + gl.getClass().getCanonicalName()); } // multiply the translations by units per em double[] matrix = g.getTransform(i); // transform the path path.transform(new AffineTransform(matrix)); // add it to the global path gp.append(path, false); } return gp; }
/** Get the outline of a character given the glyph id */ protected synchronized GeneralPath getOutline(int glyphId, float width) { // find the glyph itself GlyfTable glyf = (GlyfTable) this.font.getTable("glyf"); Glyf g = glyf.getGlyph(glyphId); GeneralPath gp = null; if (g instanceof GlyfSimple) { gp = renderSimpleGlyph((GlyfSimple) g); } else if (g instanceof GlyfCompound) { gp = renderCompoundGlyph(glyf, (GlyfCompound) g); } else { gp = new GeneralPath(); } // calculate the advance HmtxTable hmtx = (HmtxTable) this.font.getTable("hmtx"); float advance = hmtx.getAdvance(glyphId) / this.unitsPerEm; // scale the glyph to match the desired advance float widthfactor = width / advance; // the base transform scales the glyph to 1x1 AffineTransform at = AffineTransform.getScaleInstance(1 / this.unitsPerEm, 1 / this.unitsPerEm); at.concatenate(AffineTransform.getScaleInstance(widthfactor, 1)); gp.transform(at); return gp; }
/** * Get a glyph outline by character code * * <p>Note this method must always return an outline * * @param src the character code of the desired glyph * @return the glyph outline */ @Override protected GeneralPath getOutline(char src, float width) { // some true type fonts put characters in the undefined // region of Unicode instead of as normal characters. if (!this.f.canDisplay(src) && this.f.canDisplay((char) (src + 0xf000))) { src += 0xf000; } // filter out control characters for (int i = 0; i < controlChars.length; i++) { if (controlChars[i] == src) { src = (char) (0xf000 | src); break; } } char[] glyph = new char[1]; glyph[0] = src; GlyphVector gv = this.f.createGlyphVector(this.basecontext, glyph); GeneralPath gp = new GeneralPath(gv.getGlyphOutline(0)); // this should be gv.getGlyphMetrics(0).getAdvance(), but that is // broken on the Mac, so we need to read the advance from the // hmtx table in the font CMap map = this.cmapTable.getCMap(mapIDs[0], mapIDs[1]); int glyphID = map.map(src); float advance = (float) this.hmtxTable.getAdvance(glyphID) / (float) this.unitsPerEm; float widthfactor = width / advance; gp.transform(AffineTransform.getScaleInstance(widthfactor, -1)); return gp; }
/** * Returns the contour of the ellipse. * * @return A new {@code GeneralPath} object containing the contour of the ellipse. */ public GeneralPath contour() { final GeneralPath gp = new GeneralPath(new Ellipse2D.Double(x - major, y - minor, 2 * major, 2 * minor)); final AffineTransform at = new AffineTransform(); at.rotate(angle, x, y); gp.transform(at); return gp; }
public void translate(double dx, double dy) { for (ConvexPolygonalZone.HalfPlane hp : convexPolygonalZone) hp.getOrg().translate(dx, dy); if (allocationIntersectionPath0 == null) { // ici la zone convexe ne coupe pas le bord du PECanvas donc on // translate son contour tout bêtement. Il se peut que le résultat // se mette à couper le PECanvas, dans ce cas le tireté à la // coupure ne sera pas affiché. if (boundaryPath0 != null) { AffineTransform at; boundaryPath0.transform(at = new AffineTransform(1.0, 0.0, 0.0, 1.0, dx, dy)); if (boundaryPath1 != null) boundaryPath1.transform(at); } } else { // ici la zone convexe coupe le bord du PECanvas donc on recalcule // brutalement les formes constituant sa vue. boundaryPath0 = null; } // toutefois on essaie de conserver le calcul de la frontière if (boundary != null) for (PicPoint pt : boundary.subdivisionPoints) pt.translate(dx, dy); }