Bitmap inside a bitmap - c#

I am trying to insert an image 800x500 inside a blank bitmap of 850x610 in the center. The inner image should be in the center and It also has a title on the top. I am attaching an image to illustrate my idea:
public static Bitmap AddBorder(Bitmap srcImage)
{
Bitmap bmp = new Bitmap(srcImage.Width + 45, srcImage.Height + 100);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(srcImage, 0, 0);
g.DrawImage(srcImage, new Rectangle(bmp.Width - 1, 0, 1, bmp.Height));
g.DrawImage(srcImage, new Rectangle(0, bmp.Height - 1, bmp.Width, 1));
return bmp;
}
I have tried to draw it using drawRectangle, drawImage etc. But, I cannot pad it properly as illustrated in the above image. I also cannot add the border to inner image.
I want to get an idea about how to do that.

The below sample sets the new bitmap size, it fills it with a background (black), draws the image in the center and finally after measuring the text will align it in the center (width check only).
public static Bitmap AddBorder(Bitmap srcImage, string text)
{
Bitmap bmp = new Bitmap(850, 610);
using(Graphics g = Graphics.FromImage(bmp))
{
// Background
g.FillRectangle(Brushes.White, new Rectangle(0, 0, bmp.Width, bmp.Height));
// Source Image
Rectangle rect = new Rectangle(25, 55, 800, 500);
g.DrawImage(srcImage, rect);
// Border
int borderThickness = 2;
using(Pen pen = new System.Drawing.Pen(Brushes.Black, borderThickness))
{
pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
g.DrawRectangle(pen, new Rectangle(rect.X - borderThickness, rect.Y - borderThickness, rect.Width + borderThickness, rect.Height + borderThickness));
}
// Text String
using (Font font = new Font("Arial", 16))
{
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.Black, new PointF((bmp.Width / 2) - (size.Width / 2), rect.Top - (size.Height + borderThickness)));
}
}
return bmp;
}
Updated based on comments (Added also text above the centered image)!

Related

RenderTargetBitmap doesn't seem to render my rectangle

I have the following code:
LinearGradientBrush linGrBrush = new LinearGradientBrush();
linGrBrush.StartPoint = new Point(0,0);
linGrBrush.EndPoint = new Point(1, 0);
linGrBrush.GradientStops.Add(new GradientStop(Colors.Red, 0.0));
linGrBrush.GradientStops.Add(new GradientStop(Colors.Yellow, 0.5));
linGrBrush.GradientStops.Add(new GradientStop(Colors.White, 1.0));
Rectangle rect = new Rectangle();
rect.Width = 1000;
rect.Height = 1;
rect.Fill = linGrBrush;
rect.Arrange(new Rect(0, 0, 1, 1000));
rect.Measure(new Size(1000, 1));
If I do
myGrid.Children.Add(rect);
Then the gradient is drawn fine on the window.
I want to use this gradient for an intensity map somewhere else, so I need to get the pixels out of it. To do this, I understand I can convert it to a bitmap, using RenderTargetBitmap. Here's the next part of the code:
RenderTargetBitmap bmp = new RenderTargetBitmap(
1000,1,72,72,
PixelFormats.Pbgra32);
bmp.Render(rect);
Image myImage = new Image();
myImage.Source = bmp;
To test this, I do:
myGrid.Children.Add(myImage);
But nothing appears on the window. What am I doing wrong?
Arrange has to be called after Measure, and the Rect values should be passed correctly.
Instead of
rect.Arrange(new Rect(0, 0, 1, 1000)); // wrong width and height
rect.Measure(new Size(1000, 1));
you should do
var rect = new Rectangle { Fill = linGrBrush };
var size = new Size(1000, 1);
rect.Measure(size);
rect.Arrange(new Rect(size));
var bmp = new RenderTargetBitmap(1000, 1, 96, 96, PixelFormats.Pbgra32);
bmp.Render(rect);

How to add shape to an existent Picturebox image C#

