jorgemgonzalez
asked on
Image resizing
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.
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.
In ASP.NET or VB.NET Windows Application?
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 --
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);
}
}
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
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
Happy coding with it! ;-)
ScreenShot419.png
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.
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)
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.
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.
ASKER
Thanks a million Idle_Mind!
ASKER
Thanks again!
> 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 --
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 --