Aspose.Words for C++ 21.1 Release Notes

Major Features

We have added the following features from Aspose.Words for .NET on this regular monthly release:

  • StartColumnBookmark and EndColumnBookmark methods were introduced in DocumentBuilder class.
  • MarkdownSaveOptions.ImageSavingCallback has been added to control how images are saved upon converting to Markdown format.
  • Added an ability to ignore <noscript> HTML elements upon loading HTML.
  • TableStyle.VerticalAlignment was exposed publicly.

Limitations and API Differences

Aspose.Words for C++ has some differences as compared to its equivalent .NET version of the API. This section contains information about all such functionality that is not available in the current release. The missing features will be added in future releases.

  • The current release does not support Metered license.
  • The current release does not support LINQ and Reporting features.
  • The current release does not support OpenGL 3D Shapes rendering.
  • The current release does not support advanced typography based on HarfBuzz shaper.
  • The current release does not support loading PDF documents.
  • The current release has limited support for database features - C++ doesn’t have common API for DB like .NET System.Data.
  • The current release supports Microsoft Visual C++ version 2017 or higher.
  • The current release supports GCC 6.3 or higher and Clang 3.9.1 or higher on Linux and only for the x86_x64 platform.

Full List of Issues Covering all Changes in this Release

Key Summary Category
WORDSCPP-925 Memory leak in Aspose.Words for C++ Bug
WORDSCPP-1038 Unable to Retrieve the Number of Pages from Word DOC document Bug
WORDSNET-4987 Support “cold” rendering of OOXML SmartArt (Diagrams) New Feature
WORDSNET-20666 Add feature to create Move revision New Feature
WORDSNET-21389 Add IImageSavingCallback into MarkdownSaveOptions New Feature
WORDSNET-17026 LINQ Reporting Engine - Support section breaks inside data bands and conditional blocks New Feature
WORDSNET-20367 Add a field to the Node class so a User can store some custom meta-data in Aspose.Words Document model New Feature
WORDSNET-18882 Add feature to bookmark the table’s column New Feature
WORDSNET-21114 Add feature to get or set Cell Vertical Alignment using TableStyle New Feature
WORDSNET-21426 MS Word should automatically pick default Icon of Inserted OLE Object Enhancement
WORDSNET-21576 Add LastChild property and AppendChild() method to StructuredDocumentRangeStart class Enhancement
WORDSNET-21433 Improve URI processing to handle relative hyperlink Enhancement
WORDSNET-21493 Convert Word to JSON in Parent Child Hierarchy Enhancement
WORDSNET-20881 Partial rendering of Arabic Words in PDF Bug
WORDSNET-21005 Document.PageCount hangs for MHTML file generated by Aspose.Email Bug
WORDSNET-18933 DOCX to PDF conversion issue with math equation Bug
WORDSNET-15142 Incorrect page count detection Bug
WORDSNET-21516 First column content spilling into second column in PDF Bug
WORDSNET-17876 Characters (subset) in charts are not rendered in output PDF Bug
WORDSNET-13179 DOCX to PDF conversion issue with text rendering of Cambodian Fonts “Khmer” Bug
WORDSNET-18333 Superscript and Subscript characters in picture are not retained in PDF Bug
WORDSNET-21191 InvalidOperationException occurs during saving to HTML Bug
WORDSNET-16704 BitonalConvertor gives not the same result as on .NET Bug
WORDSNET-17362 Brackets and equation rendering issue in output PDF Bug
WORDSNET-21509 DOCX to PDF conversion exception: System.ArgumentOutOfRangeException Bug
WORDSNET-21415 Document.Compare generates the incorrect output Bug
WORDSNET-17888 Arabic characters are improperly rendered to another font Bug
WORDSNET-17986 Position of BookmarkStart and BookmarkEnd nodes is changed in output DOCX Bug
WORDSNET-21534 Incorrect value of STYLEREF field in header - Word to PDF Conversion Bug
WORDSNET-21535 Aspose.Words.FileCorruptedException is thrown for DOC Bug
WORDSNET-21462 DOCX to HTML conversion fails with Stack empty error message Bug
WORDSNET-21506 Hidden runs located in a Structured Document tag cannot be iterated Bug
WORDSNET-20715 The conversion to PDF never ends Bug
WORDSNET-21510 System.ArgumentOutOfRangeException occurs upon saving to PDF Bug
WORDSNET-21519 DOCX to PDF conversion exception Bug
WORDSNET-21494 Document.UpdateFields throws NullReferenceException Bug
WORDSNET-20010 Infinity loop in FloaterOverlapResolver due to zero height floating table Bug
WORDSNET-21545 Add obfuscation check to ApiTests.License.Net task Bug
WORDSNET-21552 Incorrect identification of list level and list item Bug
WORDSNET-17735 Certain Arabic characters are wrong when converting DOCX to PDF Bug
WORDSNET-20166 Infinity loop in FloaterOverlapResolver Bug
WORDSNET-18940 Conversion issue DOC/DOCX to PDF Bug
WORDSNET-17428 Superscript and Subscript characters in Picture render as question mark in PDF Bug
WORDSNET-21579 Insert SVG image failed on .NetFramework Bug
WORDSNET-21434 DOCX to PDF conversion: The numbering issue in the output Bug
WORDSNET-21253 Unexpected chart type Bug
WORDSNET-20876 SmartArt to PNG conversion issue with wrong background color and wrong font Bug
WORDSNET-21443 LINQ Reporting Engine - An issue with a JSON object having only complex properties Bug
WORDSNET-20892 ODT to Html: Frame borders and position are lost when converting .odt to html Bug
WORDSNET-21116 PDF/A-1a fails accessibility check Bug
WORDSNET-3814 Line numbering shows up in OpenOffice after changing PageSetup settings Bug
WORDSNET-21419 Inline ole shape overlaps container cell border after DOCX to PDF conversion Bug
WORDSNET-21325 Comments date do not reflect to changed time zone Bug
WORDSNET-21453 “Arithmetic operation resulted in an overflow.” exception when converting DOCX file to PNG/HTML/PDF Bug
WORDSNET-20954 Table lost formatting on page extraction Bug
WORDSNET-21268 DOC to PDF conversion hangs Bug
WORDSNET-21460 Bibliography text disappears during conversion Bug
WORDSNET-21153 UpdatePageLayout is throwing Array Dimensions exceeded supported range Bug
WORDSNET-20681 OutOfMemoryException when SaveAs document as PNG Bug
WORDSNET-21173 No content is loaded from a CHM file Bug
WORDSNET-21282 Preserve Text Alignment in Table Cell during Word DOT to HTML Conversion Bug
WORDSNET-21286 DataLabel customization does not work when chart is inserted into template Bug
WORDSNET-21171 FileCorruptedException is thrown when trying to load a CHM document Bug
WORDSNET-21299 Sunburst Chart DOCX to PDF - System.ArgumentException Unexpected chart type Bug
WORDSNET-21476 Aspose.Words corrupts document containing statistical chart Bug
WORDSNET-21481 Comment.DateTime get time in UTC without conversion to local Bug
WORDSNET-21326 Execution of the Aspose.Words hangs on Linux when Tahoma font is absent Bug
WORDSNET-21203 HTML to PDF output incomplete Bug
WORDSNET-21341 3rd level of Thai text is not shown and replaced by strange symbol - DOCX to PDF Bug
WORDSNET-19932 Number list issues while converting DOCX -> HTML -> DOCX Bug
WORDSNET-21216 Diffrent behavior of “=SUM(ABOVE)” compared to Microsoft Word Bug
WORDSNET-21366 DOC->PDF conversion: Heading loses capitalization and bold effect in the output Bug
WORDSNET-16770 Image’s text is rendered as “?” mark in output PDF Bug
WORDSNET-14872 Lack of CSS background images while converting from HTML to Word Bug
WORDSNET-16336 Khmer Mondulkiri font renders incorrectly Bug
WORDSNET-17887 Arial Font is used instead of Calibri Fonts during DOCM to PDF conversion Bug
WORDSNET-16703 TestRadialGradient is rendered improperly. Bug
WORDSNET-11650 System.NullReferenceException is thrown while saving DOCX to PDF Bug
WORDSNET-19294 TestLoadPerformanceLarge() performance test fails Bug
WORDSNET-16717 Background in MHT looks differently Bug

