Quinn-Curtis Forums
Quinn-Curtis Forums
Home | Profile | Register | Active Topics | Members | Search | FAQ
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 Tools for Microsoft .Net & .Net Compact Framework
 QCChart2D and QCChart2D CF (VB and C#)
 BufferedImage.SaveImage causes exception
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

bret@infowest.com

3 Posts

Posted - 02 Dec 2004 :  17:35:51  Show Profile  Reply with Quote
Presume the following:

BufferedImage image = new BufferedImage(chart, ImageFormat.Emf);
MemoryStream stream = new MemoryStream();
image.SaveImage(stream);

When executing on a perfectly legitimate chart, the SaveImage call dies w/ the following exception:

An unhandled exception of type 'System.ArgumentNullException' occurred in system.drawing.dll
Additional information: Value cannot be null.

Any clues as to why?

(My needs are to copy the graph to the clipboard in EMF format; I'm not using the realtime version of the product.)

quinncurtis

1164 Posts

Posted - 03 Dec 2004 :  11:37:25  Show Profile  Reply with Quote
There seems to be something in the .Net runtime that prevents an image from being saved to a stream using the ImageFormat.Emf and ImageFormat.Wmf modes. Enter "ImageFormat.Emf" "stream" into Google Groups for related discussions. No solutions or work-arounds though.

Based on your example, save a graph to the clipboard using in the following manner:

BufferedImage image = new BufferedImage(chart, ImageFormat.Emf);
Clipboard.SetDataObject(image.GetBufferedImage() ,true);

Go to Top of Page

bret@infowest.com

3 Posts

Posted - 03 Dec 2004 :  12:19:39  Show Profile  Reply with Quote
Thanks for the reply. Your code snippet does work, but it appears that it is simply a raster (bitmap) image.

Is there any way to get the image it as a true metafile (i.e. vector image)? I need to scale/resize the image (and maintain quality) after copied to the clipboard and pasted in the target application (Word/PowerPoint).

Thanks
Go to Top of Page

quinncurtis

1164 Posts

Posted - 03 Dec 2004 :  13:48:24  Show Profile  Reply with Quote
.Net does not seem to have the same type of vector metafile support that the Windows GDI has. I think that the best you can do is make sure that you save the source graph as large as possible, so that it does not have to be scaled up, rather it is always scaled down. You can create a large version of the graph, save it to the clipboard, but not change the way it displays on the screen.

.
.
.
Size oldsize = chart.Size;
Size newsize = new Size(1000,1000);
chart.Size = newsize;
BufferedImage savegraph = new BufferedImage(chart, fileimageformat);
savegraph.SaveImage(filename);
Clipboard.SetDataObject(savegraph.GetBufferedImage() ,true);
chart.Size = oldsize;
Go to Top of Page

bret@infowest.com

3 Posts

Posted - 03 Dec 2004 :  15:06:11  Show Profile  Reply with Quote
Yes, you are absolutely correct, the .Net metafile format is different than the traditional metafile format (thanks MS!).

There is a KB article that documents how to convert from the .Net format to the traditional format:

http://support.microsoft.com/default.aspx?scid=kb;en-us;323530

This is a go/no-go issue for me, do you plan on adding support for streaming/saving a graph as a vector metafile?

Thanks
Go to Top of Page

quinncurtis

1164 Posts

Posted - 03 Dec 2004 :  16:22:16  Show Profile  Reply with Quote
There are two issues. The QCChart2D software renders the chart to a bitmap Image buffer, then saves that image to a particular file format using the Image.Save method. The .Net Image.Save method simply ignores requests to save the image as a Emf or Wmf file type and instead stores the image as a PNG file type. See the Microsoft article: "Image.Save Method Does Not Save the File as the Selected File Type" at the link http://support.microsoft.com/default.aspx?scid=kb;en-us;316563
Even if the Image.Save method worked with metafiles, it would still not convert a graph stored as a bitmap in an Image buffer to a vector graphics version of the same graph. Instead it would just embed the graph as bitmap in the metafile.


It is possible to record images as true Metafiles using .Net, using the .Net Metafile class, though this seems to be very poorly documented. The article that you reference relates to the issue that the new .Net metafile format is incompatible with virtually all application programs (particularly Word, Excel, Powerpoint) that use metafiles. We will have to investigate further whether or not it is possible to use the Metafile class to create true vector graphics metafiles of QCChart2D charts. At the very least it will be a couple months before we know more. We will send you an e-mail should the situation change.

Go to Top of Page

quinncurtis

1164 Posts

Posted - 04 Dec 2004 :  19:48:07  Show Profile  Reply with Quote
It did not take as long as we thought. Based on the ClipboardMetafileHelper class
we were able to create a method that copyies a chart as an EMF to the clipboard. The best part is that it resides outside of the QCChart2D library and can just be added to your main program. Based on your example, here is the usage:

Code is in a Form or UserControl derived class that has a this.Handle property.

ClipboardMetafileHelper.CopyChartToClipboardEMF(this.Handle, chart );

where the ClipboardMetafileHelper class is:

using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using com.quinncurtis.chart2dnet;

public class ClipboardMetafileHelper
{
[DllImport("user32.dll")]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
static extern bool EmptyClipboard();
[DllImport("user32.dll")]
static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[DllImport("user32.dll")]
static extern bool CloseClipboard();
[DllImport("gdi32.dll")]
static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
[DllImport("gdi32.dll")]
static extern bool DeleteEnhMetaFile(IntPtr hemf);

// Metafile mf is set to a state that is not valid inside this function.
static public bool PutEnhMetafileOnClipboard( IntPtr hWnd, Metafile mf )
{
bool bResult = false;
IntPtr hEMF, hEMF2;
hEMF = mf.GetHenhmetafile(); // invalidates mf
if( ! hEMF.Equals( new IntPtr(0) ) )
{
hEMF2 = CopyEnhMetaFile( hEMF, new IntPtr(0) );
if( ! hEMF2.Equals( new IntPtr(0) ) )
{
if( OpenClipboard( hWnd ) )
{
if( EmptyClipboard() )
{
IntPtr hRes = SetClipboardData( 14 /*CF_ENHMETAFILE*/, hEMF2 );
bResult = hRes.Equals( hEMF2 );
CloseClipboard();
}
}
}
DeleteEnhMetaFile( hEMF );
}
return bResult;
}

static public void CopyChartToClipboardEMF(IntPtr hWnd, ChartView component)
{
Graphics g= component.CreateGraphics();
IntPtr hdc=g.GetHdc();
Metafile mf=new Metafile(hdc,EmfType.EmfOnly);
g.ReleaseHdc(hdc);
g.Dispose();
g=Graphics.FromImage(mf);
if (g != null)
{
// Make sure all objects rejustified before final rendering
component.ResetPreviousChartObjectList();
component.RenderingMode = ChartObj.BUFFERED_IMAGE_RENDERING;
component.Draw(g);
component.RenderingMode = ChartObj.SCREEN_RENDERING;
g.Dispose();
}
PutEnhMetafileOnClipboard(hWnd, mf);
}

}


Add a new class to your project named ClipboardMetafileHelper, replace the shell class with this code and you should be rolling.

Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
Quinn-Curtis Forums © 2000-07 Quinn-Curtis, Inc. Go To Top Of Page
Powered By: Snitz Forums 2000 Version 3.4.07