Skip to main content
All docs
V25.1
  • v24.2 Office File API Release Notes

    • 17 minutes to read

    Important Changes

    GDI+ (Libgdiplus) - End of Support for Non Windows-based systems

    Due to our commitment to .NET 8 and following the release of our cross-platform SkiaSharp-based engine last year, we refactored our source code and removed all GDI+ related method calls for non-Windows environments (libgdiplus).

    Support Skia for Windows Environment and Deprecation of the AzureCompatibility Property

    Multiple DevExpress products (Reporting, BI Dashboard, and Office File API) ship with printing and data export functionality for restricted environments such as Microsoft Azure (where certain GDI/GDI+ calls related to metafiles and font objects are unavailable). The AzureCompatibility.Enable property manages this functionality.

    In our v23.2 release cycle, we ended support for capabilities offered by this property toggle for non-Windows environments. With v24.2, we phased out the AzureCompatibility.Enabled toggle for Office File API libraries in Windows-based environments as well. We recommend use of our Skia-based Cross-Platform Graphics Engine when targeting cloud/restricted environments. Office File API libraries automatically determine the applicable drawing engine. You can switch to a different drawing engine manually by using the static DevExpress.Drawing.Settings.DrawingEngine option.

    DevExpress.Drawing.Settings.DrawingEngine = DevExpress.Drawing.DrawingEngine.Skia;
    

    Resolve Missing Fonts

    We added a new DXFontRepository.QueryNotFoundFont event for fonts used within a document but missing in an application’s hosting environment. This feature allows you to identify and resolve missing fonts by adding them to DevExpress.Drawing.DXFontRepository before document generation.

    In the following code snippet, we use Google Fonts to locate/add fonts to DXFontRepository:

    DXFontRepository.QueryNotFoundFont+= QueryNotFoundFont;
    
    void QueryNotFoundFont(object sender, NotFoundFontEventArgs e) {
        var service = new FontCollectorService();
        var fontData = service.ProcessFont(e.RequestedFont).Result;
        e.FontFileData = fontData;
    }
    

    With this enhancement, you are now able to identify and address document appearance issues, ensuring that documents appear as designed, regardless of the hosting platform.

    Our components will also log font names in the application output for debugging purposes.

    Spreadsheet Document API

    Dynamic Array Formulas

    We’ve extended our formula calculation engine and integrated dynamic arrays into our Spreadsheet Document API library. Unlike standard array formulas, which return a single value for each cell with a formula, dynamic array functions return a dynamic array of values (this array of values automatically spills into neighboring cells). New functionality includes:

    • Dynamic array calculations and Spill Range support.
    • New formula error type (#SPILL!).
    • Implicit intersection operator (@ symbol) to return a single formula value instead of an array.

    spreadsheet document api dynamic array formulas

    You can now import Excel documents containing dynamic array formulas in the Spreadsheet Document API library, call the Workbook.Calculate method to recalculate these formulas, and save the document calculated with values to the Excel formats. Printing and export to PDF are also available.

    Additionally, you can manage dynamic array formulas in code. v24.2 ships the following new APIs:

    Refer to the following code snippet if you’d like to obtain, insert, or clear dynamic array formulas using the new APIs:

    Worksheet worksheet = workbook.Worksheets.ActiveWorksheet;
    // Insert dynamic array formulas
    worksheet["A1"].DynamicArrayFormulaInvariant = "={\"Red\",\"Green\",\"Orange\",\"Blue\"}";
    worksheet.DynamicArrayFormulas.Add(worksheet["A2"], "=LEN(A1:D1)");
    
    // Clear dynamic array formulas
    Cell cell = worksheet.Cells["B2"];
    if (cell.HasDynamicArrayFormula)
    {
        CellRange dymanicArrayRange = cell.GetDynamicArrayFormulaRange();
        dymanicArrayRange.Clear();
    }
    worksheet.DynamicArrayFormulas.Remove(worksheet.Cells["A1"].GetDynamicArrayFormulaRange());
    

    To suppress dynamic array formula calculations and revert to the previous behavior, set the WorkbookCapabilitiesOptions.DynamicArrayFormulas property to DocumentCapability.Disabled. In this instance, dynamic array formulas will be calculated as standard array formulas.

    Refer to the following article for more information: Array Formulas in Spreadsheet Documents

    Embed Images in Cells

    The DevExpress Spreadsheet Document API library (v24.2) allows you to embed images directly into worksheet cells (using Microsoft Excel’s Place in Cell option). You can import documents with images embedded in worksheet cells, print these documents, export them to the PDF and save them to a XLSX file (without the content loss).

    spreadsheet document api embed image in cells

    v24.2 includes new APIs designed to manage cell embedded images in code. Embedded images are stored as cell values. To determine if a cell has an embedded image, use the CellValue.IsCellImage property. Use the CellValue.ImageValue property to obtain the cell image value as an OfficeImage object (allows you to check the image format or obtain image bytes). To insert an image in a cell, assign it to the CellRange.Value property.

    The Spreadsheet Document API library supports the following object types as an image source:

    Additionally, we implemented options to specify image Alt Text (a meaningful description) values and mark the cell image as decorative. These settings are available via the Cell.ImageInfo property.

    The following code snippet demonstrates this new API in action:

    byte[] imageBytes = File.ReadAllBytes("image.png");
    MemoryStream imageStream = new MemoryStream(imageBytes);
    DXImage dxImage = DXImage.FromStream(imageStream);
    
    // Insert cell images from a byte array, stream and DXImage object
    worksheet.Cells["A1"].Value = imageBytes;
    worksheet.Cells["A2"].Value = imageStream;
    worksheet.Cells["A3"].Value = dxImage;
    
    // Set image Alt Text values
    worksheet.Cells["A1"].ImageInfo.AlternativeText = "Image AltText";
    // Mark the cell image as decorative
    if (worksheet.Cells["A2"].Value.IsCellImage)
        worksheet.Cells["A2"].ImageInfo.Decorative = true;
    
    // Save the cell image to a new file
    OfficeImage cellImage = worksheet.Cells["A1"].Value.ImageValue;
    if (cellImage.RawFormat == OfficeImageFormat.Png)
    {
        byte[] cellImageBytes = cellImage.GetImageBytes(cellImage.RawFormat);
        File.WriteAllBytes("saved_image.png", cellImageBytes);
    }
    
    // Remove cell image
    worksheet.Cells["A3"].ClearContents();
    

    Justify & Distributed Vertical Text Alignment

    v24.2 adds support for Justify and Distributed vertical alignment types within Spreadsheet cells. Excel files with these alignment options can be printed and exported to PDF.

    You can use the Cell.Alignment.Vertical property to specify vertical alignment in code.

    The following code snippet specifies alignment in code:

    var workbook = new Workbook();
    var worksheet = workbook.Worksheets[0];
    
    Cell cellA1 = worksheet.Cells["A1"];
    cellA1.Value = "Centered and Justified";
    cellA1.Alignment.Horizontal = SpreadsheetHorizontalAlignment.Center;
    cellA1.Alignment.Vertical = SpreadsheetVerticalAlignment.Justify;
    workbook.ExportToPdf("Result.pdf");
    

    PDF Document API

    ZuGFeRD v2.3.2 Support

    The DevExpress PDF File API (part of the Office File API Suite) fully supports Germany’s ZuGFeRD e-invoicing standard (ZuGFeRD v2.3.2).

    You can attach ZuGFeRD v2.3.2 XML files to your PDF documents by calling the PdfDocument.AttachZugferdInvoice method (using the new PdfZugferdVersion.Version2_3_2 enumeration value as an argument):

    using (var pdfDocumentProcessor = new PdfDocumentProcessor())
    {
        pdfDocumentProcessor.LoadDocument("Invoice.pdf");
        pdfDocumentProcessor.Document.AttachZugferdInvoice
            (File.ReadAllBytes("ZUGFeRD-invoice.xml"),  PdfZugferdVersion.Version2_3_2,  PdfZugferdConformanceLevel.Extended);
        pdfDocumentProcessor.SaveDocument("Invoice_ZuGFeRD.pdf");
    }
    

    Signature Validation Enhancements

    v24.2 ships with enhanced PDF Signature Validation APIs. New capabilities include:

    • API to verify certificate revocation based on Online Certificate Status Protocol (OCSP) responses.
    • APIs to verify certificate revocation based on Certificate Revocation List (CRL).
    • APIs to validate Long Term Validation (LTV) signatures.
    • APIs to validate Document Level Timestamps.

    Call the PdfPkcs7Signature.CheckCertificateRevocation method to obtain information about signature certificate revocation.

    using DevExpress.Pdf;
    // ...
    CheckCertificateRevocationInfo();
    // ...
    public static void CheckCertificateRevocationInfo() {
    using (PdfDocumentSigner documentSigner = new PdfDocumentSigner("Signed_file.pdf"))
        // Retrieve the list of `PdfSignatureInfo` objects in the document.
        foreach (var signature in documentSigner.GetSignatureInfo()){
            Console.WriteLine("Signature field name : {0}", signature.FieldName);
            Console.WriteLine("Signer name : {0}", signature.SignerName);
            var pkcs7 = documentSigner.GetPdfPkcs7Signature(signature.FieldName);
            Console.WriteLine("Is signature valid? : {0}", pkcs7.VerifySignature());
            // Check whether the CRL/OCSP responses are embedded in the signature; otherwise, request them online.
            Console.WriteLine("Is CRL embedded?: {0}", pkcs7.CrlList != null);
            Console.WriteLine("Is OCSP embedded?: {0}", pkcs7.OcspList != null);
            PdfRevocationVerificationOptions options = new PdfRevocationVerificationOptions(){
                TryFetchCrlOnline = pkcs7.CrlList == null,
                TryFetchOcspOnline = pkcs7.OcspList == null,
            };
            // Obtain information about the signature certificate revocation.
            var result = pkcs7.CheckCertificateRevocation(DateTime.UtcNow, options);
            Console.WriteLine("Is certificate revoked?: {0}", result.IsCrlRevoked);
            if (result.IsCrlRevoked)
                Console.WriteLine("Is CRL found online?: {0}", result.IsCrlFoundOnline);
            Console.WriteLine("OCSP Response Status: {0}", result.OcspRevocationStatus);
            if (result.OcspRevocationStatus != PdfOcspRevocationStatus.None)
                Console.WriteLine("Is OCSP found online?: {0}", result.IsOcspFoundOnline);
            // Check whether the signature is a TimeStamp.
            Console.WriteLine("Is Document Timestamp?: {0}", pkcs7.IsDocumentTimeStamp);
            Console.WriteLine();
        }
    }
    

    Call the PdfDocumentSigner.VerifyLtv method to obtain Long Term Validation (LTV) records about the state of the signature certificate.

    int largestEdgeLength = 1000;
    using (PdfDocumentProcessor processor = new PdfDocumentProcessor())
    {
        // Load a document
        processor.LoadDocument("..\\..\\Document.pdf");
        for (int i = 1; i <= processor.Document.Pages.Count; i++)
        {
            // Export pages to SVGs
            DXSvgImage image = processor.CreateSvgImage(i, largestEdgeLength);
    
            // Save the images
            image.Save("..\\..\\MySvg" + i + ".svg", DXImageFormat.Svg);
        }
    }
    

    Export PDF Documents to SVG

    We implemented the PdfDocumentProcessor.CreateSvgImage method designed to convert individual PDF pages to SVG images.

    int largestEdgeLength = 1000;
    using (PdfDocumentProcessor processor = new PdfDocumentProcessor())
    {
        // Load a document
        processor.LoadDocument("..\\..\\Document.pdf");
        for (int i = 1; i <= processor.Document.Pages.Count; i++)
        {
            // Export pages to SVGs
            DXSvgImage image = processor.CreateSvgImage(i, largestEdgeLength);
    
            // Save the images
            image.Save("..\\..\\MySvg" + i + ".svg", DXImageFormat.Svg);
        }
    }
    

    Refer to the following article for more information: How to: Export a PDF Page to an SVG Image

    Note

    SVG export ships with limitations. We do not embed fonts in target SVG files. PDF patterns and shadings are not supported. Limited transparency support.

    Image Extraction API

    To improve user experiences when extracting PDF content and analyzing document structure, we introduced PdfDocumentProcessor.GetImagesInfo method overloads for the PDF Document API library. With our new APIs, you can obtain additional information about PDF page images and determine image size and location on a page.

    Refer to the following article for more information: How to: Extract Images from a Document.

    Word Processing Document API

    SmallCaps Formatting

    Our Word Processing Document API library now supports Small Caps character formatting. Word documents with Small Caps formatting can be printed and exported to PDF.

    To enable formatting in code, use the CharacterProperties.SmallCaps property:

    Document document = wordDocumentProcessor.Document;
    Paragraph paragraph = document.Paragraphs[0];
    CharacterProperties characterProperties = document.BeginUpdateCharacters(paragraph.Range);
    characterProperties.SmallCaps = true;
    document.EndUpdateCharacters(characterProperties);
    

    Page Borders

    The DevExpress Word Processing Document API library now supports page borders. Word documents with page borders can be saved without content loss, printed, and exported to PDF.

    word processing document api page borders

    New APIs allow you to manage page borders in code. Borders can be set for each document section individually. Use the Section.PageBorders property to access and modify borders for a specific section.

    New members help you adjust the following border settings:

    • Line style
    • Color
    • Width
    • Distance from text or page edge

    You can also apply borders to specific pages within a section: to all pages, only the first page, or all pages except the first. And you can change border z-order to show them in front or behind main text. The following code snippet applies different borders in a document with two sections:

    Document document = wordDocumentProcessor.Document;
    string pageBreaks = "\f\f\f";
    // Generate a document with two sections and multiple pages in each section
    document.AppendText(pageBreaks);
    document.Paragraphs.Append();
    document.AppendSection();
    document.AppendText(pageBreaks);
    
    // Set borders for the first page of the first section
    SetPageBorders(pageBorders1.LeftBorder, BorderLineStyle.Single, 1f, Color.Red);
    SetPageBorders(pageBorders1.TopBorder, BorderLineStyle.Single, 1f, Color.Red);
    SetPageBorders(pageBorders1.RightBorder, BorderLineStyle.Single, 1f, Color.Red);
    SetPageBorders(pageBorders1.BottomBorder, BorderLineStyle.Single, 1f, Color.Red);
    pageBorders1.AppliesTo = PageBorderAppliesTo.FirstPage;
    
    Section secondSection = document.Sections[1];
    SectionPageBorders pageBorders2 = secondSection.PageBorders;
    
    // Set borders for all pages of the second section
    SetPageBorders(pageBorders2.LeftBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetPageBorders(pageBorders2.TopBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetPageBorders(pageBorders2.RightBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetPageBorders(pageBorders2.BottomBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    pageBorders2.AppliesTo = PageBorderAppliesTo.AllPages;
    pageBorders2.ZOrder = PageBorderZOrder.Back;
    
    //.....
    void SetPageBorders(PageBorder border, BorderLineStyle lineStyle,
    float borderWidth, Color color)
    {
        border.LineStyle = lineStyle;
        border.LineWidth = borderWidth;
        border.LineColor = color;
    }
    

    Refer to the following article for more information: Specify Page Borders

    Paragraph Borders API

    v24.2 includes new APIs to manage Word document paragraph borders in code. You can now add borders to document paragraphs, change border style, color, and thickness for each border type (Top, Left, Right, Bottom or Horizontal) individually, or remove border formatting as needed. Additionally, you can manage paragraph border settings for paragraph styles and list levels in numbered lists.

    word processing document api paragraph borders

    Paragraph border settings are available via the ParagraphBorders class. Use the Paragraph.Borders, ParagraphProperties.Borders, or ParagraphStyle.Borders property to obtain the ParagraphBorders object and modify border settings based on your usage scenario.

    RichEditDocumentServer documentProcessor = new RichEditDocumentServer();
    documentProcessor.Text = "paragraph 1\r\nparagraph 2\r\nparagraph 3\r\nparagraph 4\r\n";
    Document document = documentProcessor.Document;
    
    // Setup borders for one paragraph
    Paragraph firstParagraph = document.Paragraphs[0];
    ParagraphBorders borders1 = firstParagraph.Borders;
    SetBorders(borders1.LeftBorder, BorderLineStyle.Single, 1f, Color.Red);
    SetBorders(borders1.TopBorder, BorderLineStyle.Single, 1f, Color.Red);
    SetBorders(borders1.RightBorder, BorderLineStyle.Single, 1f, Color.Red);
    SetBorders(borders1.BottomBorder, BorderLineStyle.Single, 1f, Color.Red);
    
    // Setup borders for multiple paragraphs
    Paragraph secondParagraph = document.Paragraphs[1];
    Paragraph forthParagraph = document.Paragraphs[3];
    DocumentRange paragraphRange = document.CreateRange(secondParagraph.Range.Start, 
                    forthParagraph.Range.End.ToInt() - secondParagraph.Range.Start.ToInt());
    ParagraphProperties paragraphProperties = document.BeginUpdateParagraphs(paragraphRange);
    ParagraphBorders borders2 = paragraphProperties.Borders;
    SetBorders(borders2.LeftBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetBorders(borders2.TopBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetBorders(borders2.RightBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetBorders(borders2.BottomBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    SetBorders(borders2.HorizontalBorder, BorderLineStyle.Double, 1.5f, Color.Green);
    document.EndUpdateParagraphs(paragraphProperties);
    
    // Reset paragraph borders
    secondParagraph.Borders.Reset();
    
    //...
    void SetBorders(ParagraphBorder border, BorderLineStyle lineStyle, 
        float borderWidth, Color color)
    {
        border.LineStyle = lineStyle;
        border.LineWidth = borderWidth;
        border.LineColor = color;
    }
    

    Alt Text for Tables

    Table.Title and Table.Description properties allow you to specify alternative, text-based representations of the information contained in a Word document table.

    Table title and description are also in use when you export a Word document to an accessible PDF format.

    RichEditDocumentServer documentProcessor = new RichEditDocumentServer();
    documentProcessor.LoadDocument("tables.docx");
    Document document = documentProcessor.Document;
    if(document.Tables.Count > 0)
    {
        Table table = document.Tables[0];
        table.Title = "Table title..";
        table.Description = "Table description..";
    }
    

    Note

    The table title and description are only supported in OpenXml document formats (.docx, .docm, .dotx, .dotm) and HTML.

    Macros API

    We implemented a Document.VbaProject property to programmatically retrieve a VBA project stored in a macro-enabled Word file. Use the VbaProject.Modules collection to obtain information about VBA project modules (the number of modules, their names and binary data) or remove a specific module from the project. If the current document format does not support macros or a macro-enabled document does not contain macros, the VbaProject.Modules collection will be empty.

    // Check if the current document has macros and remove them
    Document document = wordProcessor.Document;
    if(document.VbaProject.Modules.Count > 0)
        document.VbaProject.Modules.Clear();
    

    Barcode Generation API

    New Aztec Barcode

    You can now generate an Aztec code when using our Barcode Generation library. Aztec barcodes offer a compact/efficient way to encode large amounts of data without requiring a quiet zone, which makes them ideal for space-constrained documents.

    To create an Aztec Barcode, set the BarCode.Symbology property value to AztecCode and specify appropriate barcode properties.

    You can also specify barcode data using BarCode.CodeText or BarCode.CodeBinaryData properties as follows:

    using DevExpress.BarCodes;
    using DevExpress.XtraPrinting.BarCode;
    using DevExpress.Drawing;
    // ...
    
    BarCode barCode = new BarCode();
    barCode.Symbology = Symbology.AztecCode;
    
    barCode.Options.AztecCode.CompactionMode = AztecCodeCompactionMode.Text;
    barCode.CodeText = "https://www.devexpress.com/";
    // OR
    // barCode.Options.AztecCode.CompactionMode = AztecCodeCompactionMode.Binary;
    // barCode.CodeBinaryData = Encoding.Default.GetBytes("https://www.devexpress.com/");
    
    barCode.Options.AztecCode.ErrorLevel = AztecCodeErrorCorrectionLevel.Level1;
    barCode.Options.AztecCode.ShowCodeText = false;
    barCode.DpiX = 72;
    barCode.DpiY = 72;
    barCode.Module = 2f;
    
    barCode.Save("aztec_code.png", DXImageFormat.Png);
    

    New Micro QR Code

    You can now create Micro QR Codes (a smaller alternative to traditional QR Codes). Micro QR Codes are suitable for space-limited documents, where only small amounts of data (35 characters or 128 bits) require encoding.

    To create a Micro QR Code, set the BarCode.Symbology property value to MicroQRCode and specify appropriate barcode properties.

    You can also specify barcode data using BarCode.CodeText or BarCode.CodeBinaryData properties as follows:

    using DevExpress.BarCodes;
    using DevExpress.XtraPrinting.BarCode;
    using DevExpress.Drawing;
    // ...
    BarCode barCode = new BarCode();
    barCode.Symbology = Symbology.MicroQRCode;
    
    barCode.Options.MicroQRCode.CompactionMode = MicroQRCodeCompactionMode.AlphaNumeric;
    barCode.CodeText = "123ABC";
    //OR
    // barCode.Options.MicroQRCode.CompactionMode = MicroQRCodeCompactionMode.Byte;
    // barCode.CodeBinaryData = Encoding.Default.GetBytes("123ABC");
    
    barCode.Options.MicroQRCode.ErrorLevel = MicroQRCodeErrorCorrectionLevel.L;
    barCode.Options.MicroQRCode.ShowCodeText = false;
    
    barCode.Save("microqr_code.png", DXImageFormat.Png);