Public API and Backward Incompatible Changes

This section lists public API changes that were introduced in Aspose.Words 21.1. It includes not only new and obsoleted public methods, but also a description of any changes in the behavior behind the scenes in Aspose.Words which may affect existing code. Any behavior introduced that could be seen as regression and modifies the existing behavior is especially important and is documented here.

Added a new public property HtmlLoadOptions::IgnoreNoscriptElements

Related issue: WORDSNET-21203

Added a new public property HtmlLoadOptions::IgnoreNoscriptElements:

/// <summary>
/// Gets a value indicating whether to ignore &lt;noscript&gt; HTML elements.
/// Default value is <c>false</c>.
/// </summary>
/// <remarks>
/// Like MS Word, Aspose.Words does not support scripts and by default loads content of &lt;noscript&gt; elements
/// into the resulting document. In most browsers, however, scripts are supported and content from &lt;noscript&gt;
/// is not visible. Setting this property to <c>true</c> forces Aspose.Words to ignore all &lt;noscript&gt; elements
/// and helps to produce documents that look closer to what is seen in browsers.
/// </remarks>
bool get_IgnoreNoscriptElements() const;

/// Setter for HtmlLoadOptions::IgnoreNoscriptElements
void set_IgnoreNoscriptElements(bool value);

Customers may now instruct Aspose.Words to ignore <noscript> HTML elements like most modern browsers do.

