How can I get a bitmap into a WebControl?

G

Guest

I have developed a standard .NET control which displays medical images and
works fine in applications, but increasingly, my customers are wishing to use
it in an ASP.NET environment, so I am looking to make a WebControl based
equivalent. [If I'm missing something important, and there is a way to use
my "normal" control, then please stop me at this point and tell me how!]

So, assuming that I need to render using HTML - how can I pass "bitmap" data
into such a control for it to be displayed. I'm open to all possible routes,
but I've not yet found one which works. Ideas I have considered include:

1) Putting the data into an <Object> - base 64 encoded, and referencing from
a standard <IMG> tag. I'm told that this works in other browsers, but it not
supported by IE, which most of my customers use.

2) making a huge "table" to specify the image as one pixel = one cell.
Obviously it would work, but would be huge!

3) Using a standard IMG tag, and somehow referencing the control through a
special URL which would cause the control to return the required bitmap as
JPG, BMP etc. This should be the best (I guess) but I have no idea how to
wire the IMG and the supporting service, especially in a way which will be
transparent to my users!

IS there are way to do this, or is it a glaing hole in the whole
"CodeBehind" scheme?
 
L

Laurent Bugnion

Hi,

Dave said:
I have developed a standard .NET control which displays medical images and
works fine in applications, but increasingly, my customers are wishing to use
it in an ASP.NET environment, so I am looking to make a WebControl based
equivalent. [If I'm missing something important, and there is a way to use
my "normal" control, then please stop me at this point and tell me how!]

There is a way to add winforms controls into web pages, but it works
only in very specific conditions (IE on Windows, and IIRC the framework
must be installed on the client) and I recommend against it.
So, assuming that I need to render using HTML - how can I pass "bitmap" data
into such a control for it to be displayed. I'm open to all possible routes,
but I've not yet found one which works. Ideas I have considered include:

1) Putting the data into an <Object> - base 64 encoded, and referencing from
a standard <IMG> tag. I'm told that this works in other browsers, but it not
supported by IE, which most of my customers use.

2) making a huge "table" to specify the image as one pixel = one cell.
Obviously it would work, but would be huge!

3) Using a standard IMG tag, and somehow referencing the control through a
special URL which would cause the control to return the required bitmap as
JPG, BMP etc. This should be the best (I guess) but I have no idea how to
wire the IMG and the supporting service, especially in a way which will be
transparent to my users!

I would use something like that:

<img src="somepage.aspx?image=hello.bmp" />

This is only an example. There are other ways to do that (for example
using HttpModules) and avoiding to have a page. However, for a starter,
this way is easier.

On the server, create a Page named somepage.aspx. Then, when a request
arrives, you can use the Request.QueryString collection to read the
parameter named "image" (in this case it's called hello.bmp). Of course,
you can have other values for example the whole path of the image to
render, if it exists on the server), or any parameter allowing your
server-side code to render the image dynamically.

Once you know how the image looks like, you can write an image to the
Response.

The example hereunder reads an image existing on the server, and creates
a thumbnail (a smaller view) of the image dynamically. I think that you
can use that as an example. In your case, instead of creating the
thumbnail, you can
IS there are way to do this, or is it a glaing hole in the whole
"CodeBehind" scheme?

The only limit to CodeBehind is imagination ;-)

Example of thumbnail:

// In OnInit, check if the page must render itself,
// or only the thumbnail

if ( Request.QueryString != null
&& Request.QueryString[ ID_QUERY_THUMBNAIL ] != null )
{
m_eAction = EAction.eRenderThubnail;

// thumbnails is of type CThumbnailMaker, responsible to produce
// thumbnails.
thumbnails.RenderThumbnail( this,
Request.QueryString[ ID_QUERY_THUMBNAIL ] );

return;
}

// Note: If m_eAction is set to EAction.eRenderThumbnail,
// the page must not be rendered. --> In Render:

protected override void Render( HtmlTextWriter writer )
{
if ( m_eAction != EAction.eRenderThubnail )
{
// Render the page normally
base.Render( writer );
}
}

In the thumbnails class, render the thumbnail:

public void RenderThumbnail( Page oPage,
string strUrlFileName )
{
oPage.Response.ContentType = "image/jpeg";

try
{
RenderThumbnail( oPage.Response.OutputStream,
strUrlFileName );
oPage.Response.StatusCode = 200;
}
catch ( Exception )
{
// Return a file not found code
oPage.Response.StatusCode = 404;
}
}

