Zooming / Resizing Images get blurry - c#

I’m using WinForms. My application works like a simple image viewer. It opens Image files goes to the next page, zooms in and zooms out. The problem with my application is that when I re-size or zoom in the image, the image starts getting blurry. How do I prevent my images from getting blurry when I’m zooming out or zooming in?
When i view and re-size the same image on Windows Photo Viewer the images is clear. When i open the image in my application the image is clear but as soon as i start re sizing it for example when i start using zoom it starts becoming blurry.
I tried implementing this code in my zoom out method but i didn't couldn't figure out how to do it.
Size newSize = new Size((int)(originalBitmap.Width * zoomFactor),
(int)(originalBitmap.Height * zoomFactor));
Bitmap bmp = new Bitmap(originalBitmap, newSize);
The image dimensions i look at:
Dimensions: 2540 x 3289
Dimensions: 2533 x 3284
Dimensions: 2538 x 3282
Dimensions: 2479 x 3508
FileStream _stream;
Image _myImg; // setting the selected tiff
string _fileName;
private int intCurrPage = 0; // defining the current page
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
lblFile.Text = openFileDialog1.FileName; //Shows the filename in the lable
Open_Image_Control();
Image img = Image.FromFile(openFileDialog1.FileName);
pictureBox1.Image = img;
pictureBox1.Width = img.Width;
pictureBox1.Height = img.Height;
this.pictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone); // Rotates image 90 degrees
}
}
public void Open_Image_Control()
{
Image myBmp;
if (_myImg == null)
{
_fileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
File.Copy(#lblFile.Text, _fileName);
_stream = new FileStream(_fileName, FileMode.Open, FileAccess.Read);
_myImg = Image.FromStream(_stream);
}
int intPages = _myImg.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page); // getting the number of pages of this tiff
intPages--; // the first page is 0 so we must correct the number of pages to -1
lblNumPages.Text = Convert.ToString(intPages); // showing the number of pages
lblCurrPage.Text = Convert.ToString(intCurrPage); // showing the number of page on which we're on
_myImg.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, intCurrPage); // going to the selected page
myBmp = new Bitmap(_myImg, pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = myBmp; // showing the page in the pictureBox1
}
private void ZoomIN_Btn_Click(object sender, EventArgs e)
{
this.pictureBox1.Width += 175; //Zoom width by 75
this.pictureBox1.Height += 175; //Zoom height by 75
}
private void ZoomOut_Btn_Click(object sender, EventArgs e)
{
this.pictureBox1.Width -= 175; //Zoom out width by 75
this.pictureBox1.Height -= 175; //Zoom out height by 75
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
if (intCurrPage == Convert.ToInt32(lblNumPages.Text)) // if you have reached the last page it ends here
// the "-1" should be there for normalizing the number of pages
{ intCurrPage = Convert.ToInt32(lblNumPages.Text); }
else
{
intCurrPage++; //page increment (Goes to next page)
Open_Image_Control();
this.pictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone); // Rotates image 90 degrees
}
}

Related

Clone jpg without losing quality in C#

Im trying to take an input from a webcam and only want the centre of the image (to passport size image).
I have a Picturebox with the webcam stream which I have set SizeMode to CentreImage. I then have a second picturebox which when I click the second picturebox i then need a cropped image i then save later (currently i get the whole original image when saving).
I have code to crop this image into the 2nd picturebox which works however it loses loads of quality. Is there a way to make this crop lossless?
private void pictureBox1_Click(object sender, EventArgs e)
{
//picPhoto.Image = pic.Image;
using (Bitmap bmp = new Bitmap(pic.Image))
{
var newImg = bmp.Clone(
new Rectangle { X = ((pic.Image.Width/2)-(350/2)), Y = ((pic.Image.Height / 2) - (450 / 2)), Width = 350, Height = 450 },
bmp.PixelFormat);
picPhoto.Image = newImg;
}
}

zoom an image in a second picturebox following cursor

