How to cut picture from pictureBox by rectangle on it - c#

I need to cut part of picture from pictureBox using rectangle which i have in this picturebox. For now i load image to picture box (and zoom it to picturebox) and draw resizable rectangle inside picturebox, but i don't know how to cut for example left down corner of picturebox by this rectangle.
EDIT
Example
I need cut wheel by this rectangle and save it to jpeg
but this rectangle is not static.

I'm not entirely sure I understand your full requirement, but you can use BitMap's Clone method to crop an image. For example, this crops an image in one pictureBox1 and loads it into pictureBox2:
using (Bitmap bmp = new Bitmap(pictureBox1.Image))
{
var newImg = bmp.Clone(
new Rectangle { X = 10, Y = 10, Width = bmp.Width / 2, Height = bmp.Height / 2 },
bmp.PixelFormat);
pictureBox2.Image = newImg;
}
It is very easy to leak Handles when manipulating images. You will need to be careful to dispose of pictureBox2.Image later, especially if you're reloading the image multiple times.

Asumming you can create your rectangle and deal with it (drawing it on your picture box, calculating its area...):
private static Image CropImage(Image img, Rectangle cropArea)
{
try {
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea /*your rectangle area*/, bmpImage.PixelFormat);
return (Image)(bmpCrop);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "CropImage()");
}
return null;
}
private void saveJpeg(string path, Bitmap img, long quality)
{
EncoderParameter qualityParam = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, (long)quality);
ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg");
if (jpegCodec == null)
{
MessageBox.Show("Can't find JPEG encoder?", "saveJpeg()");
return;
}
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
private ImageCodecInfo getEncoderInfo(string mimeType)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
private void btnPerformSaveImage_Click(object sender, EventArgs e)
{
try
{
Image img = (Bitmap)CropImage(new Bitmap(pictureBox1.Image, pictureBox1.Size), CropRect);
this.DialogResult = System.Windows.Forms.DialogResult.OK;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "btnOK_Click()");
}
}

Related

C# Bitmap Draw Image is Scaling

