Rendering DashStyle.Dot Line using Graphics.PageScale as 0.50 - winforms

In Windows form, I am trying to render the Line by setting style as DashStyle.Dot by using Graphics and Graphics page scale as 0.50. But the line does not rendered in form. Please anyone suggest me on this....
refer to the below code snippet:
protected override void OnPaint(PaintEventArgs e)
{
gp = e.Graphics;
gp.PageScale = 0.50f;
using (System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.White))
{
gp.FillRectangle(myBrush, new RectangleF(30, 100, 400, 600));
}
// Create pen.
using (Pen blackPen = new Pen(Color.Black, 0))
{
blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
gp.DrawLine(blackPen, 30, 200, 430, 200);
}
}

I believe it's being drawn but it has too small width so it's practically invisible.
Try another width, similar to:
using (Pen blackPen = new Pen(Color.Black, 4.0F))
{
blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
gp.DrawLine(blackPen, 30, 200, 430, 200);
}

Related

How to optimally find the smallest image rendered by a WPF control

I am using the FormulaControl from WPF-Math to render a bitmap for a tek equation. The bitmap will be delivered as content over a web service ( slack ). There is no desktop component. I am only using the WPF framework to try to capture the image from the tek control. The code for the renderer component is
public static class Renderer
{
private static readonly StaTaskScheduler _StaTaskScheduler = new StaTaskScheduler( 1 );
public static async Task<string> GenerateImage(string formula)
{
string Build()
{
var control = new FormulaControl
{
Formula = formula
, Background = Brushes.White
};
control.Measure(new Size(300, 300));
control.Arrange(new Rect(new Size(300, 300)));
var bmp = new RenderTargetBitmap(300, 300, 96, 96, PixelFormats.Pbgra32);
bmp.Render(control);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
var file = #"test.png";
using (Stream stm = File.Create(file))
encoder.Save(stm);
return file;
}
return await Task.Factory.StartNew
( Build, CancellationToken.None, TaskCreationOptions.None, _StaTaskScheduler );
}
}
Using the above code and the input
k_{n+1} = n^2 + k_n^2 - k_{n-1}
the below image is generated
As you can see, in this case, an arbitrary size of 300x300 is too big and for a different tek input it maybe too small.
The challenge is to generate a bitmap of exactly the correct size for the rendered equation. How can this be done?
One solution is to render to a large bitmap then auto crop the whitespace. There is a solution for auto cropping whitespace at
Cropping whitespace from image in C#
Using the ImageCrop class from above I modified the rendering code to
public static class Renderer
{
private static readonly StaTaskScheduler _StaTaskScheduler = new StaTaskScheduler( 1 );
public static Bitmap Convert( RenderTargetBitmap inmap )
{
MemoryStream stream = new MemoryStream();
BitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(inmap));
encoder.Save(stream);
Bitmap bitmap = new Bitmap(stream);
return bitmap;
}
public static async Task<string> GenerateImage(string formula)
{
string Build()
{
var control = new FormulaControl
{
Formula = formula
, Background = Brushes.White
};
control.Measure(new Size(300, 300));
control.Arrange(new Rect(new Size(300, 300)));
var bmp = new RenderTargetBitmap(300, 300, 96, 96, PixelFormats.Pbgra32);
bmp.Render(control);
var image = ImageCrop.AutoCrop( Convert( bmp ) );
var file = #"test.png";
image.Save( file,ImageFormat.Png );
return file;
}
return await Task.Factory.StartNew
( Build, CancellationToken.None, TaskCreationOptions.None, _StaTaskScheduler );
}
}
The output in my slackbot is now perfectly cropped.
Obviously this is not perfect as there is an upper bound on the render size.

shadow on geometry drawn by drawcontext in wpf