i have a picturebox that contain an image (1280 X 720), i want to create a second picturebox that contain a zoomed version of the image centered around the cursor (for example a 40 X 40 square around the cursor zomed to be in a 120 X 120 square picturebox) that follow the cursor in real time in real time (if it's possible also to have a cross in the middle of the picturebox that show the precise placing of the cursor is even better).
private void Button1_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "All jpg files (*.jpg)|*.jpg";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
Bitmap img = new Bitmap(openFileDialog1.FileName);
double imageHeight = img.Height;
double imageWidth = img.Width;
pictureBox1.Image = img;
}
}
private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
int xupleft = e.X - 20;
int yupleft = e.Y - 20;
Rectangle myrectangle = new Rectangle(xupleft, yupleft, 40, 40);
pictureBox2.Image = pictureBox1.Image;
}
Here is a simple example with the layout I described in the comment:
Both PictureBoxes are nested in Panels.
The first one is in Zoom mode and upon loading a file its size is adapted to avoid blank stripes to the sides. Its parent panel is used to reset to the maximum allowed size.
The 2nd one is in AutoSize mode and its parent panel is used to 1) hide the outer portions and 2) to calculate the offset to center the image.
Here is the simple Paint event for pbox1:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Size sz = pictureBox1.ClientSize;
Point pt = pictureBox1.PointToClient(Control.MousePosition);
e.Graphics.DrawLine(Pens.OrangeRed, pt.X, 0, pt.X, sz.Height);
e.Graphics.DrawLine(Pens.OrangeRed, 0, pt.Y, sz.Width, pt.Y);
}
Here is the MouseMove the triggers the Paint and moves pbox2:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
pictureBox1.Invalidate();
float f = 1f * pictureBox2.ClientSize.Width / pictureBox1.ClientSize.Width;
Size s2 = pictureBox2.Parent.ClientSize;
Point p2 = Point.Round(new PointF(s2.Width/2 - e.X * f , s2.Height/2 - e.Y * f ));
pictureBox2.Location = p2;
}
The file loading is a bit tricky, as it needs to analyze the aspect ratios of image and pbox:
void loadFile(string fileName)
{
if (File.Exists(fileName))
{
pictureBox1.Size = panel1.ClientSize;
pictureBox1.Location = Point.Empty;
pictureBox1.Image = Image.FromFile(fileName);
pictureBox2.Image = Image.FromFile(fileName);
pictureBox2.Location = Point.Empty;
}
Size csz = pictureBox1.ClientSize;
Size isz = pictureBox1.Image.Size;
float iar = 1f * isz.Width / isz.Height; // aspect..
float car = 1f * csz.Width / csz.Height; //..ratios
if (iar < car)
{
pictureBox1.ClientSize = new Size((int)(pictureBox1.ClientSize.Height * iar),
pictureBox1.ClientSize.Height);
}
else if (iar > car)
{
pictureBox1.ClientSize = new Size((pictureBox1.ClientSize.Width,
(int)(pictureBox1.ClientSize.Width / iar));
}
}
Note that before loading the new images one should Dispose of the previous images! Also that after setting the pbox2.SizeMode to Autosize one could set it to Zoom and scale its Size up or down to zoom in or out, if one keeps the aspect ratio the same.
Result:

Using Print Page Range

I’m using WinForms. In my form I have a pictureBox and (a From: textbox and a To: Textbox). These textboxes are used to print certain page ranges from a multipage Tif document. The problem is that the application doesn’t print the page ranges. Another problem is that the print preview doesn’t show the correct page, for example If I type number 2 in the From textbox I expect the print preview dialog to show page number 2 from the Tif document, it doesn't show that it shows the wrong page which is page 1.
Test 1: Let’s say if I wanted to print pages 2-5 from the tif document I would type (From: 2 , To: 5).
The weird thing is that the application would only print page 2.
Test 2: I added the line below under print_preview_Setting() and for some reason the print range works using this, but the weird thing is print preview still displays wrong pages.
if (printDialog1.ShowDialog() == DialogResult.OK)
{
currentPrintPage = Convert.ToInt32(From_Pg_txtBox.Text) - 1;
printDocument1.Print();
}
Note: I’ve been printing to PDF for my test cases
Below is a sample Tif Document for Testing
http://www.filedropper.com/tifbordernumberpage
using System.Drawing.Printing;
using System.Drawing.Imaging;
private int currentPrintPage;
private void Form1_Load(object sender, EventArgs e)
{
//using (var dialog = new OpenFileDialog())
//{
// if (dialog.ShowDialog(this) == DialogResult.OK)
// {
// string filename = dialog.FileName;
// pictureBox1.Load(filename);
// }
//}
pictureBox1.Load("C:\\image\\Tif_Document.tif");
}
private void Print_button_Click(object sender, EventArgs e)
{
print_preview_Settings();
// if (printDialog1.ShowDialog() == DialogResult.OK)
// {
// currentPrintPage = Convert.ToInt32(From_Pg_txtBox.Text) - 1;
// printDocument1.Print();
// }
}
private void print_preview_Settings()
{
printPreviewDialog1.Document = printDocument1;
printDocument1.DefaultPageSettings.Margins.Top = 100;
printDocument1.DefaultPageSettings.Margins.Left = 200;
printDocument1.DefaultPageSettings.Margins.Right = 0;
printDocument1.DefaultPageSettings.Margins.Bottom = 0;
currentPrintPage = Convert.ToInt32(From_Pg_txtBox.Text) - 1;
printPreviewDialog1.ShowDialog();
}
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
Image i;
i = Image.FromFile("C:\\image\\Tif_Document.tif");
i.SelectActiveFrame(FrameDimension.Page, currentPrintPage);
//Print while maintating aspect ratio of the image
var img_width = e.PageBounds.Width - e.MarginBounds.Left - Math.Abs(e.MarginBounds.Right - e.PageBounds.Width);
var img_height = e.PageBounds.Height - e.MarginBounds.Top - Math.Abs(e.MarginBounds.Bottom - e.PageBounds.Height);
var img = ResizeAcordingToImage(i, img_width, img_height);
e.Graphics.DrawImage(i,
e.MarginBounds.Left, e.MarginBounds.Top, img.Width, img.Height);
currentPrintPage++; //increment page from the Tif doc
if (currentPrintPage < Convert.ToInt32(to_Pg_txtBox.Text))
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false;
}
}
private Image ResizeAcordingToImage(Image Source, int boxWidth, int boxHeight)
{
Image resizedImage;
double dbl = (double)Source.Width / (double)Source.Height;
//set height of image to boxHeight and check if resulting width is less than boxWidth,
//else set width of image to boxWidth and calculate new height
if ((int)((double)boxHeight * dbl) <= boxWidth)
{
resizedImage = new Bitmap(Source, (int)((double)boxHeight * dbl), boxHeight);
}
else
{
resizedImage = new Bitmap(Source, boxWidth, (int)((double)boxWidth / dbl));
}
return resizedImage;
}
For some reason, the PrintPage seems to interfere with the active frame of the TIF, so try extracting the image that needs to be displayed:
Image i = Image.FromFile("C:\\image\\Tif_Document.tif");
i.SelectActiveFrame(FrameDimension.Page, currentPrintPage);
using (MemoryStream ms = new MemoryStream()) {
i.Save(ms, ImageFormat.Tiff);
using (Image pageImage = Image.FromStream(ms)) {
var img = ResizeAcordingToImage(pageImage, img_width, img_height);
e.Graphics.DrawImage(pageImage, e.MarginBounds.Left, e.MarginBounds.Top,
img.Width, img.Height);
}
}

