split image to multiple image from the bottom up - c#

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.

Related

How to save graphics created on a PictureBox?

In c# and Visual Studio Windows forms I have loaded an image into a picture box (pictureBox2) and then cropped it and show in another picture box (pictureBox3).
Now I want to save what is inside pictureBox3 as an image file.
How can I do this?
private void crop_bttn_Click(object sender, EventArgs e)
{
Image crop = GetCopyImage("grayScale.jpg");
pictureBox2.Image = crop;
Bitmap sourceBitmap = new Bitmap(pictureBox2.Image,
pictureBox2.Width, pictureBox2.Height);
Graphics g = pictureBox3.CreateGraphics();
g.DrawImage(sourceBitmap, new Rectangle(0, 0,
pictureBox3.Width, pictureBox3.Height), rectCropArea, GraphicsUnit.Pixel);
sourceBitmap.Dispose();
}
Never use control.CreateGraphics! Either draw into a Bitmap bmp using a Graphics g = Graphics.FromImage(bmp) or in the Paint event of a control, using the e.Graphics parameter..
Here is a cropping code that draws into a new Bitmap and that makes use of your controls etc but changes a few things:
It uses a Graphics object that is created from a new Bitmap
It make use of using clauses to make sure it won't leak
It takes the size of the pictureBox3.ClientSize so it won't include any borders..
private void crop_bttn_Click(object sender, EventArgs e)
{
Image crop = GetCopyImage("grayScale.jpg");
pictureBox2.Image = crop;
Bitmap targetBitmap = new Bitmap(pictureBox3.ClientSize.Width,
pictureBox3.ClientSize.Height);
using (Bitmap sourceBitmap = new Bitmap(pictureBox2.Image,
pictureBox2.ClientSize.Width, pictureBox2.ClientSize.Height))
{
using (Graphics g = Graphics.FromImage(targetBitmap))
{
g.DrawImage(sourceBitmap, new Rectangle(0, 0,
pictureBox3.ClientSize.Width, pictureBox3.ClientSize.Height),
rectCropArea, GraphicsUnit.Pixel);
}
}
if (pictureBox3.Image != null) pictureBox3.Image.Dispose();
pictureBox3.Image = targetBitmap;
targetBitmap.Save(somename, someFormat);
}
The alternative would be to..:
move all your code to the Paint event
replace the Graphics g = pictureBox3.CreateGraphics(); be Graphics g = e.Graphics;
insert these two lines to the click event:
Bitmap targetBitmap = new Bitmap(pictureBox3.ClientSize.Width,
pictureBox3.ClientSize.Height);
pictureBox3.DrawToBitmap(targetBitmap, pictureBox3.ClientRectangle);
The method PictureBox.CreateGraphics() should not be used unless you know what you are doing because it can cause some not-so-obvious problems. For example, in you scenario, the image in pictureBox3 will disappear when you minimize or resize the window.
A better way is to draw to a bitmap, which you also can save:
var croppedImage = new Bitmap(pictureBox3.Width, pictureBox3.Height);
var g = Graphics.FromImage(croppedImage);
g.DrawImage(crop, new Point(0, 0), rectCropArea, GraphicsUnit.Pixel);
g.Dispose();
//Now you can save the bitmap
croppedImage.Save(...);
pictureBox3.Image = croppedImage;
Btw, please use more reasonable variable names, especially for pictureBox1..3.

Cropping an image from file and resaving in C#