with:

// I separate these two methods because the last one is
// generic, rendering to any outputstream, not just
// to a System.Web.UI Page class.
private void RenderThumbnail( Stream streamOutput,
string strUrlFileName )
{
string strPath = Context.Request.MapPath( strUrlFileName );
if ( !File.Exists( strPath ) )
{
throw new FileNotFoundException( "Picture not found: " + strPath );
}

Bitmap bmpOriginal = new Bitmap( strPath );

// Calculate the thumbnail's new size. The property m_iMaxSize
// determine the maximum width, resp. height, for example 120 pixels.
int iNewHeight = m_iMaxSize;
float fRate = (float) iNewHeight / (float) bmpOriginal.Height;
int iNewWidth = (int) Math.Round( (float) bmpOriginal.Width * fRate );
if ( iNewWidth > m_iMaxSize )
{
iNewWidth = m_iMaxSize;
fRate = (float) iNewWidth / (float) bmpOriginal.Width;
iNewHeight = (int) Math.Round( (float) bmpOriginal.Height * fRate );
}

Bitmap bmpNew = new Bitmap( bmpOriginal, iNewWidth, iNewHeight );

bmpNew.Save( streamOutput, bmpOriginal.RawFormat );
bmpOriginal.Dispose();
bmpOriginal = null;
}

Don't forget to Dispose() the bitmap, or else the file will be blocked
by the process.

To use this, I have one page thumbnails.aspx, which displays all
pictures in a folder thumbnailed in a table. The thumbnails don't exist
on the server, they're created dynamically. See it work here:

About this page, two things: The rendering takes more time than with a
standard call to an image existing on the server, because all thumbnails
calls go through one single class, and because they're rendered
dynamically instead of just "read". Also, the thumbnails quality is less
good than when I use a dedicated program to create "static" thumbnails.

HTH,
Laurent
 
G

Guest

Laurent,

Thanks for the reply - I had guessed that I could do something like this,
but you reply does raise 2 further questions:

1) If I use the something.aspx method, I would need to call a method on the
originating viewer to get the required (dynamically created) bitmap
information......how would I be able to pass and use sufficient information
to tie the something.aspx and the originating control together?

2) Given that I need to make this easy for other developers to use my
control, I don't really wish to make them have to add extra .aspx files to
the project, and link them back to my control (they would rightly consider
that part of what my control should be doing!) I would therefore be very
interested to hear more of your suggestion to do it "without a page".

Note that I need to render exactly what my control would have been showing
as a Windows control - toally dynamically generated - so references to
existing BMP files etc. are not auitable!
 
L

Laurent Bugnion

Hi,

Dave said:
Laurent,

Thanks for the reply - I had guessed that I could do something like this,
but you reply does raise 2 further questions:

1) If I use the something.aspx method, I would need to call a method on the
originating viewer to get the required (dynamically created) bitmap
information......how would I be able to pass and use sufficient information
to tie the something.aspx and the originating control together?

I am not aware of what the original control does exactly. But anyway, if
you have this control in a DLL and reference this DLL in your web
application, you can call public methods in the control directly.

Note that a better approach would be to export the image creating logic
in its own layer (and possibly its own DLL too), and so to reference
only this layer from the web application and from the WinForms control.

Since the call to the external DLL happens within the bounds of .NET,
you can pass a Bitmap object directly as a result of your method.

In short:

A (new) DLL presents a method, for example
public Bitmap CreateImage( ... )
{
// ...
}

In your WinForms control, reference this DLL and call the public method.
In your web application, reference this DLL and call the public method.

2) Given that I need to make this easy for other developers to use my
control, I don't really wish to make them have to add extra .aspx files to
the project, and link them back to my control (they would rightly consider
that part of what my control should be doing!) I would therefore be very
interested to hear more of your suggestion to do it "without a page".

Similarly to WinForms controls, you can also create controls for web
applications. In your case, it would probably be the best approach,
since you want to have the same approach as on Windows.

There are two major types of controls in ASP.NET: User controls (ASCX)
and custom controls. I personally prefer custom controls, because they
don't have the ASCX file to "drag along", but it's a question of preference.

If you want to pack a web "solution" in your WinForms control, you could
for example add a class in the WinForms DLL and derive it from
System.Web.UI.Control. This will make it accessible from a web application.

