Wrong Count of Animated Text Paragraphs in a Text Frame Is Returned in C#

Hi Team,

I have a sample PPTX with a slide containing animated text frame. Text frame has four animated paragraphs. I use Aspose to read this PPTX and want to get images of individual animated text paragraphs. Ideally, I should get four separate images corresponding to four animated paragraphs in the PPTX slide, but I get more than 4.

The code:

using Aspose.Slides;
using Aspose.Slides.Export;
using System.Drawing.Imaging;
using Aspose.Slides.Animation;
using Aspose.Slides.Charts;
using Aspose.Slides.SmartArt;
using Aspose.Slides.Ink;
using System.Drawing;
using System.Drawing.Imaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Aspose.Slides;
using Aspose.Slides.Animation;
using Aspose.Slides.Charts;
using Aspose.Slides.SmartArt;
using Aspose.Slides.Ink;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using Aspose.Slides.Export;
class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Starting Aspose.Slides processing...");
            
            // Apply Aspose.Slides license
            License license = new License();
            license.SetLicense("Aspose.Total.lic"); // Make sure this file is in your application's directory
            Console.WriteLine("License applied successfully");
            
            // Check if file exists
            string presentationPath = "sample.pptx";
            if (!File.Exists(presentationPath))
            {
                Console.WriteLine($"ERROR: Presentation file not found at: {Path.GetFullPath(presentationPath)}");
                return;
            }
            
            Console.WriteLine($"Loading presentation from: {Path.GetFullPath(presentationPath)}");
            
            // Load the presentation
            using (Presentation presentation = new Presentation(presentationPath))
            {
                Console.WriteLine($"Presentation loaded successfully. Total slides: {presentation.Slides.Count}");
                
                // Loop through all slides
                for (int slideIndex = 0; slideIndex < presentation.Slides.Count; slideIndex++)
                {
                    // Get current slide
                    ISlide slide = presentation.Slides[slideIndex];
                    Console.WriteLine($"Processing slide {slideIndex + 1}. Total shapes: {slide.Shapes.Count}");

                    // Process each shape in the current slide
                    foreach (var curShape in slide.Shapes)
                    {
                        try
                        {
                            Console.WriteLine($"  Shape type: {curShape.GetType().Name}");
                            
                            IAutoShape curAutoShape = curShape as AutoShape;
                            if (curAutoShape == null)
                            {
                                Console.WriteLine("  Not an AutoShape - skipping");
                                continue;
                            }
                            
                            if (curAutoShape.TextFrame == null)
                            {
                                Console.WriteLine("  No TextFrame found - skipping");
                                continue;
                            }
                            
                            Console.WriteLine($"  AutoShape has TextFrame with {curAutoShape.TextFrame.Paragraphs.Count} paragraphs");
                            
                            using (var cloneShapeImage = curAutoShape.GetThumbnail())
                            {
                                Console.WriteLine($"  Got thumbnail of size: {cloneShapeImage.Width}x{cloneShapeImage.Height}");
                                Rectangle finalRect = new Rectangle();
                                List<Tuple<Rectangle, Bitmap>> paragraphs = new List<Tuple<Rectangle, Bitmap>>();

                                int paraCounter = 1;
                                foreach (var curPara in curAutoShape.TextFrame.Paragraphs)
                                {
                                    var paraRect = curPara.GetRect();
                                    Console.WriteLine($"  Paragraph {paraCounter} rect: X={paraRect.X}, Y={paraRect.Y}, W={paraRect.Width}, H={paraRect.Height}");

                                    Double lineWidth = curAutoShape.LineFormat.Width;

                                    if (Double.IsNaN(lineWidth) || Double.IsInfinity(lineWidth))
                                    {
                                        lineWidth = 0.0;
                                    }

                                    finalRect.X = (int)(curAutoShape.X + lineWidth);
                                    finalRect.Y = (int)(curAutoShape.Y + paraRect.Y);
                                    double paraHeight = Math.Ceiling(paraRect.Height);
                                    finalRect.Width = Math.Max(1, (int)(curAutoShape.Width - (2 * lineWidth)));
                                    finalRect.Height = Math.Max(1, (int)paraHeight);
                                    
                                    Console.WriteLine($"  Final rect: X={finalRect.X}, Y={finalRect.Y}, W={finalRect.Width}, H={finalRect.Height}");

                                    string fileName = $"slide_{slideIndex + 1}_para_{paraCounter}.png";
                                    Console.WriteLine($"  Saving to file: {fileName}");

                                    var dstImage = new Bitmap((int)(finalRect.Width), (int)(finalRect.Height));

                                    using (Graphics g = Graphics.FromImage(dstImage))
                                    {
                                        g.DrawImage(cloneShapeImage, new Rectangle(0, 0, dstImage.Width, dstImage.Height), finalRect, GraphicsUnit.Pixel);
                                    }
                                    dstImage.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
                                    Console.WriteLine($"  Successfully saved paragraph {paraCounter}");
                                    paraCounter++;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"  ERROR processing shape: {ex.Message}");
                            Console.WriteLine($"  Stack trace: {ex.StackTrace}");
                        }
                    }
                }
            }
            
            Console.WriteLine("Processing completed successfully");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"An error occurred: {ex.Message}");
            Console.WriteLine($"Stack trace: {ex.StackTrace}");
        }
    }
}

