silvercity
silvercity

Reputation: 603

Preview images before upload

I have a page with four images for the user to select. I want the user to be able to preview each image on the site before upload.

The JavaScript code below works for only one image but I would like it to work for multiple images uploaded via <input type="file">.

What will be the best way to do this?

function readURL(input) {
    if (input.files && input.files[0]) {
        var reader = new FileReader();

        reader.onload = function (e) {
            $('#output').attr('src', e.target.result);
        }

        reader.readAsDataURL(input.files[0]);
    }
}

$("#file-input").change(function () {
    readURL(this);
});

Upvotes: 56

Views: 137181

Answers (10)

Roko C. Buljan
Roko C. Buljan

Reputation: 206699

  • Add the multiple attribute to your HTMLInputElement
  • Add the accept attribute to your HTMLInputElement
    To filter your files selection to images only, use accept="image/*", or a comma separated MIME list: accept="image/png, image/jpeg"
  • Use FileReader.readAsDataURL to get the Base64 string,
    or URL.createObjectURL to get the file Blob object

Using FileReader.readAsDataURL

The asynchronous way to read the image data is by using FileReader API and its readAsDataURL method which returns a Base64 String:

const preview = (file) => {
  const fr = new FileReader();
  fr.onload = () => {
    const img = document.createElement("img");
    img.src = fr.result;  // String Base64 
    img.alt = file.name;
    document.querySelector('#preview').append(img);
  };
  fr.readAsDataURL(file);
};

document.querySelector("#files").addEventListener("change", (ev) => {
  if (!ev.target.files) return; // Do nothing.
  [...ev.target.files].forEach(preview);
});
#preview img { max-height: 100px; }
<input id="files" type="file" accept="image/*" multiple>
<div id="preview"></div>

Async strategy:

Due to the asynchronous nature of FileReader, you could implement an async/await strategy:

// DOM utility functions:

const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, props) => Object.assign(document.createElement(tag), props);


// Preview images before upload:

const elFiles = el("#files");
const elPreview = el("#preview");

const previewImage = (props) => elPreview.append(elNew("img", props));

const reader = (file, method = "readAsDataURL") => new Promise((resolve, reject) => {
  const fr = new FileReader();
  fr.onload = () => resolve({ file, result: fr.result });
  fr.onerror = (err) => reject(err);
  fr[method](file);
});

const previewImages = async(files) => {
  // Remove existing preview images
  elPreview.innerHTML = "";

  let filesData = [];

  try {
    // Read all files. Return Array of Promises
    const readerPromises = files.map((file) => reader(file));
    filesData = await Promise.all(readerPromises);
  } catch (err) {
    // Notify the user that something went wrong.
    elPreview.textContent = "An error occurred while loading images. Try again.";
    // In this specific case Promise.all() might be preferred over
    // Promise.allSettled(), since it isn't trivial to modify a FileList
    // to a subset of files of what the user initially selected.
    // Therefore, let's just stash the entire operation.
    console.error(err);
    return; // Exit function here.
  }

  // All OK. Preview images:
  filesData.forEach(data => {
    previewImage({
      src: data.result, // Base64 String
      alt: data.file.name // File.name String
    });
  });
};

elFiles.addEventListener("change", (ev) => {
  if (!ev.currentTarget.files) return; // Do nothing.
  previewImages([...ev.currentTarget.files]);
});
#preview img { max-height: 100px; }
<input id="files" type="file" accept="image/*" multiple>
<div id="preview"></div>

Using URL.createObjectURL

The synchronous way to read the image is by using the URL API and its createObjectURL method which returns a Blob:

const preview = (file) => {
  const img = document.createElement("img");
  img.src = URL.createObjectURL(file);  // Object Blob
  img.alt = file.name;
  document.querySelector('#preview').append(img);
};

document.querySelector("#files").addEventListener("change", (ev) => {
  if (!ev.target.files) return; // Do nothing.
  [...ev.target.files].forEach(preview);
});
#preview img { max-height: 120px; }
<input id="files" type="file" accept="image/*" multiple>
<div id="preview"></div>

