ContrastResult.java
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2026 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 <https://www.gnu.org/licenses/>.
*/
package com.itextpdf.kernel.contrast;
import java.util.ArrayList;
import java.util.List;
/**
* Represents the complete contrast analysis result for a single text element.
* <p>
* This class encapsulates all the contrast information for a text element, including
* the text itself and a list of all background elements that it overlaps with, along
* with their respective contrast ratios.
* <p>
* Each text element may have multiple background elements behind it, especially in
* complex PDF layouts. This class collects all such relationships to provide a
* comprehensive view of the text's contrast characteristics for accessibility analysis.
*/
public class ContrastResult {
private final TextColorInfo textRenderInfo;
private final List<OverlappingArea> overlappingAreas;
private final int pageNumber;
/**
* Constructs a new {@link ContrastResult} for the specified text element.
* <p>
* The result is initialized with an empty list of background entries, which should
* be populated using {@link #addContrastResult(OverlappingArea)}.
*
* @param textRenderInfo the text element for which contrast is being analyzed
* @param pageNumber the page number where the text element is located
*
*/
public ContrastResult(TextColorInfo textRenderInfo, int pageNumber) {
this.textRenderInfo = textRenderInfo;
this.pageNumber = pageNumber;
this.overlappingAreas = new ArrayList<>();
}
/**
* Gets the page number where the text element is located.
*
* @return the page number
*/
public int getPageNumber() {
return pageNumber;
}
/**
* Gets the text render information for this contrast result.
* <p>
* The text information includes the character, parent text, color, geometric path,
* and font size of the text element being analyzed.
*
* @return the text render information
*/
public TextColorInfo getTextRenderInfo() {
return textRenderInfo;
}
/**
* Adds a background contrast entry to this result.
* <p>
* Each entry represents a background element that the text overlaps with, along
* with the calculated contrast ratio between the text color and background color.
* Multiple entries indicate that the text appears over multiple backgrounds.
*
* @param overlappingArea the contrast result entry containing background information and contrast ratio
*/
public void addContrastResult(OverlappingArea overlappingArea) {
this.overlappingAreas.add(overlappingArea);
}
/**
* Gets all the background contrast entries for this text element.
* <p>
* Each entry in the list represents a background element that the text overlaps with,
* containing the background's color, path, and the calculated contrast ratio.
* The list may be empty if no backgrounds were detected, or may contain multiple
* entries if the text overlaps multiple background elements.
*
* @return an unmodifiable view of the list of contrast result entries
*/
public List<OverlappingArea> getOverlappingAreas() {
return new ArrayList<>(overlappingAreas);
}
/**
* Represents a single contrast analysis result entry between text and a background element.
* <p>
* This class encapsulates the information about a specific background element that intersects
* with a text element, along with the calculated contrast ratio between them. It is used as
* part of a {@link ContrastResult} to provide detailed information about all backgrounds
* that contribute to the overall contrast of a text element.
* <p>
* The contrast ratio is calculated according to WCAG 2.1 guidelines and ranges from 1:1
* (no contrast) to 21:1 (maximum contrast between black and white).
*/
public static class OverlappingArea {
private final BackgroundColorInfo backgroundRenderInfo;
private final double contrastRatio;
private double overlapRatio;
/**
* Constructs a new ContrastResultEntry with the specified background information and contrast ratio.
*
* @param backgroundRenderInfo the background element that was analyzed for contrast
* @param contrastRatio the calculated contrast ratio between the text and this background,
* according to WCAG 2.1 guidelines (ranges from 1.0 to 21.0)
*/
public OverlappingArea(BackgroundColorInfo backgroundRenderInfo, double contrastRatio) {
this.backgroundRenderInfo = backgroundRenderInfo;
this.contrastRatio = contrastRatio;
}
/**
* Gets the background render information for this contrast entry.
* <p>
* The background information includes the color and geometric path of the background
* element that was compared against the text.
*
* @return the background render information
*/
public BackgroundColorInfo getBackgroundRenderInfo() {
return backgroundRenderInfo;
}
/**
* Gets the contrast ratio between the text and this background element.
* <p>
* The contrast ratio is calculated according to WCAG 2.1 guidelines:
* <p>
* *1.0 indicates no contrast (identical colors)
* *21.0 is the maximum contrast (black and white)
*
* @return the contrast ratio value, ranging from 1.0 to 21.0
*/
public double getContrastRatio() {
return contrastRatio;
}
/**
* Gets the percentage of the text area that overlaps with this background element.
*
* @return the overlapping area in percentage.
*/
public double getOverlapRatio() {
return overlapRatio;
}
/**
* Sets the percentage of the text area that overlaps with this background element.
* Should be a value between 0 and 1 representing 0% to 100%.
*
* @param overlappingAreaInPercentage the overlapping area in percentage.
*/
public void setOverlapRatio(double overlappingAreaInPercentage) {
if (overlappingAreaInPercentage < 0 || overlappingAreaInPercentage > 1) {
throw new IllegalArgumentException("Overlap ratio must be between 0 and 1.");
}
this.overlapRatio = overlappingAreaInPercentage;
}
}
}