Use Case:

auto loadOptions = MakeObject<HtmlLoadOptions>();
loadOptions->set_IgnoreNoscriptElements(true);

Added a new public property Node::CustomNodeId

Related issue: WORDSNET-21203

Added a new public property Node::CustomNodeId:

/// <summary>
/// Specifies custom node identifier.
/// </summary>
/// <remarks>
/// <p>Default is zero.</p>
/// <p>This identifier can be set and used arbitrarily. For example, as a key to get external data.</p>
/// </remarks>
void int32_t get_CustomNodeId() const;
void void set_CustomNodeId(int32_t value);

Customers now may track node position in the model tree and bind external data based on assigned identifier:

Use Case:

auto doc = MakeObject<Document>();
auto builder = MakeObject<DocumentBuilder>(doc);
auto shape = builder->InsertShape(ShapeType::Rectangle, 100, 100);
shape->set_CustomNodeId(100);

Added a new public property TableStyle::VerticalAlignment

Related issue: WORDSNET-21114

Added a new public options that allows to set table style cell vertical alignment.

/// <summary>
/// Specifies the vertical alignment for the cells.
/// </summary>
/// <remarks>
/// The default value is <see cref="CellVerticalAlignment::Top"/>.
/// </remarks>
CellVerticalAlignment get_VerticalAlignment() const;
void set_VerticalAlignment(CellVerticalAlignment value);

Use Case:

auto doc = MakeObject<Document>(filename);
auto style = StaticCast<TableStyle>(doc->get_Styles()->idx_get(u"Custom Table 1"));
style->set_VerticalAlignment(CellVerticalAlignment::Center);

Added new public methods StartColumnBookmark and EndColumnBookmark to DocumentBuilder class

Related issue: WORDSNET-18882

The following public methods have been added to the DocumentBuilder class:

/// <summary>
/// Marks the current position in the document as a column bookmark start. The position must be in a table cell.
/// </summary>
/// <remarks>
/// <p>A column bookmark covers one or more columns in a range of rows. To create a valid bookmark you
/// need to call both <see cref="StartColumnBookmark"/> and <see cref="EndColumnBookmark"/> with the same
/// <b>bookmarkName</b> parameter.</p>
/// <p>Badly formed bookmarks or bookmarks with duplicate names will be ignored when the document is saved.</p>
/// <p>The actual position of the inserted <see cref="BookmarkStart"/> node may differ from the current document
/// builder position.</p>
/// </remarks>
/// <param name="bookmarkName">Name of the bookmark.</param>
/// <returns>The bookmark start node that was just created.</returns>
SharedPtr<BookmarkStart> StartColumnBookmark(System::String bookmarkName);
 