I am rendering a rectangle on a textbox using the drawing context using the following code.
drawingContext.DrawRoundedRectangle(
new SolidColorBrush(Color.FromRgb(255, 246, 178)), null,
new Rect(new Point(rect.TopRight.X + 20, rect.TopRight.Y),
new Size(130, rect.Height)),
3,
3);
I want to render a shadow on this rectangle that I draw programmatically in WPF. How can i do it ?
Add effect to Visual
Try something like this
public class MyControl: Control
{
private Rect rect = new Rect(100, 100, 200, 200);
protected override void OnRender(DrawingContext drawingContext)
{
var r = new Rect(new Point(rect.TopRight.X + 20, rect.TopRight.Y),
new Size(130, rect.Height));
var brush = new SolidColorBrush(Color.FromRgb(255, 246, 178));
DropShadowEffect effect = new DropShadowEffect();
effect = new DropShadowEffect {Color = Colors.Gainsboro, Direction = 30};
this.Effect = effect;
drawingContext.DrawRoundedRectangle(brush, null, r, 3, 3);
base.OnRender(drawingContext);
}
}
This gives me:
EDIT
If you do not have UI element to attach Effect, then you need to do shadow on your own.
Just add another rectangle under your main, with some gradient brush that becomes transparent.
protected override void OnRender(DrawingContext drawingContext)
{
var r = new Rect(new Point(rect.TopRight.X + 20, rect.TopRight.Y),
new Size(130, rect.Height));
var r2 = new Rect(new Point(rect.TopRight.X + 25, rect.TopRight.Y+5),
new Size(130, rect.Height));
var brush = new SolidColorBrush(Color.FromRgb(255, 246, 178));
var gradientBrush = new LinearGradientBrush(Colors.Black, Colors.Gray, 30);
drawingContext.DrawRoundedRectangle(gradientBrush, null, r2, 3, 3);
drawingContext.DrawRoundedRectangle(brush, null, r, 3, 3);
base.OnRender(drawingContext);
}
This will give you something like this

how to change pie chart colors of JFreeChart?