I have created an Image and I want to add a rectangle around the image and recreate it as Image again to be drawn in a PictureBox
but I'm getting out of memory exception
How can I modify the image.
public void Draw(SizeF size)
{
int scale = 100;
Graphics refGraph = this.CreateGraphics();
IntPtr hdc = refGraph.GetHdc();
SolidBrush brush = new SolidBrush(Color.Black);
Pen pen = new Pen(Color.Black, 4);
try
{
Metafile image = new Metafile(hdc, EmfType.EmfOnly, "Shapes");
using (Graphics g = Graphics.FromImage(image))
{
PointF center = new PointF((float)base.Width / 2, base.Height / 2);
//Draw a rect
RectangleF Block = new RectangleF(new PointF(center.X - size.Width * scale / 2, center.Y - size.Height * scale / 2), new SizeF(size.Width * scale, size.Height * scale));
g.FillRectangle(brush, Block);
}
//Image = image;
ModifyImage(image);
}
finally
{
refGraph.ReleaseHdc(hdc);
refGraph.Dispose();
pen.Dispose();
brush.Dispose();
}
Invalidate();
}
public void ModifyImage(Metafile image)
{
Graphics g = Graphics.FromImage(image);
PointF center = new PointF((float)Image.Width / 2, Image.Height / 2);
int bufferAmount = 5;
g.DrawRectangle(Pens.White, center.X - (Image.Width + bufferAmount) / 2, center.Y - (Image.Height + bufferAmount) / 2, Image.Width + bufferAmount, Image.Height + bufferAmount);
pictureBox.Image = image;
}
Thanks
You can create a Graphics from the image using the FromImage method, then use Graphics drawing methods to draw whatever you like. Here is a code sample:
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(yourImage);
//you may use any pen
graphics.DrawRectangle(System.Drawing.Pens.Blue,0,0,yourImageWidth,yourImageHeight)
yourPictureBox.Image = yourImage;
Create a Graphics object from your image and draw onto it by using a Pen defining the border strength and its color:
using (var gfx = Graphics.FromImage(img))
{
using (var pen = new Pen(MYCOLOR, 3)
gfx.DrawRectangle(pen, MYRECT)
}
Note, this will manipulate your source image directly. If you want to have two images, one with and another without a border, you should clone your image before you draw over it:
var imgWithBorder = img.Clone();
// work with imgWithBorder ...

Drawline with same pen width, but the line widths are different in result

I draw lines with the same pen, but the line widths are different in result. Why?
Bitmap b = new Bitmap(400, 400);
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Point;
g.Clear(Color.White);
Pen pen = new Pen(Color.Red, 1.2f);
for (int i = 20; i < 200; i = i + 20)
{
g.DrawLine(pen, 10, i, 190, i);
}
g.Dispose();
b.Save("d:/temp/test.png", ImageFormat.Png);
b.Dispose()
Here is the result:
MSDN for GraphicsUnit
It's because you're working with Points and not Pixels and the variation in the width of the lines is the result of a rounding errors in the placement of the line and the width of the line in relation to how it gets rendered in pixels in the final product.
If you don't care about printing the image, it might be best to stick with Pixels.
Edit: If you want to continue using points, space things relative to your pen width:
Bitmap b = new Bitmap(400, 400);
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Point;
g.Clear(Color.White);
Pen pen = new Pen(Color.Red, 1.2f);
for (float i = 20f * pen.Width; i < 200f * pen.Width; i = i + 20f * pen.Width)
{
g.DrawLine(pen, 10f, i, 190f, i);
}
g.Dispose();
b.Save("c:/temp/test.png", ImageFormat.Png);
b.Dispose();

Overlaying a bitmap over a white background using a resize method

I have a method that takes in a value called sourceBMP, width, and height, and resizes the image according to those specification.
The result variable is the specified dimensions of the new BMP. What this method does is it takes the sourceBMP, renders it on the points 0, 0, and interpolates it using the NearestNeighbor (since these are pixels that are being interpolated, NearestNeighbor was the best choice) to the desired width and height.
private Bitmap ResizeBitmap(Bitmap sourceBMP, int width, int height) {
Bitmap result = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(result)) {
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.DrawImage(sourceBMP, 0, 0, width, height);
}
return result;
}
With that said - how do I change it so I overlay this graph over a white background instead (so I can add x and y axis labels onto the graph)? Trying to change the parameters myself, like specifying the starting point in a position higher than 0, 0 (like result.Width/6 )only made the image go off the screen.
EDIT: For example:
private Bitmap overlayBitmap(Bitmap sourceBMP, int width, int height) {
Bitmap result = new Bitmap(width + (width/3), height + (height/3));
using (Graphics g = Graphics.FromImage(result)) {
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.DrawImage(sourceBMP, width / 6, height / 6, width + (width / 3), height + (height / 3));
}
return result;
}
The above code pushes the graph off-screen instead of fitting inside the dimensions.
private Bitmap overlayBitmap(Bitmap sourceBMP, int width, int height) {
Bitmap result = new Bitmap(width + (width/3), height + (height/3));
using (Graphics g = Graphics.FromImage(result)) {
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.DrawImage(sourceBMP, width / 6, height / 6, width, height);
}
return result;
}

