-1

I'm working on a little card creator. The idea behind it, is to take data from a CSV, accordingly get some images from a folder, put them into a canvas with the related text (name, power, bonus etc) and then save it as images (would be awesome if filename = cardname.jpg). But I'm actually stucked with getting the download working properly. The main problem is that every solution I tried, gives me back a blank jpeg, with no trace of my filled canvas. The second problem is that I don't want the download event to be triggered by a button. Just pick the CSV, upload it, let the code create a canvas for each card and download each card in the same folder without any need for confirmation. Is it possible?

The CSV structure is easy, just a lot of rows with the same pattern: ClanName,CardName,1,1,1,CardPower,CardBonus,FullName

The Papaparse library is handled by the two filed I got from their site, as I did not find any CDN.

I'm a beginner, so the easiest the answer the better it is. The important point is to have every img, saved as a jpg inside the same folder. (For example: C:\Users\MyName\Desktop\CardCollectionFolder)

The code is meant to be run once, just to create the bulk of cards as jpegs, offline and on my own computer. So, no security issues within.

Here my code (HTML/CSS + JS/JQuery)

$( document ).ready(function() {

  function loadImages(sources, callback) {
      var images = {};
      var loadedImages = 0;
      var numImages = 0;
      // get num of sources
      for(var src in sources) {
        numImages++;
      }
      for(var src in sources) {
        images[src] = new Image();
        images[src].onload = function() {
          if(++loadedImages >= numImages) {
            callback(images);
          }
        };
        images[src].src = sources[src];
      }

    }

    function creaCartaFinale(results, i){
        

      var canvas = document.getElementById("myCanvas"+i);
      var context = canvas.getContext('2d');
      
        var clan=(results.data[i][0]);
        const nome =(results.data[i][1]); 
        var rarita =(results.data[i][2]);
        var stelle =(results.data[i][3]);
        var potenza =(results.data[i][4]);
        var danno =(results.data[i][5]);
        const potere =(results.data[i][6]);
        const bonus=(results.data[i][7]);
        var nomeintero=(results.data[i][8]);
    
        imgStelle = "Immagini/LivelloCarte/livello"+ stelle +".png";
        imgClan= "Immagini/IconeClan/"+ clan +"_42.png";
        if (rarita=="Non comune"){
            imgRarita = "Immagini/RaritaCarta/raritanoncomune.png";
        } else {
            imgRarita = "Immagini/RaritaCarta/rarita"+rarita+".png";
        }
    
        immagine ="Immagini/ImmaginiChar/"+clan+"_"+nomeintero+"_N"+stelle+"_HD_673.png"
    
        var sources = {
            image1: 'Immagini/SfondoCarte/base.png',
            image2:'Immagini/SfondoCarte/riquadro.png',
            image3: immagine,
            image4:'Immagini/SfondoCarte/poteri.png',
            image5: imgRarita,
            image6: imgStelle,
            image7: 'Immagini/SfondoCarte/riquadrobis.png',
            image8: imgClan,
            image9: 'Immagini/Numeri/'+potenza+'.png',
            image10:'Immagini/Numeri/'+danno+'.png',
          };
    
        
          loadImages(sources, function(images) {
            context.drawImage(images.image1, 0, 0,  2220 , 3240);  //SFONDO *   x - y
            context.drawImage(images.image2, 80, 80,  2040 ,1900);//RIQUADRO
            context.drawImage(images.image3, 0, 0,  2220 ,3150);  //IMMAGINE *
            context.drawImage(images.image4, 80, 2000,  2050 ,1150);  //LAYOUT POTERI *
            context.drawImage(images.image5, 520, 80,  1610 ,200);   //RARITA *
            context.drawImage(images.image6, 600, 2000,  1240 ,260);  //STELLE *
            context.drawImage(images.image7, 100, 70,  360 ,360);  //RIQUADRO CLAN *
            context.drawImage(images.image8, 120, 80,  320 ,320);  //CLAN *
            context.drawImage(images.image9, 170, 2350,  130 ,170);  //FORZA *
            context.drawImage(images.image10, 170, 2950,  130 ,170);  //DANNO *
    
            //STAMPA NOME
            context.font = "200px Calibri";
            var gradient = context.createLinearGradient (0,0, canvas.width,0)
            gradient.addColorStop("0", "white")
            context.fillStyle = gradient;
            context.fillText(nome, 600, 250);
    
    
            //STAMPA POTERI E BONUS
            context.font = "105px Calibri";
            if (potere.length > 34){
              var ultimoIndice = potere.length -1;
              var frase30 = potere.slice(0,33);
              var n = frase30.lastIndexOf(" ");
              var primaFrase = potere.slice(0,n)
              var secondaFrase = potere.slice(n,ultimoIndice)
              context.fillText(primaFrase, 750, 2500);
              context.fillText(secondaFrase, 750, 2620);
    
            }
            else{
               context.fillText(potere, 750, 2500);
            }
            if (bonus.length > 34){
              var ultimoIndice = bonus.length -1;
              var frase30 = bonus.slice(0,33);
              var n = frase30.lastIndexOf(" ");
              var primaFrase = bonus.slice(0,n)
              var secondaFrase = bonus.slice(n,ultimoIndice)
              context.fillText(primaFrase, 750, 2850);
              context.fillText(secondaFrase, 750, 2970);
            }
            else{
              context.fillText(bonus,750, 2850);
            }
    
          });
    }


  document.getElementById('txtFileUpload').addEventListener('change', upload, false);
  
  function upload(evt) {
      var file = evt.target.files[0];
      var reader = new FileReader();
      reader.readAsText(file);
      reader.onload = function (event) {
          var csvData = event.target.result;
          Papa.parse(csvData, {
              complete: function (results) {
                  console.log(results.data);
                  var numeroCarte=(results.data.length);
                  for(var i=0; i<numeroCarte; i++){
                    $( ".cartaSingola" ).prepend( "<canvas class='cardCanvas' id='myCanvas"+i+"' width='2500' height='3500'></canvas>" );
                    creaCartaFinale(results,i);
                    download_image(i);
                  }
              }
          });
      };
  }

  //THIS FUNCTION DOES NOT WORK, JUST GIVES BACK A BLANK FILE
  function download_image(i){
    var canvas = document.getElementById("myCanvas"+i);
    image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
    var link = document.createElement('a');
    link.download = "my-image.png";
    link.href = image;
    link.click();
  }
      

});
/* .contenitoreCarte{
    height:88mm;
    width:63mm;
} */

