Draw Images on Image/Canvas without showing - c#

I want to create a collage (different images on an image). This works with a canvas which is defined and visible in my XAML. But how can I achieve this without showing the canvas?
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Source = new BitmapImage(new System.Uri(System.Environment.CurrentDirectory + "/" + b.Wert, System.UriKind.RelativeOrAbsolute));
TransformGroup tg = new TransformGroup();
double scaleX = (double)w / (double)img.Source.Width;
double scaleY = (double)h / (double)img.Source.Height;
tg.Children.Add(new ScaleTransform(scaleX, scaleY));
if (b.Rotation != null)
tg.Children.Add(new RotateTransform(b.Rotation, w/2, h/2));
tg.Children.Add(new TranslateTransform(x, y));
img.RenderTransform = tg;
canvas.Children.Add(img);
double dpi = 96d;
RenderTargetBitmap rtb = new RenderTargetBitmap(collage.Breite, collage.Hoehe, dpi, dpi, System.Windows.Media.PixelFormats.Default);
canvas.UpdateLayout();
rtb.Render(canvas);
// save as png
BitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
using (var fs = System.IO.File.OpenWrite("test.png"))
{
pngEncoder.Save(fs);
}

Related

C# WPF Capture UI element to picture with white background

I need to capture UI element in this case LiveCharts chart and save it to a PNG/JPEG
I got this code
private void Button_Click(object sender, RoutedEventArgs e) {
var filePath = "qwerty.png";
var res = CaptureScreen(charts, charts.ActualWidth, charts.ActualHeight);
using (var fileStream = new FileStream(filePath, FileMode.Create)) {
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(res));
encoder.Save(fileStream);
}
}
private BitmapSource CaptureScreen(Visual target, double dpiX, double dpiY) {
if (target == null) {
return null;
}
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen()) {
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
I can get a png no problem. Though it is the picture created is 30k x 9k pixels. The picture has a transparent background. what would be the best practice to capture a UI element and export as a picture with a white backgroun?

How to rotate Image

I'm trying to rotate an Image but couldn't get expected result.
I want rotate image as 90 degree. After executing my code i got unexpected result.
here is my code:
public async Task Rotate(string path, Rect rect, float degrees)
{
int h = (int)Math.Sqrt(rect.Width * rect.Width + rect.Height * rect.Height);
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget webCardImage = null;
CanvasBitmap bitmap = null;
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
Vector2 endpoint = new Vector2((float)rect.Width / 2, (float)rect.Height / 2);
try
{
webCardImage = new CanvasRenderTarget(device, h, h, logicalDpi);
using (var ds = webCardImage.CreateDrawingSession())
{
ds.Clear(Colors.Transparent);
using (FileStream imageStream = new FileStream(path, FileMode.Open))
{
IRandomAccessStream fileStream = imageStream.AsRandomAccessStream();
bitmap = await CanvasBitmap.LoadAsync(device, fileStream);
}
ICanvasImage image = new Transform2DEffect
{
Source = bitmap,
TransformMatrix = Matrix3x2.CreateRotation(degrees, endpoint),
};
var sourceRect = image.GetBounds(ds);
ds.DrawImage(image, new Rect(rect.X, rect.Y, rect.Width, rect.Height), sourceRect, 1, CanvasImageInterpolation.HighQualityCubic);
}
}
catch (Exception ex)
{
}
//Convert to Image
}
My Code generated Image:
I'm not sure what your code does, but this code should make the trick
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.UriSource = new Uri(#"C:\Images\Dock.jpg", UriKind.RelativeOrAbsolute);
bmpImage.EndInit();
TransformedBitmap transformBmp = new TransformedBitmap();
transformBmp.BeginInit();
transformBmp.Source = bmpImage;
RotateTransform transform = new RotateTransform(90);
transformBmp.Transform = transform;
transformBmp.EndInit();
This is for WPF application, for Windows Forms application you can see here:
https://learn.microsoft.com/it-it/dotnet/api/system.drawing.image.rotateflip?view=netframework-4.5
Hope this helps

How to Create High-Resolution Image from a FrameworkElement?

I have a FrameworkElement and I want to save it as a Height-Resolution Image (Jpeg). I tried the following code, but the results are not what I had hoped. I got an image with bad resolution when I print it with A4 as the paper size.
// ...
FrameworkElement element = this.Content;
element.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(element.DesiredSize));
element.UpdateLayout();
// i used element.ActulaHeight and ActualWidth but not works.
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)element.Width, (int)element.Height, GPFReporstPageSizeExtension.DPI, GPFReporstPageSizeExtension.DPI, System.Windows.Media.PixelFormats.Pbgra32);
bitmap.Render(element);
// ....
Finally i solved my problem, i posted the full solution in my blog "gamadev web site":
Saving FrameworkElement as Image
FrameworkElement element = myControl.Content;
// you can set the size as you need.
Size theTargetSize = new Size(1500,2000)
element.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(theTargetSize ));
// to affect the changes in the UI, you must call this method at the end to apply the new changes
element.UpdateLayout();
double dpiScale = 300.0 / 96;
double dpiX = 300.0;
double dpiY = 300.0;
RenderTargetBitmap bmp = new RenderTargetBitmap(Convert.ToInt32(
(theTargetSize .Width) * dpiScale),
Convert.ToInt32((theTargetSize .Height) * dpiScale),
dpiX, dpiY, PixelFormats.Pbgra32);
bmp.Render(element);
element.Measure(new System.Windows.Size());
element.Arrange(new Rect());
element.UpdateLayout();
System.Windows.Media.Imaging.BitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
MemoryStream myStream = new MemoryStream();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(this.CreateRenderTargetBitmap()));
encoder.Save(myStream);
var img = System.Drawing.Bitmap.FromStream(myStream);
Bitmap bmp = new Bitmap((int)theTargetSize .Width, (int)theTargetSize .Height);
var g = Graphics.FromImage(bmp);
g.Clear(System.Drawing.Color.White);
g.DrawImage(this.GetPageAsImage(), (int)this.Margin.Left, (int)this.Margin.Top);
fileName = #”D:\myImage.png”;
bmp.Save(fileName);

