ASP.NET基于GDI+生成报表图片

本文介绍如何使用ASP.NET结合GDI+技术生成报表图片,并提供了具体实现代码及示例。该方法适用于手机网站等无法使用Flash的场景。

来博客园很久了,也从大牛们那里学到了好多东西。今天开始写博客,写下自己的技术点滴!

前两天接到公司一个需求,是公司手机网站那边要求提供一个接口,用于生成报表图片,方便手机用户查看。公司的报表原先好多是基于FlashChat的,但是用flash是不能满足需求的,好多手机是不支持flash的,而且即使支持也会比较消耗流量。所以需要把报表画到图片上,这样就可以直接调用了。

由于对GDI+也不是太熟悉,花了一天时间才搞定,期间查了很多资料。最后还是被我搞出来了,哈哈,鉴于怕以后有其它类似需求,我做了下封装。现提供给大家,有需要的朋友可以拿走。目前封装的还不是太完美,缺点是纵轴目前只支持6个刻度。纵轴刻度的生成算法是,取数据最小值,最大值然后差值平均为5份。

效果如下:

2011022211310277.jpg

2011022211295930.jpg

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace ImageTest
{
    /// <summary>
    /// MakeImage 的摘要说明
    /// </summary>
    public class MakeImage
    {

        private List<string> xStr = new List<string>();
        /// <summary>
        /// x轴的刻度
        /// </summary>
        public List<string> XStr
        {
            set { this.xStr = value; }
            get { return this.xStr; }
        }

        private List<string> yStr = new List<string>();
        /// <summary>
        /// y轴的刻度
        /// </summary>
        public List<string> YStr
        {
            set { this.yStr = value; }
            get { return this.yStr; }
        }

        /// <summary>
        /// 计算后的数据点在图片中的坐标
        /// </summary>
        private List<Point> pointItem = new List<Point>();

        /// <summary>
        /// 数据点集合
        /// </summary>
        public List<float> PointDataEsf;

        /// <summary>
        /// 生成图片
        /// </summary>
        /// <returns>字节数组</returns>
        public byte[] BuildTrendPic()
        {
            int width = 550;
            int height = 300;

            if (PointDataEsf.Count < 6)
            {
                return new byte[0];
            }

            Bitmap bmp = new Bitmap(width, height);
            Graphics gph = Graphics.FromImage(bmp);
            gph.InterpolationMode = InterpolationMode.HighQualityBicubic;
            gph.SmoothingMode = SmoothingMode.HighQuality;
            gph.Clear(Color.White);
            gph.DrawRectangle(new Pen(Color.Silver), 0, 0, bmp.Width - 1, bmp.Height - 1);


            Point zero = new Point(50, 29);
            gph.DrawLine(Pens.Black, zero, new Point(zero.X, 250));
            gph.DrawLine(Pens.Black, new Point(zero.X, 250), new Point(530, 250));

            //计算Y轴间隔和Y轴数据 最大,最小千位取整 平均为5份
            List<int> avgSpan = this.ySpanAvg(PointDataEsf);
            for (int i = avgSpan[0]; i < (avgSpan[1]); i += avgSpan[2])
            {
                this.YStr.Add(i.ToString());
            }
            this.YStr.Add((avgSpan[1]).ToString());


            //计算x轴刻度间隔
            int xSpanPix = Convert.ToInt32(480.0 / (this.XStr.Count));


            //计算每个数据点在坐标图中的像素位置
            for (int i = 0; i < PointDataEsf.Count; i++)
            {
                Point p = new Point();
                double tts = ((PointDataEsf[i] - avgSpan[0]) * 221.0) / (avgSpan[1] - avgSpan[0]);
                p.Y = 250 - Convert.ToInt32(tts);
                p.X = 80 + i * xSpanPix;
                this.pointItem.Add(p);
            }

            int xspan = 22;
            //画横线
            for (int i = 1; i <= 10; i++)
            {
                gph.DrawLine(Pens.Silver, new Point(zero.X, 250 - i * xspan), new Point(530, 250 - i * xspan));
                if (i % 2 == 0)
                {
                    gph.DrawLine(Pens.Black, new Point(zero.X, 250 - i * xspan), new Point(55, 250 - i * xspan));
                }
            }

            //画纵轴文字内容
            for (int i = 0; i < 6; i++)
            {
                gph.DrawString(yStr[i] + "元", new Font("宋体", 10), Brushes.Black, new PointF(0, 250 - i * xspan * 2 - 5));
            }

            //画横轴和纵线
            for (int i = 0; i < xStr.Count; i++)
            {
                gph.DrawString(xStr[i], new Font("宋体", 10), Brushes.Black, new PointF(zero.X + 20 + i * xSpanPix, 255));
            }

            for (int i = 0; i < 12; i++)
            {
                //画大竖线
                gph.DrawLine(Pens.Silver, new Point(zero.X + 30 + i * xSpanPix, zero.Y), new Point(zero.X + 30 + i * xSpanPix, 250));
                //画小竖线
                gph.DrawLine(Pens.Black, new Point(zero.X + 30 + i * xSpanPix, 250), new Point(zero.X + 30 + i * xSpanPix, 255));
            }
            gph.DrawLine(Pens.Silver, new Point(530, zero.Y), new Point(530, 250));


            #region 画折线图
            //画折线
            gph.DrawLines(new Pen(new SolidBrush(Color.FromArgb(255, 0, 0)), 2f), pointItem.ToArray());

            //画折线中的点
            int j = 0;
            foreach (Point p in pointItem)
            {
                gph.FillPie(new SolidBrush(Color.Red), p.X - 4, p.Y - 4, 8, 8, 0, 360);
                gph.DrawString(PointDataEsf[j].ToString(), new Font("宋体", 10), Brushes.OrangeRed, new PointF(p.X - 12, p.Y - 18));
                j++;
            }
            #endregion

            gph.DrawString("本次评估数据截止时间" + DateTime.Now.AddMonths(-1).ToString("yyyy年MM月") + " 更多数据请登录 www.xxxxxx.com", new Font("宋体", 10), Brushes.Black, new PointF(100, 278));
            gph.Dispose();
            using (MemoryStream ms = new MemoryStream())
            {
                bmp.Save(ms, ImageFormat.Jpeg);
                bmp.Dispose();
                return ms.ToArray();
            }
        }


        #region 求数组中的最大数 初以5后的数 用于y轴间隔
        /// <summary>
        /// 求数组中的最大数 除以5后的数 用于y轴间隔
        /// </summary>
        /// <param name="tempArray"></param>
        /// <returns>最大值,最小值,平均值</returns>
        private List<int> ySpanAvg(List<float> tempArray)
        {
            List<int> rStruct = new List<int>();
            float lower = tempArray[0];
            float higher = tempArray[1];
            foreach (float x in tempArray)
            {
                if (higher < x)
                    higher = x;
                if (lower > x)
                    lower = x;
            }
            int hstr = Convert.ToInt32(higher);
            int lstr = Convert.ToInt32(lower);

            int avgSpan = Convert.ToInt32((higher - lower) / 5.0);
            rStruct.Add(Convert.ToInt32(lower));
            rStruct.Add(Convert.ToInt32(higher));
            rStruct.Add(avgSpan);
            return rStruct;
        }
        #endregion

    }
}

用法,在aspx页面添加如下代码

protected void Page_Load(object sender, EventArgs e)
        {

            List<float> PointItems = new List<float>();
            PointItems.Add(537); PointItems.Add(479);
            PointItems.Add(836); PointItems.Add(895);
            PointItems.Add(611); PointItems.Add(995); 
            PointItems.Add(998);

            MakeImage ImageMake = new MakeImage();
            ImageMake.XStr.Add("08月"); ImageMake.XStr.Add("09月");
            ImageMake.XStr.Add("10月"); ImageMake.XStr.Add("11月");
            ImageMake.XStr.Add("12月"); ImageMake.XStr.Add("01月");
            ImageMake.XStr.Add("02月");

            ImageMake.PointDataEsf = PointItems;

            Response.ClearContent();
            Response.ContentType = "image/Jpeg";
            byte[] ImageByte = ImageMake.BuildTrendPic();
            Response.BinaryWrite(ImageByte);
        }

目前还不太完善,以后再好好完善下!

posted on 2011-02-22 11:21 断鱼 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/wybin/archive/2011/02/22/1961106.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值