Extract pages from prepared report to new prepared report

edited 5:07AM in FastReport .NET
I would like to extract prepared pages from an fpx file, to either save to a new fpx stream/file or present in a viewer. The use case is extracting a specific user's invoice from a batch of invoices. I know which pages through report indexing.

Currently I do this with reports saved as PDF, but fpx files are much more compact and faster. I tried these ways below with a valid input fpx and page numbers. When I try to open the resulting fpx file, either the previewer doesn't open or it throws an exception. Speed is very important. What is best code to achieve this?
        var report = new Report();
        report.LoadPrepared(@"E:\test.fpx");  //has 104 pages
        var subReport = GetPreparedPages(report, new[] { 55, 56});

    private static Report GetPreparedPages(Report report, int[] pageNumbers)
    {
        var report2 = new Report();
        report2.Prepare();
        foreach (var pageNumber in pageNumbers)
        {
            var page = report.PreparedPages.GetPage(pageNumber);
            report2.PreparedPages.AddPage(page);
            //report2.PreparedPages.AddPage(new ReportPage());
            //report2.PreparedPages.ModifyPage(report2.PreparedPages.Count - 1, page);
        }
        return report2;
    }

    private static Report GetPreparedPages2(Report report, int[] pageNumbers)
    {
        var report2 = new Report();
        report2.Pages.AddRange(pageNumbers.Select(pn => new ReportPage()).ToArray());
        report2.Prepare();
        
        for(var pn = 0; pn < report2.PreparedPages.Count; pn++)
        {
            var page = report.PreparedPages.GetPage(pageNumbers[pn]);
            report2.PreparedPages.ModifyPage(pn,page);
        }
        return report2;
    }

Comments

  • edited May 2018
    // list of pages to extract
    int[] filterPages = { 0, 2, 4, 6 };
    
    FastReport.Report report = new FastReport.Report();
    report.LoadPrepared(@"d:\Repeat Headers.fpx");
    
    FastReport.Preview.PreparedPages pages = report.PreparedPages;
    int maxPage = pages.Count - 1;
    
    for (int i = maxPage; i >= 0; i--)
    {
        if (!filterPages.Contains(i))
            pages.RemovePage(i);
    }
    
    // Save to file
    //pages.Save(@"d:\Filtered Repeat Headers.fpx");
    
    // OR
    // Save to stream
    using (MemoryStream stream = new MemoryStream())
    {
        pages.Save(stream);
        using (FileStream writer = new FileStream(@"d:\Filtered Repeat Headers.fpx", FileMode.Create, FileAccess.Write))
        {
            stream.Position = 0;
            writer.Write(stream.ToArray(), 0, (int)stream.Length);
        }
    }
    
  • edited 5:07AM
    Thanks! Works great though I must test the performance of this with a larger fpx file.

    The fpx has a document outline. When the pages are removed, the outline remains and the invalid links raise an exception. Is there a way to either remove the invalid links or even remove the outline altogether?
  • edited May 2018
    this way is preferable, can remove anything and less overhead:
    int[] filter = { 0, 2, 4, 6 };
    string output = string.Empty;
    
    using (FileStream fs = new FileStream(@"d:\outline.fpx", FileMode.Open, FileAccess.Read))
    {
        using (GZipStream zip = new GZipStream(fs, CompressionMode.Decompress))
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(zip);
    
            XmlNode pages = doc.SelectSingleNode("/preparedreport/pages");
            XmlNodeList list = pages.ChildNodes;
            int count = list.Count - 1;
            for (int i = count; i >= 0; i--)
            {
                if (!filter.Contains(i))
                    pages.RemoveChild(list[i]);
            }
    
            XmlNode outline = doc.SelectSingleNode("/preparedreport/outline");
            outline.ParentNode.RemoveChild(outline);
    
            output = doc.OuterXml.Replace("#xD;", "#13;").Replace("#xA;", "#10;");
        }
    }
    
    using (FileStream fs = new FileStream(@"d:\Filtered outline.fpx", FileMode.Create, FileAccess.Write))
    {
        using (GZipStream zip = new GZipStream(fs, CompressionMode.Compress))
        {                    
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(output);
            zip.Write(buffer, 0, buffer.Length);
        }
    }
    
  • edited 5:07AM
    Great. Thanks for the code. I will test with this.

    This also answers another question I had about the fpx file format (xml & gzip).

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.