Carregando uma imagem para um <img> de <arquivo de entrada>

86

Estou tentando carregar uma imagem selecionada pelo usuário por meio de um elemento.

Eu adicionei um manipulador de eventos onchange ao elemento de entrada como este:

<input type="file" name="picField" id="picField" size="24" onchange="preview_2(this);" alt=""/>

e a função preview_2 é:

var outImage ="imagenFondo";
function preview_2(what){
    globalPic = new Image();
    globalPic.onload = function() {
        document.getElementById(outImage).src = globalPic.src;
    }
    globalPic.src=what.value;
}

onde outImage tem o valor de id da tag onde desejo que a nova imagem seja carregada.

No entanto, parece que o onload nunca acontece e não carrega nada no html.

O que devo fazer?

Valentina
fonte

Respostas:

102

Em navegadores que suportam a API de arquivo , você pode usar o construtor FileReader para ler arquivos, uma vez que eles tenham sido selecionados pelo usuário.

Exemplo

document.getElementById('picField').onchange = function (evt) {
    var tgt = evt.target || window.event.srcElement,
        files = tgt.files;

    // FileReader support
    if (FileReader && files && files.length) {
        var fr = new FileReader();
        fr.onload = function () {
            document.getElementById(outImage).src = fr.result;
        }
        fr.readAsDataURL(files[0]);
    }

    // Not supported
    else {
        // fallback -- perhaps submit the input to an iframe and temporarily store
        // them on the server until the user's session ends.
    }
}

Suporte de navegador

  • IE 10
  • Safari 6.0.2
  • Chrome 7
  • Firefox 3.6
  • Opera 12.02

Onde a API de arquivo não é suportada, você não pode (na maioria dos navegadores preocupados com a segurança) obter o caminho completo de um arquivo de uma caixa de entrada de arquivo, nem pode acessar os dados. A única solução viável seria enviar o formulário para um iframe oculto e ter o arquivo pré-carregado no servidor. Então, quando a solicitação for concluída, você pode definir o src da imagem para o local do arquivo carregado.

Andy E
fonte
certo, então não há como fazer upload de uma imagem selecionada do usuário de forma tão simples quanto parece ...?
Valentina
1
sim, estou procurando soluções do navegador x, então acho que vou tentar usar a opção de servidor. Muito obrigado!
Valentina
1
Eu me pergunto por que converter isso em um DataURL e não apenas em um URL de objeto?
ShrekOverflow
4
Se você quiser a versão síncrona, você pode usar: URL.createObjectURL(document.getElementById("fileInput").files[0]);.
Константин Ван
1
@ КонстантинВан Você deve garantir que ligou URL.revokeObjectURLpara evitar vazamentos de memória! developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
Dai
53

Como iEamin disse em sua resposta, o HTML 5 agora oferece suporte para isso. O link que ele deu, http://www.html5rocks.com/en/tutorials/file/dndfiles/ , é excelente. Aqui está uma amostra mínima com base nas amostras desse site, mas consulte esse site para obter exemplos mais completos.

Adicione um onchangeouvinte de evento ao seu HTML:

<input type="file" onchange="onFileSelected(event)">

Faça uma tag de imagem com um id (estou especificando height=200para garantir que a imagem não seja muito grande na tela):

<img id="myimage" height="200">

Aqui está o JavaScript do onchangeouvinte de eventos. Ele pega o Fileobjeto que foi passado como event.target.files[0], constrói um FileReaderpara ler seu conteúdo e configura um novo ouvinte de evento para atribuir o data:URL resultante à imgtag:

function onFileSelected(event) {
  var selectedFile = event.target.files[0];
  var reader = new FileReader();

  var imgtag = document.getElementById("myimage");
  imgtag.title = selectedFile.name;

  reader.onload = function(event) {
    imgtag.src = event.target.result;
  };

  reader.readAsDataURL(selectedFile);
}
Mike Morearty
fonte
Ótimo link! O código que você apresenta para o script não está definido embora.
rashadb
13

