public class ben:harrell

March 1, 2007

Reporting Services 2005 Rotation and Orientation

Filed under: .NET, ASP.NET, C#, Reporting Services 2005, SQL Server 2005, Technology — benjamin harrell @ 4:54 pm

As many of you might have figured out by now Reporting Services 2005 doesn’t support rotating objects or multiple orientation (as in per sub report).  Depending on your situation there might still be an answer.  I was in a situation recently where I need certain pages of a report in landscape and some in portrait.  I was told that this is not possible out of the box in Reporting Services 2005 but have since found a workaround that might work for you.  Microsoft has done a great job with making SSRS an open architecture and the web services are a key part of this approach.  Behind the scenes of your Report Viewer control (in “remote” mode) it is actually making a request to the Render command of the SSRS Web Service.  So to pull of the rotation of a report I created a new web page with a web reference to the ReportService.  I then request the report in IMAGE format and store the byte[].  I create a new Bitmap object and stream in the byte[] so that I have full control over my newly created report Image in GDI.NET.  Bitmap supports a RotateFlip method that has just what we need and then I save the Bitmap to the Response.OutputStream object.  You are probably familiar with the concept of pointing an Image to an ASPX page that dynamically generates the bytes of the Image and this solution is no different.  Once you have an ASPX that can generate a rotated Image of the report then you treat it just like any other Image in the Report or on a WebForm.

This solution was adapted from Bryan Kelly’s post on Programmatically Printing RS 2000 Reports found HERE

The source code for the page is below:

 using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing.Imaging;
using System.Drawing;
using System.Runtime.InteropServices; // For Marshal.Copy
using System.IO;
using System.Web.Services.Protocols;

public partial class ASR_ReportAsImage : System.Web.UI.Page
{
    ReportService.ReportingService rs;
    private byte[][] m_renderedReport;
    private System.Drawing.Graphics.EnumerateMetafileProc m_delegate = null;
    private System.IO.MemoryStream m_currentPageStream;
    private System.Drawing.Imaging.Metafile m_metafile = null;
    int m_numberOfPages;
 
    protected void Page_Load(object sender, EventArgs e)
    {
       
        rs = new ReportService.ReportingService();
        rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
        PrintReportAsImage();
    }

    public byte[][] RenderReport(string reportPath)
    {
        // Private variables for rendering
        string deviceInfo = null;
        string format = “IMAGE”;
        Byte[] firstPage = null;
        string encoding;
        string mimeType;
        ReportService.Warning[] warnings = null;
        ReportService.ParameterValue[] reportHistoryParameters = null;
        string[] streamIDs = null;
        Byte[][] pages = null;

        // Build device info based on the start page
        deviceInfo =
           String.Format(@”<DeviceInfo><OutputFormat>{0}</OutputFormat></DeviceInfo>”, “emf”);

        //Exectute the report and get page count.

        // Renders the first page of the report and returns streamIDs for
        // subsequent pages
        firstPage = rs.Render(
           reportPath,
           format,
           null,
           deviceInfo,
           null,
           null,
           null,
           out encoding,
           out mimeType,
           out reportHistoryParameters,
           out warnings,
           out streamIDs);
        // The total number of pages of the report is 1 + the streamIDs        
        m_numberOfPages = streamIDs.Length + 1;
        pages = new Byte[m_numberOfPages][];

        // The first page was already rendered
        pages[0] = firstPage;

        for (int pageIndex = 1; pageIndex < m_numberOfPages; pageIndex++)
        {
            // Build device info based on start page
            deviceInfo =
               String.Format(@”<DeviceInfo><OutputFormat>{0}</OutputFormat><StartPage>{1}</StartPage></DeviceInfo>”,
                 “emf”, pageIndex + 1);
            pages[pageIndex] = rs.Render(
               reportPath,
               format,
               null,
               deviceInfo,
               null,
               null,
               null,
               out encoding,
               out mimeType,
               out reportHistoryParameters,
               out warnings,
               out streamIDs);
        }

        return pages;
    }

