David Schmidt
10/21/2004 5:59:00 PM
I bumped into this problem a while back while caching images for use in a
presentation application.
It appears that if you are using the Graphics.DrawLines(Pen,PointF[]) method
while drawing to a metafile, there is some threshold on how many points may
be in that record. The result of that DrawLines(...) function will not show
up in a viewer. Any subsequent calls is iffy. (My test app seems to always
render the subsequent stuff, but my "real" application had mixed results.)
I ended up working around it by drawing to another format instead- I think
bitmap. However, I still do have a need for implementing this for emf's,
without the limitation.
I've attached a sample application that first draws an "x" across the
destination graphics object, then a sin function with a user-defined number
of points. It seems to always render to the screen just fine. If you hit the
button, it will create a metafile to the file name specified in the text
box. Like I said, a quick sample app.
If you tell it to use 8125 points or less, it renders fine. If you tell it
to use 8126+ points, the sin wave will not appear in an emf viewer.
Is this just part of the emf spec, a bug in my logic, or a GDI+ bug?
Any feedback would be appreciated.
-Dave Schmidt
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Drawing.Imaging;
namespace emftest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Panel m_viewPanel;
private System.Windows.Forms.TextBox m_textBox_ptCount;
private System.Windows.Forms.TextBox m_textBox_emfFileName;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
m_viewPanel.Paint += new PaintEventHandler(m_viewPanel_Paint);
m_viewPanel.Resize += new EventHandler(m_viewPanel_Resize);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.m_viewPanel = new System.Windows.Forms.Panel();
this.m_textBox_ptCount = new System.Windows.Forms.TextBox();
this.m_textBox_emfFileName = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(8, 8);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "Button 1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// m_viewPanel
//
this.m_viewPanel.Anchor =
((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.To
p | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.m_viewPanel.Location = new System.Drawing.Point(8, 64);
this.m_viewPanel.Name = "m_viewPanel";
this.m_viewPanel.Size = new System.Drawing.Size(432, 280);
this.m_viewPanel.TabIndex = 1;
//
// m_textBox_ptCount
//
this.m_textBox_ptCount.Location = new System.Drawing.Point(88, 8);
this.m_textBox_ptCount.Name = "m_textBox_ptCount";
this.m_textBox_ptCount.TabIndex = 2;
this.m_textBox_ptCount.Text = "8000";
//
// m_textBox_emfFileName
//
this.m_textBox_emfFileName.Location = new System.Drawing.Point(8, 40);
this.m_textBox_emfFileName.Name = "m_textBox_emfFileName";
this.m_textBox_emfFileName.Size = new System.Drawing.Size(432, 20);
this.m_textBox_emfFileName.TabIndex = 0;
this.m_textBox_emfFileName.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(448, 350);
this.Controls.Add(this.m_textBox_emfFileName);
this.Controls.Add(this.m_textBox_ptCount);
this.Controls.Add(this.m_viewPanel);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
CreateMetafile();
}
private void CreateMetafile()
{
try
{
Graphics g = CreateGraphics();
IntPtr hdc = g.GetHdc();
string imagePath = m_textBox_emfFileName.Text;
RectangleF metaBounds = m_viewPanel.ClientRectangle;
Metafile meta = new
Metafile(imagePath,hdc,metaBounds,MetafileFrameUnit.Pixel,EmfType.EmfPlusOnl
y);
g.ReleaseHdc(hdc);
Graphics gMeta = Graphics.FromImage(meta);
Draw(gMeta,metaBounds);
gMeta.Dispose();
meta.Dispose();
g.Dispose();
}
catch (System.Exception ex)
{
MessageBox.Show("Error occurred creating metafile. " + ex.Message);
}
}
private void Draw(Graphics g,RectangleF bounds)
{
Pen pen = new Pen(Color.Black,3);
Brush brush = new SolidBrush(Color.Gray);
g.FillRectangle(brush,bounds);
g.DrawRectangle(pen,bounds.X,bounds.Y,bounds.Width,bounds.Height);
// DRAW A 'SIN WAVE'
ArrayList al = new ArrayList();
float xMid = bounds.X + bounds.Width/2f;
double theta = 0;
int ptCount = int.Parse(this.m_textBox_ptCount.Text);
for (int i = 0 ; i < ptCount ; i++)
{
float x,y;
x = xMid + (float)Math.Sin(theta) * bounds.Width/2f;
y = bounds.Y + (float)i/(float)ptCount * bounds.Height;
al.Add(new PointF(x,y));
theta = theta + Math.PI/1000;
if (theta > 2*Math.PI)
theta = 0;
}
PointF[] pts = (PointF[])al.ToArray(typeof(PointF));
g.DrawLines(pen,pts);
// DRAW AN 'X'
pen.Color = Color.Red;
g.DrawLine(pen,bounds.Left,bounds.Top,bounds.Right,bounds.Bottom);
g.DrawLine(pen,bounds.Right,bounds.Top,bounds.Left,bounds.Bottom);
pen.Dispose();
brush.Dispose();
}
private void m_viewPanel_Paint(object sender, PaintEventArgs e)
{
RectangleF r = m_viewPanel.ClientRectangle;
Draw(e.Graphics,r);
}
private void m_viewPanel_Resize(object sender, EventArgs e)
{
m_viewPanel.Invalidate();
}
}
}