2012-10-09 37 views
9

estoy unsing el plugin canvas2Image.js:Canavas2Image.js ahorrar img base 64 como elemento de png a través de clic

/* 
* Canvas2Image v0.1 
* Copyright (c) 2008 Jacob Seidelin, [email protected] 
* MIT License [http://www.opensource.org/licenses/mit-license.php] 
*/ 

var Canvas2Image = (function() { 

    // check if we have canvas support 
    var bHasCanvas = false; 
    var oCanvas = document.createElement("canvas"); 
    if (oCanvas.getContext("2d")) { 
     bHasCanvas = true; 
    } 

    // no canvas, bail out. 
    if (!bHasCanvas) { 
     return { 
      saveAsBMP : function(){}, 
      saveAsPNG : function(){}, 
      saveAsJPEG : function(){} 
     } 
    } 

    var bHasImageData = !!(oCanvas.getContext("2d").getImageData); 
    var bHasDataURL = !!(oCanvas.toDataURL); 
    var bHasBase64 = !!(window.btoa); 

    var strDownloadMime = "image/octet-stream"; 

    // ok, we're good 
    var readCanvasData = function(oCanvas) { 
     var iWidth = parseInt(oCanvas.width); 
     var iHeight = parseInt(oCanvas.height); 
     return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight); 
    } 

    // base64 encodes either a string or an array of charcodes 
    var encodeData = function(data) { 
     var strData = ""; 
     if (typeof data == "string") { 
      strData = data; 
     } else { 
      var aData = data; 
      for (var i=0;i<aData.length;i++) { 
       strData += String.fromCharCode(aData[i]); 
      } 
     } 
     return btoa(strData); 
    } 

    // creates a base64 encoded string containing BMP data 
    // takes an imagedata object as argument 
    /*var createBMP = function(oData) { 
     var aHeader = []; 

     var iWidth = oData.width; 
     var iHeight = oData.height; 

     aHeader.push(0x42); // magic 1 
     aHeader.push(0x4D); 

     var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes 
     aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize/256); 
     aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize/256); 
     aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize/256); 
     aHeader.push(iFileSize % 256); 

     aHeader.push(0); // reserved 
     aHeader.push(0); 
     aHeader.push(0); // reserved 
     aHeader.push(0); 

     aHeader.push(54); // dataoffset 
     aHeader.push(0); 
     aHeader.push(0); 
     aHeader.push(0); 

     var aInfoHeader = []; 
     aInfoHeader.push(40); // info header size 
     aInfoHeader.push(0); 
     aInfoHeader.push(0); 
     aInfoHeader.push(0); 

     var iImageWidth = iWidth; 
     aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth/256); 
     aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth/256); 
     aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth/256); 
     aInfoHeader.push(iImageWidth % 256); 

     var iImageHeight = iHeight; 
     aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight/256); 
     aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight/256); 
     aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight/256); 
     aInfoHeader.push(iImageHeight % 256); 

     aInfoHeader.push(1); // num of planes 
     aInfoHeader.push(0); 

     aInfoHeader.push(24); // num of bits per pixel 
     aInfoHeader.push(0); 

     aInfoHeader.push(0); // compression = none 
     aInfoHeader.push(0); 
     aInfoHeader.push(0); 
     aInfoHeader.push(0); 

     var iDataSize = iWidth*iHeight*3; 
     aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize/256); 
     aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize/256); 
     aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize/256); 
     aInfoHeader.push(iDataSize % 256); 

     for (var i=0;i<16;i++) { 
      aInfoHeader.push(0); // these bytes not used 
     } 

     var iPadding = (4 - ((iWidth * 3) % 4)) % 4; 

     var aImgData = oData.data; 

     var strPixelData = ""; 
     var y = iHeight; 
     do { 
      var iOffsetY = iWidth*(y-1)*4; 
      var strPixelRow = ""; 
      for (var x=0;x<iWidth;x++) { 
       var iOffsetX = 4*x; 

       strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]); 
       strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]); 
       strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]); 
      } 
      for (var c=0;c<iPadding;c++) { 
       strPixelRow += String.fromCharCode(0); 
      } 
      strPixelData += strPixelRow; 
     } while (--y); 

     var strEncoded = encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData); 

     return strEncoded; 
    } 
*/ 

    // sends the generated file to the client 
    var saveFile = function(strData) { 
     document.location.href = strData; 
    } 

    var makeDataURI = function(strData, strMime) { 
     return "data:" + strMime + ";base64," + strData; 
    } 

    // generates a <img> object containing the imagedata 
    var makeImageObject = function(strSource) { 
     var oImgElement = document.createElement("img"); 
     oImgElement.src = strSource; 
     return oImgElement; 
    } 

    var scaleCanvas = function(oCanvas, iWidth, iHeight) { 
     if (iWidth && iHeight) { 
      var oSaveCanvas = document.createElement("canvas"); 
      oSaveCanvas.width = iWidth; 
      oSaveCanvas.height = iHeight; 
      oSaveCanvas.style.width = iWidth+"px"; 
      oSaveCanvas.style.height = iHeight+"px"; 

      var oSaveCtx = oSaveCanvas.getContext("2d"); 

      oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iHeight); 
      return oSaveCanvas; 
     } 
     return oCanvas; 
    } 

    return { 

     saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) { 
      if (!bHasDataURL) { 
       return false; 
      } 
      var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight); 
      var strData = oScaledCanvas.toDataURL("image/png"); 
      if (bReturnImg) { 
       return makeImageObject(strData); 
      } else { 
       saveFile(strData.replace("image/png", strDownloadMime)); 
      } 
      return true; 
     }, 

     saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) { 
      if (!bHasDataURL) { 
       return false; 
      } 

      var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight); 
      var strMime = "image/jpeg"; 
      var strData = oScaledCanvas.toDataURL(strMime); 

      // check if browser actually supports jpeg by looking for the mime type in the data uri. 
      // if not, return false 
      if (strData.indexOf(strMime) != 5) { 
       return false; 
      } 

      if (bReturnImg) { 
       return makeImageObject(strData); 
      } else { 
       saveFile(strData.replace(strMime, strDownloadMime)); 
      } 
      return true; 
     }, 

    /* saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) { 
      if (!(bHasImageData && bHasBase64)) { 
       return false; 
      } 

      var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight); 

      var oData = readCanvasData(oScaledCanvas); 
      var strImgData = createBMP(oData); 
      if (bReturnImg) { 
       return makeImageObject(makeDataURI(strImgData, "image/bmp")); 
      } else { 
       saveFile(makeDataURI(strImgData, strDownloadMime)); 
      } 
      return true; 
     }*/ 
    }; 

})(); 

