Problem in tiling image starting at different height using TextureBrush in C# - c#

I am trying to tile an image(16x16) over a Rectangle area of dimensions width=1000, height=16 using TextureBrush to get a strip like UI.
Rectangle myIconDrawingRectangle = new Rectangle(x, y, 1000, 16);
using (TextureBrush brush = new TextureBrush(myIcon, WrapMode.Tile))
{
e.Graphics.FillRectangle(brush, myIconDrawingRectangle );
}
When I draw with x=0, y=0 tiling happens as expected starting from (0,0).
When I draw with x=0, y=50 tiling starts at (0,50) but the the painting rectangle does not start with the start of the image. It starts with cropped portion of the image and then repeats.
How to solve this?
P.S: I do not want to tile it manually looping repeatedly over DrawImage.

To ensure that start of the rectangle starts with start of the image we have use transforms as shown in below code.
Rectangle myIconDrawingRectangle = new Rectangle(x, y, 1000, 16);
using (TextureBrush brush = new TextureBrush(myIcon, WrapMode.Tile))
{
brush.TranslateTransform(x,y);
e.Graphics.FillRectangle(brush, myIconDrawingRectangle);
}
I found this link helpful. This explains about brushes and transforms in detail.

I tried this in a Windows Forms application, and it works as expected, drawing at (0, 14) when y == 14. Is it possible y is being set to 16, 32, etc. between the time you assign it and the time the rectangle is created?
Here is the code I used to test:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Image myIcon = Image.FromFile(#"C:\Users\me\Pictures\test.jpg");
int x = 0;
int y = 14;
Rectangle myIconDrawingRectangle = new Rectangle(x, y, 1000, 16);
using (TextureBrush brush = new TextureBrush(myIcon, WrapMode.Tile))
{
e.Graphics.FillRectangle(brush, myIconDrawingRectangle);
}
e.Graphics.DrawLine(Pens.Black, 0, 16, 1000, 16);
}
and the result:

using TransalteTransform() to set up start point,if u do not do this, tiling would have some offset, to corect this, like below:
brush.TranslateTransform(0,50);

Related

Apply the opacity of a LinearGradientBrush to an image in winforms

I want to apply the opacity of a linear gradient to an image, but all I have been able to get is the gradient painted on top of the image.
Following this stackoverflow post, I created a user control that inherits from PictureBox and I overrode the OnPaint method
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
this.ClientRectangle,
Color.FromArgb(255, Color.White),
Color.FromArgb(0, Color.White),
0f);
e.Graphics.FillRectangle(linearGradientBrush, this.ClientRectangle);
}
However, that simply paints the linear gradient on top of the image.
How do I apply the opacity of the linear gradient to the image?
I find examples in XAML (), but not for winforms.
It is not necessary to use a user control and override the OnPaint event. Just create a graphics object from a blank image and do your image manipulation and assign the image to a PicturePox.
First draw the linearGradientBrush to the background and afterwards draw the image over it. Always take care about the sequence of your image operations.
FileInfo inputImageFile = new FileInfo(#"C:\Temp\TheSimpsons.png");
Bitmap inputImage = (Bitmap)Bitmap.FromFile(inputImageFile.FullName);
// create blank bitmap with same size
Bitmap combinedImage = new Bitmap(inputImage.Width, inputImage.Height);
// create graphics object on new blank bitmap
Graphics g = Graphics.FromImage(combinedImage);
// also use the same size for the gradient brush and for the FillRectangle function
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
new Rectangle(0,0,combinedImage.Width, combinedImage.Height),
Color.FromArgb(255, Color.White), //Color.White,
Color.FromArgb(0, Color.White), // Color.Transparent,
0f);
g.FillRectangle(linearGradientBrush, 0, 0, combinedImage.Width, combinedImage.Height);
g.DrawImage(inputImage, 0,0);
previewPictureBox.Image = combinedImage;
Result with black as the forms background color and the example image with transparency.
EDIT:
I may have misunderstood the intention, and either haven't found an easy way like in WPF, but it is not this much difficult.
FileInfo inputImageFile = new FileInfo(#"C:\Temp\TheSimpsons.png");
Bitmap inputImage = (Bitmap)Bitmap.FromFile(inputImageFile.FullName);
// create blank bitmap
Bitmap adjImage = new Bitmap(inputImage.Width, inputImage.Height);
// create graphics object on new blank bitmap
Graphics g = Graphics.FromImage(adjImage);
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
new Rectangle(0, 0, adjImage.Width, adjImage.Height),
Color.White,
Color.Transparent,
0f);
Rectangle rect = new Rectangle(0, 0, adjImage.Width, adjImage.Height);
g.FillRectangle(linearGradientBrush, rect);
int x;
int y;
for (x = 0; x < adjImage.Width; ++x)
{
for (y = 0; y < adjImage.Height; ++y)
{
Color inputPixelColor = inputImage.GetPixel(x, y);
Color adjPixelColor = adjImage.GetPixel(x, y);
Color newColor = Color.FromArgb(adjPixelColor.A, inputPixelColor.R, inputPixelColor.G, inputPixelColor.B);
adjImage.SetPixel(x, y, newColor);
}
}
previewPictureBox.Image = adjImage;