.cartabase{
    margin:15px;
    height:88mm;
    width:63mm;
}

.nomeCarta{
    position: relative;
    top: -352px;
    right: -102px;
    width:45mm;
    height:6mm;
    text-align: center;
    z-index:1;
    
}

.nomeCarta p{
    text-align: center;
    width: 100%;
    left: -32px;
    position: relative;
}

.potereCarta{
    position: relative;
    top: -352px;
    right: -102px;
    width:45mm;
    height:6mm;
    text-align: center;
}
.potereCarta p{
    text-align: center;
    
    position: relative;
    bottom: -194px;
    width: 82%;
    left: -6px;
    word-wrap: break-word
}
.bonusCarta{
    position: relative;
    top: -352px;
    right: -102px;
    width:45mm;
    height:6mm;
    text-align: center;
}
.bonusCarta p{
    text-align: center;
    width: 82%;
    left: -6px;
    bottom: -195px;
    position: relative;
    word-wrap: break-word
}

.forzaCarta{
    position: relative;
    top: -352px;
    right: -102px;
    width:45mm;
    height:6mm;
    text-align: center;
}
.forzaCarta p{
    text-align: center;
    width: 100%;
    left: -148px;
    bottom: -119px;
    position: relative;
}

.dannoCarta{
    position: relative;
    top: -352px;
    right: -100px;
    width:45mm;
    height:6mm;
    text-align: center;
}
.dannoCarta p{
    text-align: center;
    width: 100%;
    left: -146px;
    bottom: -139px;
    position: relative;
}

