Jamie Hartnoll
Jamie Hartnoll

Reputation: 7341

Improving my Image Resize Function for Better Quality Images... loop reductions?

Some while ago I was trying to create an image uploading facility for the back-end of my website. I managed to achieve this, but I have still got poor image quality on the smaller images.

I need to create 4 images:

  1. Zoom image 1800 x 1800 px max
  2. Display image 180 x 275px max
  3. Search Image 120 x 100px max
  4. Tiny thumbnail 50 x 50px max

I generally manually resize and image to 1800 x 1800 with Photoshop or something before uploading it, then upload and resize using the code below (images are all jpgs)

Variables are:

  1. FileName = initially uploaded fine
  2. NewFileName = file name to save resized image as
  3. maxWidth / maxHeight - self explanatory
  4. uploadDir = the directory to save to
  5. resolution = the quality jpg resolution 0-100, I'm using 80 for these examples

     Public Shared Sub ResizeImages(FileName, NewFileName, maxWidth, maxHeight, uploadDir, resolution)
     Try
        Dim originalImg As System.Drawing.Image = System.Drawing.Image.FromFile(uploadDir & FileName)
        Dim aspectRatio As Double
        Dim newHeight As Integer
        Dim newWidth As Integer
       ' Calculate Size '
            If originalImg.Width > maxWidth Or originalImg.Height > maxHeight Then
                If originalImg.Width >= originalImg.Height Then ' image is wider than tall
                    newWidth = maxWidth
                    aspectRatio = originalImg.Width / maxWidth
                    newHeight = originalImg.Height / aspectRatio
                Else ' image is taller than wide
                    newHeight = maxHeight
                    aspectRatio = originalImg.Height / maxHeight
                    newWidth = originalImg.Width / aspectRatio
                End If
            Else ' if image is not larger than max then keep original size
                newWidth = originalImg.Width
                newHeight = originalImg.Height
            End If
    
            Dim newImg As New Bitmap(originalImg, CInt(newWidth), CInt(newHeight)) '' blank canvas
            Dim canvas As Graphics = Graphics.FromImage(newImg) 'graphics element
    
            '*** compress ***'
            Dim myEncoderParameters As EncoderParameters
            myEncoderParameters = New EncoderParameters(1)
            ' set quality level based on "resolution" variable
            Dim myEncoderParameter = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(resolution, Int32))
            myEncoderParameters.Param(0) = myEncoderParameter
    
            canvas.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality
            canvas.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
            canvas.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
    
            canvas.DrawImage(newImg, New Rectangle(0, 0, newWidth, newHeight))
            newImg.Save(uploadDir & (NewFileName), getCodec("image/jpeg"), myEncoderParameters)
    
            '*** Close ***'
            canvas.Dispose()
            originalImg.Dispose()
            newImg.Dispose()
            '*** Nothing ***'
            canvas = Nothing
            newImg = Nothing
            originalImg = Nothing
    
        Catch ex As Exception
            HttpContext.Current.Response.Write(ex.ToString & " " & uploadDir & " " & FileName & " _ " & NewFileName)
        End Try
    
    End Sub
    

To achieve all four images, I pass the sizes required as a list, and then loop that list, in descending order of intended file size, so, the largest one first, I then pass the most recently uploaded image into the function as the FileName parameter so that each time, the function is receiving a smaller image, so not trying to resize a 2000x2000px image to 50x50px as I realise from reading various posts, that this much reduction will result in poor quality.

Having run the loops through in this method, my tiny thumbnails are quite good quality, but my middle images are still poor.

Here they are in descending size order:

http://www.hartnollguitars.co.uk/Products2/0/0/0/9/6/57/1347831580.jpg http://www.hartnollguitars.co.uk/Products2/0/0/0/9/6/57/1347831580-dis.jpg http://www.hartnollguitars.co.uk/Products2/0/0/0/9/6/57/1347831580-se.jpg http://www.hartnollguitars.co.uk/Products2/0/0/0/9/6/57/1347831580-tb.jpg

as you can see, both the "search" and "display" images are still blocky around the edge of the guitar.

What am I doing wrong?!

If my reduction is to much, how would I go about running an in-memory gradual reduction.

What I mean by this, is, it strikes me, that the function above is saving the file to disc each time, that must take up some time, so if I were to loop a reduction function, reducing the image in size, in small increments (say 10% at a time) in memory, and then save the final image to disc when the reduction reaches the correct size. I'm not sure how to do this though.

I'm using ASP.NET 2.0 and am relatively new to it, so I am not fully aware of all the methods available to me.

Any code examples would help greatly!

Thanks

Upvotes: 0

Views: 635

Answers (1)

Guffa
Guffa

Reputation: 700302

What you are doing wrong is that you are creating a downsized image using the Bitmap constructor, then you draw that image onto itself. The Bitmap constructor can naturally not use the quality settings that you set in the Graphics object later on to resize the image, so the quality will be poor.

Instead you should create a blank Bitmap object with the constructor that takes only the size:

Dim newImg As New Bitmap(newWidth, newHeight)

Then you should draw the original image on the canvas:

canvas.DrawImage(originalImg, New Rectangle(0, 0, newWidth, newHeight))

Upvotes: 1

Related Questions