I'm creating a regular gallery in ASP.NET but I have little experiences with creation of thumbnails. I know the algorithms and the GetThumbnailImage method, but my problem is somewhere else - I'm currently displaying the images (just resized) using the ImageButton control. And that's the point - I have no idea how to hook up the "thumbnailed" image to the ImageUrl property. Is it even possible and if yes, how? Or should I use some other control instead? Thanks for any suggestions!
It sounds like you need to set up an HttpHandler, which would create the resized image and probably cache it to disk as well, to save having to recreate the thumbnail on each request.
So, for example:
<asp:ImageButton ID="ImageButton1" ImageUrl="~/ImageHandler.ashx?ImageId=123" runat="server />
You would then have a handler:
namespace MyProject
{
public class ImageHandler : IHttpHandler
{
public virtual void ProcessRequest(HttpContext context)
{
// 1. Get querystring parameter
// 2. Check if resized image is in cache
// 3. If not, create it and cache to disk
// 5. Send the image
// Example Below
// -------------
// Get ID from querystring
string id = context.Request.QueryString.Get("ImageId");
// Construct path to cached thumbnail file
string path = context.Server.MapPath("~/ImageCache/" + id + ".jpg");
// Create the file if it doesn't exist already
if (!File.Exists(path))
CreateThumbnailImage(id);
// Set content-type, content-length, etc headers
// Send the file
Response.TransmitFile(path);
}
public virtual bool IsReusable
{
get { return true; }
}
}
}
You'd also need to set this up in web.config
<system.web>
<httpHandlers>
<add verb="*" path="ImageHandler.ashx" type="MyProject.ImageHandler, MyProject"/>
</httpHandlers>
</system.web>
This should be enough to get you started. You'll need to modify the ProcessRequest method to create the thumbnail, but you mentioned having taken care of this already. You'll also need to make sure that you set the headers correctly when transmitting the file to the browser.
You can create a HttpHandler which handles image requests and returns thumbnails (or does whatever you need on the images).
Whenever you do graphics stuff in ASP.NET, keep in mind that almost all of System.Drawing is a wrapper for GDI+ and thetrefore holds references to unmanaged memory which needs to be disposed properly (use the using statement). This holds true even for simple classes like StringFormat etc.
Http Handler is the way to go.
Another note on performance: manipulating images is expensive relative to disk space, both from a memory and cpu standpoint. Therefore generating the thumbnail from a full image is is something you only want to do once for each full image. The best time to do it is probably at the time where the image is uploaded, especially if you will be showing a number of these on the same page.
Related
In xamarin forms we can create images like this:
Image i = new Image { Source = "http://www.foo.com/foo.jpg };
After adding this to layout if url returns an image it will display it. What I want to now is is there a way to know if ths Url is an actual image. Otherwise I am going to show an default image.
Regards.
Edit
I have created a function:
public string GetImageSourceOrDefault(string orgUrl)
{
var req = (HttpWebRequest)WebRequest.Create(orgUrl);
req.Method = "HEAD";
try
{
using (var resp = req.GetResponse())
{
bool res = resp.ContentType.ToLower(CultureInfo.InvariantCulture)
.StartsWith("image/");
if (res)
return orgUrl;
else
return "defualt_logo.jpg";
}
}
catch
{
return "default_logo.jpg";
}
}
This function does the trick. However, for every image it does a request. I have a listview which shows like 220 entries. Using this method messed up the time that listview gets loaded.
Note: this function is natively called using dependency injection.
Maybe further improvements will do. Any ideas?
FFImageLoading CachedImage supports Loading and Error Placeholders (and much more). It's basically a API compatible replacement for Image with additional properties. You could try that.
var cachedImage = new CachedImage() {
LoadingPlaceholder = "Loading.png",
ErrorPlaceholder = "Error.png"
};
https://github.com/molinch/FFImageLoading
With Xamarin.Forms UriImageSource you can specify different caching length, and whether caching is used by using the properties CacheValidity and CachingEnabled.
By default it will automatically cache results for 1 day on the local storage of the device.
In your function, as you mention, you are downloading the image every single time.
You have no current functionality that is storing and caching the result for later re-use.
By implementing something like this on the platform specific layer would get around your current solution of re-downloading the image every single time.
Alternatively as a workaround, if you didn't want to implement the above, you could try putting two Image controls stacked upon each other, maybe in a Grid, with the bottom image showing a default placeholder image, and on-top another Image control that would show the intended image, if successfully downloaded, using the UriImageSource.
You could also possibly hook hook into the PropertyChange notification of the Image.Source and detect it being set, with the image then being displayed. Upon detection you could then release the image from the temporary place holder Image control perhaps?
I've written a custom httphandler for DocX files, and I'm trying to have the files be displayed through an iframe.
Here's my controller:
public ActionResult LoadDOC(string path)
{
var fsSource = new FileStream(path, FileMode.Open, FileAccess.Read);
return new FileStreamResult(fsSource, "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
{
FileDownloadName = "newfile.docx"
};
}
}
The file name needs to be changed so that the httphandler can pick it up. The files reside on the fileserver without extensions (they're renamed to a guid).
For example:
"\\\\fileservername\\Documents\\811943a3-56f7-42cb-8450-1b8319a426b4\\633d9f3e-df99-408e-b59c-ec8efa4fa41f"
I can't change the way the files reside on the server, I'll have to add the extension through code.
When the above is executed in an iframe, the file is immediately downloaded. PDF files and text files render properly however.
Here is the custom httphandler:
<add name="DOCXhandler" path="*.docx" verb="GET" type="MyProject.Handlers.DocxHandler, MyProject" preCondition="integratedMode" />
How can I go about either changing the file stream extension using this approach, or another approach to perhaps achieve the desired result of the file displayed in an iframe?
Is it possible to just change the handler by content type?
Edit: Question for clarity;
Is it possible to make an http handler work by content type, instead of file extension?
How can I make sure the filestreamresult uses my custom httphandler for .docx files when displaying in the iframe?
Am I going about this the correct way, or am I missing something?
Consider adding ".docx" extension to rendered Url to the file and than removing it your LoadDoc action (i.e. cheap hack - path = path.Replace(".docx", ""), prefer using methods from Path class to do that manipulation).
Side note: exposing server side file path is generally bad idea from security point of view.
I actually was going about the issue very poorly.
I changed the way the controller set the iframe to an actual dummy file path:
for example: "localhost/Project/12345_6789.docx" where 12345 is the group identifier, and 6789 is the document identifier.
The httphandler I made expects these, and changes the file path to:
"////fileserverpath/documentspath/12345/6789"
I'm no longer streaming the file directly through the controller, but instead through my handler for the request.
Hope this helps someone out there!
There are so many good tutorials out there about inserting an image inside a table in a database, using the FileUpload controller.
Yet I cannot find a good tutorial about how to fetch these images and display them.
When I used to store the image name or path in the database (as a Varchar), It would be very simple by doing something like this...
HTML/ASP:
<img src="" runat="server" id="myImage" />
C#:
myImage.Src = myReader.getValue(0).toString();
The Result:
<img src="/Images/pic.png" runat="server" id="myImage" />
And Voila, the picture will be displayed.
But Now I would like to fetch uploaded images, not a path, means the type of the table column is IMAGE.
Some tutorials will eventually lead to display a picture in FULL SCREEN.
I do not want that, I simply want to fetch and display the image the same way it is displayed in the previous example, with a given size and place inside my web page.
Why am I uploading images to the database? Because these images are "Profile Pictures", not public pictures, I do not want a guest to simply browse for /Images/ to find all the pictures of my web site, public and private.
First of all, to do what you want, I would just copy the file to a temporary location and use that location for the "src" attribute. Later, you could delete the file. The much more complicated way is to create an aspx page that writes the image to the webpage as a binary stream. This page would grab the image from the database and just write the stream out in the response. You would then use this aspx page in the src attribute of your image. However, storing the image path in the database and actual file on the file system doesn't mean that the folder has to be browse-able or public. You can turn directory browsing off for example.
Create a custom IHttpHandler implementation that can serve your images from your database. You could, for example, get the bytes into a stream and copy that stream to the output of the web response.
Here is a simple example:
public class MyImageHandler : IHttpHandler
{
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext ctx)
{
Stream yourStream = ...; // This is where you get your data from your database
ctx.Response.ContentType = "image/jpeg";
yourStream.CopyTo(ctx.Response.OutputStream);
}
}
Then you need to configure it to respond to the URLs you wish.
You could either use the Web.config file to do this
Or create an .ashx file and have it point to your own HTTP handler
If you have any questions about it, just write a comment.
You will need an aspx page reading the image from the database and returning the raw bytes.
Here's a quick sketch how to do this:
byte[] data = (byte[])myReader.getValue(0);
Response.ContentType = "image/jpeg"; //or whatever your used image type is
Response.OutputStream.Write(data, 0, data.Length);
Response.End();
An alternative would be to implement a custom HttpHandler for this.
The other part is "calling" this page from your img tags with a parameter specifying the image id:
myImage.Src = "/image.aspx?id=" + myReader.getValue(0).toString();
I'm so stuck on something i thought would be easy.
I have a DLL that returns an Image object.
I just cant figure out how to display that image on a webpage.
I've tried a few ways, and google a million different variations.
Is it not possible to just bind an Image object to an element on the page like an HtmlImage or a simple img?
Or do i need to convert the Image to a Stream? or a Bitmap? I'm really stuck!
Any help appreciated.....
V
With Asp.Net WebForm, the easiest way is to create a custom ashx file.
In Visual Studio, create a new Custom Handler (I'm not sure of the name of the template in Visual Studio). This will create a .ashx file.
In the code of this handler, write something like (does not have VS under the hand to test the syntax) :
public void ProcessRequest(System.Web.HttpContext context)
{
byte[] raw;
using(var ms = new MemoryStream()){
Image myImage = GetFromDll();
myImage.Save(ms, ImageFormat.Png);
raw=ms.ToArray();
}
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(raw);
}
Then, in your browser, navigate to http://yourserver/app/yourhandler.ashx.
You can if you want add url parameter, and get it from the Request.QueryString collection
It's not as simple as binding. On the client side images are retrieved from the web server as a separate GET request, which means you have to have a URL that resolves to an image. The other option, as Asif suggested, is embedding your image in the HTML as a Base64 string, which is bad practice for shared images (see Steve B's comment).
You either have to provide an URL (route that returns the image file in MVC, or a custom page with proper content type and Response.Write in WebForms), or embed in html.
EDIT:
There is also a third option involving custom HTTP handlers. These have the advantage of bypassing the app framework and serving the content almost directly off the web server, see MSDN.
Convert your image to base64 string and then set it in the <img/> tag.
<img/> can show the image in base64 string.
Alternatively you can save the image and use the path in the <img/>.
how do external counter track unique visitors via image
i'd also like to get Referrer if possible.
something like img="http://www.somecounterdomain.com/count.php?page=83599"
i'm using ASP.NET, c#
i'm aware of a user can "cheat" but would like to make that posibility minimal.
additional difficulty is that i should trach external server and can't implement c# code there.
what i can is only imlement a counter imag or smth like that.
i try to use generated image.
thx for answers.
Basically what you need to do is the following.
1- Create either a .ashx or .aspx. Assuming you go with .aspx and call it StatServer.aspx, the Page_Load function will read the query string and write the data to a database, you will see the querystring in step 2. If you want, you can return a image which can be rendered. Some rough code will look something like this.
private void Page_Load(object sender, EventArgs e)
{
WriteQueryStringInformationToDB(Request.QueryString);
Image image = LoadYourImageHere();
using (MemoryStream stream = new MemoryStream())
{
base.Response.Clear();
base.Response.ContentType = "image/png";
image.Save(stream, ImageFormat.Png);
stream.WriteTo(base.Response.OutputStream);
base.Response.End();
}
}
2- This is the magic, you create a small .js file. In this file you have a function lets call it mystats() which will essentially gather the client side information and make a call to the URL hosting the page you created in step 1. The client side information like screen size, referer etc. is all passed on the querystring. One important thing to include in the function is an ID which indicates which which counter you are updating, that way you can use your counter on multiple sites. A very simple .js might look something like this. (Note tested etc... :))
function mystats(id)
{
// Base URL including the ID of the counter
var url="http://yourdomainorservername/statserver.aspx?id="+id;
// Add the referer to the url querystring
url += "&r=" + escape(document.referrer);
// Add screen width + height
url += "&w=" + screen.width + "&h=" + screen.height;
document.write('<img src="'+url+'" border=0 alt="Site statistics">');
}
3- On the web pages that you want to apply the counter, you add a script block that includes the the .js file from your server and calls the mystats function from an img tag, this causes the js code to collect the info and send a request to your server, which in turn updates the DB and returns the image stream to display.
Getting the 'referer' is easy and for counting unique visitors you'll need to set/check for cookies.