Crop and Print Image Documents without Distortion In C#

I'm using WinForms. In my form I have a picturebox I use to display image documents. The problem is when I crop the image and then print the document out the image becomes slightly distorted. If I don't crop the image document and print it regularly the image document does not become distorted.
How do I crop and print the image documents without them being distorted?
Or is there a better way to code this so it can crop and print without the image document being distorted? If so, how can i do it?
Notes:
My picturebox is set to Zoom because the images i work with is big:
Example of image document Dimensions: 2500 x 3100
My picturebox does not have a border
int _cropX, _cropY, _cropWidth, _cropHeight;
public Pen _cropPen;
private State _currentState;
private enum State
{
Crop
}
private void Open_btn_Click(object sender, EventArgs e)
{
// open file dialog
OpenFileDialog open = new OpenFileDialog();
if (open.ShowDialog() == DialogResult.OK)
{
// display image in picture box
pictureBox1.Image = new Bitmap(open.FileName);
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
try
{
if (Crop_Checkbox.Checked == true)
{
Cursor = Cursors.Default;
if (_currentState == State.Crop)
{
if (_cropWidth < 1)
{
return;
}
Rectangle rect = new Rectangle(_cropX, _cropY, _cropWidth, _cropHeight);
//First we define a rectangle with the help of already calculated points
Bitmap originalImage = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);
//Original image
Bitmap img = new Bitmap(_cropWidth, _cropHeight);
// for cropinf image
Graphics g = Graphics.FromImage(img);
// create graphics
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
//set image attributes
g.DrawImage(originalImage, 0, 0, rect, GraphicsUnit.Pixel);
pictureBox1.Image = img;
pictureBox1.Width = img.Width;
pictureBox1.Height = img.Height;
}
}
else
{
Cursor = Cursors.Default;
}
}
catch (Exception)
{
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (Crop_Checkbox.Checked == true)
{
if (_currentState == State.Crop)
{
Cursor = Cursors.Cross;
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
//X and Y are the coordinates of Crop
pictureBox1.Refresh();
_cropWidth = e.X - _cropX;
_cropHeight = e.Y - _cropY;
pictureBox1.CreateGraphics().DrawRectangle(_cropPen, _cropX, _cropY, _cropWidth, _cropHeight);
}
}
}
else
{
Cursor = Cursors.Default;
}
}
private void Crop_Checkbox_CheckedChanged(object sender, EventArgs e)
{
if (Crop_Checkbox.Checked == true)
{
this.Cursor = Cursors.Cross;
}
}
private void Print_btn_Click(object sender, EventArgs e)
{
System.Drawing.Printing.PrintDocument myPrintDocument1 = new System.Drawing.Printing.PrintDocument();
PrintDialog myPrinDialog1 = new PrintDialog();
myPrintDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(printDocument1_PrintPage);
myPrinDialog1.Document = myPrintDocument1;
if (myPrinDialog1.ShowDialog() == DialogResult.OK)
{
myPrintDocument1.Print();
}
}
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.DrawImage(pictureBox1.Image, 10, 10); //(Standard paper size is 850 x 1100 or 2550 x 3300 pixels)
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (Crop_Checkbox.Checked == true)
{
if (_currentState == State.Crop)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Cursor = Cursors.Cross;
_cropX = e.X;
_cropY = e.Y;
_cropPen = new Pen(Color.FromArgb(153, 180, 209), 3); //2 is Thickness of line
_cropPen.DashStyle = DashStyle.DashDotDot;
pictureBox1.Refresh();
}
}
}
else
{
Cursor = Cursors.Default;
}
}
Test: Slightly Distorted:
Test: Not Distorted:
Test:
The picture above is a test. This is what happened when i took the below code out from pictureBox1_MouseUp:
Bitmap originalImage = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);
And edited/replaced (originalImage to pictureBox1.Image):
g.DrawImage(pictureBox1.Image, 0, 0, rect, GraphicsUnit.Pixel);
Bitmap originalImage = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);
That is most likely where the problem started. This can cause pictureBox1.Image to be rescaled to force-fit it to the pictureBox1 size. Depends on whether the picturebox has borders and its SizeMode property value. Rescaling causes the image to be resampled, the color of a pixel in the new bitmap is calculated from the values of its neighboring pixels in the original image as directed by the selected InterpolationMode.
This in effect blurs the resulting image. That works well on a photo but this is text that critically depends on anti-aliasing pixels to look decent on a low-resolution monitor. Slight changes to those pixels ruins the effect and they no longer smoothly blend the letter shape against the background anymore. They become more visible, best way to describe it is that the resulting text looks "fat".
I see no obvious reason to do this at all in the posted code. Delete the statement and replace originalImage with pictureBox1.Image.
Also beware that printing this image is likely to be disappointing. Now those anti-aliasing pixels get turned into 6x6 blobs of ink on paper. That only ever looks good when you have long arms. As long as the font size is this small and you have no control over the anti-aliasing choice then there's very little you can do about that. Printed text only ever looks good when you use PrintDocument and Graphics.DrawString().

