use of com.itextpdf.kernel.geom.Path in project i7j-pdfsweep by itext.
the class LineDashPattern method applyDashPattern.
/**
* Apply a LineDashPattern along a Path
*
* @param path input path
* @param lineDashPattern input LineDashPattern
* @return a dashed Path
*/
public static Path applyDashPattern(Path path, LineDashPattern lineDashPattern) {
Set<Integer> modifiedSubpaths = new HashSet<>(path.replaceCloseWithLine());
Path dashedPath = new Path();
int currentSubpath = 0;
for (Subpath subpath : path.getSubpaths()) {
List<Point> subpathApprox = subpath.getPiecewiseLinearApproximation();
if (subpathApprox.size() > 1) {
dashedPath.moveTo((float) subpathApprox.get(0).getX(), (float) subpathApprox.get(0).getY());
float remainingDist = 0;
boolean remainingIsGap = false;
for (int i = 1; i < subpathApprox.size(); ++i) {
Point nextPoint = null;
if (remainingDist != 0) {
nextPoint = getNextPoint(subpathApprox.get(i - 1), subpathApprox.get(i), remainingDist);
remainingDist = applyDash(dashedPath, subpathApprox.get(i - 1), subpathApprox.get(i), nextPoint, remainingIsGap);
}
while (Float.compare(remainingDist, 0) == 0 && !dashedPath.getCurrentPoint().equals(subpathApprox.get(i))) {
LineDashPattern.DashArrayElem currentElem = lineDashPattern.next();
nextPoint = getNextPoint(nextPoint != null ? nextPoint : subpathApprox.get(i - 1), subpathApprox.get(i), currentElem.getVal());
remainingDist = applyDash(dashedPath, subpathApprox.get(i - 1), subpathApprox.get(i), nextPoint, currentElem.isGap());
remainingIsGap = currentElem.isGap();
}
}
// the first dash (or gap) of the path.
if (modifiedSubpaths.contains(currentSubpath)) {
lineDashPattern.reset();
LineDashPattern.DashArrayElem currentElem = lineDashPattern.next();
Point nextPoint = getNextPoint(subpathApprox.get(0), subpathApprox.get(1), currentElem.getVal());
applyDash(dashedPath, subpathApprox.get(0), subpathApprox.get(1), nextPoint, currentElem.isGap());
}
}
// According to PDF spec. line dash pattern should be restarted for each new subpath.
lineDashPattern.reset();
++currentSubpath;
}
return dashedPath;
}
use of com.itextpdf.kernel.geom.Path in project i7j-pdfsweep by itext.
the class PdfCleanUpProcessor method writePath.
private void writePath() {
PathRenderInfo path = ((PdfCleanUpEventListener) getEventListener()).getEncounteredPath();
boolean stroke = (path.getOperation() & PathRenderInfo.STROKE) == PathRenderInfo.STROKE;
boolean fill = (path.getOperation() & PathRenderInfo.FILL) == PathRenderInfo.FILL;
boolean clip = path.isPathModifiesClippingPath();
// Here we intentionally draw all three paths separately and not combining them in any way:
// First of all, stroke converted to fill paths, therefore it could not be combined with fill (if it is
// stroke-fill operation) or clip paths, and also it should be drawn after the fill, because in case it's
// stroke-fill operation stroke should be "on top" of the filled area.
// Secondly, current clipping path modifying happens AFTER the path painting. So if it is drawn separately, clip
// path should be the last one.
// So consider the situation when it is stroke-fill operation and also this path is marked as clip path.
// And here we have it: fill path is the first, stroke path is the second and clip path is the last. And
// stroke path could not be combined with neither fill nor clip paths.
// Some improved logic could be applied to distinguish the cases when some paths actually could be drawn as one,
// but this is the only generic solution.
Path fillPath = null;
PdfCanvas canvas = getCanvas();
if (fill) {
fillPath = filter.filterFillPath(path, path.getRule());
if (!fillPath.isEmpty()) {
writeNotAppliedGsParams(true, false);
openNotWrittenTags();
writePath(fillPath);
if (path.getRule() == FillingRule.NONZERO_WINDING) {
canvas.fill();
} else {
// FillingRule.EVEN_ODD
canvas.eoFill();
}
}
}
if (stroke) {
Path strokePath = filter.filterStrokePath(path);
if (!strokePath.isEmpty()) {
// we pass stroke here as false, because stroke is transformed into fill. we don't need to set stroke color
writeNotAppliedGsParams(false, false);
openNotWrittenTags();
writeStrokePath(strokePath, path.getStrokeColor());
}
}
if (clip) {
Path clippingPath;
if (fill && path.getClippingRule() == path.getRule()) {
clippingPath = fillPath;
} else {
clippingPath = filter.filterFillPath(path, path.getClippingRule());
}
if (!clippingPath.isEmpty()) {
writeNotAppliedGsParams(false, false);
openNotWrittenTags();
writePath(clippingPath);
if (path.getClippingRule() == FillingRule.NONZERO_WINDING) {
canvas.clip();
} else {
// FillingRule.EVEN_ODD
canvas.eoClip();
}
} else {
// If the clipping path from the source document is cleaned (it happens when reduction
// area covers the path completely), then you should treat it as an empty set (no points
// are included in the path). Then the current clipping path (which is the intersection
// between previous clipping path and the new one) is also empty set, which means that
// there is no visible content at all. But at the same time as we removed the clipping
// path, the invisible content would become visible. So, to emulate the correct result,
// we would simply put a degenerate clipping path which consists of a single point at (0, 0).
// we still need to open all q operators
writeNotAppliedGsParams(false, false);
canvas.moveTo(0, 0).clip();
}
canvas.endPath();
}
}