protected internal virtual Path FilterStrokePath(Path path, Matrix ctm, float lineWidth, int lineCapStyle,
                                                int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
            JoinType joinType = GetJoinType(lineJoinStyle);
            EndType endType = GetEndType(lineCapStyle);

            if (lineDashPattern != null) {
                if (IsZeroDash(lineDashPattern)) {
                    return new Path();
                }
                
                if (!IsSolid(lineDashPattern)) {
                    path = ApplyDashPattern(path, lineDashPattern);
                }
            }

            ClipperOffset offset = new ClipperOffset(miterLimit, PdfCleanUpProcessor.ArcTolerance * PdfCleanUpProcessor.FloatMultiplier);
            AddPath(offset, path, joinType, endType);

            PolyTree resultTree = new PolyTree();
            offset.Execute(ref resultTree, lineWidth * PdfCleanUpProcessor.FloatMultiplier / 2);

            return FilterFillPath(ConvertToPath(resultTree), ctm, PathPaintingRenderInfo.NONZERO_WINDING_RULE);
        }
Пример #2
0
        private static Path ApplyDashPattern(Path path, LineDashPattern lineDashPattern) {
            HashSet2<int> modifiedSubpaths = new HashSet2<int>(path.ReplaceCloseWithLine());
            Path dashedPath = new Path();
            int currentSubpath = 0;

            foreach (Subpath subpath in path.Subpaths) {
                IList<Point2D> subpathApprox = subpath.GetPiecewiseLinearApproximation();

                if (subpathApprox.Count > 1) {
                    dashedPath.MoveTo((float) subpathApprox[0].GetX(), (float) subpathApprox[0].GetY());
                    float remainingDist = 0;
                    bool remainingIsGap = false;

                    for (int i = 1; i < subpathApprox.Count; ++i) {
                        Point2D nextPoint = null;

                        if (remainingDist != 0) {
                            nextPoint = GetNextPoint(subpathApprox[i - 1], subpathApprox[i], remainingDist);
                            remainingDist = ApplyDash(dashedPath, subpathApprox[i - 1], subpathApprox[i], nextPoint, remainingIsGap);
                        }

                        while ((Util.compare(remainingDist, 0) == 0) && !dashedPath.CurrentPoint.Equals(subpathApprox[i])) {
                            LineDashPattern.DashArrayElem currentElem = lineDashPattern.Next();
                            nextPoint = GetNextPoint(nextPoint ?? subpathApprox[i - 1], subpathApprox[i], currentElem.Value);
                            remainingDist = ApplyDash(dashedPath, subpathApprox[i - 1], subpathApprox[i], nextPoint, currentElem.IsGap);
                            remainingIsGap = currentElem.IsGap;
                        }
                    }

                    // If true, then the line closing the subpath was explicitly added (see Path.ReplaceCloseWithLine).
                    // This causes a loss of a visual effect of line join style parameter, so in this clause
                    // we simply add overlapping dash (or gap, no matter), which continues the last dash and equals to 
                    // the first dash (or gap) of the path.
                    if (modifiedSubpaths.Contains(currentSubpath)) {
                        lineDashPattern.Reset();
                        LineDashPattern.DashArrayElem currentElem = lineDashPattern.Next();
                        Point2D nextPoint = GetNextPoint(subpathApprox[0], subpathApprox[1], currentElem.Value);
                        ApplyDash(dashedPath, subpathApprox[0], subpathApprox[1], nextPoint, currentElem.IsGap);
                    }
                }

                // According to PDF spec. line dash pattern should be restarted for each new subpath.
                lineDashPattern.Reset();
                ++currentSubpath;
            }

            return dashedPath;
        }
Пример #3
0
        protected internal Path FilterStrokePath(Path sourcePath, Matrix ctm, float lineWidth, int lineCapStyle,
                                int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
            Path path = sourcePath;
            JoinType joinType = GetJoinType(lineJoinStyle);
            EndType endType = GetEndType(lineCapStyle);

            if (lineDashPattern != null && !lineDashPattern.IsSolid()) {
                path = ApplyDashPattern(path, lineDashPattern);
            }

            ClipperOffset offset = new ClipperOffset(miterLimit, PdfCleanUpProcessor.ArcTolerance * PdfCleanUpProcessor.FloatMultiplier);
            IList<Subpath> degenerateSubpaths = AddPath(offset, path, joinType, endType);

            PolyTree resultTree = new PolyTree();
            offset.Execute(ref resultTree, lineWidth * PdfCleanUpProcessor.FloatMultiplier / 2);
            Path offsetedPath = ConvertToPath(resultTree);

            if (degenerateSubpaths.Count > 0) {
                if (endType == EndType.etOpenRound) {
                    IList<Subpath> circles = ConvertToCircles(degenerateSubpaths, lineWidth / 2);
                    offsetedPath.AddSubpaths(circles);
                } else if (endType == EndType.etOpenSquare && lineDashPattern != null) {
                    IList<Subpath> squares = ConvertToSquares(degenerateSubpaths, lineWidth, sourcePath);
                    offsetedPath.AddSubpaths(squares);
                }
            }

            return FilterFillPath(offsetedPath, ctm, PathPaintingRenderInfo.NONZERO_WINDING_RULE);
        }
        /**
         * @param fillingRule If the path is contour, pass any value.
         */

        private Path FilterCurrentPath(Matrix ctm, bool stroke, int fillingRule, float lineWidth, int lineCapStyle, 
                                       int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
            Path path = new Path(unfilteredCurrentPath.Subpaths);

            if (stroke) {
                return filter.FilterStrokePath(path, ctm, lineWidth, lineCapStyle, lineJoinStyle,
                    miterLimit, lineDashPattern);
            } else {
                return filter.FilterFillPath(path, ctm, fillingRule);
            }
        }
 public void Invoke(PdfContentStreamProcessor processor, PdfLiteral oper, List<PdfObject> operands) {
     LineDashPattern pattern = new LineDashPattern(((PdfArray) operands[0]),
                                                   ((PdfNumber) operands[1]).FloatValue);
     processor.Gs().SetLineDashPattern(pattern);
 }
 private static bool IsSolid(LineDashPattern lineDashPattern) {
     return lineDashPattern.DashArray.IsEmpty();
 }
        private static bool IsZeroDash(LineDashPattern lineDashPattern) {
            PdfArray dashArray = lineDashPattern.DashArray;
            float total = 0;

            // We should only iterate over the numbers specifying lengths of dashes
            for (int i = 0; i < dashArray.Size; i += 2) {
                float currentDash = dashArray.GetAsNumber(i).FloatValue;
                // Should be nonnegative according to spec.
                if (currentDash < 0) {
                    currentDash = 0;
                }

                total += currentDash;
            }

            return Util.compare(total, 0) == 0;
        }