Yet another blog about WPF, Surface, SL, MVVM, NUI....

2011

2010

2009

2008

Tag - bitmap

Entries feed - Comments feed

 

XAML to PNG converter...

25 June 2009

Hello,

Today a post about creating a PNG from a XAML file. Easy some will says but we will see some more tips :

  • How to create a screenshot from a control in the size you want (not the actual size).
  • How to load an external XAML file and display it inside your application.



How to load an external XAML

This snippet will use a XAMLReader, and create a visual from the XAML and the put it inside you application :

Microsoft.Win32|>.OpenFileDialog dialog = new Microsoft.Win32|>.OpenFileDialog();
         dialog.Title = "Select the XAML file.";
         dialog.AddExtension = true;
         dialog.CheckFileExists = true;
         dialog.DefaultExt = ".xaml";
         dialog.Filter = "Xaml files |*.xaml";
 
         if (dialog.ShowDialog() == true)
         {
            String path = dialog.FileName;
            UIElement visual = XamlReader.Load(System.Xml.XmlReader.Create(path)) as UIElement;
            if (visual != null)
            {
               _docker.Children.Add(visual);
            }
            else
            {
               MessageBox.Show("Cannot load the UiElement from the XAML.", "Error", MessageBoxButton.OK);
               this.Close();
            }
         }


Quite simple in fact.

How to create a screenshot in the size you want...

Then to create a sample from a control or anything which is a visual you will use a different syntax than the one presented sooner in this blog.

The tips is to create a brush from the visual, and fill a Rectangle in a drawingContext.

Here is the code :

Visual theVisual = _docker; //Put the aimed visual here.
 
         //Get the size you wants from the UI
         double width = Convert.ToDouble(_widthTextB.Text);
         double height = Convert.ToDouble(_heightTextB.Text);
 
         if (double.IsNaN(width) || double.IsNaN(height))
         {
            throw new FormatException("You need to indicate the Width and Height values of the UIElement.");
         }
         Size size = new Size(width, height);
 
         DrawingVisual drawingVisual = new DrawingVisual();
         VisualBrush vBrush = new VisualBrush(theVisual);
 
         using (DrawingContext dc = drawingVisual.RenderOpen())
         {
            dc.DrawRectangle(vBrush, null, new Rect(new Point(), size));
         }
 
         RenderTargetBitmap render = new RenderTargetBitmap(
               Convert.ToInt32(1900),
               Convert.ToInt32(1200),
               96,
               96,
               PixelFormats.Pbgra32);
         // Indicate which control to render in the image
         render.Render(drawingVisual);
         Stream oStream = new FileStream("out.png", FileMode.Create);
 
         PngBitmapEncoder encoder = new PngBitmapEncoder();
         encoder.Frames.Add(BitmapFrame.Create(render));
         encoder.Save(oStream);
         oStream.Flush();
         oStream.Close();



The resulting app

There is a little drawback: the xaml visual you load must be configured to stretch when putted inside a layout control...
Here is some screenShot of the app running :

Xaml To Png Exporter



The code source is attached to the post.

kick it on DotNetKicks.com
 

Write text inside an image: add a poster to add it in your Mogre Scene

28 May 2009

Introduction

To display informations into your scene you can use a billboard represented by the MovableText into (M)ogre but sometimes you just want to put some static text somewhere because it's more readable.

For example :

Create a poster to add it in your Mogre Scene

The code

Here is the code which use a lot of my last article .

The steps are :

  1. Create a bitmap with the text in it,
  2. Create a texture with this image, then a material,
  3. Create a poster (rectangle) and put the texture on it,
  4. Return the manualObject created.

The part which may be interest you is how to get the right size for the created bitmap based on the text...

Also the creation of the manualObject is not necessary but I think it may interest some people to see how to use it.

