Extract pages from prepared report to new prepared report

edited 3:02PM 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 3:02PM
    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 3:02PM
    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