Choose file, set image and upload without blocking UI - javascript

Problem
I can successfully achieve the following steps, but the UI can become unresponsive for files of 2 MB or more. These files are in the size range of what a user might upload from their camera or desktop, so I will need to handle them.
User uploads file using the standard file input HTML element:
<input class="cancel" type="file" name="userFile" id="userFile" accept="image/*"/>
On the client side I resize the file so that the width is 500px or less (specifically to reduce the image size for large files) and show the image.
On the client side I upload the resized smaller file.
Demo
See this fiddle.
There you can see that the - stops moving when uploading larger files. The delay seems more significant in Chrome than Firefox, but it still noticeable on Firefox.
Cause of blocking
When the file data URL is set on the img src. This is needed so that the image can be resized in the canvas.
img.src = e.target.result;//blocking here
When the img is written to the canvas. This is needed to resize the image.
ctx.drawImage( img, 0, 0, width, height );//blocking here
Options I have considered
Doing the blocking actions in a Web Worker. This is not possible because Web Workers cannot manipulate DOM elements and the blocking calls both occur when manipulating the DOM.
Resizing the raw image data in a Web Worker. Unfortunately, I don't know what the format of the img will be so resizing will need to handle all image types. I am not aware of any JavaScript library that will do this and I don't particularly want to write my own cross-format image compression library.
Resizing the img directly, but this does not change the underlying data size that needs to be uploaded.
Doing the resizing on the server is not an option because I want to reduce the upload size. Resizing on the client is also better since the memory for the large image is released early and the resized image is displayed immediately.
Other thoughts
I know that setting the img src is async, so I guess that it is the copying of the data that is causing the blocking. I wonder if there is a way to share the same data rather than doing a copy?
I am using what I believe to be a standard approach of using FileReader to get a data URL, then set the data URL to an img.src and canvas.drawImage to resize (there are many examples of this, one being here). Any assistance in improving the responsiveness of this approach or another approach would be appreciated.

What I assume you are trying to do is the following
User uploads image
The client displays a reduced quality image to the user.
The client then uploads that reduced quality image to your server for later use.
The problem you are running into is you are forcing javascript (the client) to do things that the would most likely be best done on the server side. As for displaying the image at a lower resolution that can be easily attained by using drawImage. There is no reason to display to the user the actual reduced file immediately on the client side. Here is my version of your use flow.
User uploads image.
Client uploads it to a server while displaying a reduced resolution version using drawImage.
The server runs a script much like this one resizing it to the requested size.
Then when the image needs to be used in the future the server coughs up the resized version.
I hope this helps!!!

Related

Rendering Multiple Images in React and HTML

I have a problem rendering images with large file sizes. When I upload a lot of large file sizes of images and display them, it becomes very laggy.
My question is:
The ideal way is the backend should provide an very small image file size url?
Or the frontend can do it using Canvas API?
Could you provide an explanation please? Thank you
If you have a bunch of thumbnails to display, the source images for those thumbnails should definitely not be the original, full-size images. If those images are large, it will take a long time for the client to download them, no matter how you render them on the client.
When figuring out an image to be shown to client, you should have two versions on the server:
Thumbnail version - low resolution, small file size, easy to download and render many at once
Full-size version, downloaded when the user wants to zoom in on one of them
It could be that the full-size version should not necessarily be the original image. For example, if the original image is 20MB (yes, they can exist), you wouldn't want to burden clients with that. So you'd want to perform resizes and optimizations on the server for both the thumbnail version and the "full" version - enough such that there isn't much of a delay between when the client tries to zoom in and the full-size image fully loads.
My recommendation is that you convert the image type to something more performant like .webp or .jpeg and give the element the exact width and height properties.
And react also have a feature to lazy load your images using react.lazy() that can boost your web performance significantly
Handling large images is too much work for a frontend client. You should get these images at a smaller size in order to just show them as they are.
Imagine someone trying to use your application with an old computer, or even an old smartphone, you shouldn't rely on client's processing power to handle all this heavy work.
I hope my answer helps you!
Jpegs are what you should be using, look at functionPreload() as well

image resizing based upon the screen sizes

I am using cfimage for image resizing and it is working well. my Question is i want to use the cfimage to resize the image based on screen size or i can use function where it should see if the screensize is smaller, use the smaller image else use larger image
some function which i can write once and do anywhere instead of doing it in all pages, i know one thing is server side and other is cf side but what if i send the viewport to the cfside, will it help or not
right now its working well but needed the update as to how can i build once and do in all
The "adaptive images" approach does exactly this. You can find a CFML (Lucee/ColdFusion) implementation at https://github.com/cfsimplicity/AdaptiveImages
Essentially it works as follows:
Javascript is used client-side to detect the screen resolution and store it in a cookie
URL rewriting is used server-side to pass image handling from the web server to the application server (ColdFusion/Lucee)
CF/Lucee uses AdaptiveImages to serve an optimally sized image according to the resolution detected in the cookie
AdaptiveImages automatically handles creating and caching the differently sized versions of each image depending on how its configured
Obviously there is a performance overhead but I've found it to be negligible and well worth the benefit in terms of reduced bandwidth.

Speed up web page by compressing large images

