Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image resizing causing slow scrolling

Tags:

html

css

I'm loading large images and having the browser resize them. I'm explicitly setting the size.

<img src="http://example.com/image1.jpg" width="240" height="360"/>

There are many such images on the page. Scrolling is very slow and choppy. The Events Timeline in chrome looks something like this when scrolling:

Paint

* Image decode (JPEG)
* Image resize (non-cached)
* Image decode (JPEG)
* Image resize (non-cached)
* ...

Paint

* Image resize (cached)
* Image resize (cached)
* Image resize (cached)
* Image resize (cached)

Paint

* Image decode (JPEG)
* Image resize (non-cached)
* Image decode (JPEG)
* Image resize (non-cached)
* ....

Paint

* Image resize (non-cached)
* Image resize (non-cached)
* Image resize (non-cached)
* Image resize (non-cached)

Paint

* Image decode (JPEG)
* Image resize (cached)
* Image decode (JPEG)
* Image resize (cached)
* ...

etc.

I'm not sure why some of the Paint events include image decoding and others don't, nor why sometimes the resizing is cached and sometimes it is not. I guess it must have to do with new images coming into the view-port.

Is there anything I can do to ensure that I only pay the image resize cost once per image when the page loads, and avoid image resizing during scroll?

(Of course, I understand that the best solution is to avoid browser resizing by loading in an image that is already of the appropriate size. In this case this is not practical.)

like image 592
Joel Avatar asked Jan 27 '13 03:01

Joel


2 Answers

This function will permit you to resize an image only once, by replacing it with a new image resized at the desired scale :

function resizeImage(image, maxWidth, maxHeight) {

  // Output scale is the minimum of the two possible scales
  var scale = Math.min((maxWidth / image.width), (maxHeight / image.height))

  // Output canvas
  var outputCanvas = document.createElement('canvas')
  outputCanvas.width = image.width * scale
  outputCanvas.height = image.height * scale

  // Draw image content in output canvas
  var outputContext = outputCanvas.getContext('2d')
  outputContext.drawImage(image, 0, 0, parseInt(image.width * scale), parseInt(image.height * scale))

  // Replace image source
  image.src = outputCanvas.toDataURL()
}

It takes the image you pass as image parameter, and creates a canvas where it resizes image, and then sets the image.src attribute to the content of the output canvas, using toDataURL().

Images you resize have to be in RELATIVE path (yes it's not cool), or you will have security error due to CORS if not fulfilled.

But you can pass base64 data as src attribute, and it can be easy to do it with AJAX.

like image 151
kube Avatar answered Oct 21 '22 06:10

kube


Your problem is that you are downloading lots of images at the same time, lots of large images. The rendering of them to differnt sizes other than the orginal will also be slow if there are lots of large images and the users individual ram and processor limitations.

no matter what size you tell the browser to render the image the browser still loads the original image size and then adjusts it on the fly. The large image has to travel down the users internet connection to the browser from the server. by using html attributes all you are doing really is using CSS to change the image size once it has been downloaded.

Your best option would in mho be to create multiple image sizes server side, preferably at the time of creation of the asset rather than on the fly and call the image size closest to your needs. If you create images on the fly using scripts etc keep them on the server to use again later on and reduce load time and server resources.

one last tip is also make sure you are caching. more info here http://betterexplained.com/articles/how-to-optimize-your-site-with-http-caching/

like image 21
Orcra Avatar answered Oct 21 '22 05:10

Orcra