Example #1
0
        //--------------------------------------------------------------------------------------------------

        public override void Remove()
        {
            _RootShape?.Remove();
            _RootShape = null;
            Components.Clear();
            base.Remove();
        }
Example #2
0
        public void DeleteAllImagesPreOrder()
        {
            Document doc = new Document(MyDir + "Image.SampleImages.doc");

            Assert.AreEqual(6, doc.GetChildNodes(NodeType.Shape, true).Count);

            //ExStart
            //ExFor:Node.NextPreOrder
            //ExSummary:Shows how to delete all images from a document using pre-order tree traversal.
            Node curNode = doc;

            while (curNode != null)
            {
                Node nextNode = curNode.NextPreOrder(doc);

                if (curNode.NodeType.Equals(NodeType.Shape))
                {
                    Shape shape = (Shape)curNode;

                    // Several shape types can have an image including image shapes and OLE objects.
                    if (shape.HasImage)
                    {
                        shape.Remove();
                    }
                }

                curNode = nextNode;
            }
            //ExEnd

            Assert.AreEqual(1, doc.GetChildNodes(NodeType.Shape, true).Count);
            doc.Save(ArtifactsDir + "Image.DeleteAllImagesPreOrder.doc");
        }
        public void GetOpaqueBoundsInPixels()
        {
            Document doc = new Document(MyDir + "Shape.TextBox.doc");

            Shape shape = (Shape)doc.GetChild(NodeType.Shape, 0, true);

            ImageSaveOptions imageOptions = new ImageSaveOptions(SaveFormat.Jpeg);

            MemoryStream  stream   = new MemoryStream();
            ShapeRenderer renderer = shape.GetShapeRenderer();

            renderer.Save(stream, imageOptions);

            shape.Remove();

            // Check that the opaque bounds and bounds have default values
            Assert.AreEqual(250, renderer.GetOpaqueBoundsInPixels(imageOptions.Scale, imageOptions.VerticalResolution).Width);
            Assert.AreEqual(52, renderer.GetOpaqueBoundsInPixels(imageOptions.Scale, imageOptions.HorizontalResolution).Height);

            Assert.AreEqual(250, renderer.GetBoundsInPixels(imageOptions.Scale, imageOptions.VerticalResolution).Width);
            Assert.AreEqual(52, renderer.GetBoundsInPixels(imageOptions.Scale, imageOptions.HorizontalResolution).Height);

            Assert.AreEqual(250, renderer.GetOpaqueBoundsInPixels(imageOptions.Scale, imageOptions.HorizontalResolution).Width);
            Assert.AreEqual(52, renderer.GetOpaqueBoundsInPixels(imageOptions.Scale, imageOptions.HorizontalResolution).Height);

            Assert.AreEqual(250, renderer.GetBoundsInPixels(imageOptions.Scale, imageOptions.VerticalResolution).Width);
            Assert.AreEqual(52, renderer.GetBoundsInPixels(imageOptions.Scale, imageOptions.VerticalResolution).Height);

            Assert.AreEqual((float)187.850006, renderer.OpaqueBoundsInPoints.Width);
            Assert.AreEqual((float)39.25, renderer.OpaqueBoundsInPoints.Height);
        }
Example #4
0
            /// <summary>
            /// Called when a Shape is encountered in the document.
            /// </summary>
            public override VisitorAction VisitShapeStart(Shape shape)
            {
                if (this.isHidden(shape))
                {
                    shape.Remove();
                }

                return(VisitorAction.Continue);
            }
Example #5
0
            /// <summary>
            /// Called when a Shape is encountered in the document.
            /// </summary>
            public override VisitorAction VisitShapeStart(Shape shape)
            {
                if (isHidden(shape))
                    shape.Remove();

                return VisitorAction.Continue;
            }
        /// <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);
                }
            }
        }