Getting correct coordinates from scaled picture box with Zoom SizeMode

I loaded the jpg to picture box (in SizeMode as Zoom).
I drew a rectangle on the picture box and took the coordinate.
I opened the jpg in paint and observed the coordinate (where I drew the rectangle on the picture box).
When I compared the rectangle coordinates (x and y) with paint coordinates, they were not the same.
I changed the SizeMode to Normal and observed that the coordinates became the same, but the image size was too large so it was display partially, so I want to use Zoom SizeMode property.
Say image with size 2825x3538 and keep the picture box size mode as Normal, the image shows partially in picture box. So I changed picture box mode to Zoom (to fit the System screen resolution), and the coordinates missmatched when comparing it with Normal mode with SizeMode.
How can I achieve the same coordinates?
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFD.FileName = "";
OpenFD.Title = "open image";
OpenFD.InitialDirectory = "C";
OpenFD.Filter = "JPEG|*.jpg|Bmp|*.bmp|All Files|*.*.*";
if (OpenFD.ShowDialog() == DialogResult.OK)
{
file = OpenFD.FileName;
image = Image.FromFile(file);
pictureBox1.Image = image;
svc = Screen.PrimaryScreen;
pictureBox1.Width = svc.Bounds.Width;
pictureBox1.Height = svc.Bounds.Height - 100;
mybitmap1 = new Bitmap(pictureBox1.Image);
mybitmap1.SetResolution(300, 300);
pictureBox1.Image = mybitmap1;
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (mybitmap == null)
{
mybitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
mybitmap.SetResolution(300, 300);
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (g = Graphics.FromImage(mybitmap))
{
using (Pen pen = new Pen(Color.Green, m))
{
e.Graphics.DrawRectangle(pen, r);
e.Graphics.DrawString(lab[c].ToString(), new Font(lab[c].ToString(), 8F), new SolidBrush(label1.ForeColor), r);
}
}
}
You can use two scale factors between the actual image and the picture box, one with height and the other with width.

Categories

Resources