Add watermarktext to image dynamically without saving image to server - asp.net

I have an image stored on my server in this folder:
\images\freemedia\largethumbs\test.png
On my default.aspx page I have an imagecontrol:
<asp:Image ID="Image1" runat="server" />
When the visitor requests the default.aspx page I want to get the test.png image from the server, add the watermark text "hello world" to it on the right bottom.
I DON'T want to save the watermarked image to the server, since I want to save storage and still want to have access to the original image.
From the image that is shown to the visitor, he should preferably not be able to derive the original filename, so he should not be allowed to see that the original filename is test.png.
I've been searching on Google a lot, but all examples save the watermarked image to disk, which I don't want.
I already have a httphandler:
Public Class pichandler : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim data As Byte()
Dim fName As String
Using w As New generaltablesTableAdapters.freemediaTableAdapter
fName = w.GetDataById(i)(0).medialink.ToString
End Using
data = My.Computer.FileSystem.ReadAllBytes(context.Server.MapPath("~/images/freemedia/thumbs/" & fName))
' --> how can I add a watermark text to the image here?!?!?!?
context.Response.ContentType = "image/jpeg"
context.Response.BinaryWrite(data)
End Sub
End Class
Does anyone have a code sample on how to do this?
If there's another way of doing this, that is fine too. But please show how I can serve the watermarked image as part of the final HTML.

Since you are working with asp.net, you might as well use an HttpHandler.
Here's an example, create a new generic handler, let's call it ImageHandler and the code can be as easy as this:
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// Clear response and set content type to image.
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
// Create your image, however you want it. Server.MapPath and so on.
var image = Bitmap.FromFile(#"C:\Images\image.jpg");
// And save it to the OutputStream.
image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
public bool IsReusable
{
get { return false; }
}
}
And then just use it like this:
<asp:Image ID="Image1" ImageUrl="~/ImageHandler.ashx" runat="server" />
Of course you could also send in some QueryString parameters like this:
<asp:Image ID="Image1" ImageUrl="~/ImageHandler.ashx?filename=myimage.jpg" runat="server" />
And then just use context.Request.QueryString["filename"] in the ImageHandler.
UPDATE:
After the comments, here's how you can add a watermark:
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim watermarkText As String = "Copyright"
Dim fName As String
Using w As New TopTrouwen.generaltablesTableAdapters.freemediaTableAdapter
fName = w.GetDataById(i)(0).medialink.ToString
End Using
' Create image directly from the path
Dim image = Drawing.Image.FromFile(context.Server.MapPath("~/images/freemedia/thumbs/" & fName))
Dim font As New Font("Tahoma", 16, FontStyle.Regular, GraphicsUnit.Pixel)
'Adds a transparent watermark
Dim color As Color = Drawing.Color.FromArgb(50, 0, 0, 0)
Dim brush As New SolidBrush(color)
Dim gr As Graphics = Graphics.FromImage(image)
' Measure the watermark text so we can offset it's width and height
Dim watermarkSize = gr.MeasureString(watermarkText, font)
' Create the point where the watermark text should be printed
Dim point As New Point(image.Width - watermarkSize.Width, image.Height - watermarkSize.Height)
gr.DrawString(watermarkText, font, brush, point)
gr.Dispose()
context.Response.ContentType = "image/jpeg"
image.Save(context.Response.OutputStream, ImageFormat.Jpeg)
End Sub

Related

New Google Recaptcha with ASP.Net

