So I have this code to crop images
private static Image Crop(Image img, Rectangle cropArea)
{
Bitmap bmpImage = (Bitmap)img.Clone();
var part = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
return part;
}
However, cropArea is occasionally out of bounds in the image, sometimes the crop extends outside the image and I want to fill these with transparent color, how do I achieve this?
Use Graphics object against the destination image and draw the original image at translated point.
private static Image Crop(Image img, Rectangle cropArea)
{
//Bitmap bmpImage = (Bitmap)img.Clone();
//var part = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
//return part;
Bitmap part = new Bitmap(cropArea.Width, cropArea.Height, img.PixelFormat);
using (var graphics = Graphics.FromImage(part))
{
graphics.DrawImage(img, -cropArea.X, -cropArea.Y);
}
return part;
}
Related
I have a picture I want to print, but it's too big for one page
so i have decided to split it into multiple images
i have tried a method, but now im using this (Talha Irfan answer)
i also tried the other solutions there but those didnt worked as well
(ex. bm.Clone(rec, bm.PixelFormat);)
and here's my code(this is on non-form class)
Bitmap bm = new Bitmap(frmPrint.Width, frmPrint.Height);
Rectangle rec = new Rectangle(0, 200, 576, 300);
Bitmap bitmap = cropImg(bm, rec);
frmPrint.DrawToBitmap(bitmap, rec);
frmPrint._img = bitmap;
frmPrint.setImage();
and setImage function(on some form)
public void setImage()
{
pictureBox3.BackgroundImage = _img;
this.ShowDialog();
}
and cropImg is the same as cropAtRect
the below shows the original image (on the left)
the wanted result in the blue rectangle
and the actual result on the right
PS
my actual image size is (height = 698, wifht = 576)
Edit - as suggested below
on non-form class
Rectangle cropRect = new Rectangle(0, 0, 576, 698);
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height, bm.PixelFormat);
frmPrint.setImage(bm, target, cropRect);
target.Dispose();
at form class
public void setImage(Bitmap src, Bitmap target, Rectangle cropRect)
{
pictureBox3.Visible = false;
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, new Rectangle(pictureBox3.Location.X, pictureBox3.Location.Y, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
}
this.ShowDialog();
}
Control.DrawToBitmap will always try to draw the whole control or form and will always start at the top. The parameter:
targetBounds
Type: System.Drawing.Rectangle
The bounds within which the control is rendered.
as the name implies, sets the target, not the source rectangle. Hence the white space above your result.
Move the line before cropping with a rectangle that holds the full area, maybe like this:
DrawToBitmap(bm, ClientRectangle);
and then crop the lower part as before..
Note that the cropping trick from your link will not work for DrawToBitmap; using a rectangle with a negative offset will cause a parameter exception.
Btw: to safely dispose of a Bitmap in a PictureBox use this:
Bitmap dummy = (Bitmap )somePictureBox.Image;
somePictureBox.Image = null;
if (dummy != null) dummy.Dispose;
And, indeed, the answer by ChrisJJ in the link leaks the Graphics object.
Update:
Since you seem to have lost control over the various changes and suggestions, here is the minimal code change from the original post:
Bitmap bm = new Bitmap(frmPrint.ClientWidth, frmPrint.ClientHeight);
DrawToBitmap(bm, frmPrint.ClientRectangle);
Rectangle rec = new Rectangle(0, 200, 576, 300);
Bitmap bitmap = cropImg(bm, rec);
frmPrint._img = bitmap;
frmPrint.setImage();
With:
public void setImage()
{
Bitmap dummy = pictureBox3.BackgroundImage;
pictureBox3.BackgroundImage = null;
if (dummy != bnull) dummy.Dispose();
pictureBox3.BackgroundImage = _img;
this.ShowDialog();
}
In the cropImg function add a g.Dispose before returning.
I need to fill an rectangle on bottom of my image, but not over the image, so it should be a kind of append a rectangle to bottom of image.
What I have for now:
private void DrawRectangle()
{
string imageFilePath = #"c:\Test.jpg";
Bitmap bitmap = (Bitmap)Image.FromFile(imageFilePath);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
using (Image img = Image.FromFile(imageFilePath))
{
SolidBrush brush = new SolidBrush(Color.Black);
int width = img.Width;
int height = img.Height - 350;
graphics.FillRectangle(brush, 0, height, width, 350);
}
}
bitmap.Save(#"c:\Test1.jpg");
}
But this is over the image.
Any idea's?
Thank you.
You need to know the dimensions of your original image in order to set the size of the new bitmap, which must be larger to accommodate the rectangle.
private void DrawRectangle()
{
string imageFilePath = #"c:\Test.jpg";
int rectHeight = 100;
using (Image img = Image.FromFile(imageFilePath)) // load original image
using (Bitmap bitmap = new Bitmap(img.Width, img.Height + rectHeight)) // create blank bitmap of desired size
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// draw existing image onto new blank bitmap
graphics.DrawImage(img, 0, 0, img.Width, img.Height);
SolidBrush brush = new SolidBrush(Color.Black);
// draw your rectangle below the original image
graphics.FillRectangle(brush, 0, img.Height, img.Width, rectHeight);
bitmap.Save(#"c:\Test1.bmp");
}
}
take a look at the FillRectangle() method overloads.. it has one with the following definition: FillRectangle(Brush brush, int PositionX, int PositionY, int Width, int Height)
your problem most likely stems on using an improper overload for what you're doing.
Anyone ever wrote a C# GDI+ function to curl the corner of a BITMAP. I need to be able to take a static image and apply the peel effect to it on the bottom right corner. And I need to do it with C# all my searching leads to CSS3/FLASH/SilverLight virtual book type examples. I just want to create a static image that has a curled up corner and save the file.
Any Ideas?
Ok so I made the image with photo shop so that I can show you what I am trying to achieve
I start this image
and I want to write some C# code that would yield this image
The end result is just an image that is not animated, and does nothing. Any thoughts.
There are some good tools to do this, such as Fred's ImageMagick plugin script, but here is a C# version as requested.
using System.Drawing.Imaging;
public partial class ImagePeelEffect : Form
{
string WorkingDirectory = #"C:\temp\";
public ImagePeelEffect()
{
InitializeComponent();
}
private void ImagePeelEffect_Load(object sender, EventArgs e)
{
picBefore.Image = Image.FromFile(WorkingDirectory + "\\before.jpg");
}
private void button1_Click(object sender, EventArgs e)
{
//create a image object containing the photograph to add page peel effect
Image imgPhoto = Image.FromFile(WorkingDirectory + "\\before.jpg");
int phWidth = imgPhoto.Width;
int phHeight = imgPhoto.Height;
//create a Bitmap the Size of the original photograph
Bitmap bmPhoto = new Bitmap(phWidth, phHeight, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
//load the Bitmap into a Graphics object
Graphics grPhoto = Graphics.FromImage(bmPhoto);
//create a image object containing the PagePeel
Image imgPagePeel = new Bitmap(WorkingDirectory + "\\PagePeel.bmp");
int ppWidth = imgPagePeel.Width;
int ppHeight = imgPagePeel.Height;
//Set the rendering quality for this Graphics object
grPhoto.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//Draws the photo Image object at original size to the graphics object.
grPhoto.DrawImage(
imgPhoto, // Photo Image object
new Rectangle(0, 0, phWidth, phHeight), // Rectangle structure
0, // x-coordinate of the portion of the source image to draw.
0, // y-coordinate of the portion of the source image to draw.
phWidth, // Width of the portion of the source image to draw.
phHeight, // Height of the portion of the source image to draw.
GraphicsUnit.Pixel); // Units of measure
//The first step in manipulating the PagePeel image is to replace
//the background color with one that is transparent (Alpha=0, R=0, G=0, B=0)
//to do this we will use a Colormap and define ImageAttributes with a RemapTable
ImageAttributes imageAttributes = new ImageAttributes();
ColorMap colorMap = new ColorMap();
//My PagePeel was defined with a background of 100% Green this will
//be the color we search for and replace with transparency
colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
//Set the Remap Table with the old and new color map
ColorMap[] remapTable = { colorMap };
imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
//For this example we will place the PagePeel in the bottom right
//hand corner of the photograph
int xPosOfPp = phWidth - ppWidth;
int yPosOfPp = phHeight - ppHeight + 1;
grPhoto.DrawImage(imgPagePeel,
new Rectangle(xPosOfPp, yPosOfPp, ppWidth, ppHeight), //Set the detination Position
0, // x-coordinate of the portion of the source image to draw.
0, // y-coordinate of the portion of the source image to draw.
ppWidth, // PagePeel Width
ppHeight, // PagePeel Height
GraphicsUnit.Pixel, // Unit of measurment
imageAttributes); //ImageAttributes Object
//Replace the original photgraphs bitmap with the new Bitmap
imgPhoto = bmPhoto;
grPhoto.Dispose();
//save new image to file system.
imgPhoto.Save(WorkingDirectory + "\\after.jpg", ImageFormat.Jpeg);
imgPhoto.Dispose();
imgPagePeel.Dispose();
//Show the After image
picAfter.Image = Image.FromFile(WorkingDirectory + "\\after.jpg");
}
The PagePeel.bmp:
The Before and After result:
Update
Here's a version that uses a Transparent Page Peel overlay so you dont neet to convert the "green screen" to invisible. The advantage of this method is when the original photograph contains the colour green RGB(0,255,0) it wont be turned into transparent:
TransparentPagePeel.png:
private void button2_Click(object sender, EventArgs e)
{
//create a image object containing the photograph to add page peel effect
Image imgPhoto = Image.FromFile(WorkingDirectory + "\\before.jpg");
int phWidth = imgPhoto.Width;
int phHeight = imgPhoto.Height;
//create a Bitmap the Size of the original photograph
Bitmap bmPhoto = new Bitmap(phWidth, phHeight, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
//load the Bitmap into a Graphics object
Graphics grPhoto = Graphics.FromImage(bmPhoto);
//create a image object containing the PagePeel
Image imgPagePeel = new Bitmap(WorkingDirectory + "\\transparentPagePeel.png");
int ppWidth = imgPagePeel.Width;
int ppHeight = imgPagePeel.Height;
//Set the rendering quality for this Graphics object
grPhoto.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//Draws the photo Image object at original size to the graphics object.
grPhoto.DrawImage(
imgPhoto, // Photo Image object
new Rectangle(0, 0, phWidth, phHeight), // Rectangle structure
0, // x-coordinate of the portion of the source image to draw.
0, // y-coordinate of the portion of the source image to draw.
phWidth, // Width of the portion of the source image to draw.
phHeight, // Height of the portion of the source image to draw.
GraphicsUnit.Pixel); // Units of measure
//For this example we will place the PagePeel in the bottom right
//hand corner of the photograph
int xPosOfPp = phWidth - ppWidth;
int yPosOfPp = phHeight - ppHeight + 1;
grPhoto.DrawImage(imgPagePeel,
new Rectangle(xPosOfPp, yPosOfPp, ppWidth, ppHeight), //Set the detination Position
0, // x-coordinate of the portion of the source image to draw.
0, // y-coordinate of the portion of the source image to draw.
ppWidth, // PagePeel Width
ppHeight, // PagePeel Height
GraphicsUnit.Pixel, // Unit of measurment
null); //ImageAttributes Object
//Replace the original photgraphs bitmap with the new Bitmap
imgPhoto = bmPhoto;
grPhoto.Dispose();
//save new image to file system.
imgPhoto.Save(WorkingDirectory + "\\after1.jpg", ImageFormat.Jpeg);
imgPhoto.Dispose();
imgPagePeel.Dispose();
picAfter.Image = Image.FromFile(WorkingDirectory + "\\after1.jpg");
}
I have a PictureBox with lots of transparent png's drawn into...
Now I'd like to save the content of this PictureBox to a file, but without the transparency.
How can I do this?
I have already tried to remove transparency from the Image like this, but it didn't work, I still got a transparent image after the save.
...
removeTransparency(pictureBox.Image).Save(saveFileDialog.FileName);
private Bitmap removeTransparency(Image transparentImage)
{
Bitmap src = new Bitmap(transparentImage);
Bitmap newImage = new Bitmap(src.Size.Width, src.Size.Height);
Graphics g = Graphics.FromImage(newImage);
g.DrawRectangle(new Pen(new SolidBrush(Color.White)), 0, 0, newImage.Width, newImage.Height);
g.DrawImage(src, 0, 0);
return newImage;
}
You may cycle through all pixel (please not using GetPixel/SetPixel) to change the color or you may create another bitmap with the same size, create a graphics context from the image, clear the image with your favorite background color and then draw your image on it (so transparent pixels simply will be replaced by the background color).
Example
Did you do something like this?
public static Bitmap Repaint(Bitmap source, Color backgroundColor)
{
Bitmap result = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(result))
{
g.Clear(backgroundColor);
g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height));
}
return result;
}
I want to crop a bitmap with this function but the bitmap could be smaller then the crop area so I want to get the bitmap bigger in that case.
As example I have a bitmap which is 200x250 and if I use the CropBitmap method with 250x250 I get an out of memory error. It should return a bitmap with 250x250 where the missing left 50px are filled with white.
How can I achieve that?
public Bitmap CropBitmap(Bitmap bitmap, int cropX, int cropY, int cropWidth, int cropHeight)
{
var rect = new Rectangle(cropX, cropY, cropWidth, cropHeight);
if(bitmap.Width < cropWidth || bitmap.Height < cropHeight)
{
// what now?
}
return bitmap.Clone(rect, bitmap.PixelFormat);
}
Create a new Bitmap with the appropriate size. Then get a System.Drawing.Graphics and use it to create the white area and to insert the source image. Something like this:
if (bitmap.Width < cropWidth && bitmap.Height < cropHeight)
{
Bitmap newImage = new Bitmap(cropWidth, cropHeight, bitmap.PixelFormat);
using (Graphics g = Graphics.FromImage(newImage))
{
// fill target image with white color
g.FillRectangle(Brushes.White, 0, 0, cropWidth, cropHeight);
// place source image inside the target image
var dstX = cropWidth - bitmap.Width;
var dstY = cropHeight - bitmap.Height;
g.DrawImage(bitmap, dstX, dstY);
}
return newImage;
}
Note, that I replaced the || in the outer if expression with &&. To make it work with ||, you have to calculate the source region and use another overload of Graphics.DrawImage