Set image position to page center - wpf

I'm trying to print an image in the center of the page but I can't come up with any idea.
System.Windows.Point printLocation = new System.Windows.Point(50,50);
printLocation.X = pageWidth - 50 / 2; 50 is the margin
imageViewer = ImagePrintAdapter.CreateImageFromBitmapImage(img,printLocation);
printerDialog.PrintVisual(imageViewer, "Identification");
This is the CreateImageFromBitmapImagemethod
public static System.Windows.Controls.Image CreateImageFromBitmapImage(BitmapImage imgSource, System.Windows.Point imgLocation)
{
System.Windows.Controls.Image imageViewer = new System.Windows.Controls.Image();
imageViewer.BeginInit();
imageViewer.Source = imgSource;
imageViewer.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
imageViewer.Arrange(new System.Windows.Rect(imgLocation, imageViewer.DesiredSize));
imageViewer.EndInit();
imageViewer.UpdateLayout();
return imageViewer;
}
If I set the printLocation.X to be the half of the pageWidth, shouldn't it start at the center ?

You may simply draw the image into a DrawingVisual and print it. The following simplified example assumes that the bitmap size is smaller than the printable area size:
ImageSource image = ...
var rect = new Rect(
(printDialog.PrintableAreaWidth - image.Width) / 2,
(printDialog.PrintableAreaHeight - image.Height) / 2,
image.Width, image.Height);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawImage(bitmap, rect);
}
printDialog.PrintVisual(visual, "");
Note that you may as well use any other size for the Rectangle, i.e. scale the printed image accordingly.

Related

How do I export my wpf InkCanvas with the proper size?