/// <summary>
/// Marks the current position in the document as a column bookmark end. The position must be in a table cell.
/// </summary>
/// <remarks>
/// <p>A column bookmark covers one or more columns in a range of rows. To create a valid bookmark you
/// need to call both <see cref="StartColumnBookmark"/> and <see cref="EndColumnBookmark"/> with the same
/// <b>bookmarkName</b> parameter.</p>
/// <p>Badly formed bookmarks or bookmarks with duplicate names will be ignored when the document is saved.</p>
/// <p>The actual position of the inserted <see cref="BookmarkEnd"/> node may differ from the current document
/// builder position.</p>
/// </remarks>
/// <param name="bookmarkName">Name of the bookmark.</param>
/// <returns>The bookmark end node that was just created.</returns>
SharedPtr<BookmarkEnd> EndColumnBookmark(System::String bookmarkName);

Use Case:

auto doc = MakeObject<Document>();
auto builder = MakeObject<DocumentBuilder>(doc);
 
builder->StartTable();
 
builder->InsertCell();
builder->StartColumnBookmark(u"Bookmark1");
builder->Write(u"Cell 1");
 
builder->InsertCell();
builder->Write(u"Cell 2");
 
builder->InsertCell();
builder->Write(u"Cell 3");
 
builder->EndRow();
 
builder->InsertCell();
builder->Write(u"Cell 4");
 
builder->InsertCell();
builder->Write(u"Cell 5");
builder->EndColumnBookmark(u"Bookmark1");
 
builder->InsertCell();
builder->Write(u"Cell 6");
 
builder->EndRow();
builder->EndTable();
 
doc->Save(u"out.docx");

MarkdownSaveOptions::ImageSavingCallback has been added to control how images are saved upon converting to Markdown format

Related issue: WORDSNET-21389

A new public property ImageSavingCallback has been added to the MarkdownSaveOptions class:

/// <summary>
/// Allows to control how images are saved when a document is saved to <see cref="SaveFormat::Markdown"/> format.
/// </summary>
SharedPtr<IImageSavingCallback> get_ImageSavingCallback() const;
void set_ImageSavingCallback(SharedPtr<IImageSavingCallback> value);

Use Case:

class SavedImageRename;

void HandleDocument()
{
    String outFileName = u"SavingCallback.DocumentParts.Rendering.md";
 
    // Open a document to be converted to Markdown.
    auto doc = MakeObject<Document>("Rendering.docx");
 
    // We can use an appropriate SaveOptions subclass to customize the conversion process.
    auto options = MakeObject<MarkdownSaveOptions>();
 
    // If we convert a document that contains images into Markdown, we will end up with one Markdown file which links to several images.
    // Each image will be in the form of a file in the local file system.
    // There is also a callback that can customize the name and file system location of each image.
    options->set_ImageSavingCallback(MakeObject<SavedImageRename>(outFileName));
 
    // The ImageSaving() method of our callback will be run at this time.
    doc->Save(outFileName, options);
}

/// <summary>
/// Renames saved images that are produced when an Markdown document is saved.
/// </summary>
class SavedImageRename : public IImageSavingCallback
{
public:
    SavedImageRename(String outFileName) : mOutFileName(outFileName) {}
 