en html hago:

<script type="text/javascript"> 
    $(document).ready(function(){ 
    var _txt = "hey"; 
    $('#qrcode').qrcode({ 
     text :_txt 
    }); 
    $("#qrcode-canvas").attr("download","file.png"); 
    var oCanvas = document.getElementById("qrcode-canvas"); 
    $("#download-qrcode").on('click',function(){ 
     Canvas2Image.saveAsPNG(oCanvas); 
    }) 
    }); 
    </script> 

<div id="qrcode" class="" style="" ></div> 
<a class="btn btn-large btn-inverse" id="download-qrcode"><i class="icon icon-download-alt icon-white"></i> download</a> 

estoy teniendo problema, i 'm usando FF MacOSX, Chrome Opera y Safari, entonces yo llamo el saveAsPNG() método a través elemento clic

la imagen devuelve un documento sin extensión para ser salvo:

data:image/octet-stream;base64,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 

me gustaría guardarlo como imagen, le gustaría png:/

es posible?

porque puedo corregirlo usando data: image/png; etc. pero se abrirá una nueva ventana en el navegador.

+1

Si no le da un tipo MIME correcto, ¿cómo se supone que debe saber qué tipo de archivo de imagen para guardarlo? – Barmar

+0

@Barmar y cómo agregar eso? – sbaaaang

+0

quiero decir, si lo hago imagen/png se abre una nueva ventana mientras imagen/octet-stream no y no quiero abrir una nueva ventana – sbaaaang

Respuesta

9

En base a esta pregunta: Name a PNG file saved from Canvas using an "open with" dialog, puede utilizar el atributo de un elemento downloada para indicar que el href debe descargarse con el nombre dado.

Mejor aún, podemos configurar el href con el valor de retorno de toDataURL que asegurará que la imagen se descargue realmente como PNG.

<a class="btn btn-large btn-inverse" id="download-qrcode" download="my_file.png"> 
    <i class="icon icon-download-alt icon-white"></i> 
    download 
</a> 

$("#download-qrcode").on('click',function(){ 
    var dataUrl = oCanvas[0].toDataURL(); 
    $(this).attr('href', dataUrl); 
}); 

Cuando se hace clic en el enlace, el archivo se descargará como my_file.png. Como se indica en esa pregunta, el atributo download no es muy compatible: el código anterior solo funcionaba en Chrome, aunque Firefox aparentemente admite ese atributo.

No estoy muy seguro de cómo evitar esto, ya que no puede establecer Content-Disposition en una dirección URL data:, lo que significa que no puede forzar la descarga como puede con un servidor.

También puede consultar esto: http://www.joeltrost.com/blog/2012/01/29/html5-canvas-save-a-jpeg-with-extension/, que se ocupa del mismo problema utilizando un enfoque posterior. Lo bueno de esto es que toma ventaja de la capacidad del servidor para especificar el Content-Disposition para que pueda forzar la descarga de la imagen.

Editar:

Así que la idea del enfoque posterior a la espalda es básicamente para enviar la URL de los datos de vuelta al servidor, que hace eco esencialmente de nuevo. El truco es que, al hacerlo, se establece Content-Disposition, forzando la descarga de la imagen.

Ahora el enlace muestra una solución en PHP, por lo que probablemente podría reutilizar la secuencia de comandos para hacer lo mismo.

+0

no me atrapó en absoluto lo siento, ¿el href attr me permite descargar el archivo como una imagen? o estás sugiriendo una llamada ajax para descargar la imagen? – sbaaaang

+0

usando su código al hacer clic para descargar el navegador, abrir una nueva pestaña que muestra la imagen en formato PNG, lo cual es un gran paso adelante. ¿Necesito usar una llamada ajax a esa url para poder recibir el archivo para descargar? – sbaaaang

+0

quiero decir, puedo enviar una solicitud xhr enviando el código img base64 a un pequeño script php que (tal vez) guarda el img y me hace descargarlo ... – sbaaaang

Cuestiones relacionadas