Although looks much simpler, it has implications on the main thread due to its synchronicity, and requires you to manually use (when possible) URL.revokeObjectURL in order to free up memory:

// Remove unused images from #preview? Consider also using
URL.revokeObjectURL(someImg.src); // Free up memory space 

jQuery example:

A jQuery implementation of the above FileReader.readAsDataURL() example:

const preview = (file) => {
  const fr = new FileReader();
  fr.onload = (ev) => {
    $('#preview').append($("<img>", {src: fr.result, alt: file.name}));
  };
  fr.readAsDataURL(file);
};

$("#files").on("change", (ev) => {
  if (!ev.target.files) return; // Do nothing.
  [...ev.target.files].forEach(preview);
});
#preview img { max-height: 120px; }
<input id="files" type="file" accept="image/*" multiple>
<div id="preview"></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

Additional read:

Tips:

Besides using the HTMLInputElement attribute accept, if you want to make sure within JavaScript that a file is-of-type, you could:

if (!/\.(jpe?g|png|gif)$/i.test(file.name)) {
   // Not a valid image
}

or like:

if (!/^image\//i.test(file.type)) {
   // File is not of type Image
}

Upvotes: 47

nkitku
nkitku

Reputation: 5788

https://stackoverflow.com/a/59985954/8784402

ES2017 Way

// convert file to a base64 url
const readURL = file => {
    return new Promise((res, rej) => {
        const reader = new FileReader();
        reader.onload = e => res(e.target.result);
        reader.onerror = e => rej(e);
        reader.readAsDataURL(file);
    });
};

// for demo
const fileInput = document.createElement('input');
fileInput.type = 'file';
const img = document.createElement('img');
img.attributeStyleMap.set('max-width', '320px');
document.body.appendChild(fileInput);
document.body.appendChild(img);

const preview = async event => {
    const file = event.target.files[0];
    const url = await readURL(file);
    img.src = url;
};

fileInput.addEventListener('change', preview);

Upvotes: 0

Emanoel Jos&#233;
Emanoel Jos&#233;

Reputation: 135

function previewMultiple(event){
        var saida = document.getElementById("adicionafoto");
        var quantos = saida.files.length;
        for(i = 0; i < quantos; i++){
            var urls = URL.createObjectURL(event.target.files[i]);
            document.getElementById("galeria").innerHTML += '<img src="'+urls+'">';
        }
    }
#galeria{
        display: flex;
    }
    #galeria img{
        width: 85px;
        height: 85px;
        border-radius: 10px;
        box-shadow: 0 0 8px rgba(0,0,0,0.2);
        opacity: 85%;
    }
<input type="file" multiple onchange="previewMultiple(event)" id="adicionafoto">
<div id="galeria">
    
</div>

Upvotes: 7

Munna ak-17
Munna ak-17

Reputation: 1

function appendRows(){
    $i++;
    var html='';
    html+='<div id="remove'+$i+'"><input type="file" name="imagefile[]" accept="image/*" onchange="appendloadFile('+$i+')"><img id="outputshow'+$i+'" height="70px" width="90px"><i onclick="deleteRows('+$i+')" class="fas fa-trash-alt"></i></div>';
     $("#appendshow").append(html);
}

function appendloadFile(i){
    var appendoutput = document.getElementById('outputshow'+i+'');
    appendoutput.src = URL.createObjectURL(event.target.files[0]);
}

Upvotes: 0

Orgkid
Orgkid

Reputation: 1

<script type="text/javascript">