    void ImageSaving(SharedPtr<ImageSavingArgs> args) override
    {
        mCount++;
        String imageFileName = String::Format(u"{0} shape {1}, of type {2}{3}",
          mOutFileName, mCount, ObjectExt::ToString(args->get_CurrentShape()->get_ShapeType()),
          Path::GetExtension(args->get_ImageFileName());
 
        args->set_ImageFileName(imageFileName);
        args->set_ImageStream(MakeObject<FileStream>(imageFileName, FileMode::Create));
    }
 
private:
    int32_t mCount = 0;
    String mOutFileName;
};

PdfSaveOptions::EscapeUri is marked as obsolete

We made several improvements in export of hyperlinks to PDF per WORDSNET-21443. Now the cases when setting PdfSaveOptions:;EscapeUri to false was required (improper unescaping of explicitly escaped URI delimiter chars) are handled well by default. Thus we do not see a reason to keep this option longer and marked it as obsolete.

/// <summary>
/// A flag specifying whether URI should be escaped before writing.
/// </summary>
/// <remarks>
/// Note that if this option is set to <c>false</c> hyperlinks are written "as is",
/// so valid (escaped) URI should be provided in document's model.
/// <para>The default value is <c>true</c>.</para>
/// </remarks>
[[deprecated("Writing of URI to PDF was improved and cases when disabled escaping was required are handled well now.")]]
bool get_EscapeUri() const;

[[deprecated("Writing of URI to PDF was improved and cases when disabled escaping was required are handled well now.")]]
void set_EscapeUri(bool value);

Removed obsolete properties FixedPageSaveOptions::PageIndex, FixedPageSaveOptions::PageCount, ImageSaveOptions::PageIndex, ImageSaveOptions::PageCount

Related issue: WORDSNET-21154

Deprecated properties related to page specification when printing were removed from the FixedPageSaveOptions and ImageSaveOptions classes.

[[deprecated("This property is obsolete. Please use PageSet property instead.")]]
int32_t get_PageCount() const;
[[deprecated("This property is obsolete. Please use PageSet property instead.")]]
void set_PageCount(int32_t value);

[[deprecated("This property is obsolete. Please use PageSet property instead.")]]
int32_t get_PageIndex() const;
[[deprecated("This property is obsolete. Please use PageSet property instead.")]]
void set_PageIndex(int32_t value);

The behavior of DocumentBuilder::InsertOleObject() and DocumentBuilder:;InsertOleObjectAsIcon() methods was changed

Related issue: WORDSNET-21426

In cases where the DocumentBuilder::InsertOleObject() and DocumentBuilder::InsertOleObjectAsIcon() methods need to create an icon with a caption, they can use the file extension to define the icon, and can use the filename for the icon caption.

More details:

SharedPtr<Shape> InsertOleObject(SharedPtr<Stream> stream, String progId, bool asIcon, SharedPtr<Stream> presentation)
If ‘presentation’ is omitted and ‘asIcon’ is set, this overloaded method selects the icon according to ‘progId’ and uses the predefined icon caption.

SharedPtr<Shape> InsertOleObject(String fileName, bool isLinked, bool asIcon, SharedPtr<Stream> presentation)
If ‘presentation’ is omitted and ‘asIcon’ is set, this overloaded method selects the icon according to the file extension and uses the filename for the icon caption.

SharedPtr<Shape> InsertOleObject(String fileName, String progId, bool isLinked, bool asIcon, SharedPtr<Stream> presentation)
If ‘presentation’ is omitted and ‘asIcon’ is set, this overloaded method selects the icon according to ‘progId’ and uses the filename for the icon caption.

SharedPtr<Shape> InsertOleObjectAsIcon(SharedPtr<Stream> stream, String progId, String iconFile, String iconCaption)
If ‘iconFile’ and ‘iconCaption’ are omitted, this overloaded method selects the icon according to ‘progId’ and uses the predefined icon caption.

SharedPtr<Shape> InsertOleObjectAsIcon(String fileName, String progId, bool isLinked, String iconFile, String iconCaption)
If ‘iconFile’ and ‘iconCaption’ are omitted, this overloaded method selects the icon according to ‘progId’ and uses the filename for the icon caption.

SharedPtr<Shape> InsertOleObjectAsIcon(String fileName, bool isLinked, String iconFile, String iconCaption)
If ‘iconFile’ and ‘iconCaption’ are omitted, this overloaded method selects the icon according to the file extension and uses the filename for the icon caption.

Changed XML comments for ‘iconCaption’ arguments of DocumentBuilder::InsertOleObjectAsIcon() methods:

/// <summary>
/// Inserts an embedded or linked OLE object as icon into the document.
/// Allows to specify icon file and caption. Detects OLE object type using file extension.
/// </summary>
/// <param name="fileName">Full path to the file.</param>
/// <param name="isLinked">
/// If true then linked OLE object is inserted otherwise embedded OLE object is inserted.
/// </param>
/// <param name="iconFile">
/// Full path to the ICO file. If the value is null, Aspose.Words will use a predefined image.
/// </param>
/// <param name="iconCaption">
/// Icon caption. If the value is null, Aspose.Words will use the file name.
/// </param>
/// <returns>Shape node containing Ole object and inserted at the current Builder position.</returns>
SharedPtr<Shape> InsertOleObjectAsIcon(String fileName, bool isLinked, String iconFile, String iconCaption)

/// <summary>
/// Inserts an embedded or linked OLE object as icon into the document.
/// Allows to specify icon file and caption. Detects OLE object type using given progID parameter.
/// </summary>
/// <param name="fileName">Full path to the file.</param>
/// <param name="progId">ProgId of OLE object.</param>
/// <param name="isLinked">
/// If true then linked OLE object is inserted otherwise embedded OLE object is inserted.
/// </param>
/// <param name="iconFile">
/// Full path to the ICO file. If the value is null, Aspose.Words will use a predefined image.
/// </param>
/// <param name="iconCaption">
/// Icon caption. If the value is null, Aspose.Words will use the file name.
/// </param>
/// <returns>Shape node containing Ole object and inserted at the current Builder position.</returns>
SharedPtr<Shape> InsertOleObjectAsIcon(String fileName, String progId, bool isLinked, String iconFile, String iconCaption)

/// <summary>
/// Inserts an embedded OLE object as icon from a stream into the document.
/// Allows to specify icon file and caption. Detects OLE object type using given progID parameter.
/// </summary>
/// <param name="stream">Stream containing application data.</param>
/// <param name="progId">ProgId of OLE object.</param>
/// <param name="iconFile">
/// Full path to the ICO file. If the value is null, Aspose.Words will use a predefined image.
/// </param>
/// <param name="iconCaption">
/// Icon caption. If the value is null, Aspose.Words will use the a predefined icon caption.
/// </param>
/// <returns>Shape node containing Ole object and inserted at the current Builder position.</returns>
SharedPtr<Shape> InsertOleObjectAsIcon(SharedPtr<Stream> stream, String progId, String iconFile, String iconCaption)

The behavior of revision tracking feature triggered by Document::StartTrackRevisions was changed

Related issue: WORDSNET-20666

When revisions are tracked using Document::StartTrackRevisions, if a node is moved from one location to another in the same document, move revisions are now generated, including move-from and move-to ranges.

Use Case:

auto doc = MakeObject<Document>();
auto builder = MakeObject<DocumentBuilder>(doc);
 
// Generate document contents.
builder->Writeln("Paragraph 1");
builder->Writeln("Paragraph 2");
builder->Writeln("Paragraph 3");
builder->Writeln("Paragraph 4");
builder->Writeln("Paragraph 5");
builder->Writeln("Paragraph 6");
 
auto body = doc->get_FirstSection()->get_Body();
 
// Returns 7.
std::cout << "Paragraph count: " << body->get_Paragraphs()->get_Count() << '\n';
 
doc->StartTrackRevisions(u"Author", DateTime(2020, 12, 23, 14, 0, 0));
 
auto node = body->get_Paragraphs()->idx_get(3);
auto endNode = body->get_Paragraphs()->idx_get(5)->get_NextSibling();
auto referenceNode = body->get_Paragraphs()->idx_get(0);
 
while (node != endNode)
{
    auto nextNode = node->get_NextSibling();
    body->InsertBefore(node, referenceNode);
    node = nextNode;
}
 
doc->StopTrackRevisions();
 
// Returns 10: there are 3 additional paragraphs in the move-from range.
std::cout << "Paragraph count: " << body->get_Paragraphs()->get_Count() << '\n';
 
doc->Save("out.docx");