I want to save my label Control, but I have no idea to save it.
I tried draw text in Graphics class, but I can't draw "even allocation".
Is there any good way?
public Label makeLabel(string text, double width, double height, FontFamily fontFamily, FontStyle fontStyle, FontStretch fontStretch)
{
var label = new Label();
label.Width = width;
label.Height = height;
label.FontFamily = fontFamily;
label.FontStyle = fontStyle;
label.FontStretch = fontStretch;
label.Content = text;
return label;
}
public void SavePicture(Label label)
{
var path = "label.png";
// I have no idea to save;
}
public void SavePicture(Label label)
{
var path = "label.png";
var width = label.Width;
var height = label.Height;
var viewBox = new Viewbox();
var renderTargetBitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
var pngBitmapEncoder = new PngBitmapEncoder();
viewBox.Child = label;
viewBox.Measure(new Size(width, height));
viewBox.Arrange(new Rect(0, 0, width, height));
viewBox.UpdateLayout();
renderTargetBitmap.Render(viewBox);
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (var fileStream = File.Create(path))
{
pngBitmapEncoder.Save(fileStream);
}
}
This works without having label displayed on screen.
void SavePicture(FrameworkElement el)
{
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)el.ActualWidth, (int)el.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(el);
using (FileStream stream = File.Create(#"label.png"))
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream);
}
}
But you can call this method only after the Label is displayed.
Related
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?
I want to draw large number of shapes (lines, ellipses and ...) and then save them as bitmap or png. I made the drawings and the question is: how can I convert a DrawingImage to BitmapImage in C#? the code is something like this:
DrawingGroup drawingGroup = new DrawingGroup();
using(DrawingContext context = drawingGroup.Open())
{
//make some drawing
}
DrawingImage drawingImage = new DrawingImage(drawingGroup)
// your suggestion? DrawingImage - > BitmapImage
You may put the ImageDrawing into an Image control and render that into a RenderTargetBitmap, which is a BitmapSource and can therefore be serialized by a BitmapEncoder (PngBitmapEncoder in this example).
public void SaveDrawingToFile(Drawing drawing, string fileName, double scale)
{
var drawingImage = new Image { Source = new DrawingImage(drawing) };
var width = drawing.Bounds.Width * scale;
var height = drawing.Bounds.Height * scale;
drawingImage.Arrange(new Rect(0, 0, width, height));
var bitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingImage);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(fileName, FileMode.Create))
{
encoder.Save(stream);
}
}
Note that you don't actually need a BitmapImage for encoding, because BitmapSource (or any derived class like RenderTargetBitmap) will be accepted as argument to BitmapFrame.Create.
A slightly different solution would involve a DrawingVisual instead of a DrawingImage:
public void SaveDrawingToFile(Drawing drawing, string fileName, double scale)
{
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.PushTransform(new TranslateTransform(-drawing.Bounds.X, -drawing.Bounds.Y));
drawingContext.DrawDrawing(drawing);
}
var width = drawing.Bounds.Width * scale;
var height = drawing.Bounds.Height * scale;
var bitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingVisual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(fileName, FileMode.Create))
{
encoder.Save(stream);
}
}
I found it pretty easy this way:
public static BitmapSource ToBitmapSource(DrawingImage source)
{
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(source, new Rect(new Point(0, 0), new Size(source.Width, source.Height)));
drawingContext.Close();
RenderTargetBitmap bmp = new RenderTargetBitmap((int)source.Width, (int)source.Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
return bmp;
}
You may use it to get System.Drawing.Bitmap
using (MemoryStream ms = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(ToBitmapSource(drawingImage)));
encoder.Save(ms);
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms))
{
bmpOut = new System.Drawing.Bitmap(bmp);
}
}
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);
}
}
I use the following method to create some image.
My question is how I can display it in .cshtml page (MVC3)? Which Razor syntax I have to use?
public FileContentResult DisplayFont()
{
int fontSize = 12;
string fontName = "Arial";
System.Drawing.Font rectangleFont = new System.Drawing.Font(fontName, fontSize, FontStyle.Bold);
int height = 150;
int width = 250;
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bitmap);
g.SmoothingMode = SmoothingMode.AntiAlias;
Color backgroundColor = Color.White;
g.Clear(backgroundColor);
g.DrawString(fontName, rectangleFont,SystemBrushes.WindowText, new PointF(10, 40));
MemoryStream outputStream = new MemoryStream();
bitmap.Save(outputStream, ImageFormat.Jpeg);
byte[] byteArray = outputStream.ToArray();
g.Dispose();
bitmap.Dispose();
return new FileContentResult(byteArray, "image/jpeg");
}
You can render it using a normal HTML img tag, using the URL of your DisplayFont action:
<img src='#Url.Action("DisplayFont")' />
I am trying to add the image of a usercontrol to viewbox.
I am creating the usercontrol dynamically. I am using the code below.
private static RenderTargetBitmap 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);
RenderTargetBitmap rtb = new RenderTargetBitmap(596,596,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 Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
I am creating the user control dynamically and passing this to capture screen method.
UserControls.UserControl1 uc1 = new UserControls.UserControl1();
visualList.Add(uc1);
for(int i = 0;i<=6;i++)
{
Image img = new Image();
img.Source = CaptureScreen(visualList[i], 96, 96);
img.Margin = new Thickness { Top = 2 };
usingWorkaround.Children.Add(img);
}
the VisualTreeHelper.GetDescendantBounds(target) is returning empty bounds. Thats why the image of the screen can not be created. Is there any other method to capture screen of dynamically created user control?
you can call Measure and Arrange As follows
private void ForceUpdate(FrameworkElement element, double width, double height)
{
Size size = new Size(width, height);
element.Measure(size);
element.Arrange(new Rect(0, 0, width, height));
element.UpdateLayout();
}
At the time when you try to create the image the controls don't yet exist in the visual tree and the size has not been calculated.
You will need to call Measure and Arrange on your visual first.