拿到任务之后首先分成了几个部分:
1.绘图。学习了GDI+
2.图片保存。
3.将图片转换成byte[]。由于使用Socket通信,只能传输byte[]数据,所以这一步是向下位机传输的关键。
相应地,编程实现了下面几个功能:
1.使用GDI+画图并保存为bmp格式的图片。画图部分是书上的例子,只增加了保存的相应代码。
public partial class Form1 : Form { Bitmap bitmap; Font myFont = new Font("Arial", 12, FontStyle.Bold);//定义字符串的样式 Rectangle ret = new Rectangle(10, 10, 160, 160);//实例化 public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { bitmap = new Bitmap(panel1.Width, panel1.Height);//用于保存 this.panel1.BackgroundImage = bitmap; int tem_Line = 0;//圆的直径 int ci_L = 4;//画笔 if (panel1.Width >= panel1.Height) { tem_Line = panel1.Height; } else tem_Line = panel1.Width; ret = new Rectangle(ci_L, ci_L, tem_Line - ci_L * 2, tem_Line - ci_L * 2); Font Star_font = new Font("Arial", 30, FontStyle.Regular); string star_str = "*"; Graphics g = Graphics.FromImage(bitmap); //Graphics g = this.panel1.CreateGraphics();//实例化画图类 g.SmoothingMode = SmoothingMode.AntiAlias;//消除绘制的锯齿,作用比较明显 g.Clear(Color.White);//以白色清空panel1控件的背景 Pen myPen = new Pen(Color.Red, ci_L);//定义画笔 g.DrawEllipse(myPen, ret);//画椭圆(绘制圆) SizeF mySize = new SizeF(ret.Width, ret.Width);//实例化SizeF类 存储有序浮点数对,通常为矩形的宽度和高度。 mySize = g.MeasureString(star_str, Star_font);//对指定字符串进行测量(测量什么??????) g.DrawString(star_str, Star_font, myPen.Brush, new PointF((ret.Width / 2F) + ci_L - mySize.Width / 2F, ret.Height / 2F - mySize.Width / 2F));//在指定的位置绘制 mySize = g.MeasureString("专用", myFont); g.DrawString("专用", myFont, myPen.Brush, new PointF((ret.Width / 2F) + ci_L - mySize.Width / 2F, ret.Height / 2F + mySize.Width / 2F));//在指定的位置绘制 string tem = "testing"; int len = tem.Length; float angle = 180 + (180 - len * 20) / 2; for (int i = 0; i < len; i++)//将文字以指定的弧度进行绘制 { g.TranslateTransform((tem_Line + ci_L / 2) / 2, (tem_Line + ci_L / 2) / 2); g.RotateTransform(angle);//将指定的旋转用于Graphics类的变换矩阵?????????????? Brush myBrush = Brushes.Red; g.DrawString(tem.Substring(i, 1), myFont, myBrush, 60, 0); g.ResetTransform();//将Graphics类的全局变换矩阵重置为单位矩阵????????? angle += 20;//设置下一个文字的角度 } bitmap.Save(@"D:\myImage123.bmp", ImageFormat.Bmp); } }
2.将图片转换成byte[]
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Bitmap bitmap;
byte[] imageBytes;
MemoryStream ms;
private void button1_Click(object sender, EventArgs e)//打开图片
{
openFileDialog1.Filter = "*.bmp|*.bmp";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
if (bitmap != null)
bitmap.Dispose();
string fileName = openFileDialog1.FileName;
bitmap = new Bitmap(fileName);
/*if (bitmap.Width > bitmap.Height)//如果 图片 的宽度大于高度
{
pictureBox1.Width = panel1.Width;//设置控件的宽度
pictureBox1.Height = (int)((double)bitmap.Height * panel1.Width / bitmap.Width);
}
else
{
pictureBox1.Height = panel1.Width;
pictureBox1.Width = (int)((double)bitmap.Height * panel1.Width / bitmap.Width);
}*/
pictureBox1.Image = bitmap;//显示图片
}
}
private void button2_Click(object sender, EventArgs e)
{
Image myImage = bitmap;//注意
ms = new MemoryStream();
imageBytes = new byte[ms.Length];//关于字节数组大小!!!!
myImage.Save(ms,ImageFormat.Gif);//存储到流
imageBytes=ms.ToArray();//将转换之后的结果赋值
richTextBox1.AppendText("长度:" + imageBytes.Length);
foreach (byte b in imageBytes)
{
richTextBox1.AppendText("转换之后的数据:" + b+"\r\n");
}
}
private void button3_Click(object sender, EventArgs e)
{
MemoryStream ms = new MemoryStream(imageBytes);
Image returnImage = Image.FromStream(ms);
pictureBox2.Image= returnImage;//显示图片
}
}
至此,绘图、保存、转换都已经正确实现。
回归到最初的任务:画正弦函数曲线,并将数据传输给下位机(ARM),经下位机处理后将数据传回,并显示。要求上位机在画曲线时用户可以改变参数(这里设定的可变参数有幅度、周期、初相),参数改变就意味着有参照,而不是单一画出正弦函数图形,所以,必须添加坐标。最初研究添加坐标时,考虑的无非就是画坐标线,然后添加图形,但是这样的效果是无法将坐标与图形联系起来。为解决此问题,考虑了两种方案:固定坐标线,调整图像与坐标线建立联系;固定图形,让坐标去适应图形。这里需要说明的是,此时我考虑的这种所谓“坐标线”只是根据绘图区大小而画的直线,并非实际意义上的坐标系!当然这两种方案都没有实现,因为在研究过程中关注到了另外的组件:zedGraph。所以接下来的实现已经转移到这上面。
目前的效果:在zedGraph中绘制参数可变的正弦函数图像(含参考图像),然后保存为bmp格式的图片。这样加入之前将图片转换为byte[]的代码,然后将数据传输给下位机,就大功告成了!
兴奋时间还没有超过十秒钟,我就意识到自己从开始就绕了一个大圈:将数据传输给下位机并令下位机处理的,是指什么数据?仔细思考,有两种可能:
1、是列表中的坐标点,这样才能将处理之后的数据返回并再次显示,并非图片。
2、确实是图片,但即使是图片也不可能将转换之后的byte[]整个处理,因为这之间必然包含各种信息,如果不了解这些信息,如何告知下位机处理哪些数据,保留哪些数据?换句话说,也就是包含传输中数据格式的问题。
总之,无论如何,距离最后的结果还有距离。
Anyway 先将这段代码附上:
public partial class Form1 : Form { //private bool flag; public Form1() { InitializeComponent(); } /*private void Form1_Paint(object sender, PaintEventArgs e) { if (flag) { CreateGraph(zedGraphControl1); SetSize(); flag = false; } } * */ private void button1_Click(object sender, EventArgs e) { //flag = true; SetSize(); CreateGraph(zedGraphControl1); } private void CreateGraph(ZedGraphControl zgc) { GraphPane myPane = zgc.GraphPane; myPane.Clear();//消除上次痕迹 myPane.Title.Text = "正弦函数"; myPane.XAxis.Title.Text = "横坐标"; myPane.YAxis.Title.Text = "竖坐标"; //获取用户设定的数据 int T = Int32.Parse(numericUpDown1 .Text);//周期 int A = Int32.Parse(numericUpDown2.Text);//幅度 int B = Int32.Parse(numericUpDown3.Text);//初相 double w=2*Math.PI/T; double x, y1, y2; PointPairList list1 = new PointPairList();//定义坐标数组 PointPairList list2 = new PointPairList(); for (int i = 0; i < 36; i++)//逐一描点画图 { x = (double)i ;//从坐标原点开始 //y1 = 1.5 + Math.Sin((double)i * 0.2); y1 = A*Math.Sin((double)i * w+B); //y2 = 3.0 * (1.5 + Math.Sin((double)i * 0.2)); y2 =3.0*(Math.Sin((double)i * 0.1*Math.PI));//作为研究的参考图形 list1.Add(x, y1); list2.Add(x, y2); } // Generate a red curve with diamond // symbols, and "Porsche" in the legend LineItem myCurve = myPane.AddCurve("Sin()", list1, Color.Red, SymbolType.Diamond); // Generate a blue curve with circle // symbols, and "Piper" in the legend LineItem myCurve2 = myPane.AddCurve("参考", list2, Color.Blue, SymbolType.Circle); // Tell ZedGraph to refigure the // axes since the data have changed zgc.AxisChange(); //发送WM_PAINT消息放在应用程序的消息队列中,WM_PAINT消息的优先级很低,所以不会立即重绘 //zgc.Invalidate();//使窗口客户区无效,这样就需要重绘, zgc.Refresh();//刷新显示 } private void Form1_Resize(object sender, EventArgs e) { //使控件大小随窗口大小改变而改变。是必要的 SetSize(); } private void SetSize() { zedGraphControl1.Location = new Point(22, 130);//20 zedGraphControl1.Size = new Size(ClientRectangle.Width-44,ClientRectangle.Height-170);//ClientRectangle.Width-22, ClientRectangle.Height-129);//20 20 //MessageBox.Show(ClientRectangle.Height.ToString() + "h w" + ClientRectangle.Width.ToString()); } private void button2_Click(object sender, EventArgs e)//保存图片 { zedGraphControl1.Refresh();//刷新图片 pictureBox1.Image = zedGraphControl1.GetImage();//提取图片 pictureBox1.Image.Save(@"D:\myImage00.bmp", ImageFormat.Bmp);//保存图片 } }
再接再励,继续。