/** * write out the faces age (formatted 'Age %.1f') to the top of the face rectangle. * ({@link ImageOverlayBuilder#outlineFaceOnImage(Face, RectangleType, BorderWeight, CognitiveJColourPalette)} * * @param face the face. * @param colourPalette the colour to use * @param textPosition location of the text boundary * @return this */ @NotNull public ImageOverlayBuilder writeAge(@NotNull Face face, @NotNull CognitiveJColourPalette colourPalette, @NotNull RectangleTextPosition textPosition) { TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), face.faceRectangle.asAwtRectangle(), new Insets(0, 0, 0, 0), DEFAULT_TEXT_FONT, colourPalette, textPosition, String.format("Age %.2f", face.faceAttributesResp.age)); bufferedImage = textOnRectangleFilter.applyFilter(bufferedImage); return this; }
@NotNull @Override public BufferedImage applyFilter(@NotNull BufferedImage bufferedImage) { Graphics2D graphics2D = bufferedImage.createGraphics(); applyText(graphics2D); graphics2D.dispose(); return bufferedImage; }
private void applyText(Graphics2D graphics2D) { graphics2D.setFont(requestedFont); graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); int availableWidthForTextContainer = boundedTextContainerWidth(graphics2D); setupFontWidth(graphics2D, availableWidthForTextContainer); int availableHeightForTextContainer = boundedTextContainerHeight(graphics2D); setupFontHeight(graphics2D, availableWidthForTextContainer, availableHeightForTextContainer); int startingX = calculateTextContainerStartingPointX(availableWidthForTextContainer); int startingY = calculateTextContainerStartingPointY(baseRectangle, availableHeightForTextContainer, rectangleTextPosition); Rectangle textContainer = new Rectangle(startingX, startingY, availableWidthForTextContainer, availableHeightForTextContainer); drawOutliningRectangle(graphics2D, textContainer, cognitiveJColourPalette.getBackground()); applyTextOver(graphics2D, textContainer); }
private int boundedTextContainerWidth(Graphics2D graphics2D) { switch (rectangleTextPosition) { case LEFT_OF: return Math.max(baseRectangle.width, graphics2D.getFontMetrics().stringWidth(maxSingleLineStringWidth(text))); case RIGHT_OF: return Math.min(fullImageDimension.width - (baseRectangle.x + baseRectangle.width + insets.right + insets.left), baseRectangle.width); case TOP_OF: /**fall through to RIGHT_OF"&**/ case BOTTOM_OF: return baseRectangle.width; } return 0; }
private void setupFontWidth(Graphics2D graphics2D, int textContainerWidth) { float fontSize = requestedFont.getSize(); FontRenderContext fontRenderContext = graphics2D.getFontRenderContext(); Rectangle2D bounds = requestedFont.getStringBounds(maxSingleLineStringWidth(text), fontRenderContext); while (bounds.getWidth() > textContainerWidth - (insets.left + insets.right)) { requestedFont = requestedFont.deriveFont((fontSize -= 2)); bounds = requestedFont.getStringBounds(maxSingleLineStringWidth(text), fontRenderContext); } graphics2D.setFont(requestedFont); }
/** * write out the faces' {@link FaceAttributes} * * @param face the face. * @param colourPalette the colour to use * @param textPosition position to locate the text * @return this */ @NotNull public ImageOverlayBuilder writeFaceAttributes(@NotNull Face face, @NotNull CognitiveJColourPalette colourPalette, RectangleTextPosition textPosition) { TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), face.faceRectangle.asAwtRectangle(), new Insets(0, 0, 0, 0), DEFAULT_TEXT_FONT, colourPalette, textPosition, FaceStringBuilder.buildStringFor(face, FaceAttributes.ALL)); bufferedImage = textOnRectangleFilter.applyFilter(bufferedImage); return this; }
private void setupFontHeight(Graphics2D graphics2D, int textContainerWidth, int maxHeightOfText) { float fontSize = requestedFont.getSize(); FontRenderContext fontRenderContext = graphics2D.getFontRenderContext(); Rectangle2D bounds = requestedFont.getStringBounds(maxSingleLineStringWidth(text), fontRenderContext); while (bounds.getWidth() > textContainerWidth || bounds.getHeight() > maxHeightOfText) { requestedFont = requestedFont.deriveFont((fontSize -= 2)); bounds = requestedFont.getStringBounds(maxSingleLineStringWidth(text), fontRenderContext); } graphics2D.setFont(requestedFont); }
@NotNull private ImageOverlayBuilder outlineOCRWord(@NotNull OCRResult.Word word) { OverlayRectangleFilter overlayRectangleFilter = new OverlayRectangleFilter(word.boundingBoxAsAwtRectangle(), RectangleType.FULL, BorderWeight.THINNER, CognitiveJColourPalette.randomColour()); TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), word.boundingBoxAsAwtRectangle(), new Insets(0, 0, 0, 0), new Font("Noto Sans", Font.PLAIN, 12), CognitiveJColourPalette.TRANS_GRAY, RectangleTextPosition.BOTTOM_OF, word.text); bufferedImage = textOnRectangleFilter.applyFilter(overlayRectangleFilter.applyFilter(bufferedImage)); return this; }
private void applyTextOver(Graphics2D graphics2D, Rectangle boundedTextContainer) { graphics2D.setColor(cognitiveJColourPalette.getForeground()); java.util.List<String> stringRows = Arrays.asList(text.split("\\n")); int width = boundedTextContainer.width; int height = boundedTextContainer.height; int textWidth = graphics2D.getFontMetrics().stringWidth(maxSingleLineStringWidth(text)); int textHeight = graphics2D.getFontMetrics().getHeight() / 2; int rowPadding = Math.max(0, (height - textHeight * stringRows.size()) / stringRows.size()); Point insideContainerPoint = PointLocations.TOP_CENTER.calculate( width, height, textWidth, 0, 0, 0, 0, 0 ); double yRatio = insideContainerPoint.y / (double) height; int yOffset = (int) ((1.0 - yRatio) * textHeight); for (int i = 0; i < stringRows.size(); i++) { String s = stringRows.get(i); graphics2D.drawString(s, insideContainerPoint.x + boundedTextContainer.x, insideContainerPoint.y + (rowPadding / 2) + yOffset + boundedTextContainer.y + ((textHeight + rowPadding) * i)); } }
/** * write out the faces gender and age (formatted '%Gender, Age %.1f') * ({@link ImageOverlayBuilder#outlineFaceOnImage(Face, RectangleType, BorderWeight, CognitiveJColourPalette)} * * @param face the face. * @param colourPalette the colors to use * @param insets any Insets to take into consideration(e.g. border thickness). * @param textPosition where to position the text container * @return this */ public ImageOverlayBuilder writeGenderAndAge(Face face, CognitiveJColourPalette colourPalette, @NotNull Insets insets, RectangleTextPosition textPosition) { TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), face.faceRectangle.asAwtRectangle(), insets, DEFAULT_TEXT_FONT, colourPalette, textPosition, String.format("%s, Age %.1f", WordUtils.capitalize(face.faceAttributesResp.gender.name()), face.faceAttributesResp.age)); bufferedImage = textOnRectangleFilter.applyFilter(bufferedImage); return this; }
/** * Draw the rectangle and outline the dominant @{@link Emotion} * * @param emotion the emotion * @param textPosition where the text is to be positioned * @return this */ @NotNull public ImageOverlayBuilder outlineDominantEmotionOnImage(@NotNull Emotion emotion, @NotNull RectangleTextPosition textPosition) { OverlayRectangleFilter overlayRectangleFilter = new OverlayRectangleFilter(emotion.faceRectangle.asAwtRectangle(), RectangleType.CORNERED, DEFAULT_BORDER_WEIGHT, CognitiveJColourPalette.STRAWBERRY); TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), emotion.faceRectangle.asAwtRectangle(), new Insets(0, 0, 0, 0), DEFAULT_TEXT_FONT, CognitiveJColourPalette.STRAWBERRY, textPosition, EmotionStringBuilder.dominantEmotion(emotion)); bufferedImage = textOnRectangleFilter.applyFilter(overlayRectangleFilter.applyFilter(bufferedImage)); return this; }
/** * Draw the rectangle and displays all @{@link Emotion} for the face. * * @param emotion all found emotions. * @param textPosition where to position the emotion * @return this */ @NotNull public ImageOverlayBuilder outlineEmotionOnImage(@NotNull Emotion emotion, @NotNull RectangleTextPosition textPosition) { OverlayRectangleFilter overlayRectangleFilter = new OverlayRectangleFilter(emotion.faceRectangle.asAwtRectangle(), RectangleType.CORNERED, DEFAULT_BORDER_WEIGHT, CognitiveJColourPalette.randomColour()); TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), emotion.faceRectangle.asAwtRectangle(), new Insets(0, 0, 0, 0), new Font("Noto Sans", Font.PLAIN, 40), CognitiveJColourPalette.GRAY, textPosition, EmotionStringBuilder.listAllEmotions(emotion)); bufferedImage = textOnRectangleFilter.applyFilter(overlayRectangleFilter.applyFilter(bufferedImage)); return this; }
/** * tags identified faces. * * @param identificationSet a set of identifications. * @param textPosition * @return this */ @NotNull public ImageOverlayBuilder identify(@NotNull IdentificationSet identificationSet, @NotNull RectangleTextPosition textPosition) { CognitiveJColourPalette identificationColor = identificationSet.isIdentified() ? CognitiveJColourPalette.GREEN : CognitiveJColourPalette.RED; Face candidateFace = identificationSet.getCandidateFace(); outlineFaceOnImage(candidateFace, RectangleType.CORNERED, DEFAULT_BORDER_WEIGHT, identificationColor); TextOnRectangleFilter textOnRectangleFilter = new TextOnRectangleFilter(new Rectangle(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()), candidateFace.faceRectangle.asAwtRectangle(), new Insets(DEFAULT_BORDER_WEIGHT.thickness(), DEFAULT_BORDER_WEIGHT.thickness(), DEFAULT_BORDER_WEIGHT.thickness(), DEFAULT_BORDER_WEIGHT.thickness()), DEFAULT_TEXT_FONT, identificationColor, textPosition, identificationSet.isIdentified() ? identificationSet.getIdentifiedPerson().name : "Unknown"); bufferedImage = textOnRectangleFilter.applyFilter(bufferedImage); return this; }