Example #7
0
        private void MergeWithWordTemplate(string templatePath, string outputPath, string imagePath)
        {
            try
            {
                lblMessage.Text = "";

                // Check for license and apply if exists
                string licenseFile = Server.MapPath("~/App_Data/Aspose.Words.lic");
                if (File.Exists(licenseFile))
                {
                    License license = new License();
                    license.SetLicense(licenseFile);
                }

                Document doc = QuoteGenerator.GetUnmergedTemplateObject(templatePath + "MailMerge_Template.doc", Session);
                if (doc != null)
                {
                    // Fill the fields in the document with user data.
                    DataSet data = QuoteGenerator.GetDataSetForGridView(Session);
                    if (data != null)
                    {
                        decimal itemtotalBeforeVAT       = 0;
                        decimal itemtotalVATAmount       = 0;
                        decimal itemtotalAmount          = 0;
                        decimal grandTotalAllItemsAmount = 0;

                        if (grdInvoiceProducts.Rows.Count > 0)
                        {
                            // removing all rows in collection
                            data.Tables[0].Rows.Clear();

                            System.Web.UI.WebControls.TextBox txtProductDescription;
                            System.Web.UI.WebControls.TextBox txtProductPrice;
                            System.Web.UI.WebControls.TextBox txtProductQuantity;
                            DropDownList ddlProductVAT;

                            foreach (GridViewRow gr in grdInvoiceProducts.Rows)
                            {
                                // find control in each gridview rows
                                txtProductDescription = (System.Web.UI.WebControls.TextBox)gr.FindControl("txtProductDescription");
                                txtProductPrice       = (System.Web.UI.WebControls.TextBox)gr.FindControl("txtProductPrice");
                                txtProductQuantity    = (System.Web.UI.WebControls.TextBox)gr.FindControl("txtProductQuantity");
                                ddlProductVAT         = (DropDownList)gr.FindControl("ddlProductVAT");

                                // varify the found controls should not be null
                                if (txtProductDescription != null && txtProductPrice != null && txtProductQuantity != null && ddlProductVAT != null)
                                {
                                    // varify the found controls should not be empty
                                    if (txtProductDescription.Text.Trim() != "" && txtProductPrice.Text.Trim() != "" && txtProductQuantity.Text.Trim() != "" && ddlProductVAT.Items.Count > 0)
                                    {
                                        // actual amount price X quantity
                                        itemtotalBeforeVAT = (decimal.Parse(txtProductPrice.Text.Trim()) * decimal.Parse(txtProductQuantity.Text.Trim()));

                                        // VAT amount = (actual X VAT)/100
                                        itemtotalVATAmount = ((itemtotalBeforeVAT * decimal.Parse(ddlProductVAT.SelectedItem.Value.Trim())) / 100);

                                        // Total amount including VAT
                                        itemtotalAmount           = itemtotalBeforeVAT + itemtotalVATAmount;
                                        grandTotalAllItemsAmount += itemtotalAmount;

                                        // Add the temp data row to the tables for each row.
                                        data.Tables[0].Rows.Add(gr.Cells[0].Text, txtProductDescription.Text.Trim(), decimal.Parse(txtProductPrice.Text.Trim()), decimal.Parse(txtProductQuantity.Text.Trim()), itemtotalBeforeVAT, decimal.Parse(ddlProductVAT.SelectedItem.Value), itemtotalVATAmount, itemtotalAmount);
                                    }
                                }
                            }
                        }

                        if (imagePath != "")
                        {
                            Shape shape = (Shape)doc.GetChild(NodeType.Shape, 0, true);
                            if (shape != null)
                            {
                                shape.ImageData.ImageBytes = File.ReadAllBytes(imagePath);
                            }
                        }
                        else
                        {
                            Shape shape = (Shape)doc.GetChild(NodeType.Shape, 0, true);
                            if (shape != null)
                            {
                                shape.Remove();
                            }
                        }
                        // updating fix fields using simple aspose mail merge
                        doc.MailMerge.Execute(
                            new string[] { "CompanyName", "CompanyAddress", "CompanyZipState", "CompanyCountry", "CustomerName", "CustomerAddress", "CustomerZipState", "CustomerCountry", "InvoiceTotalAmount", "DocCaption", "DocDate", "DocNo", "DocDescription", "DocTC" },
                            new object[] { txtCompanyName.Text.Trim(), txtCompanyAddress.Text.Trim(), txtCompanyStateZip.Text.Trim(), txtCompanyCountry.Text.Trim(), txtCustomerName.Text.Trim(), txtCustomerAddress.Text.Trim(), txtCustomerStateZip.Text.Trim(), txtCustomerCountry.Text.Trim(), grandTotalAllItemsAmount, txtDocCaption.Text.Trim(), txtDocDate.Text.Trim(), txtDocNo.Text.Trim(), txtDescription.Text.Trim(), txtTC.Text.Trim() });

                        doc.MailMerge.ExecuteWithRegions(data);

                        // removing unused fields in template
                        doc.MailMerge.CleanupOptions = MailMergeCleanupOptions.RemoveEmptyParagraphs | MailMergeCleanupOptions.RemoveContainingFields | MailMergeCleanupOptions.RemoveUnusedFields;

                        // updating document layout, to be cached and re-use
                        doc.UpdatePageLayout();

                        // Saves the document to disk.
                        string fname = System.Guid.NewGuid().ToString() + "." + QuoteGenerator.GetSaveFormat(ExportTypeDropDown.SelectedValue);
                        doc.Save(outputPath + fname);
                        Response.Clear();
                        Response.Buffer = true;
                        Response.AddHeader("content-disposition", "attachment;filename=ExportedFile_" + DateTime.Now.Day.ToString() + "_" + DateTime.Now.Month.ToString() + "_" + DateTime.Now.Year.ToString() + "_" + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + "_" + DateTime.Now.Millisecond.ToString() + "." + QuoteGenerator.GetSaveFormat(ExportTypeDropDown.SelectedValue));
                        Response.Charset     = "";
                        Response.ContentType = "application/pdf";
                        Response.Cache.SetCacheability(HttpCacheability.NoCache);

                        Response.ContentType = "Application/" + QuoteGenerator.GetSaveFormat(ExportTypeDropDown.SelectedValue);
                        //Get the physical path to the file.
                        string FilePath = MapPath(GetDataDir_OutputDocs() + fname);

                        //Write the file directly to the HTTP content output stream.
                        Response.WriteFile(FilePath);
                        Response.Flush();

                        // delete file as its already in stream and available for user to download/save/view.
                        FileInfo file = new FileInfo(FilePath);
                        if (file.Exists)//check file exsit or not
                        {
                            file.Delete();
                        }
                        file = new FileInfo(imagePath);
                        if (file.Exists)//check file exsit or not
                        {
                            file.Delete();
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                lblMessage.Text = exc.Message;
                Response.Clear();
                Response.Flush();
            }
        }
Example #8
0
        //ExStart
        //ExId:RenderNode
        //ExSummary:Shows how to render a node independent of the document by building on the functionality provided by ShapeRenderer class.
        /// <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="path">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 static void RenderNode(Node node, string filePath, ImageSaveOptions imageOptions)
        {
            // Run some argument checks.
            if (node == null)
                throw new ArgumentException("Node cannot be null");

            // If no image options are supplied, create default options.
            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 instead clone the entire document including all nodes,
            // find the matching node in the cloned document and render 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; // We must make the shape and paper color transparent.

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

            // Move up through the DOM until we find node which is suitable to insert into a Shape (a node with a parent can contain paragraph, 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();
            shape.GetShapeRenderer().Save(stream, imageOptions);
            shape.Remove();

            // Load the image into a new bitmap.
            using (Bitmap renderedImage = new Bitmap(stream))
            {
                // Extract the actual content of the image by cropping transparent space around
                // the rendered shape.
                Rectangle cropRectangle = FindBoundingBoxAroundNode(renderedImage);

                Bitmap croppedImage = new Bitmap(cropRectangle.Width, cropRectangle.Height);
                croppedImage.SetResolution(imageOptions.Resolution, imageOptions.Resolution);

                // 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), cropRectangle.X, cropRectangle.Y, cropRectangle.Width, cropRectangle.Height, GraphicsUnit.Pixel);
                    croppedImage.Save(filePath);
                }
            }
        }
        public static void FormatFLow(SlidePart slidePart)
        {
            if (slidePart != default(SlidePart))
            {
                IEnumerable <Shape> flowChartShapes = slidePart.Slide.Descendants <Shape>().Where(d => d.Descendants <NonVisualDrawingProperties>().Where(e => e.Name.InnerText.Contains(Constants._ARROW_)).Count() > 0);
                int           i       = 0;
                long          firstId = 0;
                D.Transform2D prevBox = new D.Transform2D();
                foreach (Shape shape in flowChartShapes)
                {
                    String title = String.Empty;
                    NonVisualDrawingProperties meta = shape.Descendants <NonVisualDrawingProperties>().FirstOrDefault();


                    //resize shape
                    D.Transform2D currentShapePos = shape.Descendants <D.Transform2D>().FirstOrDefault();

                    currentShapePos.Extents.Cx = 2775204;
                    currentShapePos.Extents.Cy = 1446936;
                    if (i == 0)
                    {
                        firstId = meta.Id;
                        currentShapePos.Offset.X = 458569;
                        currentShapePos.Offset.Y = 1712339;
                    }
                    else
                    {
                        currentShapePos.Offset.X = Convert.ToInt64((prevBox.Extents.Cx.Value - (prevBox.Extents.Cx.Value * 0.20)) + prevBox.Offset.X);
                        currentShapePos.Offset.Y = prevBox.Offset.Y;
                    }



                    prevBox = currentShapePos;


                    if (meta != default(NonVisualDrawingProperties))
                    {
                        long idToFind = (firstId + i) - (flowChartShapes.Count() + 1);//check

                        Shape titleShape = slidePart.Slide.Descendants <Shape>().Where(d => d.Descendants <NonVisualDrawingProperties>().First() != default(NonVisualDrawingProperties) &&
                                                                                       d.Descendants <NonVisualDrawingProperties>().First().Id == idToFind &&
                                                                                       d.Descendants <NonVisualDrawingProperties>().First().Name.InnerText.Contains(Constants._TEXTBOX_))
                                           .FirstOrDefault();
                        if (titleShape != default(Shape))
                        {
                            D.Paragraph data = titleShape.Descendants <D.Paragraph>().FirstOrDefault();

                            title = data != default(D.Paragraph) ? data.InnerText : title;
                        }

                        //slidePart.Slide.RemoveChild(titleShape);
                        titleShape.Remove();
                        slidePart.Slide.Save();

                        D.Paragraph paragraph = shape.Descendants <D.Paragraph>().FirstOrDefault();
                        if (paragraph != default(D.Paragraph))
                        {
                            paragraph.RemoveAllChildren();
                            slidePart.Slide.Save();
                            D.Run run1 = new D.Run();
                            paragraph.AppendChild(new D.ParagraphProperties()
                            {
                                Alignment = D.TextAlignmentTypeValues.Center
                            });
                            run1.AppendChild(new D.RunProperties()
                            {
                                Language = "en-US", Dirty = true
                            });
                            run1.Text = new D.Text(title);
                            paragraph.AppendChild(run1);
                        }
                        slidePart.Slide.Save();
                    }
                    i++;
                }
            }
        }
        /// <summary>
        /// Converts a textbox to a table by copying the same content and formatting.
        /// Currently export to HTML will render the textbox as an image which looses any text functionality.
        /// This is useful to convert textboxes in order to retain proper text.
        /// </summary>
        /// <param name="textbox">The textbox shape to convert to a table</param>
        private static void ConvertTextboxToTable(Shape textBox)
        {
            if (textBox.StoryType != StoryType.Textbox)
                throw new ArgumentException("Can only convert a shape of type textbox");

            Document doc = (Document)textBox.Document;
            Section section = (Section)textBox.GetAncestor(NodeType.Section);

            // Create a table to replace the textbox and transfer the same content and formatting.
            Table table = new Table(doc);
            // Ensure that the table contains a row and a cell.
            table.EnsureMinimum();
            // Use fixed column widths.
            table.AutoFit(AutoFitBehavior.FixedColumnWidths);

            // A shape is inline level (within a paragraph) where a table can only be block level so insert the table
            // after the paragraph which contains the shape.
            Node shapeParent = textBox.ParentNode;
            shapeParent.ParentNode.InsertAfter(table, shapeParent);

            // If the textbox is not inline then try to match the shape's left position using the table's left indent.
            if (!textBox.IsInline && textBox.Left < section.PageSetup.PageWidth)
                table.LeftIndent = textBox.Left;

            // We are only using one cell to replicate a textbox so we can make use of the FirstRow and FirstCell property.
            // Carry over borders and shading.
            Row firstRow = table.FirstRow;
            Cell firstCell = firstRow.FirstCell;
            firstCell.CellFormat.Borders.Color = textBox.StrokeColor;
            firstCell.CellFormat.Borders.LineWidth = textBox.StrokeWeight;
            firstCell.CellFormat.Shading.BackgroundPatternColor = textBox.Fill.Color;

            // Transfer the same height and width of the textbox to the table.
            firstRow.RowFormat.HeightRule = HeightRule.Exactly;
            firstRow.RowFormat.Height = textBox.Height;
            firstCell.CellFormat.Width = textBox.Width;
            table.AllowAutoFit = false;

            // Replicate the textbox's horizontal alignment.
            TableAlignment horizontalAlignment;
            switch (textBox.HorizontalAlignment)
            {
                case HorizontalAlignment.Left:
                    horizontalAlignment = TableAlignment.Left;
                    break;
                case HorizontalAlignment.Center:
                    horizontalAlignment = TableAlignment.Center;
                    break;
                case HorizontalAlignment.Right:
                    horizontalAlignment = TableAlignment.Right;
                    break;
                default:
                    // Most other options are left by default.
                    horizontalAlignment = TableAlignment.Left;
                    break;

            }

            table.Alignment = horizontalAlignment;
            firstCell.RemoveAllChildren();

            // Append all content from the textbox to the new table
            foreach (Node node in textBox.GetChildNodes(NodeType.Any, false).ToArray())
            {
                table.FirstRow.FirstCell.AppendChild(node);
            }

            // Remove the empty textbox from the document.
            textBox.Remove();
        }
Example #11
0
        /// <summary>
        /// Converts a textbox to a table by copying the same content and formatting.
        /// Currently export to HTML will render the textbox as an image which looses any text functionality.
        /// This is useful to convert textboxes in order to retain proper text.
        /// </summary>
        /// <param name="textbox">The textbox shape to convert to a table</param>
        private static void ConvertTextboxToTable(Shape textBox)
        {
            if (textBox.StoryType != StoryType.Textbox)
            {
                throw new ArgumentException("Can only convert a shape of type textbox");
            }

            Document doc     = (Document)textBox.Document;
            Section  section = (Section)textBox.GetAncestor(NodeType.Section);

            // Create a table to replace the textbox and transfer the same content and formatting.
            Table table = new Table(doc);

            // Ensure that the table contains a row and a cell.
            table.EnsureMinimum();
            // Use fixed column widths.
            table.AutoFit(AutoFitBehavior.FixedColumnWidths);

            // A shape is inline level (within a paragraph) where a table can only be block level so insert the table
            // after the paragraph which contains the shape.
            Node shapeParent = textBox.ParentNode;

            shapeParent.ParentNode.InsertAfter(table, shapeParent);

            // If the textbox is not inline then try to match the shape's left position using the table's left indent.
            if (!textBox.IsInline && textBox.Left < section.PageSetup.PageWidth)
            {
                table.LeftIndent = textBox.Left;
            }

            // We are only using one cell to replicate a textbox so we can make use of the FirstRow and FirstCell property.
            // Carry over borders and shading.
            Row  firstRow  = table.FirstRow;
            Cell firstCell = firstRow.FirstCell;

            firstCell.CellFormat.Borders.Color     = textBox.StrokeColor;
            firstCell.CellFormat.Borders.LineWidth = textBox.StrokeWeight;
            firstCell.CellFormat.Shading.BackgroundPatternColor = textBox.Fill.Color;

            // Transfer the same height and width of the textbox to the table.
            firstRow.RowFormat.HeightRule = HeightRule.Exactly;
            firstRow.RowFormat.Height     = textBox.Height;
            firstCell.CellFormat.Width    = textBox.Width;
            table.AllowAutoFit            = false;

            // Replicate the textbox's horizontal alignment.
            TableAlignment horizontalAlignment;

            switch (textBox.HorizontalAlignment)
            {
            case HorizontalAlignment.Left:
                horizontalAlignment = TableAlignment.Left;
                break;

            case HorizontalAlignment.Center:
                horizontalAlignment = TableAlignment.Center;
                break;

            case HorizontalAlignment.Right:
                horizontalAlignment = TableAlignment.Right;
                break;

            default:
                // Most other options are left by default.
                horizontalAlignment = TableAlignment.Left;
                break;
            }

            table.Alignment = horizontalAlignment;
            firstCell.RemoveAllChildren();

            // Append all content from the textbox to the new table
            foreach (Node node in textBox.GetChildNodes(NodeType.Any, false).ToArray())
            {
                table.FirstRow.FirstCell.AppendChild(node);
            }

            // Remove the empty textbox from the document.
            textBox.Remove();
        }