How to show dropshadow on drawingcontext tools

Actually i am using drawingContext.DrawRectangle method for drawing rectangle on canvas..
i want to add shadow effect on rectangle..
drawingContext.DrawRectangle(new SolidColorBrush(graphicsObjectFillColor),
new Pen(new SolidColorBrush(ObjectColor), ActualLineWidth),
Rectangle);
or i am using this to add drop shadow..
DropShadowEffect effect = new DropShadowEffect();
effect = new DropShadowEffect { Color = Colors.Black, Direction = -45, Opacity = 0.5, ShadowDepth = 4};
this.Effect = effect;
the shadow is showing but add the time of draw all tool on image tha shodow is not shawing
i am using
DrawingVisual vs = new DrawingVisual();
DrawingContext dc = vs.RenderOpen();
// Draw image
dc.DrawImage(image.Source, rect);
double scale = width / image.Source.Width;
// Keep old existing actual scale and set new actual scale.
double oldActualScale = drawingCanvas.ActualScale;
drawingCanvas.ActualScale = oldActualScale;
// Remove clip in the canvas - we set our own clip.
drawingCanvas.RemoveClip();
// Prepare drawing context to draw graphics
rect = new Rect(left, top, width, height);
dc.PushClip(new RectangleGeometry(rect));
double horizontalScale = Math.Abs((positionDrawingCanvas.X) - (positionImage.X));
double verticalScale = Math.Abs((positionDrawingCanvas.Y) - (positionImage.Y));
double difX = 0.0;
double difY = 0.0;
//if (horizontalScale != 0 && verticalScale != 0)
//{
// //horizontalScale = Math.Abs((positionDrawingCanvas.X + Math.Abs((positionImage.X / sliderScale.Value - positionImage.X))) - (positionImage.X));
// //verticalScale = Math.Abs((positionDrawingCanvas.Y + Math.Abs((positionImage.Y / sliderScale.Value - positionImage.Y))) - (positionImage.Y));
// difX = (positionImage.X - positionImage.X / sliderScale.Value);
// difY = (positionImage.Y - positionImage.Y / sliderScale.Value);
//}
dc.PushTransform(new TranslateTransform(difX + left - horizontalScale, difY+top - verticalScale));
dc.PushTransform(new ScaleTransform(1, 1));
// Ask canvas to draw overlays
drawingCanvas.Draw(dc);
// Restore old actual scale.
drawingCanvas.ActualScale = oldActualScale;
// Restore clip
drawingCanvas.RefreshClip();
dc.Pop();
dc.Pop();
dc.Pop();
dc.Close();
width = (Utilityhelper.GetDIPIndependentHorizontal(rect.Width));
height = (Utilityhelper.GetDIPIndependentVertical(rect.Height));
bmp = new RenderTargetBitmap((int)width, (int)(height), Utilityhelper.graphics.DpiX, Utilityhelper.graphics.DpiY, PixelFormats.Default);
//bmp = new RenderTargetBitmap((int)(scale * (rect.Width)), (int)(scale * (rect.Height)), scale * 96, scale * 96, PixelFormats.Default);
bmp.Render(vs);
sliderScale.Value = oldScale;
//imageBackground.Stretch = Stretch.Uniform;
//drawingCanvas.Width = (Utilityhelper.GetDIPDependentHorizontal(drawingCanvas.Width));
//drawingCanvas.Height = (Utilityhelper.GetDIPDependentVertical(drawingCanvas.Height));
return bmp;
You have to just change your render method
RenderTargetBitmap bmp = new RenderTargetBitmap((int)width, (int)(height), DpiX, DpiY, PixelFormats.Default);
BitmapSource source = null;
if (bmp != null)
{
bmp.Render(image);
bmp.Render(drawingCanvas);
source = bmp;
}
Here is how you get image (bitmap) from visual in wpf:
// render content into image
var render = new RenderTargetBitmap((int)ContentPresenter.RenderSize.Width, (int)ContentPresenter.RenderSize.Height, 96, 96, PixelFormats.Default);
render.Render(ContentPresenter);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(render));
using (var stream = new MemoryStream())
{
// create bitmap image
encoder.Save(stream);
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
// use BitmapImage
...
}
ContentPresenter is some visual.

