The image has 200px width and the pictureBox has 400px.
Which property of pictureBox should I set to display the image repeat-x?
I don't think there is any property which makes the image display x times repeatedly horizontally. But a little custom code can help, here is my code:
public static class PictureBoxExtension
{
public static void SetImage(this PictureBox pic, Image image, int repeatX)
{
Bitmap bm = new Bitmap(image.Width * repeatX, image.Height);
Graphics gp = Graphics.FromImage(bm);
for (int x = 0; x <= bm.Width - image.Width; x += image.Width)
{
gp.DrawImage(image, new Point(x, 0));
}
pic.Image = bm;
}
}
//Now you can use the extension method SetImage to make the PictureBox display the image x-repeatedly
myPictureBox.SetImage(myImage, 3);//repeat 3 images horizontally.
You can customize the code to make it repeat vertically or look like a check board.
Hope it helps!
Related
I'm trying to generate a custom Bitmap through code at a very small size and display it to a PictureBox, upscaled to fit said PictureBox. I am using the graphics object to do this in order to use NearestNeighbor interpolation to upscale single pixels perfectly.
I'm using the graphics object of a temporary default image that is in the PictureBoxs "Image" component on Form.Load, which is sized to be the perfect width and height to maintain the correct aspect ratio from the original Bitmap.
Here is the relevant code:
private void Form1_Load(object sender, EventArgs e)
{
bmp = new Bitmap(16, 9, PixelFormat.Format24bppRgb);
rnd = new Random();
GenerateImage();
}
private void GenerateImage()
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
int num = rnd.Next(2);
if (num == 0)
{
bmp.SetPixel(x, y, Color.White);
}
else
{
bmp.SetPixel(x, y, Color.Gold);
}
}
}
Bitmap image = new Bitmap(picOutput.Image);
grp = Graphics.FromImage(image);
grp.InterpolationMode = InterpolationMode.NearestNeighbor;
grp.DrawImage(
bmp,
new Rectangle(0, 0, image.Width, image.Height),
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel
);
grp.Dispose();
picOutput.Image = image;
}
The problem is that the Bitmap seems to be drawn incorrectly. About half a pixel from the original Bitmap is cut off on the left and top edges of the Bitmap when displayed through the PictureBox, and that roughly half a pixel shows up as the original default image on the right and bottom edges. It's almost like the Bitmap was offset up and to the left while being drawn by the graphics object, it doesn't perfectly cover up the original default image like it was supposed to.
My first thought was the PictureBoxs SizeMode, which is still set to "Normal," but none of them change the problem at all. Here is a picture of the problem. The black edges on the right and bottom are part of the temporary default image (the image I used graphics from), which is completely black and covers the entire PictureBox area.
Can anyone offer some insight?
As user Jimi pointed out in a comment, grp.PixelOffsetMode = PixelOffsetMode.Half from this post solved the issue.
Imagine you are drawing a 10x10 .png picture on 700x700 PictureBox in WinForms app. The problem is the shifting picture on 0.5 pixel up and left on PictureBox.
The test picture you can watch here:
It is square with 1px width border.
And the resulting PictureBox looks like:
You can see, that border has not the same width everywhere and is shifted on 0.5 px left and up (I called px an px equivalent on PictureBox, because this px from 10x10 picture is like 100x100 real pixels).
In code I use InterpolationMode.NearestNeighbor for correct displaying small picture on big canvas. But it does not change the result.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
testBmp = new Bitmap("some_path_here\\test.png");
drawBitmapOnPictureBox(pictureBox1, testBmp);
}
private void drawBitmapOnPictureBox(PictureBox pictureBox, Bitmap bmp)
{
if (pictureBox.Size != bmp.Size)
{
float zoom = 60.0f;
Bitmap zoomed = new Bitmap((int)(bmp.Width * zoom), (int)(bmp.Height * zoom));
using (Graphics g = Graphics.FromImage(zoomed))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, zoomed.Size));
}
pictureBox.Image = zoomed;
}
else
pictureBox.Image = bmp;
}
Bitmap testBmp;
}
Good day
i don't know if my title is correct. sorry for my bad english
How to overlay two picturebox using c# inoder to achieve the image below, and change the opacity of upper picture box on runtime.
what i need to achieve is something like this. i have two images and i need to overlay them
first image:
enter image description here
and i have second image with a text of: Another Text on image.
and the location of the text is lower than the text location of the first image
(i can't upload more than two image because i don't have 10 reputation yet.)
i need to do like on the image below, but using two picturebox and can change the opacity in order for the second picturebox below the first one to be seen
and the output of the two image:
enter image description here
i created the output image using java. i know that i can run the jar file using c#. but the user required to changed the opacity on run time. so how can i do this?
this is the java code i used
BufferedImage biInner = ImageIO.read(inner);
BufferedImage biOutter = ImageIO.read(outter);
System.out.println(biInner);
System.out.println(biOutter);
Graphics2D g = biOutter.createGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
int x = (biOutter.getWidth() - biInner.getWidth()) / 2;
int y = (biOutter.getHeight() - biInner.getHeight()) / 2;
System.out.println(x + "x" + y);
g.drawImage(biInner, x, y, null);
g.dispose();
ImageIO.write(biOutter, "PNG", new File(output));
i hope my question is understandable. thank you
Here you go, just a sample, but blueBox is transparent (0.5):
public sealed partial class Form1 : Form
{
private readonly Bitmap m_BlueBox;
private readonly Bitmap m_YellowBox;
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
m_YellowBox = CreateBox(Color.Yellow);
m_BlueBox = CreateBox(Color.Blue);
m_BlueBox = ChangeOpacity(m_BlueBox, 0.5f);
}
public static Bitmap ChangeOpacity(Image img, float opacityvalue)
{
var bmp = new Bitmap(img.Width, img.Height);
using (var graphics = Graphics.FromImage(bmp))
{
var colormatrix = new ColorMatrix();
colormatrix.Matrix33 = opacityvalue;
var imgAttribute = new ImageAttributes();
imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
graphics.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height,
GraphicsUnit.Pixel, imgAttribute);
}
return bmp;
}
private static Bitmap CreateBox(Color color)
{
var bmp = new Bitmap(200, 200);
for (var x = 0; x < bmp.Width; x++)
{
for (var y = 0; y < bmp.Height; y++)
{
bmp.SetPixel(x, y, color);
}
}
return bmp;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(m_YellowBox, new Point(10, 10));
e.Graphics.DrawImage(m_BlueBox, new Point(70, 70));
}
}
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
I have a WinForm C# app. It displays an image 720x360 pixels size on my UserControl in the onpaint event.
I am comparing constantly the current image with the new image that comes every 1/10 second.
I had been using Validate() to force the onpaint event to redraw the new image.
What I decided to do instead was Invalidate and pass regions in.
So, I compare the current image with the new image. Look for differences. Create a new rectangle object and then use the Union method to add the new image.
This is my code:
//I use EMGU to compare 2 images.
Image<Bgr, byte> _diffBetweenCurrentAndPrevious = newImage.AbsDiff(currentFrame);
//I enumerate through the resultant image to list the differences beyond a threshold.
for (int y = 0; y < 576; y++)
{
for (int x = 0; x < 720; x++)
{
//if beyond a threshold then note it
motionRegions.Union(new Rectangle(x, y, 1, 1));
}
}
I assign the new image:
newImage =(Bitmap) currentFrame.Clone();
I then call:
Invalidate(motionRegions);
Which will call this:
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
if (newImage != null)
{
pe.Graphics.DrawImageUnscaled(newImage, 0, 0);
}
}
The problem is I do not seem to be improving on response time / RAM when just re-drawing what I need to redraw.
Am I doing something wrong?
Thanks