var upcontrol = {
  queue : null, // upload queue
  now : 0, // current file being uploaded
  start : function (files) {
  // upcontrol.start() : start upload queue

    // WILL ONLY START IF NO EXISTING UPLOAD QUEUE
    if (upcontrol.queue==null) {
      // VISUAL - DISABLE UPLOAD UNTIL DONE
      upcontrol.queue = files;
      document.getElementById('uploader').classList.add('disabled');
      // PREVIEW UPLOAD IMAGES
       upcontrol.preview();*enter code here*
      //PROCESS UPLOAD ON CLICK 

    $('#add_files').on('click', function() {
       upcontrol.run();
    });
    }
  },
  preview : function() {
    //upcontrol.preview() : preview uploading file
        if (upcontrol.queue) {
            var filesAmount = upcontrol.queue.length;

            for (i = 0; i < filesAmount; i++) {
                var reader = new FileReader();

                reader.onload = function(event) {
                  var fimg = document.createElement('img') 
                    fimg.src =  event.target.result,
                      fimg.classList = "col-sm-6 col-md-6 col-lg-4 float-left center",
                      document.getElementById('gallery').appendChild(fimg);                
                }
                reader.readAsDataURL(upcontrol.queue[i]);
            }
        }
    },
  run : function () {
  // upcontrol.run() : proceed upload file

    var xhr = new XMLHttpRequest(),
        data = new FormData();
    data.append('file-upload', upcontrol.queue[upcontrol.now]);
    xhr.open('POST', './lockeroom/func/simple-upload.php', true);
    xhr.onload = function (e) {

      // SHOW UPLOAD STATUS
      var fstat = document.createElement('div'),

          txt = upcontrol.queue[upcontrol.now].name + " - ";
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          // SERVER RESPONSE
          txt += xhr.responseText;
        } else {
          // ERROR
          txt += xhr.statusText;
        }
      }
      fstat.innerHTML = txt;
      document.getElementById('upstat').appendChild(fstat);

      // UPLOAD NEXT FILE
      upcontrol.now++;
      if (upcontrol.now < upcontrol.queue.length) {
        upcontrol.run();
      }
      // ALL DONE
      else {
        upcontrol.now = 0;
        upcontrol.queue = null;
        document.getElementById('uploader').classList.remove('disabled');
      }
    };
    xhr.send(data);
  }
};

window.addEventListener("load", function () {
  // IF DRAG-DROP UPLOAD SUPPORTED
  if (window.File && window.FileReader && window.FileList && window.Blob) {
    /* [THE ELEMENTS] */
    var uploader = document.getElementById('uploader');

    /* [VISUAL - HIGHLIGHT DROP ZONE ON HOVER] */
    uploader.addEventListener("dragenter", function (e) {
      e.preventDefault();
      e.stopPropagation();
      uploader.classList.add('highlight');
    });
    uploader.addEventListener("dragleave", function (e) {
      e.preventDefault();
      e.stopPropagation();
      uploader.classList.remove('highlight');
    });

    /* [UPLOAD MECHANICS] */
    // STOP THE DEFAULT BROWSER ACTION FROM OPENING THE FILE
    uploader.addEventListener("dragover", function (e) {
      e.preventDefault();
      e.stopPropagation();
    });

    // ADD OUR OWN UPLOAD ACTION
    uploader.addEventListener("drop", function (e) {
      e.preventDefault();
      e.stopPropagation();
      uploader.classList.remove('highlight');
      upcontrol.start(e.dataTransfer.files);
    });
  }
  // FALLBACK - HIDE DROP ZONE IF DRAG-DROP UPLOAD NOT SUPPORTED
  else {
    document.getElementById('uploader').style.display = "none";
  }
});
</script>

i used somthing like this and i got the best result and easy to understand.

Upvotes: 0

J. Jerez
J. Jerez

Reputation: 794

Just use FileReader.readAsDataURL()

HTML:

<div id='photos-preview'></div>
<input type="file" id="fileupload" multiple (change)="handleFileInput($event.target.files)" />

JS:

 function handleFileInput(fileList: FileList) {
        const preview = document.getElementById('photos-preview');
        Array.from(fileList).forEach((file: File) => {
            const reader = new FileReader();
            reader.onload = () => {
              var image = new Image();
              image.src = String(reader.result);
              preview.appendChild(image);
            }
            reader.readAsDataURL(file);
        });
    }

DEMO

Upvotes: 5

Shashi Kumar
Shashi Kumar

Reputation: 17