I have a blog slideshow on my web page which accesses images from a given url.
The problem is, people add images with massive resolution (3000px*6000px), which noticeably slows down the animation of the slideshow.
These high resolution images are necessary, but not for this particular purpose, since the images live inside a div of size (300*600)
Is there any way CSS (or some other way) can convert the image to a smaller specified resolution (say 300px * 600px), before scaling down.
This way the animation won't involve high res image frames and so it won't be as laggy.
The only alternative I can think of, is that everytime an image is uploaded on the database, the backend creates a secondary compressed image for this purpose.
However, this seems like a lot of effort.
Since you said in the comments that bandwidth and download time are not the issue and it's acceptable to download the full res image, scale it down, then add it to the page, please consider the following solution which does exactly that.
Download the original image via AJAX, then use ctx.drawImage to draw the image to an HTML canvas with much smaller size. For instance, you can take a 3000px*6000px image and draw it scaled onto a 300px*600px canvas. Then free the original image using JavaScript so that it no longer takes up memory in the browser.
After that, you can use the canvas to do your animations and there should not be nearly as much lag as using the large, original image (since the compositor will need to move much fewer pixels).
Edit: According to your later comment, your users are uploading to an external image hosting service, so this solution will prevent them from having to upload a thumbnail version in addition to their full-res version.
If you choose Imgur.com like you are considering in the comments: They let you modify the image size a bit in the URL. So for instance if you have an image at https://i.imgur.com/9ZC02Os.jpg, you can use https://i.imgur.com/9ZC02Oss.jpg for the small version, https://i.imgur.com/9ZC02Osm.jpg for the medium version, and https://i.imgur.com/9ZC02Osl.jpg for the large scaled version (note the s, m, and l at the end of the URLs). That way you can probably avoid drawing to a canvas completely.
This was a site I found a few years agowhich may be of interest: http://sneak.co.nz/projects/img-resizing/
You could store a small version on your site for use in the slideshow. A good way to do this may be to check if a small image is available and if not create it the first time it is called and save it somewhere.
This code will resize an image on the fly but I think you would still have some lag while the image is resized.
$photo="sunflower.jpg";
$cmd = "convert $photo -thumbnail 200x200 ".
" -quality 100 JPG:-";
header("Content-type: image/jpeg");
passthru($cmd, $retval);

dynamically generating multiple thumbnails from a video src with javascript

Before you say it can't be done please take a look at my train of thought and entertain me.
I have read on stackoverflow that it can't be done and how to implement this using ffmpeg and other stuff on the server side which is great and simpleish enough to comprehend .. ive even used an extensiion to Video.js i found on github that makes this one step easier. But none the less what if I dont have a copy of the <video src=... > and I really dont care to get one?
I Do not want to use a server to do this Okay with that out of the way, I understand thanks to a post from Paul Irish that video playback is not a shared aspect of web-kit ports (the code which powers basically every browser ... minus chrome canary now using blink a webkit fork) This kinda makes sense why certain browsers only support certain video containers.
So for the sake of simplicity: I want to make this functionality only available on Chrome and only MPEG-4 AVC video containers, why can't this be done if some how I can actually view each frame of the video while its playedback?
additional note
So the generating of video thumbnails is possible using by drawing frames to a canvas, this will only be part of a final solution to my problem, I'm looking to do this each and everytime a video is viewed not store images on my server after a first playback is completed by a user. What I would like to eventually work up to is generating a thumbnail as the video is downloaded that can be viewed while a user uses a dragging scrollbar to ff/rw to a point in the video. So this will need to be done as frames of video come available, not once they have been rendered by the browser for user to view
One can actually feed in a video to the canvas, as seen here in HTML5Doctor. Basically, the line that does the magic is:
canvasContext.drawImage(videoElement,0,0,width,height);
Then you can run a timer that periodically retrieves the frames from the canvas. There are 2 options on this one
get raw pixel data
get the base64 encoded data
As for saving, send the data to the server to reconstruct an image using that data, and save to disk. I also suggest you size your canvas and video to the size you want your screenshots to be since the video-canvas transfer automatically manages scaling.
Of course, this is limited by the video formats that are supported by the browser. As well as support for canvas and video.
Generating thumbnails during first render? You'd run into problems with that since:
You can't generate all frames unless it's rendered on the video element.
Suppose you have generated thumbnails during first run and want to use them for further runs. Base64 data is very long, usually 3 times the file size if the image. Raw pixel data array is width x height x 4 in length. The most viable storage candidate is localStorage, which is just 5-10MB depending on the browser.
No way to cache the images generated into the browser cache (there could be a cache hack that I don't know using data-urls).
I suggest you do it on the server instead. It's too much burden and hassle to do in the client side.

Are there any good Javascript/Jquery thumbnail script equivalents to TimThimb (PHP)?

For those unaware of TimThumb, it will take any image, of any size or dimension and create a thumbnail on the fly to any desired size. The beauty of it is that it really works on any dimension you feed it through a combination of either resizing the image, cropping or zoom cropping the image.
Ive been searching for jscript equvalents but they either require the user to actually mask out the thumbs manually (looking for a script that automatically does it to images) or the scripts can't handle images in a different aspect ratio.
Thanks for any leads on this!
It is impossible to do this only with client-side javascript. PHP has GD, ImageMagick libraries which create the new image (actual thumbnail) and javascript alone can't do this, as it is client side script, it can't create files.
So the answer is: There is no any.
As #papirtiger pointed out you can still do it with server-side javascript (such as node.js).
Please see this link
It depends.
You can use CSS or Javascript for simple image scaling.
There are tons of available plugins to this.
I doubt that there is one that does the guesstimation exactly the same as timthumb.
If you are going resize a large amount images on the page it will really hurt performance.
Another alternative is to several fixed size "layouts" (960, 320) etc and have the server generate thumbs for each.
You can than use javascript to load the appriate size.
If you really need to rescale the file:
Use external webservice to resize the image.
Most of them take a url and return a resized image:
example.com/resize?image="http://example.com/image1.jpg"&height="...
If you have TimThumb running on your server you can set up a simple API to allow you to call your own service.
othrwise see Image resizing web service for a few alternatives.

Categories

Resources