C# How to get pixel from stretched bitmap/picturebox - c#

Okay, i have a pictureBox with an image, with a sizeMode set to: StretchImage,
Now, i want to get the pixel that i click. (bitmap.GetPixel(x,y)).
But when the image is streched from the normal size, i get the original pixel. as in the pixel that would be there before the strech(if that makes sense?)
My Code:
Private void pictureBox1_MouseUp(object sender, MouseEventArgs e) {
Bitmap img = (Bitmap)pictureBox1.Image;
var color = img.GetPixel(e.X, e.Y)
}
Thanks In Advance

There should be a way to compensate for the stretching factor induced by the picture box. I'm thinking about taking the stretched width and height from the picture box, and the width and height from the original image, computing a stretching factor, and multiplying these with the e.X and e.Y coordinates.
Maybe something like:
Bitmap img = (Bitmap)pictureBox1.Image;
float stretch_X = img.Width / (float)pictureBox1.Width;
float stretch_Y = img.Height / (float)pictureBox1.Height;
var color = img.GetPixel((int)(e.X * stretch_X), (int)(e.Y * stretch_Y));

Divide the e.X and e.Y with stretching factor. Here is the stretched image fills the entire picture box.
Bitmap img = (Bitmap)pictureBox1.Image;
float factor_x = (float)pictureBox1.Width / img.Width;
float factor_y = (float)pictureBox1.Height / img.Height;
var color = img.GetPixel(e.X / factor_x, e.Y / factor_y)
By doing so, we make sure that e.X and e.Y will not exceed the limits of the original image.

You could store the original image and leave that untouched. It would be easier than resizing the stretched image and getting the specified pixel afterwords. Make sure that e.X and e.Y don't go outside the bounds of the original bitmap.
private Bitmap _img;
public void LoadImage(string file) {
// Get the image from the file.
pictureBox1.Image = Bitmap.FromFile(file);
// Convert it to a bitmap and store it for later use.
_img = (Bitmap)pictureBox1.Image;
// Code for stretching the picturebox here.
// ...
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e) {
var color = _img.GetPixel(e.X, e.Y);
}
EDIT: Disregard. Maximilian's answer is better.

Related

How to zoom picturebox along with graphics

I want to zoom picture box along with graphics.
this will Zoom the only image part not the graphics part.
public Image PictureBoxZoom(Image imgP, Size size)
{
Bitmap bm = new Bitmap(imgP, Convert.ToInt32(imgP.Width * size.Width), Convert.ToInt32(imgP.Height * size.Height));
Graphics grap = Graphics.FromImage(bm);
grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
return bm;
}
private void zoomSlider_Scroll(object sender, EventArgs e)
{
if (zoomSlider.Value > 0 && img != null)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox1.Image = null;
pictureBox1.Image = PictureBoxZoom(img, new Size(zoomSlider.Value, zoomSlider.Value));
}
}
the source of image is:
img = Image.FromStream(openFileDialog1.OpenFile());
Picture is zooming but when we draw the rectangle outside image then it's not zooming along with image.
See image:
You can do this (rather) easily by scaling the e.Graphics object in the Paint event.. See here for an example!
So to work with you code you probably should add this to the Paint event:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.ScaleTransform(zoom, zoom);
// now do your drawing..
// here just a demo ellipse and a line..
Rectangle rect = panel1.ClientRectangle;
g.DrawEllipse(Pens.Firebrick, rect);
using (Pen pen = new Pen(Color.DarkBlue, 4f)) g.DrawLine(pen, 22, 22, 88, 88);
}
To calculate the zoom factor you need to do a little calculation.
Usually you would not create a zoomed Image but leave that job to the PictureBox with a SizeMode=Zoom.
Then you could write:
float zoom = 1f * pictureBox1.ClientSize.Width / pictureBox1.Image.Width;
To center the image one usually moves the PictureBox inside a Panel. And to allow scrolling one sets the Panel to Autocroll=true;
But since you are creating a zoomed Image you should keep track of the current zoom by some other means.
Note:
But as you use PictureBoxSizeMode.CenterImage maybe your problem is not with the zooming after all?? If your issue really is the placement, not the size of the drawn graphics you need to do a e.Graphics.TranslateTransform to move it to the right spot..

ImageLayout.Center does not center background image

I want to center a background image. However the background image is larger than my control(which is a flat style checkbox).
A picture to make my problem clear
Usually if the background image is smaller than the control, it will be shown like the black box(which is properly centered); but in my case it will show partial image in the green box(left top corner), but the end result I want is the orange box(the center of the image), or zoomed proportionally to fill the control with extra part cut off(ImageLayout.Zoom will show whole image with blank space).
Update: Code used:
Image img = Image.FromFile("xxxx.png");
mycheckbox.BackgroundImage = img;
mycheckbox.BackgroundImageLayout = ImageLayout.Center;
Image can be used instead of BackgroundImage to get the part of the image as the orange rectangle of the example.
If the image doesn't fill the entire checkbox and if it's acceptable to alter the image being set (should work without problems, but would not be dynamic in case the checkbox size changes during runtime), the image could be resized first according to the largest ratio:
var img = Image.FromFile("xxxx.png");
float ratio = Math.Max(mycheckbox.Height / (float)img.Height,mycheckbox.Width / (float)img.Width);
if (ratio > 1)
{
Func<float, int> calc = f => (int)Math.Ceiling(f * ratio);
var bmp = new Bitmap(img, calc(img.Width ), calc(img.Height ));
img.Dispose();
img = bmp;
}
mycheckbox.ImageAlign = ContentAlignment.MiddleCenter;
mycheckbox.Image = img;
The line float ratio = Math.Max(mycheckbox.Height / (float)img.Height,mycheckbox.Width / (float)img.Width); simply calculates both the height ratio and the width ratio. If either is larger than 1, it means the checkbox height or width is larger. It doesn't matter which one, only which is larger, hence the Math.Max. The check of larger than 1 is performed on the largest ratio and if needed the image is enlarged with said ratio.
Edit A more generic approach, that scales and cuts the image so that if fills the control size and the BackGroundImage property can be used:
public static void SetImage(this Control ctrl, Image img)
{
var cs = ctrl.Size;
if (img.Size != cs)
{
float ratio = Math.Max(cs.Height / (float)img.Height, cs.Width / (float)img.Width);
if (ratio > 1)
{
Func<float, int> calc = f => (int)Math.Ceiling(f * ratio);
img = new Bitmap(img, calc(img.Width), calc(img.Height));
}
var part = new Bitmap(cs.Width, cs.Height);
using (var g = Graphics.FromImage(part))
{
g.DrawImageUnscaled(img, (cs.Width - img.Width) /2, (cs.Height - img.Height) / 2);
}
img = part;
}
ctrl.BackgroundImageLayout = ImageLayout.Center;
ctrl.BackgroundImage = img;
}