I am attempting to get the new Google reCaptcha working in my ASP.NET project and I am having problems getting it to be the new one "I'm not a robot".
I had the old one in there and after doing much research on the developers.google.com web site, everything looks the same (they even point me to a download of the same dll - 1.0.5). So, I got the new keys and put them in and it works but it looks just like the old reCaptcha.
Has anyone gotten the new one to work with their ASP.Net? What am I missing?
EDIT:
So playing around in a test app and searching some other web sites I found that if I create a page like this:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>reCAPTCHA demo: Simple page</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<form id="form1" runat="server" action="?" method="POST">
<div>
<div class="g-recaptcha" data-sitekey="My Public Key"></div>
<br/>
<asp:Button ID="Button1" runat="server" Text="Submit" />
</div>
</form>
</body>
</html>
And then in my code-behind (Button1_Click), I do this:
Dim Success As Boolean
Dim recaptchaResponse As String = request.Form("g-recaptcha-response")
If Not String.IsNullOrEmpty(recaptchaResponse) Then
Success = True
Else
Success = False
End If
The recaptchaResponse will either be empty or filled in depending on if they are a bot or not. The issue is, I now need to take this response and send it to google with my private key so I can verify that the response was not provided by a bot, in my code-behind, but I cannot figure out how. I tried this (in place of Success = True):
Dim client As New System.Net.Http.HttpClient()
client.BaseAddress = New Uri("https://www.google.com/recaptcha/")
client.DefaultRequestHeaders.Accept.Clear()
client.DefaultRequestHeaders.Accept.Add(New Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"))
Dim response As Net.Http.HttpResponseMessage = Await client.GetAsync("api/siteverify?secret=My Private key&response=" + recaptchaResponse)
If (response.IsSuccessStatusCode) Then
Dim CaptchResponse As ReCaptchaModel = Await response.Content.ReadAsAsync(Of ReCaptchaModel)()
Success = CaptchResponse.success
Else
Success = False
End If
But, I could not figure out how to get the async stuff working and I cannot find anything on what ReCaptchaModel is, so I found another way to call a web service and get a json response and tried this instead:
Dim request As Net.WebRequest = Net.WebRequest.Create("https://www.google.com/recaptcha/")
Dim Data As String = "api/siteverify?secret=My Private Key&response=" + recaptchaResponse
request.Method = "POST"
request.ContentType = "application/json; charset=utf-8"
Dim postData As String = "{""data"":""" + Data + """}"
'get a reference to the request-stream, and write the postData to it
Using s As IO.Stream = request.GetRequestStream()
Using sw As New IO.StreamWriter(s)
sw.Write(postData)
End Using
End Using
'get response-stream, and use a streamReader to read the content
Using s As IO.Stream = request.GetResponse().GetResponseStream()
Using sr As New IO.StreamReader(s)
'decode jsonData with javascript serializer
Dim jsonData = sr.ReadToEnd()
Stop
End Using
End Using
But, this just gives me the content of the web page at https://www.google.com/recaptcha. Not what I want. The Google page isn't very useful and I am stuck on where to go. I need some help either calling the Google verify service or if anyone has found another way to do this from ASP.NET.
I had just about given up when I ran across something unrelated that made me think about it again and in a different way. In my last attempt above, I was attempting to pass the private key and recaptcha response as the data, so I tried it in the create of the WebRequest and it worked. Here is the final solution:
Using the same HTML posted above, I created a function that I can call in the button click event where I check the Page.IsValid and call this function:
Private Function IsGoogleCaptchaValid() As Boolean
Try
Dim recaptchaResponse As String = Request.Form("g-recaptcha-response")
If Not String.IsNullOrEmpty(recaptchaResponse) Then
Dim request As Net.WebRequest = Net.WebRequest.Create("https://www.google.com/recaptcha/api/siteverify?secret=My Private Key&response=" + recaptchaResponse)
request.Method = "POST"
request.ContentType = "application/json; charset=utf-8"
Dim postData As String = ""
'get a reference to the request-stream, and write the postData to it
Using s As IO.Stream = request.GetRequestStream()
Using sw As New IO.StreamWriter(s)
sw.Write(postData)
End Using
End Using
''get response-stream, and use a streamReader to read the content
Using s As IO.Stream = request.GetResponse().GetResponseStream()
Using sr As New IO.StreamReader(s)
'decode jsonData with javascript serializer
Dim jsonData = sr.ReadToEnd()
If jsonData = "{" & vbLf & " ""success"": true" & vbLf & "}" Then
Return True
End If
End Using
End Using
End If
Catch ex As Exception
'Dont show the error
End Try
Return False
End Function
I'm sure there are improvements to be made to the code, but it works. I couldn't see adding references to some JSON libraries for reading one thing I just check the string.
Thank you for sharing this. It worked for me. I went ahead and converted it to C# (since that's what I was using) and added a few things.
I changed the validation step. I split the JSON string and evaluated if success was found where it should be.
I used the ConfigurationManager to store the ReCaptcha Keys.
Finally, I changed it from using a WebRequest to using and HttpClient. This cut the code in half because I don't need to read the stream now.
Feel free to use this code as well.
private static bool IsReCaptchaValid(string response)
{
if (string.IsNullOrWhiteSpace(response))
{
return false;
}
var client = new HttpClient();
string result =
client.GetStringAsync(string.Format("{0}?secret={1}&response={2}", ConfigurationManager.AppSettings["ReCaptchaValidationLink"],
ConfigurationManager.AppSettings["ReCaptchaSecretKey"], response)).Result;
string[] split = result.Split('\"');
return split[1] == "success";
}
I took a slightly different approach, using the data-callback option and a Session parameter. The following sits within the MainContent block of the .aspx file:
<asp:ScriptManager ID="scrEnablePage" EnablePageMethods="true" runat="server" />
<asp:Panel ID="pnlCaptcha" runat="server" Visible="true">
<div class="g-recaptcha"
data-sitekey='<asp:Literal ID="litKey" runat="server" Text="<%$ AppSettings:recaptchaPublicKey%>" />'
data-callback="handleCaptcha"></div>
</asp:Panel>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script type="text/javascript">
function handleCaptcha(e) {
PageMethods.RecaptchaValid(e);
location.reload(true);
}
</script>
Then in the code-behind:
Private Const GoogleUrl As String = "https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}"
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
pnlCaptcha.Visible = Not (Session("VerifiedHuman") = "True")
...
End Sub
<System.Web.Services.WebMethod(EnableSession:=True)> _
Public Shared Sub RecaptchaValid(response As String)
Dim client As New System.Net.WebClient()
Dim outcome As Dictionary(Of String, String)
Dim result As String = String.Join(vbCrLf,
{"{", """success"": true", "}"})
Dim serializer As New System.Web.Script.Serialization.JavaScriptSerializer()
Dim url As String = String.Format(GoogleUrl,
ConfigurationManager.AppSettings.Get("recaptchaPrivateKey"),
response)
Try
result = client.DownloadString(url)
Catch ex As System.Net.WebException
Exit Sub ' Comment out to default to passing
End Try
outcome = serializer.Deserialize(Of Dictionary(Of String, String))(result)
HttpContext.Current.Session("VerifiedHuman") = outcome("success")
End Sub
Now in Page_Load you can check Session("VerifiedHuman") = "True" and update your page controls accordingly, hiding the panel with the Captcha control and showing the other appropriate items.
Note that this takes the keys from Web.config, i.e.
<configuration>
<appSettings>
<add key="recaptchaPublicKey" value="..." />
<add key="recaptchaPrivateKey" value="..." />
...
</appSettings>
...
</configuration>
This adds a few things. It converts the response from Google into a Json object, it adds a timeout on the verification request, and it adds a verification of the hostname (required by Google if sending requests from multiple domains and the domains aren't listed in the Google Admin area).
Imports Newtonsoft.Json
Public Class Google
Public Class ReCaptcha
Private Const secret_key = "YOUR_SECRET_KEY"
Public Shared Function Validate(Request As HttpRequest, hostname As String) As Boolean
Dim g_captcha_response = Request.Form("g-recaptcha-response")
If Not String.IsNullOrEmpty(g_captcha_response) Then
Dim response = ExecuteVerification(g_captcha_response)
If Not response.StartsWith("ERROR:") Then
Dim json_obj = JsonConvert.DeserializeObject(Of ValidateResponse)(response)
If json_obj.success Then
If json_obj.hostname.ToLower = hostname.ToLower Then Return True
End If
End If
End If
Return False
End Function
Private Shared Function ExecuteVerification(g_captcha_response As String) As String
Dim request As Net.WebRequest = Net.WebRequest.Create("https://www.google.com/recaptcha/api/siteverify?secret=" & secret_key & "&response=" & g_captcha_response)
request.Timeout = 5 * 1000 ' 5 Seconds to avoid getting locked up
request.Method = "POST"
request.ContentType = "application/json"
Try
Dim byteArray As Byte() = Encoding.UTF8.GetBytes("")
request.ContentLength = byteArray.Length
Dim dataStream As Stream = request.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
dataStream.Close()
Dim response As Net.WebResponse = request.GetResponse()
dataStream = response.GetResponseStream()
Dim reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
reader.Close()
response.Close()
Return responseFromServer
Catch ex As Exception
Return "ERROR: " & ex.Message
End Try
End Function
Public Class ValidateResponse
Public Property success As Boolean
Public Property challenge_ts As DateTime
Public Property hostname As String
<JsonProperty("error-codes")>
Public Property error_codes As List(Of String)
End Class
End Class
End Class
So in the button's Click event, just call:
If Google.ReCaptcha.Validate(Request, Request.Url.Host) Then
' good to go
Else
' validation failed
End If

Large File Upload Using HttpHandler or HttpModule?

I have a webform application. It required to be able to upload large file (100MB). I intended to use httpHandler and httpModule to split the file to chunk.
I also had a look at http://forums.asp.net/t/55127.aspx
But it is a very old post and I've seen some example on the internet using httpHandler.
e.g. http://silverlightfileupld.codeplex.com/
I'm not sure httpModule is still better then httpHandler.
Since httpModule apples to the request of the whole application, and I just want it apply to specify page.
Can anybody explain the shortcoming of httpHandler for large file upload clearly (if it has)?
If you know a good example without flash/silverlight , could you post the link here? thx
Edit: Would Like to see some Source Code example.
Why not try plupload which has lot of features with many fallbacks and here how it is done.
This is the http handler code:
Imports System
Imports System.IO
Imports System.Web
Public Class upload : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim chunk As Integer = If(context.Request("chunk") IsNot Nothing, Integer.Parse(context.Request("chunk")), 0)
Dim fileName As String = If(context.Request("name") IsNot Nothing, context.Request("name"), String.Empty)
Dim fileUpload As HttpPostedFile = context.Request.Files(0)
Dim uploadPath = context.Server.MapPath("~/uploads")
Using fs = New FileStream(Path.Combine(uploadPath, fileName), If(chunk = 0, FileMode.Create, FileMode.Append))
Dim buffer = New Byte(fileUpload.InputStream.Length - 1) {}
fileUpload.InputStream.Read(buffer, 0, buffer.Length)
fs.Write(buffer, 0, buffer.Length)
End Using
context.Response.ContentType = "text/plain"
context.Response.Write("Success")
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class

Is there any control that take System.Drawing.Image object and view as image?

I return array of images ( System.Drawing.Image[] ) from database and i want to show them in datagrid or datalist .. Can any tell me how to do that ?
If the images are fairly small, you could send them Base64 encoded with the markup of the web page.
Please note: This is only a demonstration in order to show that it is possible to do this, I don't think this should be done on a real web site.
In reality, you should:
consider writing those images to disk and serving them as regular images and with proper caching headers without hitting the database each time.
implement a handler which checks first if the image exists already on disk, and only retrieve it from the db if needed (which will only be the first time a image is asked for).
use url rewriting, and only pass the image urls which do not correspond to a image on disk to the handler. This is faster than passing all request through the ASP.Net pipe. IIRF does that perfectly well.
This said, here's the demonstration with base64 encoded images.
Add a Repeater to your page:
<asp:Repeater ID="ImageRepeater" runat="server">
<ItemTemplate>
<asp:Literal ID="ltImage" runat="server"><img src="data:image/jpg;base64,{0}" alt="" /></asp:Literal>
</ItemTemplate>
</asp:Repeater>
In your codebehind, bind the images to the repeater:
private void BindImages(System.Drawing.Image[] images)
{
this.ImageRepeater.DataSource = images;
this.ImageRepeater.ItemDataBound += delegate(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
System.Drawing.Image img = e.Item.DataItem as System.Drawing.Image;
Literal lt = e.Item.FindControl("ltImage") as Literal;
lt.Text = string.Format(lt.Text, ImageToBase64(img, ImageFormat.Jpeg));
}
};
this.ImageRepeater.DataBind();
}
private string ImageToBase64(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
You may want to disable Viewstate...
Thanks to dailycoding.com and Dean Edwards for code bits.
No, there's no control that does that as far as I know.
Basically what you need to do is add a new Page (or Handler) to your solution, and from that page, you do a Response.BinaryWrite to write the image directly to the response. Then in your main page, you link an image to that new page kind of like <img src="MyImage.aspx?Id=1"/>
These links should provide you a good start.
http://odetocode.com/articles/172.aspx
https://web.archive.org/web/20210304133428/https://www.4guysfromrolla.com/articles/120606-1.aspx

IHttpHandler for images producing a stackoverflow in IE

I have a directory of images that reside outside the context of my web application that I need to serve to the user. Currently I'm using an IHttpHandler to serve the images and using some javascript to navigate through a set of images (the navigation is primitive for now). I followed examples for using IHttpHandler to serve images closely but when I view the images in firefox the browser hangs and when I view in IE I get a "Stack overflow at line: 0".
Code for the IHttpHandler
Public Class ShowImage : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
Dim picid As String
If context.Request.QueryString("id") IsNot Nothing Then
picid = context.Request.QueryString("id")
Else
Throw New ArgumentException("No parameter specified")
End If
'' Convert Byte[] to Bitmap
context.Response.Cache.SetCacheability(HttpCacheability.NoCache)
context.Response.Cache.SetNoStore()
context.Response.Cache.SetExpires(DateTime.MinValue)
Dim newBmp As Bitmap = GetPhoto(picid)
If newBmp IsNot Nothing Then
Dim imgGraphics As Graphics = Graphics.FromImage(newBmp)
imgGraphics.DrawImageUnscaled(newBmp, 0, 0, 640, 480)
context.Response.StatusCode = 200
context.Response.ContentType = "image/jpeg"
newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
newBmp.Dispose()
Else
'' Return 404
context.Response.StatusCode = 404
context.Response.End()
End If
End Sub
...
Public ReadOnly Property IsReusable() As Boolean _
Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class
Here is the javascript code that's calling the IHttpHandler defined above:
function updateImage(){
var ddlPhotos = document.getElementById("ddlPhotos");
var selected = ddlPhotos.options[ddlPhotos.selectedIndex].value;
if( selected != -1 ){
// Update the image
retrievePicture(document.getElementById("propertyImage"), selected)
}
}
function retrievePicture(imgCtrl, picid)
{
imgCtrl.src = 'ShowImage.ashx?id=' + picid;
}
Finally here's the img tag that is the "place holder":
<img src="#"
alt="Property Photo"
width="640px"
height="480px"
id="propertyImage"
onload="retrievePicture(this, '<%= pictureId.value %>');"
/>
I'm confused as to why the javascript seems to spiral out of control...
My guess - not being a JavaScript expert - is that the onload event is triggered any time the image finishes loading. In other words, as soon as the image is loaded, it triggers loading a new one... which triggers loading a new one... which triggers loading a new one etc.
You will probably be able to see that in multiple calls to the server for the same image - unless the browser is caching it, of course. Anyway, you'll either need to trigger it in some other way, or make the trigger detect that the image which has been loaded is already the right one, and there's no need to replace it.
I suspect the act of changing the src and loading a new image may be triggering the "onload" event of the image again.
Try clearing the event before setting the source, will probably look similar to this:
function retrievePicture(imgCtrl, picid)
{
imgCtrl.onload = null;
imgCtrl.src = 'ShowImage.ashx?id=' + picid;
}

Why am I getting this generic, non-descript error in GDI+ when trying to save a PNG?

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?
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.
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.

Resources