All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.svg.utils.SvgTextUtil Maven / Gradle / Ivy

/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.svg.utils;


import com.itextpdf.styledxmlparser.css.CommonCssConstants;
import com.itextpdf.styledxmlparser.css.util.CssTypesValidationUtils;
import com.itextpdf.styledxmlparser.css.util.CssDimensionParsingUtils;
import com.itextpdf.styledxmlparser.util.WhiteSpaceUtil;
import com.itextpdf.svg.SvgConstants;
import com.itextpdf.svg.renderers.impl.ISvgTextNodeRenderer;
import com.itextpdf.svg.renderers.impl.TextLeafSvgNodeRenderer;
import com.itextpdf.svg.renderers.impl.TextSvgBranchRenderer;


/**
 * Class containing utility methods for text operations in the context of SVG processing
 */
public final class SvgTextUtil {


    private SvgTextUtil() {
    }

    /**
     * Trim all the leading whitespace characters from the passed string
     *
     * @param toTrim string to trim
     * @return string with all leading whitespace characters removed
     */
    public static String trimLeadingWhitespace(String toTrim) {
        if (toTrim == null) {
            return "";
        }
        int current = 0;
        int end = toTrim.length();
        while (current < end) {
            char currentChar = toTrim.charAt(current);
            if (Character.isWhitespace(currentChar) && !(currentChar == '\n' || currentChar == '\r')) {
                //if the character is whitespace and not a newline, increase current
                current++;
            } else {
                break;
            }
        }
        return toTrim.substring(current);
    }

    /**
     * Trim all the trailing whitespace characters from the passed string
     *
     * @param toTrim string to trim
     * @return string with al trailing whitespace characters removed
     */
    public static String trimTrailingWhitespace(String toTrim) {
        if (toTrim == null) {
            return "";
        }
        int end = toTrim.length();
        if (end > 0) {
            int current = end - 1;
            while (current >= 0) {
                char currentChar = toTrim.charAt(current);
                if (Character.isWhitespace(currentChar) && !(currentChar == '\n' || currentChar == '\r')) {
                    //if the character is whitespace and not a newline, increase current
                    current--;
                } else {
                    break;
                }
            }
            if (current < 0) {
                return "";
            } else {
                return toTrim.substring(0, current + 1);
            }
        } else {
            return toTrim;
        }
    }


    /**
     * Process the whitespace inside the Text Tree.
     * Whitespace is collapsed and new lines are handled
     * A leading element in each subtree is handled different: the preceding whitespace is trimmed instead of kept
     *
     * @param root             root of the text-renderer subtree
     * @param isLeadingElement true if this element is a leading element(either the first child or the first element after an absolute position change)
     */
    public static void processWhiteSpace(TextSvgBranchRenderer root, boolean isLeadingElement) {
        // when svg is parsed by jsoup it leaves all whitespace in text element as is. Meaning that
        // tab/space indented xml files will retain their tabs and spaces.
        // The following regex replaces all whitespace with a single space.
        boolean performLeadingTrim = isLeadingElement;
        for (ISvgTextNodeRenderer child : root.getChildren()) {
            //If leaf, process contents, if branch, call function again
            if (child instanceof TextSvgBranchRenderer) {
                //Branch processing
                processWhiteSpace((TextSvgBranchRenderer) child, child.containsAbsolutePositionChange());
                ((TextSvgBranchRenderer) child).markWhiteSpaceProcessed();
            }
            if (child instanceof TextLeafSvgNodeRenderer) {
                //Leaf processing
                TextLeafSvgNodeRenderer leafRend = (TextLeafSvgNodeRenderer) child;
                //Process text
                String toProcess = leafRend.getAttribute(SvgConstants.Attributes.TEXT_CONTENT);
                toProcess = toProcess.replaceAll("\\s+", " ");
                toProcess = WhiteSpaceUtil.collapseConsecutiveSpaces(toProcess);
                if (performLeadingTrim) {
                    //Trim leading white spaces
                    toProcess = trimLeadingWhitespace(toProcess);
                    toProcess = trimTrailingWhitespace(toProcess);
                    performLeadingTrim = false;
                } else {
                    //only collapse whitespace
                    toProcess = trimTrailingWhitespace(toProcess);
                }
                leafRend.setAttribute(SvgConstants.Attributes.TEXT_CONTENT, toProcess);
            }
        }
    }

    /**
     * Check if the String is only composed of whitespace characters
     *
     * @param s string to check
     * @return true if the string only contains whitespace characters, false otherwise
     */
    public static boolean isOnlyWhiteSpace(String s) {
        String trimmedText = s.replaceAll("\\s+", " ");
        //Trim leading whitespace
        trimmedText = SvgTextUtil.trimLeadingWhitespace(trimmedText);
        //Trim trailing whitespace
        trimmedText = SvgTextUtil.trimTrailingWhitespace(trimmedText);
        return "".equals(trimmedText);
    }

    /**
     * Resolve the font size stored inside the passed renderer
     *
     * @param renderer       renderer containing the font size declaration
     * @param parentFontSize parent font size to fall back on if the renderer does not contain a font size declarations or if the stored declaration is invalid
     * @return float containing the font-size, or the parent font size if the renderer's declaration cannot be resolved
     */
    public static float resolveFontSize(ISvgTextNodeRenderer renderer, float parentFontSize) {
        //Use own font-size declaration if it is present, parent's otherwise
        float fontSize = Float.NaN;
        final String elementFontSize = renderer.getAttribute(SvgConstants.Attributes.FONT_SIZE);
        if (null != elementFontSize && !elementFontSize.isEmpty()) {
            if (CssTypesValidationUtils.isRelativeValue(elementFontSize)
                    || CommonCssConstants.LARGER.equals(elementFontSize)
                    || CommonCssConstants.SMALLER.equals(elementFontSize)) {
                fontSize = CssDimensionParsingUtils.parseRelativeFontSize(elementFontSize, parentFontSize);
            } else {
                fontSize = CssDimensionParsingUtils.parseAbsoluteFontSize(elementFontSize, CommonCssConstants.PX);
            }
        }
        if ((Float.isNaN(fontSize)) || fontSize < 0f) {
            fontSize = parentFontSize;
        }
        return fontSize;
    }

    /**
     * The reference value may contain a hashtag character or 'url' designation and this method will filter them.
     *
     * @param name value to be filtered
     * @return filtered value
     */
    public static String filterReferenceValue(String name) {
        return name.replace("#", "").replace("url(", "").replace(")", "").trim();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy