I have put this simple code together to draw a line. Now I want to apply a ScaleTransform to it by a factor of 10; but the code below doesn't work.
var bitmap = new Bitmap(pictureBox1.Size.Width, pictureBox1.Size.Height);
var g = Graphics.FromImage(bitmap);
pictureBox1.Image = bitmap;
var pn = new Pen(Color.Wheat, -1);
g.DrawLine(pn, 0, 0, 10, 10);
pn.Dispose();
// I'm trying to scaletransform here!
g.ScaleTransform(10, 10);
Update:
What is the correct way to update the changes? I'm not getting any results from this :(
g.ScaleTransform(1, 1);
pictureBox1.Invalidate();
You must apply the transformation BEFORE drawing the line!
var g = Graphics.FromImage(bitmap);
g.ScaleTransform(10, 10);
using (pn = new Pen(Color.Wheat, -1)) {
g.DrawLine(pn, 0, 0, 10, 10);
}
Transformations are applied to the transformation matrix of the graphics object (g.Transform).
Also make use of the using statement in order to dispose the resources. It will even dispose the pen if an exception should occur or if the using statement-block should be left with a return or break statement.
Related
I am currently writing a .NET Core App to run cross-platform. Part of this is App is Drawing a Text and overlay onto a Bitmap.
So I added System.Drawing.Common and finally ended up with a working Code(On Windows) like this:
public static Bitmap WriteText(Bitmap bmp, string txt)
{
RectangleF rectf = new RectangleF(0, 0, bmp.Width, bmp.Height);
// Create graphic object that will draw onto the bitmap
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
StringFormat format = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
// dampening
using (Brush brush = new SolidBrush(Color.FromArgb(69, Color.Black)))
g.FillRectangle(brush, rectf);
var fSize = 26;
var fFam = Fonts.GetDefaultFontName();
// Draw the path
GraphicsPath p = new GraphicsPath();
p.AddString(txt, fFam, (int)FontStyle.Regular, g.DpiX * fSize / 72.2f, rectf, format);
g.DrawPath(new Pen(Color.FromArgb(180, Color.Black), 8), p);
// Draw the text
g.DrawString(txt, new Font(fFam, fSize), Brushes.White, rectf, format);
// Flush all graphics changes to the bitmap
g.Flush();
}
// Now save or use the bitmap
return bmp;
}
On Windows Outputs are generated correctly or as expected like this for Example:
But when run on my Ubuntu/linux server, the GraphicsPath/Shadow would generate like this:
My first thought was an Error in the DPI-calculation since my Server doesn't have an X-Server installed but apparently the GraphicsPath is drawn correct; just the position is wrong?
*Editnote: Also the "Formatting" apparently works on the usual DrawString... so thats extra weird
Maybe I've missed something but this looks like a platform-specific bug to me?
I'd appreciate any help & opinions at this point... Thanks
I have roughly this logic:
Bitmap bmp = ....
Pen pen = new Pen(Color.FromArgb(125, 0, 0, 255), 15);
var graphics = Graphics.FromImage(bmp);
graphics.DrawLines(pen, points1);
graphics.DrawLines(pen, points2);
The problem is, that points1 and points2 contain some line segments that are overlaping.
If I draw this lines, the overlapping part have a different color then the rest, due to the blending of the same segments (first, 1 with background and later 2 with already blended 1 with background). Is there a way, how to achieve the effect, that the overlapping parts have the same color as a single non-overlapping segmens?
DrawLines will not work in this case as it will only draw connected lines in one go.
You need to add the line sets to one GraphicsPath using StartFigure to separate the two sets.
Example, Drawline to the left, DrawPath to the right:
Here is the code for both:
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
..
Pen pen = new Pen(Color.FromArgb(125, 0, 0, 255), 15)
{ LineJoin = LineJoin.Round };
var graphics = Graphics.FromImage(bmp);
graphics.Clear(Color.White);
graphics.DrawLines(pen, points1);
graphics.DrawLines(pen, points2);
bmp.Save("D:\\__x19DL", ImageFormat.Png);
graphics.Clear(Color.White);
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddLines(points1);
gp.StartFigure();
gp.AddLines(points2);
graphics.DrawPath(pen, gp);
bmp.Save("D:\\__x19GP", ImageFormat.Png);
}
Don't forget to Dispose of the Pen and the Graphics object, or, better, put them in using clauses!
I have a large DrawingVisual that is added to a Canvas and I want to get the color value of a pixel when I click the mouse. I tried rendering the entire Visaul to a RenderTargetBitmap but got an "Out of memory" exception. then using an example I found here How to render (bitmap) only part of a Visual?
I tried rendering only part of the Visual but I dont get the correct pixel value. currently my code looks like this
private void OnMouseDown(object sender, System.Windows.Input.MouseEventArgs e)
{
// Retreive the coordinates of the mouse button event.
Point pt = e.GetPosition((UIElement)sender);
VisualBrush vb = new VisualBrush(myDrawingVisual);
vb.ViewboxUnits = BrushMappingMode.Absolute;
// create rect from the position in the canvas - starting point of the DrawingVisual
vb.Viewbox = new Rect(point.X - myDrawingVisual.ContentBounds.Left,point.Y - myDrawingVisual.ContentBounds.Top, 1, 1);
vb.ViewportUnits = BrushMappingMode.Absolute;
vb.Viewport = new Rect(point, new Size(1, 1));
System.Windows.Shapes.Rectangle r = new System.Windows.Shapes.Rectangle();
r.Width = 1;
r.Height = 1;
r.Fill = vb;
// Use RenderTargetBitmap to get the visual, in case the image has been transformed.
var renderTargetBitmap = new RenderTargetBitmap(1,
1,
96, 96, PixelFormats.Default);
renderTargetBitmap.Render(r);
var pixels = new byte[4];
renderTargetBitmap.CopyPixels(pixels, 4, 0);
}
You haven't laid out the Rectangle. For details refer to the Layout article on MSDN.
Add the following lines:
r.Measure(new Size(1, 1));
r.Arrange(new Rect(0, 0, 1, 1));
var renderTargetBitmap = ...
renderTargetBitmap.Render(r);
I have a panel on which I'm drawing lines using:
Point PreviousPoint = new Point (0,0);
Point NewPoint = new Point (10,10);
Pen MyPen = new Pen(Color.Black, 2);
Graphics MyGraphics = panel1.CreateGraphics();
MyGraphics.DrawLine(MyPen, PreviousPoint, NewPoint);
This all works fine. I obviously change the points to draw more lines, but that doesn't matter for this question. I want to export that panel as a jpg file. I'm using this code:
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, panel1.Width, panel1.Height));
bmp.Save("C:\\panel.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
This outputs a blank jpg. The background of my panel is gray, and the background of the jpg is the same gray, so I know it's actually exporting the panel. Also, I added a button into the panel just to see if it would get saved, and it did. So for some reason the jpg isn't saving the lines being drawn.
So I made a workaround that solves the core problem. I made an array of the points I plotted to draw the lines, then I did this:
// make sure you actually drew something
if (MyLines.Length > 0)
{
// instantiate the stuff you need
Image img = new Bitmap(panel1.Width, panel1.Height);
Graphics g = Graphics.FromImage(img);
Pen pen = new Pen(Color.Black, 2);
// draw every line (from every even index to the one after it)
for (int i = 0; i < MyLines.Length; i++)
{
if (i % 2 == 0)
{
g.DrawLine(pen, MyLines[i], MyLines[i + 1]);
}
}
img.Save("C:\\panel.png", System.Drawing.Imaging.ImageFormat.Png);
}
}
here is the code i'm using, i really need to make it so the text does not appear inside of a box. is that possible?
int width = (int)g.MeasureString(line, f).Width;
int height = (int)g.MeasureString(line,f).Height;
b = new Bitmap(b, new Size(width, height));
g = Graphics.FromImage(b);
g.Clear(Color.Empty);
g.DrawString(line,f, new SolidBrush(Color.Black), 0, 0);
b.Save(savepoint+line+".tif", System.Drawing.Imaging.ImageFormat.Tiff);
g.Flush();
What i mean is there can be no Rectangle around the text that is converted to image. So I need to watch it to the same color to create the illusion there is no box, or to never write out that rectangle period.
Use the color Transparent for the backgtround and a file format that supports transparency, like PNG:
var measure = g.MeasureString(line, f);
int width = (int)measure.Width;
int height = (int)measure.Height;
using (Bitmap b = new Bitmap(width, height)) {
using (Graphics bg = Graphics.FromImage(b)) {
bg.Clear(Color.Transparent);
using (Brush black = new SolidBrush(Color.Black)) {
bg.DrawString(line, f, black, 0, 0);
}
}
b.Save(savepoint+line+".png", System.Drawing.Imaging.ImageFormat.Png);
}
I notice that you did overwrite your Graphics instance, didn't dispose the objects that you create, and called Graphics.Flush for no apparent reason...