none
Duplex printing in reporting services

    Question

  • I have been working on this problem for days. I have a report that is grouped
    and will be printed duplex (front and back). There is a page break after each
    group. I want to ensure that the start of a new group does not end up printed
    on the back side of an old group. For example:

    Page 1 (printed on front side of paper): group 1
    Page 2 (printed on back side of paper): more group 1
    Page 3 (printed on front side of paper): more group 1
    Page 4 (printed on on back side of paper): group 2  <--- This is a problem

    I need:

    Page 1 (front side): group 1
    Page 2 (back side): more group 1
    Page 3 (front side): more group 1
    Page 4 (back side): <This Page Intentionally Left Blank>
    Page 5 (front side): group 2

    Issues that I've run into include the fact that SSRS renders the entire body
    first, before rendering the header/footer. This prevents the body of the
    report from knowing which page it will end up on when it is rendered (and is
    also why you cannot reference Globals!PageNumber from the body).

    The restriction above also prevents using a variable in custom code to know
    when to generate a page break. If you set this variable in the header/footer
    then the body will never see it as the entire body is rendered first and will
    therefore only see the initial state of the variable.

     

    I have seen this issue posted in a number of places,
    but no one ever has a solution to this (except switching back to
    Crystal Reports).  Have any MVPs ever addressed this issue?  I am
    really hoping someone can offer a good solution or work-around.


     

     

    Thursday, September 13, 2007 10:15 PM

Answers

  • Finally - I have resolved this problem.  We are writing the results to a pdf file, and was therefore able to use PDFSharp to update the output file before making it available to our users.  With PDFSharp, I loop through each page of the exported report and determine whether it is the start of a new group (by checking the contents of the page).  If it is a new group and the page number is EVEN, then I insert a blank page just before.  So while there is no way to determine page numbers in Reporting Services, there is a way to manipulate the pdf output to be correct for duplex printing.

     

    Friday, September 14, 2007 10:47 PM

All replies

  • Finally - I have resolved this problem.  We are writing the results to a pdf file, and was therefore able to use PDFSharp to update the output file before making it available to our users.  With PDFSharp, I loop through each page of the exported report and determine whether it is the start of a new group (by checking the contents of the page).  If it is a new group and the page number is EVEN, then I insert a blank page just before.  So while there is no way to determine page numbers in Reporting Services, there is a way to manipulate the pdf output to be correct for duplex printing.

     

    Friday, September 14, 2007 10:47 PM
  • Flanger,

     

    Do you have some sample code you would be willing to post? I'm relatively new to programming and especially Reporting Services. I'm working on a project that requires duplexing and I like see your solution. Thanks in advance!

     

    Greg

    Friday, November 09, 2007 8:49 PM
  • Flanger,

    Would you be so kind and share any code with us?
    Monday, August 10, 2009 8:13 AM
  •   string showHideToggle = null;

      string encoding;

      string mimeType;

      string extension;

      Warning[] warnings = null;

      ParameterValue[] reportHistoryParameters = null;

      string[] streamIDs = null;

     

      ExecutionInfo execInfo = new ExecutionInfo();

      ExecutionHeader execHeader = new ExecutionHeader();

      rs.ExecutionHeaderValue = execHeader;

     

      execInfo = rs.LoadReport(reportPath, historyID);

      String SessionId = rs.ExecutionHeaderValue.ExecutionID;

      rs.Timeout = System.Threading.Timeout.Infinite; // disable timeouts

     

      // loop through each of the Payees and generate the individual file

      DataSet dsPayees = db.ExecuteDataSet("spMainReport", null,

          paymentCycleID); 

     

      // determine what the LAST Payee ID will be so that we can print the report footer

      DataRow r = dsPayees.Tables[0].Rows[dsPayees.Tables[0].Rows.Count - 1];

      string lastPayee = r["uPayeeID"].ToString();

     

      //Render each original PDF document for each Payee and add it to the output document

      PdfDocument originalDocument = new PdfDocument();

      PdfDocument outputDocument = new PdfDocument();

      PdfPage page = null;

      foreach (DataRow row in dsPayees.Tables[0].Rows)

      {

          // set the Display Footer parameter to true if this is the last row

          if (row["uPayeeID"].ToString() == lastPayee)
              parameters[24].Value = "true";  //DisplayReportFooter

     

          //Render the report for a single Payee

          parameters[21].Value = row["uPayeeID"].ToString();

          parameters[25].Value = row["uPayeeName"].ToString();

          rs.SetExecutionParameters(parameters, culture);

          result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);

     

          // Write the contents of the report to a document as a Stream.

          Stream s = new MemoryStream(result);

          originalDocument = PdfReader.Open(s, PdfDocumentOpenMode.Import);

     

          // Iterate pages to the output document

          int cnt = originalDocument.PageCount;

          for (int idx = 0; idx < cnt; idx++)

          {

            // Get the page from the original report and add it to the output document.

            page = originalDocument.Pages[idx];

            outputDocument.AddPage(page);

          }

     

          //if the last page of the document is on an odd page, remove it if it is a blank page

          if ((outputDocument.PageCount + 1 & 1) == 0)

          {

            string pageContents = page.Contents.CreateSingleContent().Stream.ToString();

            if (pageContents.IndexOf("page intentionally left blank") > 0)

                // we're on an odd page number and it's blank - this is no good for Duplex printing - so

                // delete the preceeding (blank) page from the output document

                outputDocument.Pages.RemoveAt(outputDocument.PageCount - 1);

           }

     

          // after each Payee, we need to update the running page number totals

          parameters[22].Value = Convert.ToString(Convert.ToInt32(outputDocument.Pages.Count));

          // Display Header parameter to false

          parameters[23].Value = "false";

      }

     

      if (outputDocument.PageCount > 0)

          // Save the document

          outputDocument.Save(fileServer + @"\RemitDent" +

            paymentCycleID.ToString() + ".pdf");

     

      return;

    • Proposed as answer by 2099 Wednesday, August 19, 2009 12:26 PM
    Monday, August 10, 2009 12:44 PM
  • Do you migrate this code to Framework 4.0?, does it work?, i'm having some troubles on it, can you help me?

     

    Regards,

     

    Mauricio Atanache G.


    Mauricio
    Tuesday, May 04, 2010 2:22 AM