    public bool PrintReportAsImage()
    {
        this.RenderedReport = this.RenderReport(“/ASR Prototype/ASR_TransactionOverview”);

        // Wait for the report to completely render.
        if (m_numberOfPages < 1)
            return false;

        for (int i = 0; i < m_renderedReport.Length; i++)
        {
            //write all of the pages to stream….

            System.IO.MemoryStream memstream = new System.IO.MemoryStream(m_renderedReport[i], false);
            System.Drawing.Bitmap oBitmap = new System.Drawing.Bitmap(memstream, true);
            //now rotate the bitmap 90 degrees
            oBitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
            //write it to the output stream
            Response.ContentType = “image/jpeg”;
            oBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);

        }
        return true;
    }
 

    // Method to draw the current emf memory stream
    private void ReportDrawPage(Graphics g)
    {
        if (null == m_currentPageStream || 0 == m_currentPageStream.Length || null == m_metafile)
            return;
        lock (this)
        {
            // Set the metafile delegate.
            int width = m_metafile.Width;
            int height = m_metafile.Height;
            m_delegate = new Graphics.EnumerateMetafileProc(MetafileCallback);
            // Draw in the rectangle
            Point destPoint = new Point(0, 0);
            g.EnumerateMetafile(m_metafile, destPoint, m_delegate);
            // Clean up
            m_delegate = null;
        }
    }
    private bool MoveToPage(Int32 page)
    {
        // Check to make sure that the current page exists in
        // the array list
        if (null == this.RenderedReport[m_currentPrintingPage - 1])
            return false;
        // Set current page stream equal to the rendered page
        m_currentPageStream = new MemoryStream(this.RenderedReport[m_currentPrintingPage - 1]);
        // Set its postion to start.
        m_currentPageStream.Position = 0;
        // Initialize the metafile
        if (null != m_metafile)
        {
            m_metafile.Dispose();
            m_metafile = null;
        }
        // Load the metafile image for this page
        m_metafile = new Metafile((Stream)m_currentPageStream);
        return true;
    }
    private bool MetafileCallback(
       EmfPlusRecordType recordType,
       int flags,
       int dataSize,
       IntPtr data,
       PlayRecordCallback callbackData)
    {
        byte[] dataArray = null;
        // Dance around unmanaged code.
        if (data != IntPtr.Zero)
        {
            // Copy the unmanaged record to a managed byte buffer
            // that can be used by PlayRecord.
            dataArray = new byte[dataSize];
            Marshal.Copy(data, dataArray, 0, dataSize);
        }
        // play the record.     
        m_metafile.PlayRecord(recordType, flags, dataSize, dataArray);

        return true;
    }
    public byte[][] RenderedReport
    {
        get
        {
            return m_renderedReport;
        }
        set
        {
            m_renderedReport = value;
        }
    }

}

About these ads

10 Comments »

  1. Wow – you think there’d be an easier way. If you read the comments in this article, Brian Welker mentiones a future capability of creating report ‘sections’ where each section can have it’s own orientation. http://blogs.msdn.com/bwelcker/archive/2005/08/19/Alien-Lanes-_2800_Logical-and-Physical-Pagination-Rules_2900_.aspx

    He posted that in 2005 and nothing has come of it that I’m aware of. It seems like this is a need to have.

    Comment by Justin Saraceno — May 22, 2007 @ 5:00 pm

  2. I was wondering if you know of a way to rotate a text box so that it is 180 degrees from the position of a tb-lr write mode so I read it from bottom to top. Please let me know. Thanks
    I hear you can create a class that converts a string to an image and then flip the image so that it is rotated the way that I wanted
    Thanks in advance.

    Comment by Kenny — May 5, 2008 @ 11:51 pm

  3. Kenny,

    I would say that it depends on how many items you need to rotate. If just the textbox for readonly/printing purposes then you could do the above method or just use an image of a textbox.

    Regards,
    -Ben

    Comment by ben — May 6, 2008 @ 7:01 am

  4. Using an image is nice but text is necessary. And as I see, that is not possible event with SSRS 2008 unfortunately.

    Comment by Eralper — March 12, 2009 @ 6:43 am

  5. I think I might handle text as an image if I absolutely needed it rotated. You could use the same method as above and just post the text to a web page that would create an image of the rotated text.

    Comment by Ben — March 12, 2009 @ 7:41 am

  6. [url]http://www.sexwithex.com[/url] SEXWITHEX.COM – The world hottest private girls pics and videos!

    Comment by Magenial — September 9, 2010 @ 11:39 pm

  7. Understanding that, many are also discovering that the ceiling is a great way to add a good dose
    of color into the interior design of their
    home. What are your top priorities and what do you want to
    spend? Let your personality and taste glow in your office using the right
    accessories, color combinations and artwork.

    Comment by Clicking Here — July 29, 2012 @ 10:16 am

  8. Thanks , I’ve recently been looking for information about this subject for a long time and yours is the greatest I have found out till now. But, what concerning the conclusion? Are you positive concerning the source?

    Comment by Jenny — June 24, 2013 @ 11:22 am

  9. Good day! Do you use Twitter? I’d like to follow you if that would be ok. I’m undoubtedly enjoying your blog and look
    forward to new updates.

    Comment by Carrie Anne — July 27, 2013 @ 9:28 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: