Crop and Print Image Documents without Distortion In C#
Asked Answered
C

1

14

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

enter image description here

Test: Slightly Distorted:

enter image description here

Test: Not Distorted:

enter image description here

enter image description here

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);
Condillac answered 1/2, 2016 at 2:23 Comment(9)
I can't really see the "distortion". What kind of distortion that you encounter?Jetport
if you print the document regular you will see its more clear. The words has a little distortion @lanCondillac
I still can't see the distortion in the image? You do not seem to show the image, do you?Jetport
The picture is up @JetportCondillac
Sometimes, this can be caused by the winform "internal drawing mechanism" (my own term for lack of better term) when adjusting several different drawn objects together due to one reason like picture/string rendering or another. But I cannot tell exactly what it is for your case. I have voted your question up however, hope you get better attention and better answerer.Jetport
Thanks for looking at it and giving me some feedback @JetportCondillac
It is only 1-4 pixels but you really should use picturebox.clientsize.width etc not picturebox.width, at least if the pb has a border! If the image is wide or high it may well show a little.. You can test the results by saving them and checking the pixels in an imageviewerIsolate
This looks to be an artifact of texture sampling. It is likely that the texels are being interpolated by the call to DrawImage in your click handler. You have the interpolation mode set to bicubic which suggests some sampling. You may be better off just keeping your crop rect around and using the original image in your print function.Serrato
Are you suggesting to remove InterpolationMode , PixelOffsetMode and CompositingQuality from the code? @SerratoCondillac
E
1
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().

Ely answered 1/2, 2016 at 2:23 Comment(9)
Thanks for your explanation. I'm reviewing my code right now and ill see if this fixes the issue.Condillac
When i take the originalImage out and replace it with pictureBox1.Image. The program doesn't crop correctly. With the originalImage gone the program only shows some of the image.Condillac
That does not help me help you, the point of cropping is to "show some of the image". The _cropXxx values are pictureBox coordinates, not Image coordinates. This code can only work when the SizeMode property equals AutoSize. That there might be something wrong with SizeMode property was already assumed in the answer and explains the rescaling artifacts. You need to document its value.Ely
You're right I wasn't real clear when i said some of the image, I will show you what i mean by uploading an images. This code does work when its on AutoSize, but it doesn't work when it is set to zoom. @HansPassantCondillac
I uploaded the images and code that i got rid of, let me know if that is what you meant by taking the: Bitmap originalImage... out and adding g.DrawImage(pictureBox1.Image....) should go there. @HansPassantCondillac
Not sure how the added image explains anything, it is not displayed zoomed. But yes, you do need to map the mouse coordinates you get from the MouseDown/Move events to image coordinates. Zoom applies a multiplier, its value depends on whether the image fits horizontally or vertically. You can see the code that calculates it here. Multiply the mouse coordinates by 1/ratio.Ely
The picturebox is actually in zoomed. I didn't change anything except taking the originalImage out like you suggested. When I took the originalImage out that's is how it was displayed @HansPassantCondillac
Do you know any other way to crop and print image documents with good quality because it looks like my code doesn't work?Condillac
maybe this will help code.msdn.microsoft.com/windowsapps/CSWinFormCropImage-d4beb1faAlcestis

© 2022 - 2024 — McMap. All rights reserved.