**BUG** Loading Images from Stream into aspx-Webform

D

Detlef Hüttenbach

Whereas loading tiffs and pngs from file into an Image WebControl work, the
images aren't shown when loaded from streams:

In a WebForm, the image's property "ImageUrl" is set to a handler, and this
handler gets the image from a database.
Please check the various image formats. (The images are stored in a SQL
database as Image type.)
I post you a demo HTTP handler below.
I guess, it's the ViewState which messes up (in Windows Forms I don't have
any problems to load the images from stream.)

Please, have a look at it.
Best wishes
Detlef
---------------Demo Handler Code --------------------------
<%@ WebHandler Language="C#" Class="PicViewer" %>

using System;

using System.Web;

using System.Drawing;

using System.Drawing.Imaging;

using System.Data;

using System.Data.SqlClient;

using System.IO;

using System.ComponentModel;

public class PicViewer : IHttpHandler

{

public void ProcessRequest(HttpContext context)

{

System.Data.SqlClient.SqlConnection sqlConnInvoice;

Graphics g;

Bitmap bmp;

MemoryStream bmpStream;

Image _img;

MemoryStream memStream;

byte[] _picBytes;

//Get PicBytes, in this case Png Data, where PngPic is a

//SQL-DataField of SQL format Image

conn = new System.Data.SqlClient.SqlConnection();

conn.ConnectionString = "...yerkyerk...";

sqlConnInvoice.Open();

System.Data.SqlClient.SqlCommand _cmdLoadPicture =

new System.Data.SqlClient.SqlCommand("select PngPic from PngPictures where
PicID=52531;",conn);

SqlDataReader drReader = _cmdLoadPicture.ExecuteReader();

drReader.Read();

_picBytes=(byte[])drReader.GetSqlBinary(0);

//Push data to Memory Stream

memStream = new MemoryStream();

memStream.Write(_picBytes,0,_picBytes.Length);

//Commented to follow a more general route:

//Make a Bitmap, print image into it and save

//it into another standard format, here *.gif,

//but could be any other

/*

//Construct image to push into response stream

_img=Image.FromStream(memStream,true);

*/

//Read image size

float _height = Image.FromStream(memStream).PhysicalDimension.Height;

float _width = Image.FromStream(memStream).PhysicalDimension.Width;

//new Bitmap - adapt size if necessary:

bmp = new Bitmap(Image.FromStream(memStream), new Size((int)_width,
(int)_height));

g = Graphics.FromImage (bmp);

//Draw on Bitmap

g.DrawImage(_img,0,0);

memStream.Close();

conn.Close();

/*

context.Response.ContentType = "image/gif";

//Save _img into Reponse stream - try other format

_img.Save(context.Response.OutputStream,ImageFormat.Gif);

*/

//Save bmp into Reponse stream

context.Response.ContentType="image/gif";

bmp.Save(context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Gif);

bmp.Dispose();

g.Dispose();

}

public bool IsReusable

{

get { return true; }

}

}
 
D

Detlef Hüttenbach

Replacement error:

Please change the line
System.Data.SqlClient.SqlConnection sqlConnInvoice;
into
System.Data.SqlClient.SqlConnection conn;

Thanks
Detlef
 
D

Detlef Hüttenbach

Sorry, there were still two replacement errors, so that's
the handler:
---------Handler----------
<%@ WebHandler Language="C#" Class="PicViewer" %>

using System;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.ComponentModel;

public void ProcessRequest(HttpContext context)
{
System.Data.SqlClient.SqlConnection conn;
Graphics g;
Bitmap bmp;
MemoryStream bmpStream;
Image _img;
MemoryStream memStream;
byte[] _picBytes;

//Get PicBytes, in this case Png Data, where PngPic is a
//SQL-DataField of SQL format Image
conn = new System.Data.SqlClient.SqlConnection();
conn.ConnectionString = "...yerkyerk...";
conn.Open();
System.Data.SqlClient.SqlCommand _cmdLoadPicture =
new System.Data.SqlClient.SqlCommand("select PngPic from PngPictures
where PicID=52531;",conn);
SqlDataReader drReader = _cmdLoadPicture.ExecuteReader();
drReader.Read();
_picBytes=(byte[])drReader.GetSqlBinary(0);
//Push data to Memory Stream
memStream = new MemoryStream();
memStream.Write(_picBytes,0,_picBytes.Length);

//Commented to follow a more general route:
//Make a Bitmap, print image into it and save
//it into another standard format, here *.gif,
//but could be any other
/*
//Construct image to push into response stream
_img=Image.FromStream(memStream,true);
*/

//Read image size
float _height = Image.FromStream(memStream).PhysicalDimension.Height;
float _width = Image.FromStream(memStream).PhysicalDimension.Width;

//new Bitmap - adapt size if necessary:
bmp = new Bitmap(Image.FromStream(memStream), new Size((int)_width,
(int)_height));
g = Graphics.FromImage (bmp);

//Draw on Bitmap
g.DrawImage(bmp,0,0);
memStream.Close();
conn.Close();

/*
context.Response.ContentType = "image/gif";
//Save _img into Reponse stream - try other format
_img.Save(context.Response.OutputStream,ImageFormat.Gif);
*/

//Save bmp into Reponse stream
context.Response.ContentType="image/gif";
bmp.Save(context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Gif);
bmp.Dispose();
g.Dispose();
}

public bool IsReusable
{
get { return true; }
}
}
 
S

Shiv Kumar

First of all, I'd suggest you make a simple test case (that anyone interested in helping you can compile and run on their machines) that shows the same problem rather than giving us a boot load of code can't be run anywhere else :). This is just from years of being involved in newsgroups and helping others and being helped.

