Solved

Image resizing

Posted on 2009-07-04
10
618 Views
Last Modified: 2012-05-07
I'm in serious need of advise on this one.

I have a code that resizes jpeg images to 200px wide or 150px high depending on portrait or landscape attributes, that I have accomplished without problems, now, obviously the target size should be 200px wide by 150px high. Therefore I need some space around the images to accomplish that requirement, meaning that I need every resulting image to be 200px wide by 150px high without cropping or distorting the originals.

It would be great if the space around the image could be of a color of choice.

Please help.

Thanks in advance.
0
Comment
Question by:jorgemgonzalez
  • 4
  • 3
  • 2
  • +1
10 Comments
 
LVL 12

Expert Comment

by:Ammar Gaffar
ID: 24777929
In ASP.NET or VB.NET Windows Application?
0
 
LVL 39

Expert Comment

by:abel
ID: 24777945
In the code below (I know, it is C#, I'll come to that) that I just created and tested, it does exactly what you want. The key is the PicureBox_Paint event and the drawScaledImage. The background color is done by the eraseImage method.

To make this work, create a form, place a button, a picturebox and a openfiledialog on it. On the buttonclick event you assign the filename of the image to a field, m_image_filename. The picturebox will be redrawn (.Invalidate()) and the drawScaledImage is called. The method DrawImage does the scaling for you, the hard part is actually the calculation of the various rectangles. I kept the code clean and simple as far as I could, the result is that it is not very optimized. But it should do for this basic task.

In my next post I'll give an update in VB code of the same.

-- Abel --

public partial class ResizeKeepRatio : Form
{
    private string m_image_filename = null;
 
    public ResizeKeepRatio()
    {
        InitializeComponent();
    }
 
    private void button1_Click(object sender, EventArgs e)
    {
        openFileDialog1.ShowDialog();
        m_image_filename = openFileDialog1.FileName;
        pictureBox1.Invalidate();
    }
 
    private void eraseImage(Graphics graph)
    {
        Rectangle rect = new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height);
        graph.DrawRectangle(new Pen(Brushes.Orange, (float) rect.Width), rect);
    }
 
    private void drawScaledImage(Graphics graph)
    {
        if(m_image_filename == null)
            return;
 
        Bitmap bmp = new Bitmap(m_image_filename);
        Rectangle sourceRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        Rectangle drawAreaRect = new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height);
        Rectangle targetRect;
 
        // determine whether to resize horizontally or vertically
        // based on the ratio width/height of source image and target rectangle
        double sourceRatio = (double)sourceRect.Height / (double)sourceRect.Width;
        double targetRatio = (double)drawAreaRect.Height / (double)drawAreaRect.Width;
        double drawRatio;
        if (sourceRatio > targetRatio)
            drawRatio = (double) drawAreaRect.Height / (double) sourceRect.Height;
        else
            drawRatio = (double) drawAreaRect.Width / (double) sourceRect.Width;
 
        // calculate target rectangle and center
        targetRect = new Rectangle(
            (int) ((drawAreaRect.Width - drawRatio * sourceRect.Width) / 2), 
            (int) ((drawAreaRect.Height - drawRatio * sourceRect.Height) / 2), 
            (int) (drawRatio * sourceRect.Width), 
            (int) (drawRatio * sourceRect.Height));
 
        // draw the image
        graph.DrawImage(bmp, targetRect);
    }
 
    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        eraseImage(e.Graphics);
        drawScaledImage(e.Graphics);
    }
 
}

Open in new window

0
 
LVL 39

Expert Comment

by:abel
ID: 24777957
The VB code is a bit less readable, as is often with calculation code (matter of taste, of course), but here you go (courtesy to http://www.developerfusion.com/tools/convert/csharp-to-vb/):

Public Partial Class ResizeKeepRatio
    Inherits Form
    Private m_image_filename As String = Nothing
    
    Public Sub New()
        InitializeComponent()
    End Sub
    
    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
        openFileDialog1.ShowDialog()
        m_image_filename = openFileDialog1.FileName
        pictureBox1.Invalidate()
    End Sub
    
    Private Sub eraseImage(ByVal graph As Graphics)
        Dim rect As New Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height)
        graph.DrawRectangle(New Pen(Brushes.Orange, CSng(rect.Width)), rect)
    End Sub
    
    Private Sub drawScaledImage(ByVal graph As Graphics)
        If m_image_filename Is Nothing Then
            Exit Sub
        End If
        
        Dim bmp As New Bitmap(m_image_filename)
        Dim sourceRect As New Rectangle(0, 0, bmp.Width, bmp.Height)
        Dim drawAreaRect As New Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height)
        Dim targetRect As Rectangle
        
        ' determine whether to resize horizontally or vertically '
        ' based on the ratio width/height of source image and target 'rectangle
        Dim sourceRatio As Double = CDbl(sourceRect.Height) / CDbl(sourceRect.Width)
        Dim targetRatio As Double = CDbl(drawAreaRect.Height) / CDbl(drawAreaRect.Width)
        Dim drawRatio As Double
        If sourceRatio > targetRatio Then
            drawRatio = CDbl(drawAreaRect.Height) / CDbl(sourceRect.Height)
        Else
            drawRatio = CDbl(drawAreaRect.Width) / CDbl(sourceRect.Width)
        End If
        
        ' calculate target rectangle and center '
        targetRect = New Rectangle(CInt(((drawAreaRect.Width - drawRatio * sourceRect.Width) / 2)), CInt(((drawAreaRect.Height - drawRatio * sourceRect.Height) / 2)), CInt((drawRatio * sourceRect.Width)), CInt((drawRatio * sourceRect.Height)))
        
        ' draw the image '
        graph.DrawImage(bmp, targetRect)
    End Sub
    
    Private Sub pictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs)
        eraseImage(e.Graphics)
        drawScaledImage(e.Graphics)
    End Sub
    