(C#) How to draw an "a" with Tahoma with height = 6

I've been trying to do this, but for some reason this is just giving me weird results:
int bpp = Screen.PrimaryScreen.BitsPerPixel;
string fontName = "Tahoma";
Font font = new Font(fontName, 10 * bpp, GraphicsUnit.Point);
Bitmap bm = new Bitmap(20 * bpp, 20 * bpp);
Graphics g = Graphics.FromImage(bm);
TextRenderer.DrawText(g, "a", font, new Rectangle(0, 0, 5 * bpp, 6 * bpp), Color.Black);
g.Flush();
pictureBox1.Image = bm;
What am I doing wrong here? I don't see anything printed on the picture. If I remove all bpp references, I can see it, but it's pretty small.
You are aware that BitsPerPixel describes the color depth (the number of memory bits that are used to describe the color of a pixel), and has nothing to do with resolution?
I assume that what you want to do is to draw the text in a size that is related to the resolution, which you can do by referring to the DpiX and DpiY properties of the Graphics object.
Update
I am not sure if yo need to bring Dpi into the calculation for this. All you need to do is to create a Rectangle that defines the desired size of your text, and then calculate the correct font size to make the text fit inside the rectangle. The following does that (but maximizes the text size both vertical and horizontal direction). It might give you some pointers to solve your problem:
Bitmap bm = new Bitmap(50, 50);
using (Font font = new Font(fontName, 10, GraphicsUnit.Point))
using (Graphics g = Graphics.FromImage(bm))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
StringFormat stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Near
};
Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
// measure how large the text is on the Graphics object with the current font size
SizeF s = g.MeasureString(text, font);
// calculate how to scale the font to make the text fit
float fontScale = Math.Max(s.Width / rect.Width, s.Height / rect.Height);
using (Font fontForDrawing = new Font(font.FontFamily, font.SizeInPoints / fontScale, GraphicsUnit.Point))
{
g.DrawString(text, fontForDrawing, Brushes.Black, rect, stringFormat);
}
}
And if you want to print the text with a given point size, you don't need to go about measuring; just set the font size:
Bitmap bm = new Bitmap(20, 20);
using (Font font = new Font(fontName, 6, GraphicsUnit.Point))
using (Graphics g = Graphics.FromImage(bm))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
StringFormat stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Near
};
Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
g.DrawString(text, font, Brushes.Black, rect, stringFormat);
}
I would try:
int ImgQual = 600;
int Width = 50;
int Height = 50;
Font TextFont = New Font("Tahoma", 14, FontStyle.Bold)
Bitmap bmp = New Bitmap(Width, Height);
bmp.SetResolution(ImgQual, ImgQual);
System.Drawing.Graphics g = Graphics.FromImage(bmp);
System.Drawing.StringFormat sf = New System.Drawing.StringFormat();
sf.Alignment = StringAlignment.Center;
g.DrawString("a", NumberTextFont, Brushes.Black, New RectangleF(0, 0, Width, Height), sf);
return bmp;
There are two primary reasons the "a" is small:
The height of a font is measured using a point size (which is 1/72nd of a inch, quite different from a number of pixels because different computer screens have different numbers of pixels per inch).
Font height is measured from the top of a line of text to the bottom. As some letters have ascenders (the tall bar in "h") and others have descenders (the dangly bit of a "g"), an "a" will occupy only about a third of the height of the font.
If you wish your "a" to fill the image, then you will need to draw it into a larger rectangle and "clip off" the empty regions above and below the "a". If you're not too worried about screen DPI on different computers, then you can just experiment until you find a font size (and position to draw at) that works.

Categories

Resources