最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Reading large images as thumbnails locally via HTML5 filereader - Stack Overflow

programmeradmin5浏览0评论

I am trying to load local images as thumbnails as explained here. My code is below.

This works fine for small images. However, when you try load larger images (e.g. 4mb) there is a huge lag. Is there any way to optimize this?

Thanks

Html

<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>

Javascript

<script>
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object

// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {

  // Only process image files.
  if (!f.type.match('image.*')) {
    continue;
  }

  var reader = new FileReader();

  // Closure to capture the file information.
  reader.onload = (function(theFile) {
    return function(e) {
      // Render thumbnail.
      var span = document.createElement('span');
      span.innerHTML = ['<img class="thumb" src="', e.target.result,
                        '" title="', escape(theFile.name), '"/>'].join('');
      document.getElementById('list').insertBefore(span, null);
    };
  })(f);

  // Read in the image file as a data URL.
  reader.readAsDataURL(f);
}
}

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

I am trying to load local images as thumbnails as explained here. My code is below.

This works fine for small images. However, when you try load larger images (e.g. 4mb) there is a huge lag. Is there any way to optimize this?

Thanks

Html

<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>

Javascript

<script>
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object

// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {

  // Only process image files.
  if (!f.type.match('image.*')) {
    continue;
  }

  var reader = new FileReader();

  // Closure to capture the file information.
  reader.onload = (function(theFile) {
    return function(e) {
      // Render thumbnail.
      var span = document.createElement('span');
      span.innerHTML = ['<img class="thumb" src="', e.target.result,
                        '" title="', escape(theFile.name), '"/>'].join('');
      document.getElementById('list').insertBefore(span, null);
    };
  })(f);

  // Read in the image file as a data URL.
  reader.readAsDataURL(f);
}
}

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
Share Improve this question asked Dec 16, 2012 at 21:20 Omar WagihOmar Wagih 8,7427 gold badges64 silver badges75 bronze badges 5
  • What is "Huge" in this case? – Cerbrus Commented Dec 16, 2012 at 21:23
  • Well it works fine if its just a small number of large images. But there is a significant lag when you try load in, for example, 10 files all of which are ~4mb. Roughly 6-7 seconds – Omar Wagih Commented Dec 16, 2012 at 21:28
  • I don't think you can improve anything when trying to render thumbnails of those images, that way. It's just a lot of work for JavaScript to work through those relatively large files. – Cerbrus Commented Dec 16, 2012 at 21:33
  • So really what you're saying is that it takes 6-7 seconds to read 40-50 megabyte of data? Sounds about right! – adeneo Commented Dec 16, 2012 at 21:44
  • 4 I wasn't asking if it sounds right. I was asking if there was a way to optimize it client side – Omar Wagih Commented Dec 16, 2012 at 22:59
Add a ment  | 

1 Answer 1

Reset to default 17

There is always a lag when you run something in the main UI thread which involves manipulating non-streaming data in huge blobs. The lag does not e from reading he data, but decoding and displaying the image in the browser UI as this involves synchronous UI operations pushing the large pixel array around in CPU and GPU memory. This is because <img> allocates and moves around memory in the blocks of actual image data size (width * height) which is very large amount for big images and unnecessary detailed to push it up to GPU for just showing it on the screen (causes the lag of several milliseconds).

You can most likely optimize your use case by shrinking the image to displayable size while reading it

  • Using a pure Javascript JPEG decoder where main event loop reads the file in chunks and posts chunks to WebWorker background thread for decoding. One example decoder library https://github./notmasteryet/jpgjs/blob/master/jpg.js

  • Allocate a <canvas> element where the WebWorker posts backs the resulting pixels progressively. This canvas element does not need to match the actual image size (see below)

  • Also you can scale down the images in the WebWorker while reading them in pure Javascript http://www.grantgalitz/image_resize/ - lessening the need to push the pixels to GPU as you are not going to fit the big image on the monitor as 1:1 pixel mapping in the first place

  • WebWorker and main thread can push data around using copy-free Transferable objects https://developer.mozilla/en-US/docs/DOM/Using_web_workers#Passing_data_by_transferring_.C2.A0ownership_%28transferable_objects%29

However, though the solution described here is near perfect, to implement this one needs to possess advanced Javascript skills and the solution is not going to be legacy patible (read: Microsoft).

发布评论

评论列表(0)

  1. 暂无评论