🤔 Para Refletir :
"Refatorar o código é como usar inseticida: Elimina bugs."
- Mayleone

[HTML5][JS] Salvando imagens geradas por canvas sem servidor

Crixus

Marquês
Membro
Membro
Juntou-se
07 de Julho de 2015
Postagens
586
Bravecoins
4
[yellowalert]A base tá prontinha, acabou de sair do forno:
https://rpgmaker.000webhostapp.com/games/html5/canvas/RMXP-CharacterMaker/


[image]

[/yellowalert]

Em navegadores mais antigos isso óbviamente não funcionará, se for IE anteriores ao Html5 só funcionaria com AtiveX (WScript talvez).

Navegadores testados que funcionou:
  • Mozilla Firefox (Desktop)
  • Google Chrome (Desktop)
  • Opera Chromium (Desktop)

Mas vamos ao que existe de mais moderno na linguagem Web para ClientSide (ou seja, que não está no servidor).
Qualquer desenho ou informação gerada dentro de um canvas gera uma imagem em BASE64.

Canvas é uma tag de HTML5 usada para desenvolver variadas aplicações, inclusive criação de jogos Web sem a necessidade do Flash, UnityWeb ou SilverLight:
Código:
<canvas></canvas>

É possivel desenhar até com plano de fundo transparente, ou seja PNG 32-Bits.

O problema em si não é como desenhar e sim como salvar o conteúdo do desenho diretamente no seu disco com um nome prédefinido ou digitado.

Para podermos capturar a informação do CANVAS basta usar o seguinte comando:
Código:
id_do_seu_canvas.toDataURL()

E ele retornará a imagem e Base64 já pronta pra ser atribuida a um link ou um SRC de uma imagem:
Código:
data:image/png;base64,iVBORw0KGgoAAA...

Mas como colocar um nome prédefinido com extensão, bem a maioria dos navegadores com suporte para HTML5 permite nomear o arquivo acessado por um link:
Código:
<a href="seu_link_ou_arquivo" download="nome_do_arquivo.extensão">LINK</a>
(Isto não funcionará no Internet Explorer 11 e anteriores)
Simples não? Mas e para atribuir outro nome dinamicamente ou o conteudo do canvas dinamicamente? Agora vamos ao JAVASCRIPT.

Para enviar o valor do canvas para o HREF este link também deve ter uma ID única, assim como o canvas:
Código:
<canvas id="meucanvas"></canvas>
<a id="arquivo" download="">FAÇA O DOWNLOAD AQUI</a>

O Javascript deverá ser assim se essas IDs forem as definidas:
Código:
function salvasImagem(a){
   /*Comentário: a variavel "a" será o nome do arquivo, use aspas para chamar a função */
   arquivo.download = a;
   arquivo.href = meucanvas.toDataURL();
}

Se não funcionar declarar as IDs como variaveis:
Código:
function salvasImagem(a){
   var meucanvas = document.getElementById('meucanvas');
   var arquivo = document.getElementById('arquivo');
   /*Comentário: a variavel "a" será o nome do arquivo, use aspas para chamar a função */
   arquivo.download = a;
   arquivo.href = meucanvas.toDataURL();
}

Então para chamar, isso pode ser feito por um botão ou link ou tempo, vai variar do seu conhecimento ou escolha:
Código:
salvasImagem('gráfico.png')

Para ter um exemplo pronto eu colocarei o código aqui e o arquivo HTML de exemplo em anexo:
Código:
<!DOCTYPE html>
<html>
<head>
	<title>Gerar e salvar imagem com CANVAS</title>
	<meta charset="UTF-8"> 
	<script>
	function iniciarExemplo(){
		var c = document.getElementById("meucanvas");
		var ctx = c.getContext("2d");

		// Criar Gradiente
		var grd = ctx.createRadialGradient(75,50,5,90,60,100);
		grd.addColorStop(0,"red");
		grd.addColorStop(1,"white");

		// Efeito
		ctx.fillStyle = grd;
		ctx.fillRect(10,10,150,80);
	}
	function salvarImagem(a){
	   var meucanvas = document.getElementById('meucanvas');
	   var arquivo = document.getElementById('arquivo');
	   /*Comentário: a variavel "a" será o nome do arquivo, use aspas para chamar a função */
	   arquivo.download = a;
	   arquivo.href = meucanvas.toDataURL();
	}
	</script>
