I'm trying to make an Image out of one of my Canvas (myPrintingCanvas). But the Width of the image is getting atleast twice wider than the Canvas, and the extra space that is created is back. If I try on another Canavas (LayoutRoot), it works as intended.
My observation is that on myPrintingCanvas the ActualWidth is always 0. LayoutRoot has a correct ActualWidth. Not sure if it has anything to do with the extra padding, and I have failed on getting the ActualWidth for myPrintingCanvas (using UpdateLayout and Measure).
Code:
//Code to render the content of myPrintingCanvas
...
//Make the WriteableBitmap
WriteableBitmap myWriteableBitmap = new WriteableBitmap(myPrintingCanvas, null);
Have you tried Creating the WriteableBitmap with a fixed size and then calling its Render method to render the bitmap? Canvas has some weird behaviors because it is an anti-pattern in Silverlight and WPF and breaks many rules about layout. The code for creating a fixed size WriteableBitmap and rendering to it would look something like this:
int width = 640;
int height = 480;
WriteableBitmap bmp = new WriteableBitmap(width, height);
bmp.Render(myPrintingCanvas, null);
bmp.Invalidate();
One advantage of this technique is that if you need to grab multiple images you can reuse the same WriteableBitmap instead of recreating it every time.
Related
In WPF ,we can use VisualBrush do some thing like ppt's left side.
But I see the VisualBrush may lost the line in Rectangle when I zoom the VisualBrush to a small size.Like the image:
You can see VisualBrush lost the Bottom line.
But what I want is like the below image:
When I try use the BitmapImage that use RenderTargetBitmap to get a image and use linear interpolation algorithm to zoom will get a clearness image.
Can I change VisualBrush's algorithm I think it may use neighborhood-pixels algorithm.
Are there any printscreen algorithm that have a good performance like VisualBrush.
When I change my search key to ViewBox ,I can find the same question as this one :how to avoid a single pixel line disappear in wpf?
There is a class named TransformedBitmap which can scale your RenderTargetBitmap with default scaling algorithm.
Use the code below:
public static BitmapSource ToBitmapSource(this Visual visual, Size size)
{
var bounds = VisualTreeHelper.GetDescendantBounds(visual);
var width = (int) Math.Round(bounds.Width);
var height = (int) Math.Round(bounds.Height);
var bitmap = new RenderTargetBitmap(width, height, 96.0, 96.0, PixelFormats.Pbgra32);
bitmap.Render(visual);
return new TransformedBitmap(bitmap, new ScaleTransform(size.Width / width, size.Height / height));
}
I've tried this method in my demo and got the result below. You may noticed that the small rectangle in the left-top corner lost nothing.
I am trying to display image using BitmapImage for some time and it worked.I have changed the image and it stopped working.
For Bitmapimage I was using this code:
`ms.Seek(0, SeekOrigin.Begin); // ms is memory stream
BitmapImage b = new BitmapImage();
b.SetSource(ms);
image.ImageSource = b;`
I have ran into piece of code where it was checking if the length of the bytes[] ==14400
if(bytes.length == 14400)
{
var bmp = new WriteableBitmap(width, height);
Buffer.BlockCopy(buffer, 0, bmp.Pixels, 0, buffer.Length);
}
I want to know when to use WriteableBitmap and BitmapImage .
From iProgrammer:
Bitmaps are generally implemented as immutable objects. What this means is that once you create a bitmap you can't make any changes to it. You can manipulate bitmaps by creating new versions, which then immediately become immutable....
The WriteableBitmap, as its name suggests, isn't immutable and you can get at its individual pixels and manipulate them as much as you want. This is the ideal way to work when you need dynamic bitmaps.
iProgrammer - WriteableBitmap
From MSDN:
"Use the WriteableBitmap class to update and render a bitmap on a per-frame basis..." MSDN - WriteableBitmap Class
The Examples section of the MSDN article also shows how to update a WritableBitmap image when responding to mouse events. The code in the example erases pixels of the image by setting the pixel's ARGB values to 0 when the mouse's right button is down. The code also shows how to update individual pixels in the image where the mouse's left button is down. Essentially the code shows a rudimentary pixel image editor.
The point, however, is that you can't change image data when using regular bitmap - you have to use WritableBitmap instead. You can, however, render both if you wish.
I have a TreeView with small icons displayed in the data template. I'm trying to save the Treeview as a PNG using RenderTargetBitmap.
The image saves correctly on small data sets. However, if the data set becomes too large, some of the icons are excluded from the final image. The magic number seems to be 200 items. It doesn't seem to matter if the tree is deep or wide, after 200 items, the icons are not rendered.
Added Code
So here is my code that I'm using to create an image.
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
(int)_treeView.ActualWidth,
(int)_treeView.ActualHeight,
96, 96, PixelFormats.Default);
targetBitmap.Render(_treeView);
Added Screen Shot
Notice the missing icons way over on the right side of the tree.
Now if I collapse a few branches, thus hiding some of the other icons, then these icons are included. It's almost like RenderTargetBitmap.Render doesn't have the power to render all of the icons. Or it may have something to do with virtual panels.
Here is a closer look.
What I immediately noticed that you have HUGE image. Width 12000. I am surprised that you even got that close.
As MSDN states, the texture width/height are limited by DirectX texture limits.
The maximum rendered size of a XAML visual tree is restricted by the maximum dimensions of a Microsoft DirectX texture; for more info see Resource Limits (Direct3D). This limit can vary depending on the hardware whre the app runs. Very large content that exceeds this limit might be scaled to fit. If scaling limits are applied in this way, the rendered size after scaling can be queried using the PixelWidth and PixelHeight properties. For example, a 10000 by 10000 pixel XAML visual tree might be scaled to 4096 by 4096 pixels, an example of a particular limit as forced by the hardware where the app runs.
http://msdn.microsoft.com/library/windows/apps/dn298548
I suspect these things:
Virtualization cutting off some things - I've had the exact problem in past with DataGrid, and the problem was virtualization. Your case doesn't seem like one though.
Too big texture can cause undefined behaviour.
You can try disabling hardware acceleration. The thing causes quite few hardcore bugs. http://msdn.microsoft.com/en-us/library/system.windows.media.renderoptions.processrendermode.aspx
Other than that - it will be tricky, but I am pretty sure that it will work beautifully:
1) start with the root object, and traverse the root object childrens recursively, until you find an object that is less than 1000 x 1000. Take picture of it using RenderTargetBitmap(BMP) and merge it to IN-MEMORY-BMP. Do it for each children.
You should be able to calculate all this stuff.
For the records: there's a workaround.
Instead of rendering your Visual directly with RenderTargetBitmap, use an interim DrawingVisual. Paint your Visual into the DrawingVisual using a VisualBrush and then use RenderTargetBitmap with the DrawingVisual.
Like this:
public BitmapSource RenderVisualToBitmap(Visual visual)
{
var contentBounds = VisualTreeHelper.GetContentBounds(visual);
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
var visualBrush = new VisualBrush(visual);
drawingContext.DrawRectangle(visualBrush, null, contentBounds);
}
var renderTargetBitmap = new RenderTargetBitmap((int)contentBounds.Width, (int)contentBounds.Height, 96, 96, PixelFormats.Default);
renderTargetBitmap.Render(drawingVisual);
return renderTargetBitmap;
}
Note however that as your VisualBrush gets bigger the resulting image gets more and more fuzzy (when rendering with high DPI). To work around this problem use a series of smaller VisualBrush "tiles" as described here:
https://srndolha.wordpress.com/2012/10/16/exported-drawingvisual-quality-when-using-visualbrush/
I'm in the process of making a WPF program that:
can scan a bitmap image, pixel-by-pixel, and assign it a data value (0-255)
design a class that allows panning and zooming of the picture
create a histogram, from the data values, that overlays the bitmap image.
I was able to do all three, however the issue that I am having is that the histogram doesn't dynamically (I think that's the word for it) stretch as I re-size the main window. Actually, nothing stretches to the correct size in the main window (the bitmap image just re-centers itself while keeping the same size). The histogram originally started as a transparent canvas that had many rectangle children. I changed it to a grid but am getting the same results as the canvas; the rectangles don't want to stretch horizontally or vertically. If I do set a horz/vert alignment the histogram disappears altogether. Can anyone help with this problem?
I ended up making a class that was a derivative of the canvas class i cave it some rendering overrides and a paint method that took into account the actual width and height of the window.
I'm able to render a Visual to a bitmap fine with this code:
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap renderBitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual visual = new DrawingVisual();
using (DrawingContext context = visual.RenderOpen())
{
VisualBrush brush = new VisualBrush(target);bounds.Value.Size));
context.DrawRectangle(brush, null, new Rect(new Point(), bounds.Value.Size));
}
renderBitmap.Render(visual);
return renderBitmap;
The problem is that if the Visual has a bitmap effect like a drop shadow on it, then the resulting image is squished. It seems that its trying to fit the visual with the drop shadow into an image the size of the visual without the drop shadow.
In most cases (like drop shadow) the actual rendering of the effect falls outside of the bounds of the element itself. Relying on the ActualHeight and ActualWidth to size you image then causes the squeezing effect you're seeing. The best solution would be to use a parent container instead but that might require changes to your layout. You may also be able to calculate additional padding values to add to the element's size that will compensate for the effect rendering. It might be possible to derive those values by inspecting the properties of the Effect itself and will probably involve some trial and error too.
The effect has a set of padding properties and thes are used to set the size of rendering area used by the effect - see if these have been modified and if so adjust the size of the rendered visual. Have a look at RenderTargetBitmap - Visual vector to bitmap and the articles at WPF Workings