Never really worked with Graphics before. I have looked around on this and pieced together a few solutions from answers which address small parts of my question. but none have worked.
I want to load an image from a file, which will always be 320x240 in size. I then want to crop it to obtain a 240x240 image, with the outer 40px on each side trimmed. After this is done I want to save as a new image.
private void croptoSquare(string date)
{
//Location of 320x240 image
string fileName = Server.MapPath("~/Content/images/" + date + "contactimage.jpg");
//New rectangle of final size (I think maybe Point is where I would eventually specify where the crop square site i.e. (40, 0))
Rectangle cropRect = new Rectangle(new Point(0, 0), new Size(240, 240));
//Create a Bitmap with correct height/width.
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
//Load image from file
using (Image image = Image.FromFile(fileName))
{
//Create Graphics object from image
using (Graphics graphic = Graphics.FromImage(image))
{
//Not sure what this does, I found it on a post.
graphic.DrawImage(image,
cropRect,
new Rectangle(0, 0, target.Width, target.Height),
GraphicsUnit.Pixel);
fileName = Server.MapPath("~/Content/images/" + date + "contactimagecropped.jpg");
image.Save(fileName);
}
}
}
Currently it is simply resaving the same image and I'm not sure why. I have specified a destination rectangle as 240x240 and a src rectangle as 320x240.
As I say I know basically nothing about working with graphics objects so I imagine this is blatant.
Can anybody tell me how to achieve what I want?
private void croptoSquare(string date)
{
//Location of 320x240 image
string fileName = Server.MapPath("~/Content/images/" + date + "contactimage.jpg");
// Create a new image at the cropped size
Bitmap cropped = new Bitmap(240,240);
//Load image from file
using (Image image = Image.FromFile(fileName))
{
// Create a Graphics object to do the drawing, *with the new bitmap as the target*
using (Graphics g = Graphics.FromImage(cropped) )
{
// Draw the desired area of the original into the graphics object
g.DrawImage(image, new Rectangle(0, 0, 240, 240), new Rectangle(40, 0, 240, 240), GraphicsUnit.Pixel);
fileName = Server.MapPath("~/Content/images/" + date + "contactimagecropped.jpg");
// Save the result
cropped.Save(fileName);
}
}
}
Why don't you use JCrop instead? http://www.programmerclubhouse.com/index.php/crop-image-using-jcrop-in-asp-net-c-shar/

Is it possible to rotate a drawing half-way its definition?