I'm trying to create a simple sketching application.
But I've ran into a weird problem. I have a Surface Pro 3 that I'm working on, with a DPI of 144, according to some system settings.
When I save the image from my app, using 96 as the dpi, it produces an image that's just a little bit smaller. Which is kind of weird.
Is there a way that I can either a) scale the canvas/strokes up that I'm saving, or tell the RenderTargetBitmap to scale properly? If I just stick 144 in there, I get the proper scale for the strokes, but my canvas size is borked.
My canvas saving code looks like this:
public void saveCanvas(object sender, RoutedEventArgs e){
this.save_filename = this.save_filename ?? this.getSaveFilename();
if (save_filename != null){
var cantwo = new InkCanvas();
cantwo.Strokes.Clear();
cantwo.Strokes.Add(this.canvas.Strokes);
cantwo.Background = this.canvas.Background;
var size = new Size(this.canvas.ActualWidth, this.canvas.ActualHeight);
cantwo.Height = size.Height;
cantwo.Width = size.Width;
cantwo.Measure(size);
cantwo.Arrange(new Rect(size));
var transform = this.canvas.LayoutTransform;
var rtb = new RenderTargetBitmap((int)this.canvas.ActualWidth, (int)this.canvas.ActualHeight, dpiX, dpiY, PixelFormats.Default);
rtb.Render(cantwo);
try {
using(var fs = File.Open(this.save_filename, FileMode.Create)){
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(fs);
}
}
catch(IOException){
MessageBox.Show("Failed to save image", "ERROR: Save Failed");
}
// Restore transformation if there was one.
this.canvas.LayoutTransform = transform;
}
}
How can I save my image at the same size/resolution/dpi as my canvas? (Or draw on my canvas at the same dpi/scale as I save my image)?
Instead of creating a second InkCanvas, draw a Rectangle that is filled with a VisualBrush into a DrawingVisual:
var rect = new Rect(canvas.RenderSize);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(new VisualBrush(canvas), null, rect);
}
var rtb = new RenderTargetBitmap(
(int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default);
rtb.Render(visual);

WPF multipage printing for FixedDocument (Visual C# 2010)

I have a question about multipage FixedPage. I have a Grid created programmatically and the Grid exceeds one A4 page. Now I want to print the Grid in several FixedPage with print margin. But on my way, I create the Grid repeatedly and offset the LeftTop point in the fixedPage Arrange function. I meet a problem that I cannot set print margin in fixedPage, because I set the print margin to the fixedPage and then the first page will have print margin and the next pages will be blank.
How do print multipage of FixedDocument for a large grid want to print?
PrintDialog pd = new System.Windows.Controls.PrintDialog();
if (pd.ShowDialog() == false)
{
return;
}
var pageSize = new Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight);
var document = new FixedDocument();
document.DocumentPaginator.PageSize = pageSize;
for (int nPage = 0; nPage < MaxPage; nPage++)
{
Grid tempGrid = LoadControlMotherInit();
tempGrid.Width = GridWidth;
tempGrid.Height = GridActualHeight;
Point leftTop = new Point();
leftTop.X = 10;
leftTop.Y = -nPage * pageSize.Height;
// Create FixedPage
var fixedPage = new FixedPage();
fixedPage.Width = pageSize.Width;
fixedPage.Height = pageSize.Height;
fixedPage.Margin = new Thickness(0, 0, 0, 96);
fixedPage.Children.Add((UIElement)tempGrid);
fixedPage.Measure(pageSize);
fixedPage.Arrange(new Rect(leftTop, pageSize));
fixedPage.UpdateLayout();
// Add page to document
var pageContent = new PageContent();
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
document.Pages.Add(pageContent);
}
pd.PrintDocument(document.DocumentPaginator, "My Document");
From looking at your example,
PrintDialog.PrintDocument method takes in a DocumentPaginator, which could come from a multitude of source.
that being said, you can inherit from DocumentPaginator and take control of everything from PageSize, PageCount to the actual DocumentPage being returned.
Imagine your DocumentPage as a sliding window over your UIElement; but instead of sliding your DocumentPage, you slide your UIElement using its RenderTransform.

WPF Clear Region on a Drawing Context?

So I am producing a transparent PNG using a DrawingContext and DrawingVisual.
Inside the DrawingContext, I drew a rectange.
I would now like to "cut out" a circle inside of the rectangle. How do I do this? I did not find any functions in drawing context to clear a region.
You can try using CombinedGeometry to combine 2 geometries (each time). It has GeometryCombineMode allowing you to specify some logic combination. In this case what you need is GeometryCombineMode.Xor. The intersection of the Rect and the Ellipse (cirlce) will be cut out. Here is the simple code demonstrating it:
DrawingVisual dv = new DrawingVisual();
using (var dc = dv.RenderOpen()) {
var rect = new Rect(0, 0, 300, 200);
var cb = new CombinedGeometry(GeometryCombineMode.Xor,
new RectangleGeometry(rect),
new EllipseGeometry(new Point(150, 100), 50, 50));
dc.DrawGeometry(Brushes.Blue, null, cb);
}
I hope you know how to render the DrawingVisual. You can use some RenderTargetBitmap to capture it into some kind of BitmapSource and then you have many ways to show this bitmap.
Here is the screenshot:
The Black region means the color is transparent.
In case you want to cut out some complex image (such as drawn text or image). You can turn the CombinedGeometry into some kind of OpacityMask (type of Brush). We can turn it into a DrawingBrush and this brush can be used as OpacityMask which can be passed into DrawingContext.PushOpacityMask method:
DrawingVisual dv = new DrawingVisual();
using (var dc = dv.RenderOpen()) {
var rect = new Rect(0, 0, 300, 200);
var cb = new CombinedGeometry(GeometryCombineMode.Xor,
new RectangleGeometry(rect),
new EllipseGeometry(new Point(150, 100), 50, 50));
var mask = new DrawingBrush(new GeometryDrawing(Brushes.Blue, null, cb));
dc.PushOpacityMask(mask);
dc.DrawImage(someImage, rect);
dc.DrawText(new FormattedText("Windows Presentation Foundation",
System.Globalization.CultureInfo.CurrentCulture,
System.Windows.FlowDirection.LeftToRight,
new Typeface("Lucida Bright"), 30, Brushes.Red){
MaxTextWidth = rect.Width,
MaxTextHeight = rect.Height,
TextAlignment = TextAlignment.Center
}, new Point());
}
Note that the rect should have the size of your whole drawing. Then positioning the hole and other drawn stuff will be exact as what you want.
Finally the DrawingVisual also has a useful property called Clip which is a Geometry. So you can prepare some CombinedGeometry and assign it to DrawingVisual.Clip property.
Suppose you already have your DrawingVisual (with some drawn stuff including text, images, ...). The following code will punch a hole through it:
//prepare the geometry, which can be considered as the puncher.
var rect = new Rect(0, 0, 300, 200);
var cb = new CombinedGeometry(GeometryCombineMode.Xor,
new RectangleGeometry(rect),
new EllipseGeometry(new Point(150, 100), 50, 50));
//punch the DrawingVisual
yourDrawingVisual.Clip = cb;

RenderToBitmap trouble in WPF

Actually, I have to print the view from a Viewport3D, obviously, I use a RenderTargetBitmap. The problem is that if the resolution of the rendered image got high, some triangles of my scene don't appear on my final image.
For example, my viewport can be 1024*768 and the resolution I use with my RenderTargetBitmap would be 3 times viewport's resolution.
http://imgur.com/PS2F9D9
I already solved the problem in a certain way... In fact, triangles don't appear when I use a big scale. If I lower the size of my RenderTargetBitmap, it will contain everything.
Actually, I have more or less 1024*768 at 96dpi. If I want to impress at 300dpi, I need to get a huge image so I would like to avoid this last solution.
Some code :
public static RenderTargetBitmap CaptureEcran(Viewport3D p_viewPort, int p_scale)
{
RenderTargetBitmap l_bmp;
p_scale = p_scale > 5 ? 5 : p_scale;
l_bmp = new RenderTargetBitmap(p_scale * Convert.ToInt32(p_viewPort.ActualWidth), p_scale * Convert.ToInt32(p_viewPort.ActualHeight), p_scale * 96.0, p_scale * 96.0, PixelFormats.Pbgra32);
DrawingVisual vis = new DrawingVisual();
DrawingContext dc = vis.RenderOpen();
dc.DrawRectangle(System.Windows.Media.Brushes.White, null, new Rect(0, 0, p_scale * p_viewPort.ActualWidth, p_scale * p_viewPort.ActualHeight));
dc.Close();
l_bmp.Render(vis);
p_viewPort.UpdateLayout();
l_bmp.Render(p_viewPort);
return l_bmp;
}
public static void SaveImage(RenderTargetBitmap renderTargetBitmap, string m_impression)
{
System.Windows.Forms.FolderBrowserDialog l_fBD = new System.Windows.Forms.FolderBrowserDialog();
l_fBD.ShowDialog();
string l_path = l_fBD.SelectedPath + "\\" + CurrentUser() + "__" + CurrentDate() + "__." + m_impression.ToLower();
FileStream stream = new FileStream(l_path, FileMode.Create);
BitmapEncoder l_encoder = null;
switch(m_impression){
case "PNG":
PngBitmapEncoder l_png = new PngBitmapEncoder();
l_encoder = l_png;
break;
case "JPEG":
JpegBitmapEncoder l_jpeg = new JpegBitmapEncoder();
l_jpeg.QualityLevel = 30;
l_encoder = l_jpeg;
break;
}
l_encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
l_encoder.Save(stream);
stream.Close();
}
My call is :
SaveImage(CaptureEcran(m_viewPortCourant.ViewPort3D,5), m_impression);
Where m_impression is .png or .jpg
It finally works by using a VisualBrush containing the viewport and drawn into the DrawingContext.
DrawingVisual vis = new DrawingVisual();
DrawingContext dc = vis.RenderOpen();
VisualBrush sourceBrush = new VisualBrush(p_viewPort);
dc.DrawRectangle(System.Windows.Media.Brushes.White, null, new Rect(0, 0, p_viewPort.ActualWidth * p_scale, p_viewPort.ActualHeight * p_scale));
dc.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0), new Vector(p_viewPort.ActualWidth, p_viewPort.ActualHeight)));
dc.Close();
l_bmp.Render(vis);