/// <summary>
/// Creates a 'poster' based on a text.
/// </summary>
/// <param name="Smgr">The scenemanager (necesary to create the manual object).</param>
/// <param name="text">The text to put on the poster.</param>
/// <author>Jonathan ANTOINE</author>
private static ManualObject createALabel(SceneManager Smgr, String text)
{
String textureName = Guid.NewGuid().ToString();
System.Drawing.Font font = new System.Drawing.Font("Calibri", 12, FontStyle.Bold);
Bitmap bitmap = new Bitmap(1, 1);
Graphics g = Graphics.FromImage(bitmap);
 
SizeF measureString = g.MeasureString(text, font);
bitmap = new Bitmap((int)measureString.Width, (int)measureString.Height);
g = Graphics.FromImage(bitmap);
g.FillRectangle(Brushes.Black, new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
g.DrawString(text, font, new System.Drawing.SolidBrush(Color.White), new Point(3, 3));
 
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
 
Stream oStream = new MemoryStream();
g.Save();
bitmap.Save(oStream, ImageFormat.Png);
oStream.Flush();
 
//bitmap.Dispose();
//Back to the start of the stream
oStream.Position = 0;
 
//read all the stream
BinaryReader oBinaryReader = new BinaryReader(oStream);
byte[] pBuffer = oBinaryReader.ReadBytes((int)oBinaryReader.BaseStream.Length);
oStream.Close(); //No more needed
TextureManager.Singleton.Remove(textureName); //Remove eventually texture with the same name
unsafe
{
GCHandle handle = GCHandle.Alloc(pBuffer, GCHandleType.Pinned);
byte* pUnsafeByte = (byte*)handle.AddrOfPinnedObject();
void* pUnsafeBuffer = (void*)handle.AddrOfPinnedObject();
 
MemoryDataStream oMemoryStream = new MemoryDataStream(pUnsafeBuffer, (uint)pBuffer.Length);
DataStreamPtr oPtrDataStream = new DataStreamPtr(oMemoryStream);
 
Mogre.Image oMogreImage = new Mogre.Image().Load(oPtrDataStream, "png");
 
TextureManager.Singleton.LoadImageW(textureName, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, oMogreImage);
 
//handle.Free();
}
String matNam = Guid.NewGuid().ToString();
MaterialPtr _dynamicMaterial = MaterialManager.Singleton.Create(matNam, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
Pass pass = _dynamicMaterial.GetTechnique(0).GetPass(0);
 
pass.ShadingMode = ShadeOptions.SO_PHONG;
 
TextureUnitState tus = pass.CreateTextureUnitState(textureName);
tus.SetTextureAddressingMode(TextureUnitState.TextureAddressingMode.TAM_CLAMP);
pass.AddTextureUnitState(tus);
 
_dynamicMaterial.Dispose(); //Dispose the pointer, not the material !
 
ManualObject manualObject = Smgr.CreateManualObject(Guid.NewGuid().ToString());
 
manualObject.EstimateIndexCount(6);
manualObject.EstimateVertexCount(6);
 
manualObject.Begin(matNam, RenderOperation.OperationTypes.OT_TRIANGLE_LIST);
 
//DESSUS
int yWidthVariable = bitmap.Width;
int xWidth = bitmap.Height;
 
manualObject.Position(new Vector3(0, 0, 0));
manualObject.TextureCoord(1, 0);
manualObject.Normal(Vector3.UNIT_Z);
 
manualObject.Position(new Vector3(0, -yWidthVariable, 0));
manualObject.TextureCoord(0, 0f);
manualObject.Normal(Vector3.UNIT_Z);
manualObject.Position(new Vector3(xWidth, 0, 0));
manualObject.TextureCoord(1f, 1);
manualObject.Normal(Vector3.UNIT_Z);
 
manualObject.Position(new Vector3(0, -yWidthVariable, 0));
manualObject.TextureCoord(0f, 0f);
manualObject.Normal(Vector3.UNIT_Z);
manualObject.Position(new Vector3(xWidth, -yWidthVariable, 0));
manualObject.TextureCoord(0f, 1.0f);
manualObject.Normal(Vector3.UNIT_Z);
manualObject.Position(new Vector3(xWidth, 0, 0));
manualObject.TextureCoord(1f, 1.0f);
manualObject.Normal(Vector3.UNIT_Z);
 
manualObject.End();
 
manualObject.CastShadows = false;
 
return manualObject;
}



Also you can get the size of the "poster" by using the boundingbox. An example of use :

manualObject.BoundingBox.Size.x * 0.5f * Vector3.UNIT_Y;

The code can be find as an attached file.

kick it on DotNetKicks.com