I have a database which stores .png images as the sql "image" type. I have some code which retrieves these images as a byte[], and sends them to the page via the FileContentResult object in .Net. Performance is key in this application, and the images have to be retrieved and displayed as quickly as possible. My question is, can this operation be performed quicker by passing a byte stream from the database to the browser, and not at anytime storing the whole byte array in memory. If this is possible and worthwhile doing, how do I do it?
Here is the code I have so far:
// Get: /Image/Get/5
public FileResult Get(int id)
{
Response.Cache.SetExpires(DateTime.Now.AddSeconds(300));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);
// Get full size image by PageId.
return base.File(page.getFullsizeImage(id), "image/png");
}
And
public byte[] getFullsizeImage(int pageId)
{
return (from t in tPage
// Filter on pageId.
where t.PageId == pageId
select t.Image).Single().ToArray();
}
Thanks for any help!
A nice question.
Reality is the code required to send the image as a stream is really minimal. It is just Response.Write~~~ byte array and setting the HTTP's content-type header which must be very fast.
Now you seem to need to open up your database to the world to get it done quicker. That, being probably possible using features that allow SQL server to serve HTTP/interact with IIS (long time ago I looked at it), not a good idea so I do not believe you should take that risk.
You are already using the caching so that is cool but files being large, cache gets purged frequently.
But one thing to do is to have a local File Cache on the IIS and if image is used, it is written to the file on teh web server and from then on (until maybe next day when this is cleared) this other URL (to the static asset) is returned so requests would not have to go through the ASP.NET layer. It is not a great idea but will achieve what you need with least risk.
Changing the linq from single to first should give you nicer SQL, if PageId is the primary key you can safely assume first and single will return the same result.
Edit: Based on your comments, I think you should consider using DeepZoom from microsoft. Essentially, what this allows you to do is generate a specialized image file on the server. When a user is browsing the image in full view, just the couple of million or so pixels that are displayed on the screen are sent to the browser via AJAX. Then when the user zooms in, the appropriate pixels for the zoom level and x and y axis are streamed out.
There is a DeepZoom Composer which can be accessed via the command line to generate these image files on demand and write them to a network share. Your users will be really impressed.
Take a look at this example. This is a massive image - Gigabytes. in about the middle of the image you will see some newspaper pages. You can zoom right in and read the articles.
End of Edit
Do you have to have images with a large file size? If they are only meant for displaying in the browser, they should be optimized for the web. All main image editing applications have this ability.
If you do need the large file size, then you could provide optimized images and then when the user clicks on the image, allow them to download the full file. They should expect this download to take some time.
In Photoshop, the task is "Save for web". There is a similarly named plugin for Gimp.
I know that this doesn't answer your direct question ("can this operation be performed quicker by passing a byte stream"), but it might help solve your problem.
Related
Actually I'm developing an "social" app for my office and I'm wondering what's the best way to load or manage pictures. Each user has a profil picture and I would like to display it wherever I want, on the profil view, in the contacts list (little smaller) for example. When the user creates its profil, he picks up a picture from the picture library on his phone and it's send to server as base64 encoded string. The code that I've used to save the picked picture on the server (SQL Server 2012 database):
var reader = new DataReader(pictureStream.GetInputStreamAt(0));
byte[] bytes = new byte[pictureStream.Size];
await reader.LoadAsync((uint)pictureStream.Size);
reader.ReadBytes(bytes);
string bytesString = Convert.ToBase64String(bytes);
So here bytesString contains the base64 encoded picture to send on the server. Atually, I'm facing two problems.
First problem:
The base64 encoded string cannot be inserted to the database even if the column type is varchar(max). The string is cut in the table.
Second problem:
If I want to build the picture from bytesString decoding the base64 string, it takes so much time that it's not possible to work like that.
So I'm wondering how applications such Instagram or other picture specialized application are managing pictures so well... Does anyone could give me some advises to manage pictures through an app ? Thanks in advance !
Two ideas come to mind:
1. Store the images in a binary-type column
I haven't used SQL server very much, but I guess there is a binary column type in which you can just store the original bytes of the image.
2. Store the images in files instead of the database.
Another thing you can do is to simply store the images in files with names based on the users' IDs (i.e. user_15.png).
Other considerations
Is there any reason to encode/decode the bytes? Sending the original image seems like a better option to me.
How are you actually sending the encoded image bytes? From what I understand varchar(max) should be able to hold quite a lot of data. Are you sure the server receives the right data?
On the client (in the WP 8.1 app) you may want to cache the images, so that you wouldn't need to load them from the server every time.
This is a follow on from my last question (Here) as I don't think I gave enough information the first time around and i can't delete it.
I've got my image converted to a byte array but the follow on help and suggestions made it seem like that the image I wanted to save needed to first exist on my computer. Where, in fact, the image I want to take only exists in the picture box (its a screen grab). When I check my server to see if the image has been passed over, I don't see anything and nothing prompts me to name my image file or anything.
So my question is thus:
What is the best way for my to upload a screen grab from my application, using webclient, to my central server? Ideally the functionality I would like would be very similar to that of saving the image to my computer. The only difference is, it's not my hard drive I'm saving the image on. It's a server somewhere.
I am building a online store for hand made jewelry. Of course there is a lot of high quality pictures that i need to show, first in small sizes and when a client clicks on the image, than redirect him to a page with a same image in high quality.
What is a better way:
on saving image save two images one in low quality and the second in original quality
or
onload image use Bitmap to lower the quality?
It depends.
Resizing on demand causes a heavier server load. When a lot of people are accessing the site this might be an issue.
Resizing on upload reduces this problem.
Resizing on your client using image processing software does usually produce the best quality with low file size.
The "normal" resize-functions in .NET is far away from that quality.
Also: Consider caching. The IIS offers everything to use this, perhaps in combination with an eTag.
I would resize them on upload/addition. I would also make sure to name them appropriately to their size, like gold_ring_640_480.jpg.
Then, should I need to change the size of the preview, I would add functionality to resize it lazily on demand if a required picture size does not exist.
Image_240p exists?
not: create
save _240p
use the image
You don't need to save all image size . For my all website, I get image on the fly depend on dimension that I need. When have a request with file size, I will create a resized image on disk. In the next time, with the same request, I just check:
if file already in browse cached, I will return the header mention that website just get image from cache.
if file not in browse cache, I will check that "the file already generate in disk". If the file is available, just return the file to response
if file not in browse cache and not in disk. I will generate it and return the file content.
For image caching you can see this reference :https://developers.google.com/speed/docs/best-practices/caching
For image resize on the fly by .net: you can refer to : http://www.codeproject.com/Articles/191424/Resizing-an-Image-On-The-Fly-using-NET
So I have this website where users can post articles, each article containing at least one photo. What I want to do is when I display the list of articles on the website I want to also show a thumbnail next to the articles name.
Here comes the tricky part: the images are not hosted on my server, are simply links hosted on some image-hosting website. Another problem is that I don't know where the images appear in the post (they could be at the beginning, at the end or in the middle of the article).
What would be the best approach to create a thumbnail system in this case?
I was thinking maybe I could do this: every time an article is posted or edited and stored into the database I could scan the entire articles for images links and store the first link in a separate value in the database (this could be kind of slow though).
Also once I have those values stored and I have to display a thumbnail the only way to do so will be by showing the full image resized to the thumbnail size (that means the user has to download multiple full-size images to see the articles list with thumbnails).
Is there any better approach? (you can see the technologies used in the tags)
Create a thumbnails task that runs in the background after an article has been published.
Find image tags in the article HTML using regular expression.
Get those images and create and thumbnail that you save locally in a folder in your server.
Protect that folder/location against hotlinking.
Use those local pictures as thumbnails
Use HtmlAgilityPack as a starter to get to the images from the image host.
Use an ASP.NET handler to generate the thumbnails. That way, you won't have to store anything locally, the thumbnails images will only exist in memory, making hotlinking impossible
Got a question. I have images hosted on my server. I already know of the method when an image is uploaded to resize it and save, but I have another thought in mind.
I was wondering if there is a way to resize when the image is requested from the user. Not when it was uploaded by the user.
So for example a user goes to upload an image and I DO NOT RESIZE it and save another copy of the resized image. Instead, when the image is requested by the user via an ASP.NET img control/tag it would resize the image on the fly to display it and display it via the img tag/control.
Why would I want to do this?
To save on disk space. Most servers have a disk space limit, but not a server processing limit. So I would like to save on disk space and use the processing space instead.
EDIT: As a startup website its currently better that I save disk than saving processing time. I don't have much money for large amount of space at this moment. Hopefully it will change when the site launches.
Any ideas? Thanks guys and girls.
I assume you can 'control' the urls to the resized images, so for example the full-sized image might be referenced as <img src="uploads/myphoto.jpg"/> the thumbnail could be to an ASPX or ASHX like <img src="uploads/myphoto.jpg.ashx"/>?
This article on CodeProject - Dynamic Image Resize seems to have exactly the source code you are looking for (and although it's in VB, it shouldn't be hard to port if you're a C# person). Hope that helps.
Finally, I'd encourage you consider the various forms of caching (both using Http-Headers, to ensure the images are cached at the client or proxy whenever possible; and using built-in ASP.NET features to avoid unnecessary processing of the same images over-and-over).
Although you'll be saving disk-quota, you're effectively slowing down every other page/request... just a thought.
Dynamic image resizing has numerous advantages, the least of which is reduced disk space usage. However, it does need to be combined with a form of persistent caching, such as either Amazon CloudFront or a disk cache.
Dynamic image resizing gives you great agility on your web site, whereas pre-generating image variants locks you in, preventing the eventual changes you will have to make. When combined with caching, there is no run-time performance difference between the two.
The ImageResizer library offers disk caching, CloudFront caching, and correct memory and cache management. It's been constantly improved and maintained since 2007, and is quite bulletproof. It's running a few social networking sites as well, some having over a million images.
It's a time-tested, traffic-tested, and unit-tested library :) It's also extremely simple to use - you just add ?width=x&height=y to the query string. Functionality can be added via 20+ plugins, so you won't be weighed down by unused code and features.
The article mentioned by CraigD is inherently limited in its performance by the fact that it uses an HttpHandler instead of using an HttpModule - an HttpHandler cannot pass a request back to IIS native code for execution after the resized image is written to disk. It also doesn't adjust jpeg encoding properly or play well with the ASP.NET cache or URL authorization system. Although, I do have to admit - compared to most of the sample code I've seen, it violates far fewer of the image resizing pitfalls I've compiled.
I strongly suggest using the ImageResizer library. It's good code, I wrote it :) If you do end up using sample code or writing your own, please avoid these pitfalls!
You can create an implementation of IHttpHandler to respond to image requests, in that handler you can have code that loads the image from disk and transforms to it a size that is needed. You need to return the proper mime type with the response, and use the WriteBytes method (or something like it, I forgot the name). Also, you may look into content expiration headers, so that the image may not have to be loaded every time by the same client, but is instead cached.
You claim unlimited processing but limited disk space. Most of the time, even if they don't enforce a processing limit, as you have more customers, hits to your site, processing will be a worse bottleneck than storage space, and it will cost more to add more processing. Furthermore,
If you have large images, resized and compressed versions will occupy %10 of the space of the originals, even if you store a display and thumbnail version.
Else, just serve them and display them resized by browser, it will be faster.
It is not really actual resize of image, it is rather resize when you display an image, but i used with success just simple
<img src="myimage" height="height you want to give" width="width you want
to give" alt="" />
It is working every time.