Question

I have a function that dynamically adds text to an image in a predesignated spot. Originally I did it with jpegs, and it was working. I switched to PNG so the images would be better quality, as the original jpegs were kind of pixely. Anyway, here is my code. It executes down to the oBitmap.Save(), then dies with "A General Error Has Occurred in GDI+".

Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
    context.Response.ContentType = "image/png"
    context.Response.Clear()
    context.Response.BufferOutput = True

    Try
        Dim oText As String = context.Server.HtmlDecode(context.Request.QueryString("t"))
        If String.IsNullOrEmpty(oText) Then oText = "Placeholder"
        Dim oPType As String = context.Server.HtmlDecode(context.Request.QueryString("p"))
        If String.IsNullOrEmpty(oPType) Then oPType = "none"

        Dim imgPath As String = ""
        Select Case oPType
            Case "c"
                imgPath = "img/banner_green.png"
            Case "m"
                imgPath = "img/banner_blue.png"
            Case Else
                Throw New Exception("no ptype")
        End Select

        Dim oBitmap As Bitmap = New Bitmap(context.Server.MapPath(imgPath))
        Dim oGraphic As Graphics = Graphics.FromImage(oBitmap)
        Dim frontColorBrush As New SolidBrush(Color.White)
        Dim oFont As New Font(FONT_NAME, 30)


        Dim oInfo() As ImageCodecInfo = ImageCodecInfo.GetImageEncoders
        Dim oEncoderParams As New EncoderParameters(2)
        Dim xOffset As Single = Math.Round((oBitmap.Height - oFont.Height) / 2, MidpointRounding.ToEven)
        Dim oPoint As New PointF(275.0F, xOffset + 10)

        oEncoderParams.Param(0) = New EncoderParameter(Encoder.Quality, 100L)
        oEncoderParams.Param(1) = New EncoderParameter(Encoder.ColorDepth,8L)

        oGraphic.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
        oGraphic.DrawString(oText, oFont, frontColorBrush, oPoint)
        oBitmap.Save(context.Response.OutputStream, oInfo(4), oEncoderParams)
        context.Response.Output.Write(oBitmap)

        oFont.Dispose()
        oGraphic.Dispose()
        oBitmap.Dispose()  
        context.Response.Flush()
    Catch ex As Exception

    End Try
End Sub

The only changes I made to this from the jpeg version are:

  • context.Response.ContentType = "image/jpeg" changed to "image/png"
  • changed base images (img/banner_green.jpg, img/banner_blue.jpg) to .png
  • added the second encoding parameter specifying color depth
  • changed oInfo(1) (jpeg) to oInfo(4) (png)

Are there more things I need to tweak to get this routine to properly generate the PNG?

Was it helpful?

Solution

According to this post, Bitmap.Save requires a seekable stream to save as PNG, which HttpResponse.OutputStream isn't. You'll have to save the image into a MemoryStream first, and then copy the contents of it to Response.OutputStream, like:

Dim tempStream as New MemoryStream
oBitmap.Save(tempStream, ImageFormat.Png, oEncoderParams)
Response.OutputStream.Write(tempStream.ToArray(), 0, tempStream.Length)

Also note that the line

context.Response.Output.Write(oBitmap)

does something different then what you are probably expecting. HttpResponse.Output is a TextWriter, and the overload you use here, TextWriter.Write(object) will just call ToString on the object and write the results into the stream, what in this case results in writing "System.Drawing.Bitmap" to the output.

OTHER TIPS

You're disposing of the bitmap before you're flushing the Response? Try flipping that around. Also, it looks like you're writing the bitmap to the stream twice. I'm not sure why you're doing that. Save the bitmap to the output stream or use the Write method of the Response object, but not both.

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