$('document').ready(function () {
    $("#imgload").change(function () {
        if (this.files && this.files[0]) {
            var reader = new FileReader();
            reader.onload = function (e) {
                $('#imgshow').attr('src', e.target.result);
            }
            reader.readAsDataURL(this.files[0]);
        }
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="imgload" >
<img src="#" id="imgshow" align="left">

Isso funciona para mim no jQuery.

Asghar
fonte
Como usar isso no caso de 'imgload' e 'imgshow' não estarem definidos com antecedência? Digamos que eu tenha 5 pares de entrada de arquivo e suporte de imagem retornados do servidor, e seus respectivos ids são gerados com base em algum índice que também é retornado do código do servidor.
Ivan
5

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);

nkitku
fonte
1

Andy E está correto ao dizer que não existe uma maneira baseada em HTML de fazer isso *; mas se você deseja usar o Flash, você pode fazê-lo. O seguinte funciona de maneira confiável em sistemas que possuem o Flash instalado. Se o seu aplicativo precisa funcionar no iPhone, é claro que você precisará de uma solução alternativa baseada em HTML.

* ( Atualização em 22/04/2013: HTML agora suporta isso, em HTML5. Veja as outras respostas.)

O upload do Flash também tem outras vantagens - o Flash oferece a capacidade de mostrar uma barra de progresso à medida que o upload de um arquivo grande avança. (Tenho certeza de que é assim que o Gmail faz, usando Flash nos bastidores, embora eu possa estar errado sobre isso.)

Aqui está um exemplo de aplicativo Flex 4 que permite ao usuário escolher um arquivo e, em seguida, exibi-lo:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
               creationComplete="init()">
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:Button x="10" y="10" label="Choose file..." click="showFilePicker()" />
    <mx:Image id="myImage" x="9" y="44"/>
    <fx:Script>
        <![CDATA[
            private var fr:FileReference = new FileReference();

            // Called when the app starts.
            private function init():void
            {
                // Set up event handlers.
                fr.addEventListener(Event.SELECT, onSelect);
                fr.addEventListener(Event.COMPLETE, onComplete);
            }

            // Called when the user clicks "Choose file..."
            private function showFilePicker():void
            {
                fr.browse();
            }

            // Called when fr.browse() dispatches Event.SELECT to indicate
            // that the user has picked a file.
            private function onSelect(e:Event):void
            {
                fr.load(); // start reading the file
            }

            // Called when fr.load() dispatches Event.COMPLETE to indicate
            // that the file has finished loading.
            private function onComplete(e:Event):void
            {
                myImage.data = fr.data; // load the file's data into the Image
            }
        ]]>
    </fx:Script>
</s:Application>
Mike Morearty
fonte
Para esclarecer, para aqueles que estão preocupados com a segurança: o Flash não permite que você acesse NENHUM arquivo local - ele só permite que você acesse um arquivo local que tenha sido explicitamente, interativamente apontado pelo usuário. Isso é semelhante ao que o HTML faz (permite que você carregue qualquer arquivo explicitamente especificado para o servidor), exceto que o Flash também permite acesso local, além da capacidade de carregar o arquivo.
Mike Morearty
Fiz upload do aplicativo Flash executável aqui para que você possa experimentá-lo: morearty.com/preview/FileUploadTest.html
Mike Morearty
1

var outImage ="imagenFondo";
function preview_2(obj)
{
	if (FileReader)
	{
		var reader = new FileReader();
		reader.readAsDataURL(obj.files[0]);
		reader.onload = function (e) {
		var image=new Image();
		image.src=e.target.result;
		image.onload = function () {
			document.getElementById(outImage).src=image.src;
		};
		}
	}
	else
	{
		    // Not supported
	}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>preview photo</title>
</head>

<body>
<form>
	<input type="file" onChange="preview_2(this);"><br>
	<img id="imagenFondo" style="height: 300px;width: 300px;">
</form>
</body>
</html>

Saeed disse
fonte