Secondly, have you tried writing to the OutputStream directly (instead of Save)

System.IO.Stream stream = Response.OutputStream;

stream can now be used

I should say that I have been doing this kind of thing but haven't encountered any problems. Are you saying this problem exists only for tiff and png and not for others?
 
H

Hermit Dave

okay i have used handler to fetch and output images from db... and i did
encounter a very stranger error
if i directly load the image onto a stream.. read it to a Image object and
use Image.Save... it used to output error which was invalid parameters of
something like that.
but on the same image i would essentially use img.GetThumbnail (cant
remember the full name) and i could output the resulting imgThumb using
imgThumb.Save(Response.OutputStream,Imagetyupe...)

to get over it loading the byte[] into stream and writing it to output
stream.. i just passed additional param saying whether i needed thumbnail...
if not then i just use Response.BinaryWrite(bytearray)
if its thumbnail then create the thumbnail and then
imgThumb.Save(Response.OutputStream, ImageType)
if posting my code would help then give me a shout..

--

Regards,

HD
Detlef Hüttenbach said:
Sorry, there were still two replacement errors, so that's
the handler:
---------Handler----------
<%@ WebHandler Language="C#" Class="PicViewer" %>

using System;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.ComponentModel;

public void ProcessRequest(HttpContext context)
{
System.Data.SqlClient.SqlConnection conn;
Graphics g;
Bitmap bmp;
MemoryStream bmpStream;
Image _img;
MemoryStream memStream;
byte[] _picBytes;

//Get PicBytes, in this case Png Data, where PngPic is a
//SQL-DataField of SQL format Image
conn = new System.Data.SqlClient.SqlConnection();
conn.ConnectionString = "...yerkyerk...";
conn.Open();
System.Data.SqlClient.SqlCommand _cmdLoadPicture =
new System.Data.SqlClient.SqlCommand("select PngPic from PngPictures
where PicID=52531;",conn);
SqlDataReader drReader = _cmdLoadPicture.ExecuteReader();
drReader.Read();
_picBytes=(byte[])drReader.GetSqlBinary(0);
//Push data to Memory Stream
memStream = new MemoryStream();
memStream.Write(_picBytes,0,_picBytes.Length);

//Commented to follow a more general route:
//Make a Bitmap, print image into it and save
//it into another standard format, here *.gif,
//but could be any other
/*
//Construct image to push into response stream
_img=Image.FromStream(memStream,true);
*/

//Read image size
float _height = Image.FromStream(memStream).PhysicalDimension.Height;
float _width = Image.FromStream(memStream).PhysicalDimension.Width;

//new Bitmap - adapt size if necessary:
bmp = new Bitmap(Image.FromStream(memStream), new Size((int)_width,
(int)_height));
g = Graphics.FromImage (bmp);

//Draw on Bitmap
g.DrawImage(bmp,0,0);
memStream.Close();
conn.Close();

/*
context.Response.ContentType = "image/gif";
//Save _img into Reponse stream - try other format
_img.Save(context.Response.OutputStream,ImageFormat.Gif);
*/

//Save bmp into Reponse stream
context.Response.ContentType="image/gif";
bmp.Save(context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Gif);
bmp.Dispose();
g.Dispose();
}

public bool IsReusable
{
get { return true; }
}
}
 
?

=?iso-8859-1?Q?Detlef_H=FCttenbach?=

Hi Shiv,