.livelloCarta{
    /* width: 32mm; */
    width: 42mm; 
    height: 7mm;
    right: -36px;
    top: -166px;
    position: relative;
}

.clanCarta{
    height: 9mm;
    width: 9mm;
    right: -15px;
    top: -278px;
    position: relative;
    z-index: 1;
}

.raritaCarta{
    height: 6mm;
    width: 45mm;
    right: -35px;
    top: -296px;
    position: relative;
}

.baseCarta{
    height: 88mm;
    width: 63mm;
    right: -7px;
    top: -312px;
    position: relative;
    z-index: -99;
}
 .riquadroCarta{
    height: 50mm;
    width: 56mm;
    right: -14px;
    top: -473px;
    position: relative;
}

.poteriCarta{
    height: 32mm;
    width: 58mm;
    right: -12px;
    top: -470px;
    position: relative;
    z-index: -99;
}

.immaginiCarta{
    height: 92mm;
    width: 68mm;
    right: -3px;
    top: -642px;
    position: relative;
    z-index: 1;
}


.cardCanvas{
    position: relative;
    display: block;
}
<html>

  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />

    <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"type="text/css" />

    <link rel="stylesheet" href="Pagina.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="Pagina.js"></script> 
    <script src="papaparse.js"></script> 
    <script src="papaparse.min.js"></script> 

    <title>Card maker</title>                             
  
  </head>


  <body>

    <input type="file" name="File Upload" id="txtFileUpload" accept=".csv" />

    <div class="cartaSingola">
       
    </div>

  </body>

</html>
  • 1
    You cannot write files with JavaScript (which would be a total security nightmare) – Andreas Mar 22 '20 at 17:03
  • Pretty sure it will, but this is meant to be run once, offline, on my own pc, to create some cards for fun. Since the code is written in JS and works fine until the saving of the jpegs, I don't see any problem about it. – Gianluca Fontana Mar 22 '20 at 18:31
  • Please review https://stackoverflow.com/questions/17311645/download-image-with-javascript I think you want to keep the MIME Type as is. – Twisty Mar 22 '20 at 18:42

1 Answers1

0

Consider the following:

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');

// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();

function download_image(trg) {
  var canvas = document.getElementById(trg);
  var dataUrl = canvas.toDataURL("image/png");
  var link = document.createElement('a');
  link.download = "my-image.png";
  link.href = dataUrl.replace("image/png", "image/octet-stream");
  console.log(link);
  link.click();
}

download_image("myCanvas");
<canvas id="myCanvas" width="578" height="200" style="display:none;"></canvas>

Unable to test this for you with your code.

Twisty
  • 30,304
  • 2
  • 26
  • 45
  • Doesn't work, I upload the CSV, the image is created but as soon as the code reached the function it gives back an error "file not found" – Gianluca Fontana Mar 22 '20 at 18:57
  • @GianlucaFontana updated after a bit of research. https://stackoverflow.com/questions/8126623/downloading-canvas-element-to-an-image – Twisty Mar 22 '20 at 18:58
  • The second solution of this post gets the automatic download, but with the same problem of having a blank jpg. – Gianluca Fontana Mar 22 '20 at 19:09
  • I tried to swap position of the callback to that function. I do receive a blank image or a message "tainted canvases may not be exported" if i call the function inside the call of loadimages, nested inside the function creaCartaFinale – Gianluca Fontana Mar 22 '20 at 19:16
  • @GianlucaFontana am not able to replicate that. When I run the script in my answer, I get a download and it saves as a PNG not a JPG. I can then open it properly after download. You will need to make a Minimal, Reproducible Example: https://stackoverflow.com/help/minimal-reproducible-example – Twisty Mar 22 '20 at 19:32
  • I made a rar with files needed, directly on my google drive, so you can test easily : https://drive.google.com/open?id=18TduQGvnivi2CP47oqZIv6PxPvgTapQB – Gianluca Fontana Mar 22 '20 at 19:59
  • have you had a chance to take a look at it? :) – Gianluca Fontana Mar 23 '20 at 18:18