I call the method UpdateRichTextBox inside a pictureBox mouse move event.
private void pbImage_MouseMove(object sender, MouseEventArgs e)
{
if (pbImage.Image == null) return;
Bitmap img = new Bitmap(pbImage.Image);
int imgWidth = img.Width;
int imgHeight = img.Height;
int pbWidth = pbImage.Width;
int pbHeight = pbImage.Height;
// Compute scale to fit in PictureBox while maintaining aspect ratio
float scaleX = (float)pbWidth / imgWidth;
float scaleY = (float)pbHeight / imgHeight;
float scale = Math.Min(scaleX, scaleY); // Maintain aspect ratio
// Calculate the actual displayed image size in PictureBox
int displayWidth = (int)(imgWidth * scale);
int displayHeight = (int)(imgHeight * scale);
// Compute offsets (padding) due to aspect ratio
int offsetX = (pbWidth - displayWidth) / 2;
int offsetY = (pbHeight - displayHeight) / 2;
// Adjust mouse coordinates relative to image
int imgX = (int)((e.X - offsetX) / scale);
int imgY = (int)((e.Y - offsetY) / scale);
// Ensure coordinates are within the image bounds
if (imgX >= 0 && imgX < imgWidth && imgY >= 0 && imgY < imgHeight)
{
// LockBits for fast pixel reading
BitmapData bmpData = img.LockBits(new Rectangle(0, 0, imgWidth, imgHeight),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
IntPtr ptr = bmpData.Scan0;
int stride = bmpData.Stride;
int bytesPerPixel = 3;
int index = (imgY * stride) + (imgX * bytesPerPixel);
byte[] pixelData = new byte[3];
Marshal.Copy(ptr + index, pixelData, 0, 3);
img.UnlockBits(bmpData);
Color pixelColor = Color.FromArgb(pixelData[2], pixelData[1], pixelData[0]);
string hexColor = $"#{pixelColor.R:X2}{pixelColor.G:X2}{pixelColor.B:X2}";
string colorName = GetClosestColorName(pixelColor);
string mouseInfoText =
$"