thanks for your answer. I posted a reply this morning from work, but that didn't show up until now fro my home site.
Yes, I do have a tiny demo here at home, and the large db at work I can't even script let alone publish even for parts.
What do you mean by "save indirectly"? I posted this morning a snippet by which that stream is wrapped by yet another one before it is pushed into the Response OutputStream. That doesn't work either. If you mean by "save" to save the stream onto the disk and then to open the file: yes, this does work, but that's not what I wanted.
As to your question whether the problem only held for tiffs and pngs: I could swear I had some code working for gifs at work, but today did not find it. Right here at home, the code that I here, does to my dismay not work for gifs either.
Hermit above kindly pointed out that the Thumbnail could be a great option. I'll try that. If not this night, then tomorrow and keep you informed.

Thanks for your input
Detlef

First of all, I'd suggest you make a simple test case (that anyone interested in helping you can compile and run on their machines) that shows the same problem rather than giving us a boot load of code can't be run anywhere else :). This is just from years of being involved in newsgroups and helping others and being helped.

Secondly, have you tried writing to the OutputStream directly (instead of Save)

System.IO.Stream stream = Response.OutputStream;

stream can now be used

I should say that I have been doing this kind of thing but haven't encountered any problems. Are you saying this problem exists only for tiff and png and not for others?
 
D

Detlef Hüttenbach

Hi Hermit,

thank you for your great response. Thumbnails are indeed what I didn't
try out and a great idea to try!
If not this night, I'll try out tomorrow and post you the outcome.

Thanks again
Detlef
 
D

Detlef Hüttenbach

Hi Hermit,

Thumbnails didn't work either.
Used the code below.

Thanks for response
Detlef
---Code:---

SqlDataReader drReader = _cmdLoadPicture.ExecuteReader();
drReader.Read();
_picBytes=(byte[])drReader.GetSqlBinary(0);
memStream = new MemoryStream();
memStream.Write(_picBytes,0,_picBytes.Length);

_img=Image.FromStream(memStream,true);

_height = Image.FromStream(memStream).PhysicalDimension.Height;
_width = Image.FromStream(memStream).PhysicalDimension.Width;

bmp = new Bitmap(Image.FromStream(memStream), new Size((int)_width,
(int)_height));
g = Graphics.FromImage (bmp);

Image.GetThumbnailImageAbort _cb =
new Image.GetThumbnailImageAbort(ThumbnailCallback);

_Thumb = _img.GetThumbnailImage((int)_width, (int)_height, _cb,
IntPtr.Zero);
g.DrawImage(_Thumb, 0, 0);

memStream.Close();
conn.Close();
context.Response.ContentType = "image/gif";

bmp.Save(context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Gif);
bmp.Dispose();
g.Dispose();
 
?

=?iso-8859-1?Q?Detlef_H=FCttenbach?=

Hi Shiv,

Thumbnails didn't work either.
(see posting under hermit above.)

Thanks
Detlef
 
S

Shiv Kumar

Your code is not really the best code to use :)

For starters I should say that I have done what you are attempting to do and
it works as expected. I use jpeg and gif image formats (have no need for
png).

Unless I've missed something in your code, all you're doing is getting a
byte[] from your database and then making a thumbnail out of your byte[].

Is that correct? If so then given a byte[] all you need to do is:

System.Drawing.Image img = System.Drawing.Image.FromStream(new
MemoryStream(bytes));
System.Drawing.Image thumbnail;

System.IntPtr ptr = new IntPtr();

thumbnail = img.GetThumbnailImage(width, height, null, ptr);

//stream is Response.OutputStream

thumbnail.Save(stream, img.RawFormat);

thumbnail.Dispose();

img.Dispose();
 
D

Detlef Hüttenbach

Hi Shiv,
Shiv Kumar said:
Your code is not really the best code to use :)
I gave up writing the best clean code, when I need to change it all the time
just to see that it works.
Unless I've missed something in your code, all you're doing is getting a
byte[] from your database and then making a thumbnail out of your byte[].
Is that correct?
Yes. But: how, when if: I want to get the code work!
If so then given a byte[] all you need to do is:
System.Drawing.Image img = System.Drawing.Image.FromStream(new
MemoryStream(bytes));
System.Drawing.Image thumbnail;

System.IntPtr ptr = new IntPtr();

thumbnail = img.GetThumbnailImage(width, height, null, ptr);

//stream is Response.OutputStream

thumbnail.Save(stream, img.RawFormat);

thumbnail.Dispose();

img.Dispose();
Did that: does not work. There could still be some hope when picking certain
palettes and trying out.. But the fact that ViewState on the client side
stores a 2 line
hash for images of 100-500k doesn't convince me that piddling with palettes
will be useful doing.
If that's not a Framework bug, at least MS should publish about that
curiosity and give us
a workaround. Something strange happens to GDI+ within ASP.NET.

Thanks

Detlef
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top