Extraction of coordinates of content control in footer

Hello
I am trying to use the ASpose Word LayoutEnumerator to do a search for a certain coordinate of a content control on a DOCX footer…

I have used the same code to extract coordinates successfully in the past… but for this particular example, I am taking exception … Msg says "Value cannot be null: in the following instruction.

enumerator.Current = collector.GetEntity(start); 

Can you tell me why ? or what it is conplaining about.

Attached is the zip of my test VS files.
Test.zip (96.2 KB)

Thank you.

I am having problem extracting the coordinate of the content control I placed in the footer of a word document.
I did not have this issue with content controls that live in the main body of the document.

It’s the one in the footer… that gives me exception when IReplaceCallback range replace codes get called…
And I used

LayoutCollector collector = new LayoutCollector((Aspose.Words.Document)e.MatchNode.Document);
enumerator.Current = collector.GetEntity(start);

I am taking exception at this instruction… saying Value cannot be null.

(See the BarCodeREplaceEvaluator class I included in the zip file)
Since I cannot debug into it… Not sure what it is complaining about.

I posted this question earlier… but somehow it disappeared from the forum.
Please advise …
Why am I getting this exception…
I am using the same code to extract coordinates of another content control else where… However that content control does not live in the footer. .I dont know if that has anything to do with it.

I am including my test files…
Thank you. Test.zip (95.5 KB)

@nick1234,

Please also provide a screenshot highlighting the area in ‘Nicktest.docx’ document that you want to obtain coordinates (Rectangle) of.

Hello Awais

As you can see in the attached screen shot, I put the docx in Developer mode so you can see that there is a content control in the footer section called Barcode.

In the attached code, you can see that I loop through looking for this content control… and once I find it
I use Aspose word IReplaceCallback to get to the coordinates of the rectangle of its position in the footer.
Again… The insruction that is blowing up is

LayoutCollector collector = new LayoutCollector((Aspose.Words.Document)e.MatchNode.Document);
** enumerator.Current = collector.GetEntity(start);

Please advise… why this is taking exception.
Thank you for your help.screenshot.jpg (161.6 KB)

@nick1234,

I believe, the following code will help you to meet this requirement. This sample adds a border around each layout element and saves each page as a JPEG image to the data directory.

Document doc = new Document("D:\\temp\\test\\Nicktest.docx");
LayoutEnumerator it = new LayoutEnumerator(doc);
OutlineLayoutEntitiesRenderer.Run(doc, it, "D:\\Temp\\");
////////////////////////////////////////////////////////////////
class OutlineLayoutEntitiesRenderer
{
    public static void Run(Document doc, LayoutEnumerator it, string folderPath)
    {
        // Make sure the enumerator is at the beginning of the document.
        it.Reset();

        for (int pageIndex = 0; pageIndex < doc.PageCount; pageIndex++)
        {
            // Use the document class to find information about the current page.
            PageInfo pageInfo = doc.GetPageInfo(pageIndex);

            const float resolution = 150.0f;
            Size pageSize = pageInfo.GetSizeInPixels(1.0f, resolution);

            using (Bitmap img = new Bitmap(pageSize.Width, pageSize.Height))
            {
                img.SetResolution(resolution, resolution);

                using (Graphics g = Graphics.FromImage(img))
                {
                    // Make the background white.
                    g.Clear(Color.White);

                    // Render the page to the graphics.
                    doc.RenderToScale(pageIndex, g, 0.0f, 0.0f, 1.0f);

                    // Add an outline around each element on the page using the graphics object.
                    AddBoundingBoxToElementsOnPage(it, g);

                    // Move the enumerator to the next page if there is one.
                    it.MoveNext();

                    img.Save(folderPath + string.Format("TestFile Page {0} Out.png", pageIndex + 1));
                }
            }
        }
    }

    /// <summary>
    /// Adds a colored border around each layout element on the page.
    /// </summary>
    private static void AddBoundingBoxToElementsOnPage(LayoutEnumerator it, Graphics g)
    {
        do
        {
            // This time instead of MoveFirstChild and MoveNext, we use MoveLastChild and MovePrevious to enumerate from last to first.
            // Enumeration is done backward so the lines of child entities are drawn first and don't overlap the lines of the parent.
            if (it.MoveLastChild())
            {
                AddBoundingBoxToElementsOnPage(it, g);
                it.MoveParent();
            }

            // Convert the rectangle representing the position of the layout entity on the page from points to pixels.
            RectangleF rectF = it.Rectangle;
            Rectangle rect = new Rectangle(PointToPixel(rectF.Left, g.DpiX), PointToPixel(rectF.Top, g.DpiY),
                PointToPixel(rectF.Width, g.DpiX), PointToPixel(rectF.Height, g.DpiY));

            // Draw a line around the layout entity on the page.
            g.DrawRectangle(GetColoredPenFromType(it.Type), rect);

            // Stop after all elements on the page have been procesed.
            if (it.Type == LayoutEntityType.Page)
                return;

        } while (it.MovePrevious());
    }

    /// <summary>
    /// Returns a different colored pen for each entity type.
    /// </summary>
    private static Pen GetColoredPenFromType(LayoutEntityType type)
    {
        switch (type)
        {
            case LayoutEntityType.Cell:
                return Pens.Purple;
            case LayoutEntityType.Column:
                return Pens.Green;
            case LayoutEntityType.Comment:
                return Pens.LightBlue;
            case LayoutEntityType.Endnote:
                return Pens.DarkRed;
            case LayoutEntityType.Footnote:
                return Pens.DarkBlue;
            case LayoutEntityType.HeaderFooter:
                return Pens.DarkGreen;
            case LayoutEntityType.Line:
                return Pens.Blue;
            case LayoutEntityType.NoteSeparator:
                return Pens.LightGreen;
            case LayoutEntityType.Page:
                return Pens.Red;
            case LayoutEntityType.Row:
                return Pens.Orange;
            case LayoutEntityType.Span:
                return Pens.Red;
            case LayoutEntityType.TextBox:
                return Pens.Yellow;
            default:
                return Pens.Red;
        }
    }

    /// <summary>
    /// Converts a value in points to pixels.
    /// </summary>
    private static int PointToPixel(float value, double resolution)
    {
        return Convert.ToInt32(ConvertUtil.PointToPixel(value, resolution));
    }
}

P.S. You can get the complete example code from here: EnumerateLayoutElements.cs

Thanks for responding quickly…

However, you did not answer my question which was why did that instruction take an exception ?
the error I got was “Value cannot be null” however, I cannot debug into it to find out what it is complaining about.

I used the same code to retrieve the coordinates of another content control just fine.
However, the difference is that content control lives in the main body instead of in the footer, I dont know if this has anything to do with it…

Please advise… Thanks.

@nick1234,

I am afraid, it is throwing exception because the LayoutCollector.GetEntity method does not work for nodes within headers/footers. The problem with headers/footers is that a single document node in header/footer has multiple corresponding objects in layout model – one per each Page where this header/footer is rendered. So, technically it is not possible to return single entity for a node which is inside header/footer.