sample.zip (49.7 KB)

tryAspose.zip (19.5 KB)

I used Aspose 25.5 version. The PPTX and the output images are attached.

Pls help resolve this issue. Thanks,

@bhav

@bhav,
Thank you for reporting on the issue. I’ve reproduced the problem the paragraph count when extracting the paragraphs and converting them to images. We apologize for any inconvenience caused.

We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): SLIDESNET-44961

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Hello Andrey,

Thank you for acknowledging this issue. This is a critical issue for our business use case and we are keen to get it fixed as soon as possible as it impacts a lot of our customer cases. Just wanted to highlight the priority of this issue to get it appropriately prioritized at your end.

Thanks,
@bhav

@bhav,
Thank you for your patience. Your request is currently being handled under our standard priority, and our developers are doing their utmost to resolve it as swiftly as possible. Should you need a faster turnaround, you are welcome to reach out to our paid support service to request an elevated priority.

The issues you found earlier (filed as SLIDESNET-44961) have been resolved in Aspose.Slides for .NET 25.8 (ZIP, MSI, NuGet, Cross-platform).
You can check all fixes on the Release Notes page.
You can also find the latest version of our library on the Product Download page.

@bhav,
The text frame you specified contains 8 paragraphs, 4 of which contain no text (they are empty). Below is the method used to determine whether a paragraph is empty:

private static bool IsParagraphEmpty(IParagraph paragraph)
{
    // If there are no portions, the paragraph is empty
    if (paragraph.Portions.Count == 0)
        return true;

    // Check each portion
    foreach (var portion in paragraph.Portions)
    {
        // If there is regular text
        if (!string.IsNullOrEmpty(portion.Text))
            return false;

        // If there is an embedded formula (math expression)
        if (portion is MathParagraph)
            return false;
    }

    // All portions are empty and contain no formulas
    return true;
}

In addition, you made several mistakes in the original code:

Issue 1:
curAutoShape.GetThumbnail() returns an image of the entire shape, not the entire slide. You then try to “crop” the paragraph from this image using slide coordinates, which is logically incorrect because the coordinates curAutoShape.X/Y and curPara.GetRect() are defined in slide space, not in the coordinate system of cloneShapeImage.
As a result, you crop the paragraph using coordinates that don’t correspond to the actual image content — leading to incorrect output.

Issue 2:
You take LineFormat.Width into account when calculating the position and size of the paragraph.
However, LineFormat.Width affects only the visual appearance of the shape’s border and does not influence the position or size of the text inside the text frame. Therefore, it should not be included in the computation of finalRect.

Issue 3:
curPara.GetRect() returns the position of the paragraph relative to the text frame, but the code treats it as if it’s defined in slide coordinates.

Below is the corrected version of the code:

using (Presentation presentation = new Presentation(pptxFileName))
{
    for (int slideIndex = 0; slideIndex < presentation.Slides.Count; slideIndex++)
    {
        ISlide slide = presentation.Slides[slideIndex];

        foreach (var curShape in slide.Shapes)
        {
            try
            {
                IAutoShape curAutoShape = curShape as AutoShape;
                if (curAutoShape == null || curAutoShape.TextFrame == null)
                {
                    continue;
                }

                using (var cloneShapeImage = curAutoShape.GetThumbnail())
                {
                    int paraCounter = 1;

                    foreach (var curPara in curAutoShape.TextFrame.Paragraphs)
                    {
                        if (IsParagraphEmpty(curPara))
                            continue;

                        var paraRect = curPara.GetRect();

                        string fileName = folderPath + (slideIndex + 1).ToString() + paraCounter.ToString() + ".png";

                        var dstImage = new Bitmap((int)(paraRect.Width), (int)(paraRect.Height));

                        using (Graphics g = Graphics.FromImage(dstImage))
                        {
                            g.DrawImage(cloneShapeImage,
                                new Rectangle(0, 0, dstImage.Width, dstImage.Height),
                                paraRect,
                                GraphicsUnit.Pixel);
                        }

                        dstImage.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
                        paraCounter++;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR processing shape");
            }
        }
    }
}