I am loading an image into an ink canvas, the input image is always monochromatic, I am then drawing on that image with a white pen and intending to save it.
When the image is loaded some of the pre-existing lines which I know to be 1 pixel thick have an edge added to them which isn't monochromatic.
The way I have though to fix this is by rendering the bitmap and then discarding all pixels with a value of less than 255.
I have tried to use the pixel format BlackWhite, however this generates the error:
An unhandled exception of type 'System.ArgumentException' occurred in PresentationCore.dll
Additional information: 'BlackWhite' PixelFormat is not supported for this operation.
The line of code rendering the bitmap
RenderTargetBitmap rtb = new RenderTargetBitmap((int)inkCanvas.ActualWidth, (int)inkCanvas.ActualHeight, 96, 96, System.Windows.Media.PixelFormats.BlackWhite);
I'm not sure if the issue lies in how I loaded it into the ink canvas so that code is also included below
private void LoadImagetoCanvas(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDlg = new Microsoft.Win32.OpenFileDialog();
Nullable<bool> result = openFileDlg.ShowDialog();
if (result == true)
{
global.canvas1filepath = openFileDlg.FileName;
System.Windows.Controls.Image myImage = new System.Windows.Controls.Image();
myImage.Source = new BitmapImage(new Uri(global.canvas1filepath));
BitmapImage bmp = new BitmapImage(new Uri(global.canvas1filepath, UriKind.Absolute));
global.canvas1imagexpixels = (int)bmp.Width;
global.canvas1imageypixels = (int)bmp.Height;
ImageBrush canvas1Background = new ImageBrush();
canvas1Background.ImageSource = new BitmapImage(new Uri(global.canvas1filepath, UriKind.Relative));
inkCanvas1.Background = canvas1Background;
}
}
I'll compile an answer here - thanks to Sinatr & Clemens for their help with the theory and examples
The solution is based in the XMAL code for the ink canvas i'm using, I found adding the two following properties removed any edges to the 1 pixel wide lines I was drawing:
RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased"
Related
I am new to C# and to WPF, and I could be looking at this completely wrong. I have a JPEG byte array as a source. I cannot change this. I need to get the array, perform some calculations and draw rectangles in areas of the JPEG. I then write it to an Image XAML control.
I get the JPEG and I can convert it into an ImageSource and display it to an ImageControl. I can't find a way to get the drawing context from the ImageSource. I use ImageSourceConverter to read in the JPEG array and this class returns an ImageSource instance, duh!.
ImageSource mImage = (ImageSource)mConverter.ConvertFrom(mImageBuffer);
ImageSource does not have a drawing context property.
What it seems like I need is a DrawingImage, it is derived from ImageSource and has a drawing context property.
How can I use a DrawingImage instead of the ImageSource.
I looked at the ImageDrawing class, it has an ImageSource property. This class doesn't have a drawing context.
I am currently looking into the Visual class, and help where to look would be appreciated.
Edit:
Thanks #nefarious for pointing me in the right direction. I ended with the following:
ImageSource mImage = (ImageSource)mConverter.ConvertFrom(mImageBuffer);
BitmapSource bImage = mImage as BitmapSource;
// Draw a Rectangle
DrawingVisual dVisual = new DrawingVisual();
using (DrawingContext dc = dVisual.RenderOpen())
{
dc.DrawImage(bImage, new Rect(0, 0, bImage.PixelWidth, bImage.PixelHeight));
dc.DrawRectangle(Brushes.Green, null, new Rect(20, 20, 150, 100));
}
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(640,480,96,96, PixelFormats.Default);
targetBitmap.Render(dVisual);
WriteableBitmap wBitmap = new WriteableBitmap(targetBitmap);
image.Source = wBitmap;
Have you looked at using Visuals, I don't know how efficient they are but it seems that you will be unable to copy the source into an ImageSource and draw directly into it.
Create a DrawingVisual and draw the ImageSource and the Rectangles into the drawing context of the drawing visual.
Then use WriteableBitmap to show it in the image;
Rather than declaring an image and setting the source from the xaml file, can someone do the initialization part, set the image coordinates, and set the source completely in the code?
// Create Image Element
Image myImage = new Image();
myImage.Width = 200;
// Create source
BitmapImage myBitmapImage = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri(#"C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg");
// To save significant application memory, set the DecodePixelWidth or
// DecodePixelHeight of the BitmapImage value of the image source to the desired
// height or width of the rendered image. If you don't do this, the application will
// cache the image as though it were rendered as its normal size rather then just
// the size that is displayed.
// Note: In order to preserve aspect ratio, set DecodePixelWidth
// or DecodePixelHeight but not both.
myBitmapImage.DecodePixelWidth = 200;
myBitmapImage.EndInit();
//set image source
myImage.Source = myBitmapImage;
You need to create a new Image specifying the source:
Image myImage = new Image();
BitmapImage bitmapImage = new BitmapImage(new Uri("/YourSource", UriKind.Relative)); //Or UriKind.Absolute depending in the path
myImage.Source = bitmapImage;
If you want to place the image into some coordenates you can place a Canvas behind and place the image using Canvas coordenates. Use:
_myCanvas.Children.Add(myImage); //To add your image to Canvas, declared on Xaml or previously created and added to your control
Canvas.SetTop(myImage, 100); //Set Y coordenate relative to Canvas initial point
Canvas.SetLeft(myImage, 100); // Set X
I'm writing an application for the surface that requires displaying data in a table (i.e. DataGrid). This is great, except the table captures the touch interactions for the ScatterViewItem control (basically a panel that can be spun, shrunk, and moved by the user). This prevents the user from easily manipulating the ScatterViewItem.
To solve this problem, I thought it would be easy to draw the control to an image and just put that up. It seems I was wrong. Here are all my attempts:
http://pastie.org/private/gfkkv9f6apgrqi1ucspwpa (no need to read this, unless you think it will be useful. That's why it's in pastie and not on here)
I'm putting the DataGrid inside of another Grid, because otherwise it won't measure properly:
Grid g = new Grid();
g.Children.Add(dataTable);
SurfaceScrollViewer viewer = new SurfaceScrollViewer();
viewer.Content = Utility.SaveWPFControlAsImage(g);
If we change that last line to
viewer.Content = g;
We get a good table:
If we don't, we get:
SaveWPFControlAsImage is as follows:
public static System.Windows.Controls.Image SaveWPFControlAsImage(FrameworkElement e)
{
e.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
RenderTargetBitmap targetBitmap =
new RenderTargetBitmap((int)e.DesiredSize.Width,
(int)e.DesiredSize.Height,
96d, 96d,
PixelFormats.Default);
targetBitmap.Render(e);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
MemoryStream stream = new MemoryStream();
encoder.Save(stream);
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = new MemoryStream(stream.ToArray());
bmp.EndInit();
return new System.Windows.Controls.Image()
{
Source = bmp,
};
}
So maybe I'm just not rendering it right, or, maybe, I'm just going about this at the wrong angle...
In WPF you have a VisualBrush which allows you to capture a live preview of a given control. Also if you don't want any input of a given control, you can always set IsHitTestVisible="False".
I can't seem to get the text I've written to show up on my image Here's the code I'm using
//Creates a bitmap with the path to the current image
Bitmap LabelImage = new Bitmap(dtImages.Rows[intCurrentImage]["ImageURL"].ToString());
Graphics graphic = Graphics.FromImage(LabelImage);
graphic.DrawString("Hello", new Font("Tahoma",40), Brushes.Azure, new System.Drawing.Point(0,0));
//put Image that I just created and put the text on into an Infragistics UltraPicureBox
picImage.Image = LabelImage
You did not update your original image (LabelImage), so why should the text you added to the Graphics object show up?.
From MSDN, Graphics.FromImage:
Creates a new Graphics from the specified Image.
(emphasis mine)
After you have added the text, you need to save the changes:
graphic.Save();
Unrelated to your question, you should really put the creation of the Graphics object in a using statement, to ensure proper disposal:
using(Graphics graphic = Graphics.FromImage(LabelImage))
{
// use graphic here
}
I just tried this
Bitmap bitmap = new Bitmap("C:\\Untitled.png");
Graphics g = Graphics.FromImage(bitmap);
g.DrawString("Hello", new Font("Tahoma", 40), Brushes.Azure, new System.Drawing.Point(0, 0));
pictureBox1.Image = bitmap;
and it works fine for me. Just try to pick a contrasting brush.
I'm trying to build a treeview like file list in a richtext box.
It should look like an explorer treeview. My code is able to get an resize the icon, but the transparency is missing (light gray background instead of transparency). What do I need to change here? Is the Image format wrong?
Is there a better way to add an image to a richtextbox?
// Get file info
FileInfo f = new FileInfo("myfile.name");
// Get icon for fileinfo
Icon ico = Icon.ExtractAssociatedIcon(f);
// Convert icon to bitmap
Bitmap bm = ico.ToBitmap();
// create new image with desired size
Bitmap img = new Bitmap(16,16,PixelFormat.Frmat32bpRgb);
// Create graphics with desired sized image
Graphics g = Graphics.FormImage(img);
// set interpolation mode
g.InterpolationMode = InterpolationMode.HighQualityBiCubic;
// draw/resize image
g.DrawImage(bm, new Rectangle(0,0,16,16), new Rectangle(0, 0, bm.Width, bm,Height), GraphicalUnit.Pixel);
// Paste to clipboard
Clipboard.SetImage(bm);
// Paste in RichtextBox
rtb.Paste();
Example:
Edit:
I've figured out that the image is transparent, but using Clipboard.SetImage() doesn't publish it as transparent image.
Any ideas why and what can I do to fix it? Do I need to switch to a differn textbox control?
I've had some luck going through Graphics.
Bitmap b = new Bitmap(pbAssetLoaded.Width, pbAssetLoaded.Height);
using (Graphics g = Graphics.FromImage(b))
{
g.DrawIcon(SystemIcons.Information, 0, 0);
}
This draws the icon with transparency to the Bitmap.
Try
img.MakeTransparent();
after you contruct it.
Note that this will change your PixelFormat to Format32bppArgb.