How can add shape to BitmapImage in wpf and c#

I want to add path to image because I want to make curves on image. I don't know how can add curves to images. I want to draw shape on image and don't want to use canvas. because I want to convert line to Raster image this is my code:
Ellipse circle = new Ellipse();
circle.BeginInit();
circle.Height = 100;
circle.Width = 100;
circle.Stroke = System.Windows.Media.Brushes.Black;
circle.StrokeThickness = 1.0;
circle.Margin = new Thickness(0, 0, 0, 0);
circle.EndInit();
circle.Measure(new Size(200, 200));
circle.Arrange(
new Rect(new Size(200, 200)));
circle.UpdateLayout();
Line line = new Line();
line.BeginInit();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 300;
line.Y2 = 300;
line.Stroke = System.Windows.Media.Brushes.Magenta;
line.StrokeThickness = 1;
line.EndInit();
line.Measure(new Size(300, 300));
line.Arrange(new
Rect(new Size(300, 300)));
SolidColorBrush blueBrush = new SolidColorBrush();
blueBrush.Color = Colors.Blue;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;
// Create a Path with black brush and blue fill
Path bluePath = new Path();
bluePath.BeginInit();
bluePath.Stroke = blackBrush;
bluePath.StrokeThickness = 3;
bluePath.Fill = blueBrush;
// Create a line geometry
LineGeometry blackLineGeometry = new LineGeometry();
blackLineGeometry.StartPoint = new Point(20, 200);
blackLineGeometry.EndPoint = new Point(300, 200);
// Create an ellipse geometry
EllipseGeometry blackEllipseGeometry = new EllipseGeometry();
blackEllipseGeometry.Center = new Point(80, 150);
blackEllipseGeometry.RadiusX = 50;
blackEllipseGeometry.RadiusY = 50;
// Create a rectangle geometry
RectangleGeometry blackRectGeometry = new RectangleGeometry();
Rect rct = new Rect();
rct.X = 80;
rct.Y = 167;
rct.Width = 150;
rct.Height = 30;
blackRectGeometry.Rect = rct;
// Add all the geometries to a GeometryGroup.
GeometryGroup blueGeometryGroup = new GeometryGroup();
blueGeometryGroup.Children.Add(blackLineGeometry);
blueGeometryGroup.Children.Add(blackEllipseGeometry);
blueGeometryGroup.Children.Add(blackRectGeometry);
// Set Path.Data
bluePath.Data = blueGeometryGroup;
bluePath.EndInit();
bluePath.Measure(new Size(300, 300));
bluePath.Arrange(new Rect(new Size(300, 300)));
RenderTargetBitmap RTbmap = new
RenderTargetBitmap(200, 200, 96, 96,
PixelFormats.Default);
RTbmap.Render(bluePath);
var renderTargetBitmap = RTbmap;
var bitmapImage = new BitmapImage();
var bitmapEncoder = new BmpBitmapEncoder();
bitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (var stream = new System.IO.MemoryStream())
{
bitmapEncoder.Save(stream);
stream.Seek(0, System.IO.SeekOrigin.Begin);
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.UriSource = new Uri("C:\\Users\\ErnaGroup.Com\\Pictures\\Pictures\\cartoon-ice-cream-3 - Copy.jpg"); // I want to add line to this image.
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
}
image1.Source = bitmapImage;
}
How can I do this?
Image is not a container control. You definitely need a container control like Canvas to hold your shapes.
Alternatively you can set your BitmapImage as Background of Canvas using ImageBrush and draw Path/Line/Ellipse on Canvas and later you can save your drawing on Canvas as a JPG image.
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="Your BitmapImage Path"></ImageBrush>
</Canvas.Background>
</Canvas>
Then you can save your modified data as a JPG image
public static void CreateBitmapFromVisual(Visual target, string filename)
{
// target will be your Canvas
// filename is the path where you want to save the image
if (target == null)
return;
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap rtb = new RenderTargetBitmap((Int32)bounds.Width, (Int32)bounds.Height, 96, 96, PixelFormats.Default);
rtb.Render(target);
JpegBitmapEncoder jpg = new JpegBitmapEncoder();
jpg.Frames.Add(BitmapFrame.Create(rtb));
using (Stream stm = File.Create(filename))
{
jpg.Save(stm);
}
}

Categories

Resources