Draw overlapping lines with same transparency - c#

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!

Related

Bitmap.MeasureString not working as expected

I need to generate a single image, with a single character (letter) in it, which completely fills the image. I found a Bitmap.MeasureString option.
So what I tried to do was measure the size the string would be using this function, and then resizing the image to match, and then draw the letter.
But I am getting loads of white space all around the letter. I need the border of the image to be on the edges of the letter.
So a W would be a wide image, but an I would be a very narrow image.
I drew a line from the top left to bottom right to show what's happening.
Can you spot an issue with my code? Am I maybe misunderstanding this function? Or, it doesn't work as I'd hoped?
In the example image I posted, I want the top border of the image to be on the top border of the A. And the left border touching the bottom right hand of the A. And the bottom being right on the bottom edge of the A.
Here's what I am trying:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace SpikeFontToImage
{
class Program
{
static void Main(string[] args)
{
Bitmap source = new Bitmap(1, 1);
Bitmap destination;
Font stringFont = new Font("Tohoma", 1024);
string text = "A";
using (var measure = Graphics.FromImage(source))
{
var size = measure.MeasureString(text, stringFont);
Console.WriteLine($"{text} is {size} in size");
destination = new Bitmap( (int)size.Width, (int)size.Height);
RectangleF rectf = new RectangleF(0, 0, destination.Width, destination.Height);
StringFormat format = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
//RectangleF rectf = new RectangleF(70, 90, 90, 50);
Graphics g = Graphics.FromImage(destination);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.DrawString(text, stringFont, Brushes.Black, rectf, format);
Pen pen = new Pen(Color.GreenYellow, 3);
g.DrawLine(pen, new Point(0, 0), new Point((int)size.Width, (int)size.Height));
g.Flush();
destination.Save(#"c:\temp\ccl.jpg");
}
}
}
}

GraphicsPath.addString is wrongly positioned on linux?

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

Generated Bitmap Displays Weirdly in PictureBox

I cannot seem to programmatically create a colored bitmap to display in a PictureBox. The bitmap saves normally as a file, but is faded at the edges when displayed in a PictureBox. Here is simplified code used to create and display the Bitmap (in actual code, the bitmap generation is completely separate from the form, so forcing the bitmap size to match the picturebox size isn't possible):
Bitmap Bmp = new Bitmap(4, 4, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, 4, 4);
}
Then set the Image value on a PictureBox to the generated Bitmap:
pictureBox1.Image = Bmp;
Here is the resulting bitmap displayed in a 300x300 picturebox:
How do I set the Image on the PictureBox so that it displays the colored bitmap properly (full solid)?
EDIT: I am restricted to generating smaller source bitmaps, so upscaling into a PictureBox is unavoidable. The problem appears when the generated source bitmap is 4px or 100px square, so I believe these are relevant cases.
EDIT: The PictureBox scaling should be set to stretch or zoom for the issue to manifest. In this example case the 4x4 source bitmap is stretched to 300x300.
EDIT: The basic problem is PictureBox's inability to upscale small bitmaps into large controls. This is confusing because the Bitmap upscales nicely into a PictureBox.Background image. Unless you have a magic bullet that will fix the image upscaling problem, I think it might be best to go for clear and simple workarounds in your answer.
You are generating a 4x4 bitmap and it's being stretched. Specify the size to match the picture box instead:
int width = pictureBox1.Width;
int height = pictureBox1.Height;
var Bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (var brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, width, height);
}
pictureBox1.Image = Bmp;
You will need to turn anti-aliasing off. Also, since you are using one color for the whole picturebox, why not make the bitmap 1x1? If you need it 4x4, change the int the top of the example from 1 to 4.
int hw = 1;
Bitmap Bmp = new Bitmap(hw, hw,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, hw, hw);
}
}
pictureBox1.Image = Bmp;
UPDATE
Since you are still having the same issue by setting the picturebox to the image, you will have to get the graphics object from the picturebox and draw directly on it.
The code is very similar.
using (Graphics gfx = Graphics.FromImage(pictureBox1.Image))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0,
pictureBox11.Width - 1,
pictureBox11.Height - 1);
}
}
// Force the picturebox to redraw with the new image.
// You could also use pictureBox11.Refresh() to do the redraw.
pictureBox11.Invalidate();
I tried to test your code and the image were properly displayed.
But when i used this code:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width, Bmp.Height);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
I did get exactly your result. In order to fix it:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width - 1, Bmp.Height - 1);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
Edit:
So you have the bitmap and you want to stretch it. And the bitmap has ane solid color. Do this insted:
Color pixelColor = Bmp.GetPixel(0, 0);
PictureBox1.BackColor = pixelColor;
valter

Graphics object making blank images

I'm trying to draw images to return as base 64 strings over a web service in .net 4.5. I can get as far as loading a custom background, but then I need to draw text onto that background. The problem is, once I go from Image->Graphics object->Image, I end up with a blank png. If I return the original srcImage (the blank template) over the service, everything works, but my label is blank so I know it must be a problem with my graphics object somewhere.
My code is:
var labelSize = new Size(400, 459);
using (var srcImage = Image.FromFile(HostingEnvironment.MapPath("~/images/labels/" + labelImageFilename))) {
PixelFormat format = srcImage.PixelFormat;
using (Bitmap newImage = new Bitmap(labelSize.Width, labelSize.Height, format))
using (Graphics g = Graphics.FromImage(newImage)) {
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
Rectangle srcRect = new Rectangle(0, 0, srcImage.Width, srcImage.Height);
Rectangle destRect = new Rectangle(0,0, labelSize.Width, labelSize.Height);
g.DrawImage(srcImage, destRect, srcRect, GraphicsUnit.Pixel);
// draw other shapes etc
g.FillRegion(Brushes.Blue,new Region(new Rectangle(0,0,200,200)));
g.Clear(Color.Red);
g.Flush();
return new Bitmap(srcImage, labelSize.Width, labelSize.Height); // this works fine, but my image is just the standard background I'm using
return new Bitmap(labelSize.Width, labelSize.Height, g); // returns a blank image
}
}
Nothing is drawn, neither the template background (srcImage), not the red or blue rectangles.
I think it looks like your graphics object is drawing on newImage, but you are returning srcImage. If you want to return the result of your drawing, I think you need to return newImage.
Try something like:
return new Bitmap(newImage, labelSize.Width, labelSize.Height);

C# Drawstring clear rectangle Or no rectangle? possible

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...

Categories

Resources