Question

Take the following two images:

Dev Version - IIS7 Windows 7 Pro 64bit Machine

Dev Copy

Live Version - IIS7 Windows Server 2008 64bit Machine

Live Copy

Note how the Live Version is "pixelly" & looks low quality, the Dev Version however is smooth, anti-aliased & looks fine. These are both generated by identical code:

' Settings
Dim MaxHeight As Integer = 140
Dim MaxWidth As Integer = 140
Dim WorkingFolderPath As String = "\\server\share\bla\"
Dim AllowedFileExtensions As New ArrayList
AllowedFileExtensions.Add(".jpg")
AllowedFileExtensions.Add(".jpeg")

' Select an image to use from the WorkingFolder
Dim ImageFileName As String = ""
Dim WorkingFolder As New IO.DirectoryInfo(WorkingFolderPath)
Dim SourceImages As IO.FileInfo() = WorkingFolder.GetFiles()

For Each SourceImage As IO.FileInfo In SourceImages
    If AllowedFileExtensions.Contains(SourceImage.Extension.ToLower) = True Then
        ImageFileName = SourceImage.Name
    End If
Next

' Determine path to selected image (if no image was found use a placeholder)
Dim PhysicalPath As String = ""
If ImageFileName = "" Then
    ' No Image was found, use the filler image
    PhysicalPath = Server.MapPath("ProductOfTheMonthMissing.jpg")
Else
    ' An Image was found, Redirect to it / build path for Thumnailing
    If Request.QueryString("FullSize") = "true" Then
        Response.Redirect("../share/bla/" & ImageFileName)
    Else
        PhysicalPath = WorkingFolderPath & ImageFileName
    End If
End If

' Load image and output in binary (resizing if necessary)
Using ProductImage As System.Drawing.Image = System.Drawing.Image.FromFile(PhysicalPath)
    Dim newWidth As Integer = ProductImage.Width
    Dim newHeight As Integer = ProductImage.Height

    ' Check if selected size is too big, if so, determine new size
    If ProductImage.Width > MaxWidth Or ProductImage.Height > MaxHeight Then
        Dim ratioX As Double = CDbl(MaxWidth) / ProductImage.Width
        Dim ratioY As Double = CDbl(MaxHeight) / ProductImage.Height
        Dim ratio As Double = Math.Min(ratioX, ratioY)

        newWidth = CInt(ProductImage.Width * ratio)
        newHeight = CInt(ProductImage.Height * ratio)
    End If

    ' Create a new bitmap from the image with new size
    Dim Codecs As ImageCodecInfo() = ImageCodecInfo.GetImageEncoders()
    Dim CodecInfo As ImageCodecInfo = Nothing
    Dim ProductOfTheMonth As New Bitmap(ProductImage, newWidth, newHeight)
    Dim ReSizer As Graphics = Graphics.FromImage(ProductOfTheMonth)

    ReSizer.InterpolationMode = InterpolationMode.HighQualityBicubic
    ReSizer.SmoothingMode = SmoothingMode.HighQuality
    ReSizer.PixelOffsetMode = PixelOffsetMode.HighQuality
    ReSizer.CompositingQuality = CompositingQuality.HighQuality

    ' Ensure the encoder uses the best quality settings
    Dim EncoderParams As New EncoderParameters(3)
    EncoderParams.Param(0) = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L)
    EncoderParams.Param(1) = New EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, CInt(EncoderValue.ScanMethodInterlaced))
    EncoderParams.Param(2) = New EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, CInt(EncoderValue.RenderProgressive))

    ' Set jpeg as the output codec
    For Each Codec As ImageCodecInfo In Codecs
        If Codec.MimeType = "image/jpeg" Then
            CodecInfo = Codec
        End If
    Next

    ' Ready a memory stream and byte array
    Dim MemStream As New MemoryStream()
    Dim bmpBytes As Byte()

    ' Save the image the the memory stream & prep ContentType for HTTP reasponse
    Response.ContentType = "image/jpeg"
    ProductOfTheMonth.Save(MemStream, CodecInfo, EncoderParams)

    ' Flush memory stream into byte array & flush to browser
    bmpBytes = MemStream.GetBuffer()
    Response.BinaryWrite(bmpBytes)

    ' Cleanup
    ProductOfTheMonth.Dispose()
    MemStream.Close()
    ProductImage.Dispose()
End Using

What is the reason behind this & how do I address the issue? Presumably its a GD issue on the live web server - but I have no idea what - I tried to be as thorough as possible in setting graphic and codec settings but its still different?

Edit: Source Image is identical in both examples too (Located on a central unc share) - copy of source image here

Was it helpful?

Solution

I've had and, answered a similar question here: Graphics wrong image interpolation in .Net, but in short it seems like different platforms use different internal algorithms (or perhaps it's an internal rounding problem in GDI).

Anyway, the problem is in the settings. So try the following:

Using s As Bitmap = DirectCast(Bitmap.FromFile(PhysicalPath), Bitmap)
    Dim scale As Double = Math.Min(140.0 / s.Width, 140.0 / s.Height)
    Using d As New Bitmap(CInt(Math.Floor(scale * s.Width)), CInt(Math.Floor(scale * s.Height)), System.Drawing.Imaging.PixelFormat.Format24bppRgb)
        Using dg As Graphics = Graphics.FromImage(d)
            dg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
            dg.SmoothingMode = SmoothingMode.HighQuality
            dg.PixelOffsetMode = PixelOffsetMode.HighQuality
            dg.CompositingQuality = CompositingQuality.HighQuality
            dg.Clear(Color.White)
            dg.DrawImage(s, New Rectangle(0, 0, d.Width, d.Height), New Rectangle(0, 0, s.Width, s.Height), GraphicsUnit.Pixel)
        End Using

        Dim jpegArgs As New EncoderParameters(3)
        jpegArgs.Param(0) = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L)
        jpegArgs.Param(1) = New EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, CInt(EncoderValue.ScanMethodInterlaced))
        jpegArgs.Param(2) = New EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, CInt(EncoderValue.RenderProgressive))

        Dim Codecs As ImageCodecInfo() = ImageCodecInfo.GetImageEncoders()
        Dim jpegParams As ImageCodecInfo = Nothing

        '#### Set jpeg as the output codec
        For Each Codec As ImageCodecInfo In Codecs
            If Codec.MimeType = "image/jpeg" Then
                jpegParams = Codec
            End If
        Next

        Response.Clear()
        Response.ContentType = "image/jpeg"

        d.Save(Response.OutputStream, jpegParams, jpegArgs)
    End Using
End Using

Good luck!

OTHER TIPS

You should compare all dependencies and check IIS are using same versions. Mor info here: How to compare if the configuration is different for IIS?

If the same configuration are used, then it could be somthing related to graphic card, usually servers don't have specific graphic cards for image proccessing. In that case, you should configure GDI+ in your develop machine to not use acceleration or card specific instructions. Using Graphics Card instead of GDI+ for Image Manipulation

May be using another engine, and change the code help as a workaround: Replace GDI+ DrawImage with PInvoked GDI and transparent PNG's

Are you using a proxy-cache web server in your production enviroment like Apache, Nginex, Varnish... between server and client?

It's very common that proxy server having modules like google page speed or similar, making compression over images to improve download speed. I that case, it should be trivial to write an exception rule.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top