function previewImages() {

  var preview = document.querySelector('#preview');
  
  if (this.files) {
    [].forEach.call(this.files, readAndPreview);
  }

  function readAndPreview(file) {

    // Make sure `file.name` matches our extensions criteria
    if (!/\.(jpe?g|png|gif)$/i.test(file.name)) {
      return alert(file.name + " is not an image");
    } // else...
    
    var reader = new FileReader();
    
    reader.addEventListener("load", function() {
      var image = new Image();
      image.height = 100;
      image.title  = file.name;
      image.src    = this.result;
      preview.appendChild(image);
    });
    
    reader.readAsDataURL(file);
    
  }

}

document.querySelector('#file-input').addEventListener("change", previewImages);
<input id="file-input" type="file" multiple>
<div id="preview"></div>

Upvotes: 0

J.Doe
J.Doe

Reputation: 51

$(function() {
    // Multiple images preview in browser
    var imagesPreview = function(input, placeToInsertImagePreview) {

        if (input.files) {
            var filesAmount = input.files.length;

            for (i = 0; i < filesAmount; i++) {
                var reader = new FileReader();

                reader.onload = function(event) {
                    $($.parseHTML('<img>')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
                }

                reader.readAsDataURL(input.files[i]);
            }
        }

    };

    $('#gallery-photo-add').on('change', function() {
        imagesPreview(this, 'div.gallery');
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="file" multiple id="gallery-photo-add">
<div class="gallery"></div>

function previewImages() {

  var preview = document.querySelector('#preview');
  
  if (this.files) {
    [].forEach.call(this.files, readAndPreview);
  }

  function readAndPreview(file) {

    // Make sure `file.name` matches our extensions criteria
    if (!/\.(jpe?g|png|gif)$/i.test(file.name)) {
      return alert(file.name + " is not an image");
    } // else...
    
    var reader = new FileReader();
    
    reader.addEventListener("load", function() {
      var image = new Image();
      image.height = 100;
      image.title  = file.name;
      image.src    = this.result;
      preview.appendChild(image);
    });
    
    reader.readAsDataURL(file);
    
  }

}

document.querySelector('#file-input').addEventListener("change", previewImages);
<input id="file-input" type="file" multiple>
<div id="preview"></div>

Upvotes: 0

Kas Elvirov
Kas Elvirov

Reputation: 8000

Here is jQuery version for you. I think it more simplest thing.

$(function() {
    // Multiple images preview in browser
    var imagesPreview = function(input, placeToInsertImagePreview) {

        if (input.files) {
            var filesAmount = input.files.length;

            for (i = 0; i < filesAmount; i++) {
                var reader = new FileReader();

                reader.onload = function(event) {
                    $($.parseHTML('<img>')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
                }

                reader.readAsDataURL(input.files[i]);
            }
        }

    };

    $('#gallery-photo-add').on('change', function() {
        imagesPreview(this, 'div.gallery');
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="file" multiple id="gallery-photo-add">
<div class="gallery"></div>

Upvotes: 87

subham
subham

Reputation: 1

$(function() {
    // Multiple images preview in browser
    var imagesPreview = function(input, placeToInsertImagePreview) {

        if (input.files) {
            var filesAmount = input.files.length;

            for (i = 0; i < filesAmount; i++) {
                var reader = new FileReader();

                reader.onload = function(event) {
                    $($.parseHTML('<img>')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
                }

                reader.readAsDataURL(input.files[i]);
            }
        }

    };

    $('#gallery-photo-add').on('change', function() {
        imagesPreview(this, 'div.gallery');
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<input type="file" multiple id="gallery-photo-add">
<div class="gallery">

$(function() {
    // Multiple images preview in browser
    var imagesPreview = function(input, placeToInsertImagePreview) {

        if (input.files) {
            var filesAmount = input.files.length;

            for (i = 0; i < filesAmount; i++) {
                var reader = new FileReader();

                reader.onload = function(event) {
                    $($.parseHTML('<img>')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
                }

                reader.readAsDataURL(input.files[i]);
            }
        }

    };

    $('#gallery-photo-add').on('change', function() {
        imagesPreview(this, 'div.gallery');
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<input type="file" multiple id="gallery-photo-add">
<div class="gallery">

Upvotes: -1

Related Questions