I'm doing some draws that are repetitive, and each of them gives lot of work.
What i need to do is rotate the drawing half-way its definition, something like this:
using (Graphics g = Graphics.FromImage(bmp))
{
//define area do pictureBox e preenche a branco
Brush brush = new SolidBrush(Color.White);
Rectangle area = new Rectangle(0, 0, 520, 520);
g.FillRectangle(brush, area);
//rotate
g.RotateTransform(some angle, some reference point)
//draw some more lines on the top of the rotated previous ones.
}
I tried using g.RotateTransform(90) as there is that function in Winforms, but it didn't change anything. Why??
Any tip?
Edit: if it helps, i only need to rotate fixed angles, 180ยบ
RotateTransform certainly does change the subsequent drawing.
Note that you usually need a TranslateTransform before to set the rotation point. But it 'it didn't change anything' is certainly wrong. Try again! And yes you can rotate (or scale or move) at any point and move/turn it back or completely reset the Graphics object.
And yes, learning about Matrix and MultiplyTransform is also very helpful..
But: You need to understand the Graphics object does not contain any graphic, a common misconception! It is the tool which does the drawing on a Bitmap, most often the surface of a Control. So the rotation will happen but only for the things you draw after:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Rectangle rect = new Rectangle(25, 25, 25, 25);
e.Graphics.TranslateTransform(25, 25);
e.Graphics.FillRectangle(Brushes.Red, rect);
for (int i = 0; i < 15; i++)
{
rect.Inflate(2, 2);
e.Graphics.TranslateTransform(5, 2);
e.Graphics.RotateTransform(2.5f);
e.Graphics.DrawRectangle(Pens.Blue, rect);
}
}
Try this:
use these references:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
I made windows application and put on form1 picturebox then this is the code in form_load:
//Load an image in from a file
Bitmap pImage = new Bitmap(Environment.CurrentDirectory + #"\Image.bmp", true);
//Set our picture box to that image
pictureBox1.Image = (Bitmap)pImage.Clone();
//Store our old image so we can delete it
Image oldImage = pictureBox1.Image;
//Pass in our original image and return a new image rotated 35 degrees right
pictureBox1.Image = RotateImage(pImage, 270);
if (oldImage != null)
{
oldImage.Dispose();
}
Then make static function with parameters of image and rotation angle return the rotated image and call it from form_load as mentioned before :
if (image == null)
{
throw new ArgumentNullException("image");
}
else
{
//create a new empty bitmap to hold rotated image
Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(rotatedBmp);
//move rotation point to center of image
g.TranslateTransform((float)image.Width / 2, (float)image.Height / 2);
//rotate
g.RotateTransform(angle);
//move image back
g.TranslateTransform(-(float)image.Width / 2, -(float)image.Height / 2);
//draw passed in image onto graphics object
g.DrawImage(image, new PointF(0, 0));
return rotatedBmp;
}
You can also use directly the code in form_load by using ready RotateFlipType (Enumeration type) but this with fixed angles like 90,270,.... but the previous method you can use any integer values to rotate the image :
private void Form1_Load(object sender, EventArgs e)
{
//Load an image in from a file
Bitmap pImage = new Bitmap(Environment.CurrentDirectory + #"\Image.bmp", true);
pImage.RotateFlip(RotateFlipType.Rotate90FlipXY);
pictureBox1.Image = pImage;
}

Generated Bitmap Displays Weirdly in PictureBox

I cannot seem to programmatically create a colored bitmap to display in a PictureBox. The bitmap saves normally as a file, but is faded at the edges when displayed in a PictureBox. Here is simplified code used to create and display the Bitmap (in actual code, the bitmap generation is completely separate from the form, so forcing the bitmap size to match the picturebox size isn't possible):
Bitmap Bmp = new Bitmap(4, 4, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, 4, 4);
}
Then set the Image value on a PictureBox to the generated Bitmap:
pictureBox1.Image = Bmp;
Here is the resulting bitmap displayed in a 300x300 picturebox:
How do I set the Image on the PictureBox so that it displays the colored bitmap properly (full solid)?
EDIT: I am restricted to generating smaller source bitmaps, so upscaling into a PictureBox is unavoidable. The problem appears when the generated source bitmap is 4px or 100px square, so I believe these are relevant cases.
EDIT: The PictureBox scaling should be set to stretch or zoom for the issue to manifest. In this example case the 4x4 source bitmap is stretched to 300x300.
EDIT: The basic problem is PictureBox's inability to upscale small bitmaps into large controls. This is confusing because the Bitmap upscales nicely into a PictureBox.Background image. Unless you have a magic bullet that will fix the image upscaling problem, I think it might be best to go for clear and simple workarounds in your answer.
You are generating a 4x4 bitmap and it's being stretched. Specify the size to match the picture box instead:
int width = pictureBox1.Width;
int height = pictureBox1.Height;
var Bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (var brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, width, height);
}
pictureBox1.Image = Bmp;
You will need to turn anti-aliasing off. Also, since you are using one color for the whole picturebox, why not make the bitmap 1x1? If you need it 4x4, change the int the top of the example from 1 to 4.
int hw = 1;
Bitmap Bmp = new Bitmap(hw, hw,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, hw, hw);
}
}
pictureBox1.Image = Bmp;
UPDATE
Since you are still having the same issue by setting the picturebox to the image, you will have to get the graphics object from the picturebox and draw directly on it.
The code is very similar.
using (Graphics gfx = Graphics.FromImage(pictureBox1.Image))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0,
pictureBox11.Width - 1,
pictureBox11.Height - 1);
}
}
// Force the picturebox to redraw with the new image.
// You could also use pictureBox11.Refresh() to do the redraw.
pictureBox11.Invalidate();
I tried to test your code and the image were properly displayed.
But when i used this code:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width, Bmp.Height);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
I did get exactly your result. In order to fix it:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width - 1, Bmp.Height - 1);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
Edit:
So you have the bitmap and you want to stretch it. And the bitmap has ane solid color. Do this insted:
Color pixelColor = Bmp.GetPixel(0, 0);
PictureBox1.BackColor = pixelColor;
valter

Save non-transparent image from a PictureBox with transparent images

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;
}

Categories

Resources