</head>
<body onload="iniciarExemplo()">
<canvas id="meucanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
Seu navegador não suporta CANVAS</canvas>
<hr>
<a id="arquivo" download="nome_do_arquivo.extensão" onclick="salvarImagem('exemplo.png')">FAÇA O DOWNLOAD AQUI</a>
</body>
</html>



Enfim, e no RpgMaker MV como se faz isso?
Até o momento não achei, pois as imagens deles são geradas por WebGL e não dentro do CANVAS realmente, então assim que eu descobrir repassarei aqui.

Eu sei que os únicos dois canvas que um jogo feito no RpgMV usa são os de IDs GameCanvas
e UpperCanvas.

O nosso amigo [member=1152]Hudell[/member] já descobriu e usou isso rsrs
Segue o link:
https://forums.rpgmakerweb.com/index.php?threads/orange-screenshot-saver.49560/
 

Anexos

Pessoal, demorei um pouco por falta de tempo, apesar de ninguém ter tido o bom senso de analisar a demo aqui está a versão atualizada:
https://rpgmaker.000webhostapp.com/resources/RMXP-CharacterMaker-Canvas/

Isso mesmo, um gerador de Charasets de RMXP feito com Canvas que não necessitará de conexão com um servidor.
Pronto, seleção de tipo de cabelo (Não é possivel escolher a cor ainda)
 
Trabalho espetacular amigo. Com certeza seus projetos são destaques e inspirações para muitos. Parabéns
 
Ótimo trabalho! Não tinha visto a thread quando ela foi criada, por isso não testei na época.

Crixus comentou:
Eu sei que os únicos dois canvas que um jogo feito no RpgMV usa são os de IDs GameCanvas
e UpperCanvas.
Na verdade o MV cria milhares de canvas enquanto o jogo está rodando. Cada charset, tileset, picture e até as janelas dos menus. Todas usam um canvas próprio internamente. Aí um canvas é pintado em outro que é pintado em outro até que todos acabam no canvas principal.
 
Vai ver que é por isso que trava em computadores domesticos comuns, mesmo o meu com 8 Gigas de RAM não fica tão legal, sente um certa perda de frames.
Mas ainda sim é uma boa idéia para separar niveis/camadas (Hud, menu, objetos, tilesets superiores e inferiores) em qualquer jogo desenvolvido em HTML5.

Sobre a demo que fiz:
Eu fiz o código errado para exportar, vou corrigir.

[Edit]
Corrigido e parte do código JS atualizado, essa etapa de carregar as opções não vai ser mais no código e sim dinamicamente, ele irá procurar os recursos de cada pasta usando "Onload" e "Onerror" para checar, dando a possibilidade de colocar mais recursos mais sem precisar editar o código.
 
Crixus comentou:
Vai ver que é por isso que trava em computadores domesticos comuns, mesmo o meu com 8 Gigas de RAM não fica tão legal, sente um certa perda de frames.
Para jogos de MV o mais importante é ter uma placa de vídeo compatível com opengl. A RAM não faz muita diferença e o processador não importa tanto quanto importava no Ace.
 
Meu notebook tem placa de video separasa e é da Dell, apesar de rodar bem não é 100%.
Resumindo o que você disse: Melhor usa Unity¿?

Bem, logo mais posto alguma atualização do código.
 
Bem, após testes eu percebi uma coisa.
Se eu usar algum recurso gráfico local, como imagens PNG sem estarem hospedadas em algum site ou acessadas via um servidor local o parametro ".toDataURL()" não funcionará no Google Chrome ou Opera por questões de segurança, diferente do Firefox onde fiz os testes primeiramente.
O erro que acontece:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
Eu tentei está solução, mas não resolve:
http://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported

Está é a mesma razão pela qual um jogo feito em RPG MAKER MV não pode ser rodado localmente, ou seja em file:///, somente através de um dominio ou ip via HTTP ou HTTPS a não ser que use o FIREFOX.

Se eu apenas "desenhar" traços e outros objetos sem usar qualquer recurso fora do código funcionará por que não tentar "roubar/acessar" nenhuma informação local do usuário.

Então eu terei que adaptar o código pra usar BLOB, ou seja, vai selecionar uma pasta e listar os arquivos no momento em que usar.
 
Voltar
Topo Inferior