Silverlight Image Cropping

Does anybody knows how to image cropping in silverlight without any library.
I have Child window and inside the child window I havev a image and this image center one rectange is there so I can panning the image to the around the rectange and selecet the perticular part of the image and this selected part I want to crop.
Also I am using WriteableBitmap and try to Crop, this will not work if correct me if I am wrong.
sheetRectangle.Children is the Image.
foreach (ucPicRect item in sheetRectangle.Children)
{
WriteableBitmap obj = new WriteableBitmap(item.imgCell.Source as BitmapSource);
obj.Crop(0,0,400,400);
obj.Invalidate();
item.imgCell.Effect = dlgcwEditPhoto.imgEdit.Effect;
item.imgCell.Source = obj;// dlgcwEditPhoto.imgEdit.Source;
}
Thanks...!!!
you can use this utility function to crop your image
public static WriteableBitmap cropImage(Image image, double[] coordonnee)
{
Image cloneImage = new Image();
cloneImage.Source = image.Source;
RectangleGeometry myRec = new RectangleGeometry();
myRec.Rect = new Rect(coordonnee[0], coordonnee[1], coordonnee[2], coordonnee[3]);
cloneImage.Clip = myRec;
TranslateTransform t = new TranslateTransform();
t.X = -coordonnee[0];
t.Y = -coordonnee[1];
WriteableBitmap wb = new WriteableBitmap(cloneImage, t);
wb.Invalidate();
return wb;
}
good luck !!

Resources