How to draw a string at an exact pixel position

I try to draw a string (single character) in C# into a Bitmap at an exact position with:
Bitmap bmp = new Bitmap(64, 64);
Graphics g = Graphics.FromImage(bmp);
g.DrawString("W", font1, new SolidBrush(myColor), new Point(32,32);
There is so much empty space rendered around a single letter, that I can not guess the "needed" position to draw the character to have it at the correct position at the end.
By now I have the pixel exact dimension of the character (looking at bits in a separately rendered bitmap). But this information is useless, if I cannot draw the character at an exact position (e.g. center or top right corner or ....).
Are there other methods to draw text in C# on a bitmap? Or are there any converting methods to convert the real pixel position in something DrawString needs?
No need to look at the pixels or start working with your own font..
You can use a GraphicsPath instead of DrawString or TextRenderer, as it will let you know its net bounds rectangle with GraphicsPath.GetBounds() .
When you know it, you can calculate how to move the Graphics object using TranslateTransform:
private void button1_Click(object sender, EventArgs e)
{
string text = "Y"; // whatever
Bitmap bmp = new Bitmap(64, 64); // whatever
bmp.SetResolution(96, 96); // whatever
float fontSize = 32f; // whatever
using ( Graphics g = Graphics.FromImage(bmp))
using ( GraphicsPath GP = new GraphicsPath())
using ( FontFamily fontF = new FontFamily("Arial"))
{
testPattern(g, bmp.Size); // optional
GP.AddString(text, fontF, 0, fontSize, Point.Empty,
StringFormat.GenericTypographic);
// this is the net bounds without any whitespace:
Rectangle br = Rectangle.Round(GP.GetBounds());
g.DrawRectangle(Pens.Red,br); // just for testing
// now we center:
g.TranslateTransform( (bmp.Width - br.Width ) / 2 - br.X,
(bmp.Height - br.Height )/ 2 - br.Y);
// and fill
g.FillPath(Brushes.Black, GP);
g.ResetTransform();
}
// whatever you want to do..
pictureBox1.Image = bmp;
bmp.Save("D:\\__test.png", ImageFormat.Png);
}
A small test routine to let us see the centering better:
void testPattern(Graphics g, Size sz)
{
List<Brush> brushes = new List<Brush>()
{ Brushes.SlateBlue, Brushes.Yellow,
Brushes.DarkGoldenrod, Brushes.Lavender };
int bw2 = sz.Width / 2;
int bh2 = sz.Height / 2;
for (int i = bw2; i > 0; i--)
g.FillRectangle(brushes[i%4],bw2 - i, bh2 - i, i + i, i + i );
}
The GetBounds method returns a RectangleF; in my example it is {X=0.09375, Y=6.0625, Width=21, Height=22.90625}. Do note that due to rounding things can always be off by one..
You may or may not want to change the Graphics setting to special Smoothingmodes etc..
Also it should be noted that this will do automatic ie mechanical centering by the bounds rectangle. This may be quite different from 'optical or visual centering', which is rather hard to code and to some extent a matter of personal taste. But typography is as much an art as a profession..

c# drawing text using custom pixels

I'm wondering if that's possible:
I got a c# application with something like a display consisting of about 11000 circles drawn on the Form.
What I want to achieve is to be able to draw text on that display, but not using the "real" pixels, but using the circles (rectangles) drawn on the form as pixels.
Edit 1:
When drawing text in c#, you would i.e. use something like Graphics.DrawString(...), giving the method a rectangle (so coordinates) in which the text should be drawn in. That text then is drawn in that rectangle using the screen pixels. What I want to do is draw text as well but not using the screen pixels but my custom pixels of which my display consists.
Edit 2
Method used to draw the circles on the Form; Circles is a list consisting of Circle objects, where circleRectangle returns the coordinates in which the circle should be drawn and Filled tells the method if the circle should be filled or not.
public void DrawCircles(Graphics g)
{
graphics = g;
graphics.SmoothingMode =System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Pen pen = new Pen(Color.Black, penthickness);
SolidBrush brush = new SolidBrush(Color.White);
for (int j = 0; j < Circles.Count;j++ )
{
graphics.DrawEllipse(pen, Circles[j].CircleRectangle);
if (Circles[j].Filled)
brush.Color = fillColor;
else
brush.Color = Color.White;
graphics.FillEllipse(brush, Circles[j].CircleRectangle);
}
}
Is this possible and if yes, how would I do that?
You could write on an invisible BitMap with the DrawText method and then scan the bitmap's pixels and turn the corresponding circles on.
Did that last week with the cells of DataGridView. Real easy.
Here is some code:
public void drawText(string text, Font drawFont)
{
Bitmap bmp = new Bitmap(canvasWidth, canvasHeight);
Graphics G = Graphics.FromImage(bmp);
SolidBrush brush = new SolidBrush(paintColor);
Point point = new Point( yourOriginX, yourOriginY );
G.DrawString(text, drawFont, brush, point);
for (int x = 0; x < canvasWidth; x++)
for (int y = 0; y < canvasHeight; y++)
{
Color pix = bmp.GetPixel(x, y);
setCell(x, y, pix); //< -- set your custom pixels here!
}
bmp.Dispose();
brush.Dispose();
G.Dispose();
}
Edit: You would use your dimensions and your origin for the DrawString, of course

How to repeat an image in C#

I have an image with a certain pattern. How do I repeat it in another image using GDI?
Is there any method to do it in GDI?
In C#, you can create a TextureBrush that'll tile your image wherever you use it, and then fill an area with it. Something like this (an example that fills the whole image)...
// Use `using` blocks for GDI objects you create, so they'll be released
// quickly when you're done with them.
using (TextureBrush brush = new TextureBrush(yourImage, WrapMode.Tile))
using (Graphics g = Graphics.FromImage(destImage))
{
// Do your painting in here
g.FillRectangle(brush, 0, 0, destImage.Width, destImage.Height);
}
Note, if you want some control over how the image is tiled, you're going to need to learn a bit about transforms.
I almost forgot (actually I did forget for a bit): You'll need to import System.Drawing (for Graphics and TextureBrush) and System.Drawing.Drawing2D (for WrapMode) in order for the code above to work as is.
There's no function to paint a particular image as a "pattern" (painting it repeatedly), but it should be pretty simple to do:
public static void FillPattern(Graphics g, Image image, Rectangle rect)
{
Rectangle imageRect;
Rectangle drawRect;
for (int x = rect.X; x < rect.Right; x += image.Width)
{
for (int y = rect.Y; y < rect.Bottom; y += image.Height)
{
drawRect = new Rectangle(x, y, Math.Min(image.Width, rect.Right - x),
Math.Min(image.Height, rect.Bottom - y));
imageRect = new Rectangle(0, 0, drawRect.Width, drawRect.Height);
g.DrawImage(image, drawRect, imageRect, GraphicsUnit.Pixel);
}
}
}

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