Image in PictureBox Become Blurry While Rotating

I am trying to rotate an image that is in side of a PictureBox in a C# WinForm. I rotate the image with every tick of the timer1 (Interval = 100). As I am rotating, however, the image becomes blurrier and blurrier. I am not sure if there is a way to fix this. I have enabled the Form to be double buffered.
Here is the code I am using:
public static Image RotateImage(Image img, float rotationAngle)
{
Bitmap bmp = new Bitmap(img.Width, img.Height);
bmp.SetResolution(img.HorizontalResolution, img.VerticalResolution);
Graphics gfx = Graphics.FromImage(bmp);
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
gfx.RotateTransform(-rotationAngle);
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
gfx.DrawImage(img, new Point(0, 0));
gfx.Dispose();
return bmp;
}
private void timer1_Tick(object sender, EventArgs e)
{
Image bmp = Form1.RotateImage(pictureBox1.Image, 10);
pictureBox1.Image = bmp;
}
Consider keeping your original image around, and each time you rotate, calculate the new image by applying the cumulative rotation to the original image.
What you're seeing is an unavoidable consequence of the rotation, which can only approximate the original image given the finite number of pixels it has to work with. You're seeing approximations of approximations, and they'll just get worse each time you rotate.

How do I get width and heigth of picturebox image coming from ImageLocation?

I'm trying to expand my form depending on the resolution of the selected image on the picturebox. But it seems like the picturebox size is not changing when I change the image... any help?
pictureBox1.ImageLocation = reader["imagem"].ToString();
pictureBox1.Height = pictureBox1.Image.Height;
pictureBox1.Width = pictureBox1.Image.Width;
/*mw and mh are the main width and main heigth,
i used this in case the user selects another
image, then the window returns to it's original
size before changing again.*/
this.Height = mh;
this.Width = mw;
this.Height += pictureBox1.Image.Height;
this.Width = pictureBox1.Image.Width + 16;
if (this.Width < mw)
{
this.Width = mw;
}
this.CenterToParent();
This is only the part of the code which I need a fix. The rest is all right and the picturebox is showing the image I select, but it's not changing sizes.
Oh I just figured it out guys, I changed
This part:
pictureBox1.ImageLocation = reader["imagem"].ToString();
To this:
pictureBox1.Image = Image.FromFile(reader["imagem"].ToString());

Image cropping in C#

I'am using PictureBox for displaying images. My images are direct from scanner so the resolutions are up to 4000*4000... Because my display area is a lot smaller I have to display the image with pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; to preserve aspect ratio.
After that the image is in the middle of the screen.
How can I find the distance between the left side of the image control and the REAL left side of an actual image (see image bellow).
Is there any solution?
Btw. displaying the image on the left side of the screen would do the trick too.
var imageHeight = pictureBox1.Image.Height;
var imageWidth = pictureBox1.Image.Width;
var userSelection = rect.Rect;
var display = pictureBox1.DisplayRectangle;
var xFactor = (float)userSelection.Width / display.Width;
var yFactor = (float)userSelection.Height / display.Height;
var realCropSizeWidth = xFactor * imageWidth;
var realCropSizeHight = yFactor * imageHeight;
var realCropX = imageWidth / display.Width;
realCropX *= userSelection.X;
var realCropY = imageHeight / display.Height;
realCropY *= userSelection.Y;
var realCropRectangle = new Rectangle(realCropX, realCropY, (int)realCropSizeWidth,
(int)realCropSizeHight);
var image = CropImage(pictureBox1.Image, realCropRectangle);
pictureBox1.Image = image;
public Image CropImage(Image source, Rectangle rectangle)
{
var target = new Bitmap(rectangle.Width, rectangle.Height);
using (var g = Graphics.FromImage(target))
{
g.DrawImage(source, new Rectangle(0, 0, target.Width, target.Height),
rectangle,
GraphicsUnit.Pixel);
}
return target;
}
As far as I know there is no direct way of getting what you want, but some simple maths would suffice:
You know the aspect ratio of your original image which is preserved and you know the aspect ratio of your picturebox in which you are showing it. Based on that you can figure out which dimension (height or width) the image fits exactly. Once you know that you can obtain the scaling factor of the image and therefore you can calculate the other dimension of the shown image.
As the image will be centered on the dimension that is not fitted exactly to the picturebox, its straighforward to get the distance you are looking for.

Categories