示例#1
0
        /// <summary>
        /// Copies content of the bookmark and adds it to the end of the specified node.
        /// The destination node can be in a different document.
        /// </summary>
        /// <param name="importer">Maintains the import context </param>
        /// <param name="srcBookmark">The input bookmark</param>
        /// <param name="dstNode">Must be a node that can contain paragraphs (such as a Story).</param>
        private static void AppendBookmarkedText(NodeImporter importer, Bookmark srcBookmark, CompositeNode dstNode)
        {
            // This is the paragraph that contains the beginning of the bookmark.
            Paragraph startPara = (Paragraph)srcBookmark.BookmarkStart.ParentNode;

            // This is the paragraph that contains the end of the bookmark.
            Paragraph endPara = (Paragraph)srcBookmark.BookmarkEnd.ParentNode;

            if ((startPara == null) || (endPara == null))
            {
                throw new InvalidOperationException("Parent of the bookmark start or end is not a paragraph, cannot handle this scenario yet.");
            }

            // Limit ourselves to a reasonably simple scenario.
            if (startPara.ParentNode != endPara.ParentNode)
            {
                throw new InvalidOperationException("Start and end paragraphs have different parents, cannot handle this scenario yet.");
            }

            // We want to copy all paragraphs from the start paragraph up to (and including) the end paragraph,
            // Therefore the node at which we stop is one after the end paragraph.
            Node endNode = endPara.NextSibling;

            // This is the loop to go through all paragraph-level nodes in the bookmark.
            for (Node curNode = startPara; curNode != endNode; curNode = curNode.NextSibling)
            {
                // This creates a copy of the current node and imports it (makes it valid) in the context
                // Of the destination document. Importing means adjusting styles and list identifiers correctly.
                Node newNode = importer.ImportNode(curNode, true);

                // Now we simply append the new node to the destination.
                dstNode.AppendChild(newNode);
            }
        }
        /// <summary>
        /// Copies content of the bookmark and adds it to the end of the specified node.
        /// The destination node can be in a different document.
        /// </summary>
        /// <param name="importer">Maintains the import context </param>
        /// <param name="srcBookmark">The input bookmark</param>
        /// <param name="dstNode">Must be a node that can contain paragraphs (such as a Story).</param>
        private static void AppendBookmarkedText(NodeImporter importer, Bookmark srcBookmark, CompositeNode dstNode)
        {
            // This is the paragraph that contains the beginning of the bookmark.
            Paragraph startPara = (Paragraph)srcBookmark.BookmarkStart.ParentNode;

            // This is the paragraph that contains the end of the bookmark.
            Paragraph endPara = (Paragraph)srcBookmark.BookmarkEnd.ParentNode;

            if ((startPara == null) || (endPara == null))
                throw new InvalidOperationException("Parent of the bookmark start or end is not a paragraph, cannot handle this scenario yet.");

            // Limit ourselves to a reasonably simple scenario.
            if (startPara.ParentNode != endPara.ParentNode)
                throw new InvalidOperationException("Start and end paragraphs have different parents, cannot handle this scenario yet.");

            // We want to copy all paragraphs from the start paragraph up to (and including) the end paragraph,
            // Therefore the node at which we stop is one after the end paragraph.
            Node endNode = endPara.NextSibling;

            // This is the loop to go through all paragraph-level nodes in the bookmark.
            for (Node curNode = startPara; curNode != endNode; curNode = curNode.NextSibling)
            {
                // This creates a copy of the current node and imports it (makes it valid) in the context
                // Of the destination document. Importing means adjusting styles and list identifiers correctly.
                Node newNode = importer.ImportNode(curNode, true);

                // Now we simply append the new node to the destination.
                dstNode.AppendChild(newNode);
            }
        }
        private CompositeNode SplitCompositeAtNode(CompositeNode baseNode, Node targetNode)
        {
            CompositeNode cloneNode      = (CompositeNode)baseNode.Clone(false);
            Node          node           = targetNode;
            int           currentPageNum = pageNumberFinder.GetPage(baseNode);

            // Move all nodes found on the next page into the copied node. Handle row nodes separately.
            if (baseNode.NodeType != NodeType.Row)
            {
                CompositeNode composite = cloneNode;
                if (baseNode.NodeType == NodeType.Section)
                {
                    cloneNode = (CompositeNode)baseNode.Clone(true);
                    Section section = (Section)cloneNode;
                    section.Body.RemoveAllChildren();
                    composite = section.Body;
                }

                while (node != null)
                {
                    Node nextNode = node.NextSibling;
                    composite.AppendChild(node);
                    node = nextNode;
                }
            }
            else
            {
                // If we are dealing with a row, we need to add dummy cells for the cloned row.
                int targetPageNum = pageNumberFinder.GetPage(targetNode);

                Node[] childNodes = baseNode.ChildNodes.ToArray();
                foreach (Node childNode in childNodes)
                {
                    int pageNum = pageNumberFinder.GetPage(childNode);
                    if (pageNum == targetPageNum)
                    {
                        if (cloneNode.NodeType == NodeType.Row)
                        {
                            ((Row)cloneNode).EnsureMinimum();
                        }

                        if (cloneNode.NodeType == NodeType.Cell)
                        {
                            ((Cell)cloneNode).EnsureMinimum();
                        }

                        cloneNode.LastChild.Remove();
                        cloneNode.AppendChild(childNode);
                    }
                    else if (pageNum == currentPageNum)
                    {
                        cloneNode.AppendChild(childNode.Clone(false));
                        if (cloneNode.LastChild.NodeType != NodeType.Cell)
                        {
                            ((CompositeNode)cloneNode.LastChild).AppendChild(
                                ((CompositeNode)childNode).FirstChild.Clone(false));
                        }
                    }
                }
            }

            // Insert the split node after the original.
            baseNode.ParentNode.InsertAfter(cloneNode, baseNode);

            // Update the new page numbers of the base node and the cloned node, including its descendants.
            // This will only be a single page as the cloned composite is split to be on one page.
            int currentEndPageNum = pageNumberFinder.GetPageEnd(baseNode);

            pageNumberFinder.AddPageNumbersForNode(baseNode, currentPageNum, currentEndPageNum - 1);
            pageNumberFinder.AddPageNumbersForNode(cloneNode, currentEndPageNum, currentEndPageNum);
            foreach (Node childNode in cloneNode.GetChildNodes(NodeType.Any, true))
            {
                pageNumberFinder.AddPageNumbersForNode(childNode, currentEndPageNum, currentEndPageNum);
            }

            return(cloneNode);
        }
        /// <summary>
        /// Renders any node in a document to the path specified using the image save options.
        /// </summary>
        /// <param name="node">The node to render.</param>
        /// <param name="filePath">The path to save the rendered image to.</param>
        /// <param name="imageOptions">The image options to use during rendering. This can be null.</param>
        public void RenderNode(Node node, string filePath, ImageSaveOptions imageOptions)
        {
            if (imageOptions == null)
            {
                imageOptions = new ImageSaveOptions(FileFormatUtil.ExtensionToSaveFormat(Path.GetExtension(filePath)));
            }

            // Store the paper color to be used on the final image and change to transparent.
            // This will cause any content around the rendered node to be removed later on.
            Color savePaperColor = imageOptions.PaperColor;

            imageOptions.PaperColor = Color.Transparent;

            // There a bug which affects the cache of a cloned node.
            // To avoid this, we clone the entire document, including all nodes,
            // finding the matching node in the cloned document and rendering that instead.
            Document doc = (Document)node.Document.Clone(true);

            node = doc.GetChild(NodeType.Any, node.Document.GetChildNodes(NodeType.Any, true).IndexOf(node), true);

            // Create a temporary shape to store the target node in. This shape will be rendered to retrieve
            // the rendered content of the node.
            Shape   shape         = new Shape(doc, ShapeType.TextBox);
            Section parentSection = (Section)node.GetAncestor(NodeType.Section);

            // Assume that the node cannot be larger than the page in size.
            shape.Width     = parentSection.PageSetup.PageWidth;
            shape.Height    = parentSection.PageSetup.PageHeight;
            shape.FillColor = Color.Transparent;

            // Don't draw a surronding line on the shape.
            shape.Stroked = false;

            // Move up through the DOM until we find a suitable node to insert into a Shape
            // (a node with a parent can contain paragraphs, tables the same as a shape). Each parent node is cloned
            // on the way up so even a descendant node passed to this method can be rendered. Since we are working
            // with the actual nodes of the document we need to clone the target node into the temporary shape.
            Node currentNode = node;

            while (!(currentNode.ParentNode is InlineStory || currentNode.ParentNode is Story ||
                     currentNode.ParentNode is ShapeBase))
            {
                CompositeNode parent = (CompositeNode)currentNode.ParentNode.Clone(false);
                currentNode = currentNode.ParentNode;
                parent.AppendChild(node.Clone(true));
                node = parent; // Store this new node to be inserted into the shape.
            }

            // We must add the shape to the document tree to have it rendered.
            shape.AppendChild(node.Clone(true));
            parentSection.Body.FirstParagraph.AppendChild(shape);

            // Render the shape to stream so we can take advantage of the effects of the ImageSaveOptions class.
            // Retrieve the rendered image and remove the shape from the document.
            MemoryStream  stream   = new MemoryStream();
            ShapeRenderer renderer = shape.GetShapeRenderer();

            renderer.Save(stream, imageOptions);
            shape.Remove();

            Rectangle crop = renderer.GetOpaqueBoundsInPixels(imageOptions.Scale, imageOptions.HorizontalResolution,
                                                              imageOptions.VerticalResolution);

            using (Bitmap renderedImage = new Bitmap(stream))
            {
                Bitmap croppedImage = new Bitmap(crop.Width, crop.Height);
                croppedImage.SetResolution(imageOptions.HorizontalResolution, imageOptions.VerticalResolution);

                // Create the final image with the proper background color.
                using (Graphics g = Graphics.FromImage(croppedImage))
                {
                    g.Clear(savePaperColor);
                    g.DrawImage(renderedImage, new Rectangle(0, 0, croppedImage.Width, croppedImage.Height), crop.X,
                                crop.Y, crop.Width, crop.Height, GraphicsUnit.Pixel);

                    croppedImage.Save(filePath);
                }
            }
        }