My setup takes .png images (with transparency) and stacks these images as layers on top of each other to form one image. The first batch I did worked perfectly. This second batch for some reason is scaling all of the images.
All of the images are 2000px x 2000px (I have individually checked each one and I can also see that Windows Explorer recognizes all of their dimensions.
All images are *.png files with transparent backgrounds.
In the Merge() function: I checked to see what the output width and height (and same of the image object) were and every single time they all came out to be 2000 (which is what it should be).
Below is a screen shot of the actual output vs what it should be. Again, I did this with different images (all 2000px x 2000px) and it worked perfectly. I'm not sure what is going on here.
public static Bitmap TestIt()
{
List<string> list = new List<string>
{
Path.Combine(dir, "body1.png"),
Path.Combine(dir, "head5.png"),
Path.Combine(dir, "legs2.png"),
Path.Combine(dir, "background2.png")
};
//Get List of Bitmaps from URLs
List<Bitmap> bitmaps = ConvertUrlsToBitmaps(list);
if (bitmaps.Any())
{
return Merge(bitmaps);
}
else
{
return null;
}
}
private static Bitmap Merge(List<Bitmap> images)
{
Bitmap bitmap = null;
var width = 0;
var height = 0;
try
{
// Get max width and height of the image
foreach (var image in images)
{
width = image.Width > width ? image.Width : width;
height = image.Height > height ? image.Height : height;
}
// merge images
bitmap = new Bitmap(width, height);
using (var g = Graphics.FromImage(bitmap))
{
foreach (var image in images)
{
g.DrawImage(image, 0, 0);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return bitmap;
}
private static List<Bitmap> ConvertUrlsToBitmaps(List<string> imageUrls)
{
List<Bitmap> bitmapList = new List<Bitmap>();
try
{
foreach (string imgUrl in imageUrls)
{
Bitmap bmp = (Bitmap)Image.FromFile(imgUrl);
bitmapList.Add(bmp);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return bitmapList;
}
Alright...I solved it.
I added a Rectangle object that will identify both position and size.
Then I forced the drawImage function to draw according to position and size
Here's the update
private static Bitmap Merge(List<Bitmap> images)
{
Bitmap bitmap = null;
var width = 0;
var height = 0;
try
{
// Get max width and height of the image
foreach (var image in images)
{
width = image.Width > width ? image.Width : width;
height = image.Height > height ? image.Height : height;
}
// merge images
bitmap = new Bitmap(width, height);
//*** Added a Rectangle object that will identify starting position and size
Rectangle rect = new Rectangle(new Point(0, 0), new Size(width, height));
using (var g = Graphics.FromImage(bitmap))
{
foreach (var image in images)
{
//*** Force the system to draw the image at location AND size
g.DrawImage(image, rect);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return bitmap;
}

Compress image from web url in asp.net using c#

I'm trying to minify image from url, my code is this
public static string GetBreaker(string fileName)
{
string cacheBreaker = null;
try
{
if (fileName.StartsWith("~"))
{
fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName.Remove(0));
}
cacheBreaker = File.GetLastWriteTime(fileName).ToFileTime().ToString();
}
catch { }
return string.IsNullOrEmpty(cacheBreaker) ? string.Empty : string.Format("?cachebreaker={0}", cacheBreaker);
}
public static void SaveJpeg(string path, System.Drawing.Image img, int quality)
{
if (quality < 0 || quality > 100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
EncoderParameter qualityParam =
new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Drawing.Image myImage = System.Drawing.Image.FromFile(ImageUrltxt.Text.ToString());
SaveJpeg(#"~/mintemp/demo.jpg", myImage, 50);
}
I'm getting error like this:
URI formats are not supported.
in
System.Drawing.Image myImage = System.Drawing.Image.FromFile(ImageUrltxt.Text.ToString());
Can anyone help me to solve out this problem. I'm very new to programming. Thanks in advance, sorry for my bad English.
1. First you have to check out your uri path is correct or not eg:
string uriPath = "file:\\C:\\Users\\john\\documents\\visual studio 2010\\Projects\\proj";
or
string localPath = new Uri(uriPath).LocalPath;
2. You have to add the uri of the image as correct Please check your uri path of image is correct.
SaveJpeg(#"~/mintemp/demo.jpg", myImage, 50);
3. This is coded in c# (for reference) resizing and compressing of image in c#
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private Boolean CheckFileType(String fileName)
{
String ext = Path.GetExtension(fileName) ;
switch (ext.ToLower())
{
case ".gif":
return true;
case ".png":
return true;
case ".jpg":
return true;
case ".jpeg":
return true;
case ".bmp":
return true;
default:
return false;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
const int bmpW = 300;// //New image target width
const int bmpH = 226;// //New Image target height
if (FileUpload1.HasFile)
{
//Clear the error label text
lblError.Text = "";
//Check to make sure the file to upload has a picture file format extention
//and set the target width and height
if (this.CheckFileType(FileUpload1.FileName))
{
Int32 newWidth = bmpW;
Int32 newHeight = bmpH;
//Use the uploaded filename for saving without the "." extension
String upName = FileUpload1.FileName.Substring(0, FileUpload1.FileName.IndexOf("."));
//Mid(FileUpload1.FileName, 1, (InStr(FileUpload1.FileName, ".") - 1)) ;
//Set the save path of the resized image, you will need this directory already created in your web site
String filePath = "~/Upload/" + upName + ".jpg";
//Create a new Bitmap using the uploaded picture as a Stream
//Set the new bitmap resolution to 72 pixels per inch
Bitmap upBmp = (Bitmap)Bitmap.FromStream(FileUpload1.PostedFile.InputStream);
Bitmap newBmp = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
newBmp.SetResolution(72, 72);
//Get the uploaded image width and height
Int32 upWidth = upBmp.Width;
Int32 upHeight = upBmp.Height;
Int32 newX = 0; //Set the new top left drawing position on the image canvas
Int32 newY = 0;
Decimal reDuce;
//Keep the aspect ratio of image the same if not 4:3 and work out the newX and newY positions
//to ensure the image is always in the centre of the canvas vertically and horizontally
if (upWidth > upHeight)
{
//Landscape picture
reDuce = newWidth / upWidth;
//calculate the width percentage reduction as decimal
newHeight = ((Int32)(upHeight * reDuce));
//reduce the uploaded image height by the reduce amount
newY = ((Int32)((bmpH - newHeight) / 2));
//Position the image centrally down the canvas
newX = 0; //Picture will be full width
}
else
{
if (upWidth < upHeight)
{
//Portrait picture
reDuce = newHeight / upHeight;
//calculate the height percentage reduction as decimal
newWidth = ((Int32)(upWidth * reDuce));
//reduce the uploaded image height by the reduce amount
newX = ((Int32)((bmpW - newWidth) / 2));
//Position the image centrally across the canvas
newY = 0; //Picture will be full hieght
}
else
{
if (upWidth == upHeight)
{
//square picture
reDuce = newHeight / upHeight;
//calculate the height percentage reduction as decimal
newWidth = ((Int32)((upWidth * reDuce)));
//reduce the uploaded image height by the reduce amount
newX = ((Int32)(((bmpW - newWidth) / 2))); //Position the image centrally across the canvas
newY = ((Int32)(((bmpH - newHeight) / 2))); //Position the image centrally down the canvas
}
}
}
//Create a new image from the uploaded picture using the Graphics class
//Clear the graphic and set the background colour to white
//Use Antialias and High Quality Bicubic to maintain a good quality picture
//Save the new bitmap image using //Png// picture format and the calculated canvas positioning
Graphics newGraphic = Graphics.FromImage(newBmp);
try
{
newGraphic.Clear(Color.White);
newGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
newGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
newGraphic.DrawImage(upBmp, newX, newY, newWidth, newHeight);
newBmp.Save(MapPath(filePath), System.Drawing.Imaging.ImageFormat.Jpeg);
//Show the uploaded resized picture in the image control
Image1.ImageUrl = filePath;
Image1.Visible = true;
}
catch (Exception ex)
{
lblError.Text = ex.ToString();
throw ex;
}
finally
{
upBmp.Dispose();
newBmp.Dispose();
newGraphic.Dispose();
}
}
else
{
lblError.Text = "Please select a picture with a file format extension of either Bmp, Jpg, Jpeg, Gif or Png.";
}
}
}
}

How to compress images before storing them in asp.net?

This is my add image code.
protected void SubmitButton_Click(object sender, EventArgs e)
{
ProductImages productImage = new ProductImages();
productImage.ProductID = Convert.ToInt32(ProductDropDownList.SelectedValue.ToString());
if (!FileUpload1.HasFile)
{
MessageLabel1.Text = "Please Select Image File"; //checking if file uploader has no file selected
}
else
{
int length = FileUpload1.PostedFile.ContentLength;
productImage.ProductImage = new byte[length];
FileUpload1.PostedFile.InputStream.Read(productImage.ProductImage, 0, length);
try
{
ProductImageBL.AddProductImages(productImage);
MessageLabel1.Text = "Product Image has been successfully added!";
}
catch (Exception ex)
{
MessageLabel1.Text = "Some error occured while processing the request. Error Description <br/>" + ex.Message;
}
}
}
Image compression depends on image type and what is on image. Photos of real life objects are typically in .jpg and you can't compress them much without noticeable quality losing.
Probably what you really want to do - is resize image to smaller size like 500*500 if you know this will be enought for all your needs. Keep in mind to save image aspect ratio during resizing.
Related SO question:
Resize an Image C#
The SO link posted by dlxeon is excellent. I use the examples there myself.
However all those examples resize the image, but you can also increase the compression in jpeg files and\or decrease the DPI.
Below a complete example of how to resize and compress a jpeg. It also checks if the image needs rotating in case the phone was held vertical for example. And you can add padding if you want to make the image square.
Note that if you use this example as is the transparency of .png and .gif files will be lost because they are converted to jpg.
protected void SubmitButton_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile == true)
{
using (Bitmap postedImage = new Bitmap(FileUpload1.PostedFile.InputStream))
{
byte [] bin = Common.scaleImage(postedImage, 400, 400, false);
Image1.ImageUrl = "data:image/jpeg;base64," + Convert.ToBase64String(bin);
}
}
}
public static byte[] scaleImage(Image image, int maxWidth, int maxHeight, bool padImage)
{
try
{
int newWidth;
int newHeight;
byte[] returnArray;
//check if the image needs rotating (eg phone held vertical when taking a picture for example)
foreach (var prop in image.PropertyItems)
{
if (prop.Id == 0x0112)
{
int rotateValue = image.GetPropertyItem(prop.Id).Value[0];
RotateFlipType flipType = getRotateFlipType(rotateValue);
image.RotateFlip(flipType);
break;
}
}
//apply padding if needed
if (padImage == true)
{
image = applyPaddingToImage(image);
}
//check if the with or height of the image exceeds the maximum specified, if so calculate the new dimensions
if (image.Width > maxWidth || image.Height > maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
newWidth = (int)(image.Width * ratio);
newHeight = (int)(image.Height * ratio);
}
else
{
newWidth = image.Width;
newHeight = image.Height;
}
//start with a new image
var newImage = new Bitmap(newWidth, newHeight);
//set the new resolution, 72 is usually good enough for displaying images on monitors
newImage.SetResolution(72, 72);
//or use the original resolution
//newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
//resize the image
using (var graphics = Graphics.FromImage(newImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
}
image = newImage;
//save the image to a memorystream to apply the compression level, higher compression = better quality = bigger images
using (MemoryStream ms = new MemoryStream())
{
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 80L);
image.Save(ms, getEncoderInfo("image/jpeg"), encoderParameters);
//save the stream as byte array
returnArray = ms.ToArray();
}
//cleanup
image.Dispose();
newImage.Dispose();
return returnArray;
}
catch (Exception ex)
{
//there was an error: ex.Message
return null;
}
}
private static ImageCodecInfo getEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType.ToLower() == mimeType.ToLower())
return encoders[j];
}
return null;
}
private static Image applyPaddingToImage(Image image)
{
//get the maximum size of the image dimensions
int maxSize = Math.Max(image.Height, image.Width);
Size squareSize = new Size(maxSize, maxSize);
//create a new square image
Bitmap squareImage = new Bitmap(squareSize.Width, squareSize.Height);
using (Graphics graphics = Graphics.FromImage(squareImage))
{
//fill the new square with a color
graphics.FillRectangle(Brushes.Red, 0, 0, squareSize.Width, squareSize.Height);
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
//put the original image on top of the new square
graphics.DrawImage(image, (squareSize.Width / 2) - (image.Width / 2), (squareSize.Height / 2) - (image.Height / 2), image.Width, image.Height);
}
return squareImage;
}
private static RotateFlipType getRotateFlipType(int rotateValue)
{
RotateFlipType flipType = RotateFlipType.RotateNoneFlipNone;
switch (rotateValue)
{
case 1:
flipType = RotateFlipType.RotateNoneFlipNone;
break;
case 2:
flipType = RotateFlipType.RotateNoneFlipX;
break;
case 3:
flipType = RotateFlipType.Rotate180FlipNone;
break;
case 4:
flipType = RotateFlipType.Rotate180FlipX;
break;
case 5:
flipType = RotateFlipType.Rotate90FlipX;
break;
case 6:
flipType = RotateFlipType.Rotate90FlipNone;
break;
case 7:
flipType = RotateFlipType.Rotate270FlipX;
break;
case 8:
flipType = RotateFlipType.Rotate270FlipNone;
break;
default:
flipType = RotateFlipType.RotateNoneFlipNone;
break;
}
return flipType;
}

'System.Runtime.InteropServices.ExternalException'

I keep getting this error of 'System.Runtime.InteropServices.ExternalException' on line 70 "img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);". Originally I had a program that stitched two photos together that worked fine, but I wanted the two images to be the same size (300 pixles by 300 pixles) so I inserted a method:
public static Image resizeImage(Image imgToResize, Size size)
{
return (Image)(new Bitmap(imgToResize, size));
}
and in my CombineImages method put:
img = resizeImage(img, new Size(300, 300));
but now I am getting an error. Here is my code:
private void cmdCombine_Click(object sender, EventArgs e)
{
//Change the path to location where your images are stored.
DirectoryInfo directory = new DirectoryInfo(#"C:\Users\Elder Zollinger\Desktop\Images");
if (directory != null)
{
FileInfo[] files = directory.GetFiles();
CombineImages(files);
}
}
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\Users\Elder Zollinger\Desktop\Images\Final.jpg";
List<int> imageHeights = new List<int>();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
img = resizeImage(img, new Size(300, 300));
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
public static Image resizeImage(Image imgToResize, Size size)
{
return (Image)(new Bitmap(imgToResize, size));
}
}
}
It is likely that the image format of the uploaded image cannot be converted directly to Jpeg. One thing we do when resizing is actually draw the image to a new Graphics instance as follows. Note that the first 2 lines attempt to get the pixel and image formats directly from the original image instance - you may have issues with CMYK and images with a transparency layer (GIF/PNG).
var pixelFormat = imgToResize.PixelFormat;
var imageFormat = imgToResize.RawFormat;
Bitmap b = new Bitmap(newWidth.Value, newHeight.Value, pixelFormat);
Graphics g = Graphics.FromImage(b);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(imgToResize, (float)-0.5, (float)-0.5, newWidth.Value + 1, newHeight.Value + 1);
g.Dispose();
b.Save(stream, imageFormat);

How do you add multiple pictureBox images to a Panel's background Image?

Hello stackoverflow community.
I do not want to draw each pictureBoxes image to Panel1 but instead I want to add each pictureBox image(pictureBox1,pictureBox2,pictureBox3) to a Bitmap, then set that Bitmap to Panel1's background Image.
Is this possible?
thanks
Here's the method I've found to combine multiple images into one bitmap
public static System.Drawing.Bitmap CombineBitmap(Image[] files)
{
//read all images into memory
List<System.Drawing.Bitmap> images = new List<System.Drawing.Bitmap>();
System.Drawing.Bitmap finalImage = null;
try
{
int width = 0;
int height = 0;
foreach (Image image in files)
{
//create a Bitmap from the file and add it to the list
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image);
//update the size of the final bitmap
width += bitmap.Width;
height = bitmap.Height > height ? bitmap.Height : height;
images.Add(bitmap);
}
//create a bitmap to hold the combined image
finalImage = new System.Drawing.Bitmap(width, height);
//get a graphics object from the image so we can draw on it
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(finalImage))
{
//set background color
g.Clear(System.Drawing.Color.Black); // Change this to whatever you want the background color to be, you may set this to Color.Transparent as well
//go through each image and draw it on the final image
int offset = 0;
foreach (System.Drawing.Bitmap image in images)
{
g.DrawImage(image,
new System.Drawing.Rectangle(offset, 0, image.Width, image.Height));
offset += image.Width;
}
}
return finalImage;
}
catch (Exception ex)
{
if (finalImage != null)
finalImage.Dispose();
throw ex;
}
finally
{
//clean up memory
foreach (System.Drawing.Bitmap image in images)
{
image.Dispose();
}
}
}
You'll need to create an array of images for this to work, then you could try this
Image[] Files = new Image[3]; // Create a new array of maximum 3 indices
Files[0] = pictureBox1.Image;
Files[1] = pictureBox2.Image;
Files[2] = pictureBox3.Image;
panel1.BackgroundImage = CombineBitmap(Files); //Add the combined bitmap to the BackgroundImage
Thanks,
Have a great day and sorry for misunderstanding :)

Categories