It's a bit difficult to explain in a post like this. If you want, I can
make a small example of what I mean, a DLL containing a WinForms user
control, a Web custom control, some Business logic method behind that,
and the way to integrate this into a WinForms application and a Web
application. Tell me if that would be helpful.
Note that I need to render exactly what my control would have been showing
as a Windows control - toally dynamically generated - so references to
existing BMP files etc. are not auitable!

I showed you how to integrate dynamically generated bitmaps into an IMG
tag, I think it's the best approach for your problem.

HTH,
Laurent
 
O

Otis Mukinfus

I have developed a standard .NET control which displays medical images and
works fine in applications, but increasingly, my customers are wishing to use
it in an ASP.NET environment, so I am looking to make a WebControl based
equivalent. [If I'm missing something important, and there is a way to use
my "normal" control, then please stop me at this point and tell me how!]

So, assuming that I need to render using HTML - how can I pass "bitmap" data
into such a control for it to be displayed. I'm open to all possible routes,
but I've not yet found one which works. Ideas I have considered include:

1) Putting the data into an <Object> - base 64 encoded, and referencing from
a standard <IMG> tag. I'm told that this works in other browsers, but it not
supported by IE, which most of my customers use.

2) making a huge "table" to specify the image as one pixel = one cell.
Obviously it would work, but would be huge!

3) Using a standard IMG tag, and somehow referencing the control through a
special URL which would cause the control to return the required bitmap as
JPG, BMP etc. This should be the best (I guess) but I have no idea how to
wire the IMG and the supporting service, especially in a way which will be
transparent to my users!

IS there are way to do this, or is it a glaing hole in the whole
"CodeBehind" scheme?

If you are just wanting to create a dynamic image and use it on the web you can
draw it with the GDI in the code behind and save it to an image file and then
load it into an image control on the page or control you are creating. I
suspect you are drawing it with the GDI anyway, so all you need to do
differently is save it and then load it.

Did I misunderstand your question?
Good luck with your project,

Otis Mukinfus
http://www.arltex.com
http://www.tomchilders.com
 
W

Walter Wang [MSFT]

Hi Dave,

Based on my understanding, your situation is:
1) You currently have a WinForm control that can show image which is
dynamically generated on the fly;
2) You want to create a Web control that can also do the same thing;
3) Also, you don't want to create a WebForm to generate the image;
If I've misunderstood anything, please feel free to post here.

I suppose you already have working code that generates the image on the fly
which I also assume it's something like a Bitmap object. A Bitmap object
can save to a MemoryStream which again can write to ASP.NET Response
directly; for example:

Bitmap bitmap = <your code to generate the image on the fly>;
MemoryStream ms = new MemoryStream();
Response.Clear();
Response.ContentType = "image/jpeg";
bitmap.Save(ms, ImageFormat.Jpeg);
ms.WriteTo(Response.OutputStream);

Next, we need to create a ASP.NET custom control which takes some
properties and generate a resource url which uses a custom http handler to
generate the image:

public class MyDynamicImage: System.Web.UI.WebControls.Image
{

protected override void OnPreRender(EventArgs e)
{
...
ImageUrl = String.Format("~/__ImageGrabber.axd?p1={0}&p2={1}",
...);
}
}

The __ImageGrabber.axd is a custom http handler which is configured in
web.config like this:

<configuration>
<system.web>
<httpHandlers>
<add verb="GET" path="__ImageGrabber.axd"
type="MsdnMag.ImageGrabber" />
</httpHandlers>
</system.web>
</configuration>

The type MsdnMag.ImageGrabber is derived from IHttpHandler:

namespace MsdnMag
{
public class ImageGrabber : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
...
}
}
}

Then in your ASP.NET WebForm, just use the MyDynamicImage control and pass
required properties to generate different images.

For more complete code listing, please refer to following MSDN Magazine
article:

#Wicked Code: Power Programming Tips for ASP.NET 2.0
http://msdn.microsoft.com/msdnmag/issues/05/06/WickedCode/

Search the section named "Fetching Images from DataBases."

I hope this helps. Please feel free to post here if anything is unclear.

Sincerely,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express, please make sure you clear the
check box "Tools/Options/Read: Get 300 headers at a time" to see your reply
promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Walter Wang [MSFT]

Hi Dave,

I am interested in this issue. Would you mind letting me know the result of
the suggestions? If you need further assistance, feel free to let me know.
I will be more than happy to be of assistance.

Have a great day!

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 

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,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top