End Class

Open in new window

0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 39

Expert Comment

by:abel
ID: 24777991
In the screenshot you can see one of Window's Vista's sample pictures with a green border. It is a test with the VB code because I wasn't sure if would compile. Don't forget to add the click and paint events! (I did). You can use a ColorDialog for picking the color, which goes into line 17 above.

Happy coding with it! ;-)

ScreenShot419.png
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 24778184
I see from one your PAQs that you have VB2008.  You could "cheat" and just use a PictureBox with the SizeMode set to Zoom.

Simple example having a PictureBox and two Buttons.  Double click the PictureBox to change the color.  Click Button1 to open an image.  Click Button2 to save the Image.
Public Class Form1
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        PictureBox1.Size = New Size(200, 150)
        PictureBox1.BackColor = Color.DarkGreen
        PictureBox1.SizeMode = PictureBoxSizeMode.Zoom
    End Sub
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Using ofd As New OpenFileDialog
            If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
                ofd.Title = "Open Image"
                ofd.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.* "
                Try
                    Using fs As New System.IO.FileStream(ofd.FileName, IO.FileMode.Open)
                        PictureBox1.Image = Image.FromStream(fs)
                    End Using
                Catch ex As Exception
                    MessageBox.Show("File: " & ofd.FileName & vbCrLf & vbCrLf & ex.Message, "Error Opening Image", MessageBoxButtons.OK, MessageBoxIcon.Error)
                End Try
            End If
        End Using
    End Sub
 
    Private Sub PictureBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.DoubleClick
        Using cd As New ColorDialog
            If cd.ShowDialog = Windows.Forms.DialogResult.OK Then
                PictureBox1.BackColor = cd.Color
            End If
        End Using
    End Sub
 
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        If Not IsNothing(PictureBox1.Image) Then
            Using sfd As New SaveFileDialog
                sfd.Title = "Save Image"
                sfd.Filter = "JPEG (*.JPG)|*.JPG|Bitmap (*.BMP)|*.BMP|GIF (*.GIF)|*.GIF"
                If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    Dim bmp As New Bitmap(PictureBox1.ClientSize.Width, PictureBox1.ClientSize.Height)
                    PictureBox1.DrawToBitmap(bmp, PictureBox1.ClientRectangle)
                    Try
                        Select Case System.IO.Path.GetExtension(sfd.FileName).ToUpper
                            Case ".BMP"
                                bmp.Save(sfd.FileName, Drawing.Imaging.ImageFormat.Bmp)
 
                            Case ".JPG"
                                bmp.Save(sfd.FileName, Drawing.Imaging.ImageFormat.Jpeg)
 
                            Case ".GIF"
                                bmp.Save(sfd.FileName, Drawing.Imaging.ImageFormat.Gif)
 
                        End Select
                    Catch ex As Exception
                        MessageBox.Show("File: " & sfd.FileName & vbCrLf & vbCrLf & ex.Message, "Error Saving Image", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    End Try
                End If
            End Using
        End If
    End Sub
 
End Class

Open in new window

0
 

Author Comment

by:jorgemgonzalez
ID: 24778554
Thank you experts for your fast reply.

I created a separate project for each solution and copied the code exactly as posted. For some reason Abel's one did not work at all after clicking button1. Is there something missing?

Idle Mind's (And I.ve always said that mind is whatever but idle) worked like a charm, I love the idea.

Now, what I missed in my question (my apologies) is that the code I have (And need) is for  resizing ingmultiple images, (For ---> Next) actually all the images in a folder via folder browser dialog, I have no picture boxes in my form!

Attached is part of the code so you can have a better idea.

Is there a way of getting the same result without the PicBox?

Otherwise please advise on how to load - unload the images on the PicBox for each file in directory.
Dim bp As New Bitmap(newSize.Width, newSize.Height)
                Dim g As Graphics = Graphics.FromImage(bp)
 
                ' Controls the quality of the image
                g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
                g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
                g.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
 
                Dim rect As New Rectangle(0, 0, newSize.Width, newSize.Height)
                g.DrawImage(currentImage, rect, 0, 0, currentImage.Width, currentImage.Height, GraphicsUnit.Pixel)
 
                ' Copy Meta from old image to new image
                For Each pItem As System.Drawing.Imaging.PropertyItem In currentImage.PropertyItems
                    bp.SetPropertyItem(pItem)
                Next
                newFileName = "Thumb_" & file.ToString
                ' Saves as jpeg
                bp.Save(NewDir & "\Thumbnails\" & newFileName, Imaging.ImageFormat.Jpeg)

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24778692
You can actually use my concept with a dynamic PictureBox that is never even visible to the user...

    Dim pb As New PictureBox
    pb.Size = New Size(200, 150)    
    pb.BackColor = Color.DarkGreen
    pb.SizeMode = PictureBoxSizeMode.Zoom

Then iterate thru your files and use "pb" in code just like in my example above.
0
 

Author Comment

by:jorgemgonzalez
ID: 24778882
Thanks a million Idle_Mind!
0
 

Author Closing Comment

by:jorgemgonzalez
ID: 31599804
Thanks again!
0
 
LVL 39

Expert Comment

by:abel
ID: 24779277
> For some reason Abel's one did not work at all after clicking button1. Is there something missing?
You just needed to add the click event and the paint event in the properties of the button and the picture box.

> Is there a way of getting the same result without the PicBox?
you can draw on almost anything using my method, but I see you already chosen Idle's, which good, because it is simpler. I just didn't even thought of it while working the solution out. Was a nice exercise regardless ;-)

-- Abel --
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question