how to customize the colors of JFreeChart graphic.
lets see my java code :
private StreamedContent chartImage ;
public void init(){
JFreeChart jfreechart = ChartFactory.createPieChart("title", createDataset(), true, true, false);
File chartFile = new File("dynamichart");
ChartUtilities.saveChartAsPNG(chartFile, jfreechart, 375, 300);
chartImage = new DefaultStreamedContent(new FileInputStream( chartFile), "image/png");
}
public PieDataset createDataset() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("J-2", 10);
dataset.setValue("J-1", 15);
dataset.setValue("J", 50);
dataset.setValue("J+1", 20);
dataset.setValue("J+2", 15);
return dataset;
}
html page :
<p:graphicImage id="MyImage" value="#{beanCreateImage.chartImage}" />
You can change the color of single pieces like this:
JFreeChart chart = ChartFactory.createPieChart("title", createDataset(), true, true, false);
PiePlot plot = (PiePlot) chart.getPlot();
plot.setSectionPaint("J+1", Color.black);
plot.setSectionPaint("J-1", new Color(120, 0, 120));
// or do this, if you are using an older version of JFreeChart:
//plot.setSectionPaint(1, Color.black);
//plot.setSectionPaint(3, new Color(120, 0, 120));
So with your code, all the pies are colored automatically, after my code changes, the J-1 and J+1 have a fixed color, the rest gets automatically colored.
To set the colous for a chart you can implement the DrawingSupplier inferface in this case I've used DefaultDrawingSupplier:
public class ChartDrawingSupplier extends DefaultDrawingSupplier {
public Paint[] paintSequence;
public int paintIndex;
public int fillPaintIndex;
{
paintSequence = new Paint[] {
new Color(227, 26, 28),
new Color(000,102, 204),
new Color(102,051,153),
new Color(102,51,0),
new Color(156,136,48),
new Color(153,204,102),
new Color(153,51,51),
new Color(102,51,0),
new Color(204,153,51),
new Color(0,51,0),
};
}
#Override
public Paint getNextPaint() {
Paint result
= paintSequence[paintIndex % paintSequence.length];
paintIndex++;
return result;
}
#Override
public Paint getNextFillPaint() {
Paint result
= paintSequence[fillPaintIndex % paintSequence.length];
fillPaintIndex++;
return result;
}
}
Then include this code in your `init()' method
JFreeChart jfreechart = ChartFactory.createPieChart("title", createDataset(), true, true, false);
Plot plot = jfreechart.getPlot();
plot.setDrawingSupplier(new ChartDrawingSupplier());
...
You can customize the colors according to the labels while getting the data from the dataset:
// Add custom colors
PiePlot plot = (PiePlot) chart.getPlot();
for (int i = 0; i < dataset.getItemCount(); i++) {
if(dataset.getKey(i).equals("J+1")){
plot.setSectionPaint(i, Color.black);
}
}
You can also use a switch-case statement or the one you prefer.

passing a vector drawing to the UI thread

Is there any way to draw actual WPF vectorgraphics (DrawingContext, VisualBrush, DrawingBrush, RenderTargetBitmap etc.) with Freezables in a separate thread offscreen?
The following solution almost has it, excpet that the drawing is a bitmap and is not scalable when this.label becomes big you'll the the pixels.
private void Draw()
{
this.dispatcher = Dispatcher.CurrentDispatcher;
Thread t = new Thread(this.DrawAsync);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void DrawAsync(object state)
{
var b1 = new Button
{
Width = 50,
Height = 50,
Content = new TextBlock
{
FontSize = 16, FontFamily = new FontFamily("Arial"), FontWeight = FontWeights.Bold, Text = "Hello"
}
};
b1.Measure(new Size(50, 50));
b1.Arrange(new Rect(0, 0, 50, 50));
PixelFormat pixelFormat = PixelFormats.Default;
var elementBrush = new VisualBrush(b1);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
// preferably I'd like to draw controls too, but shapes and text would suffice too
dc.DrawRectangle(elementBrush, null, new Rect(0, 0, 50, 50));
dc.DrawEllipse(Brushes.Green, new Pen(Brushes.Black, 2), new Point(75, 25), 25, 15);
dc.Close();
}
var bitmap = new RenderTargetBitmap(100, 50, 96, 96, pixelFormat);
bitmap.Render(visual);
bitmap.Freeze();
var br = new ImageBrush(bitmap) { Stretch = Stretch.Uniform };
br.Freeze();
this.dispatcher.Invoke((ThreadStart)delegate { this.label.Background = br; });
}
You could use DrawingImage which is a type of freezeable. Load or fill it in a BackgroundWorker, freeze it and pass it to an Image in the Completed Event.

Unable to position Rectangle in Canvas in Silverlight 4

I'm new to SL. I just wrote a simple app drawing a Rectangle and Line. When I try to position the Rectangle it has no effect and always puts it in the lower-right corner:
Canvas.SetLeft(r, 100);
Canvas.SetTop(r, 100);
When I try to use SetValue, the app hangs (ie. get stuck on the loading animation in the browser):
r.SetValue(Canvas.LeftProperty, 10);
r.SetValue(Canvas.TopProperty, 10);
Has anyone experienced anything like this, and/or know how to get past it?
[EDIT] Here's the more complete source:
public MainPage()
{
InitializeComponent();
Rectangle r = new Rectangle() {
Stroke = new SolidColorBrush(Colors.Black),
Width = 100,
Height = 20,
Fill = new SolidColorBrush { Color = Color.FromArgb(80, 143, 12, 28) }
};
//r.SetValue(Canvas.LeftProperty, 10);
//r.SetValue(Canvas.TopProperty, 10);
Canvas.SetLeft(r, 100);
Canvas.SetTop(r, 100);
this.LayoutRoot.Children.Add(r);
var line = new Line() {
Stroke = new SolidColorBrush(Colors.Black),
X1 = 10, Y1 = 10, X2 = 100, Y2 = 200
};
LayoutRoot.Children.Add(line);
}
I've tried putting the LayoutRoot..Add call before the SetValue/SetLeft but it doesn't seem to make any difference.
Try this :
this.LayoutRoot.Children.Add(r);
Canvas.SetLeft(r, 100);
Canvas.SetTop(r, 100);
Rather than:
Canvas.SetLeft(r, 100);
Canvas.SetTop(r, 100);
this.LayoutRoot.Children.Add(r);
Update : It got fixed since in XAML it is by default a grid tag as LayoutRoot. After changing it to a canvas tag and it no longer gets stuck.

Resources