saveFileDialog(blob) // dark theme

Dark background. Преобразование canvas в blob для отсылки на сервер в бинарном виде (а не dataURL) или для сохранения в файл на клиенте Диалог сохранения blob на клиенте

by denvdmj

HTML

<body>
    <h1>Диалог сохранения blob&#96;а</h1>
    <ul>
      <li>Преобразование canvas в blob для отсылки на сервер в бинарном виде (а не dataURL) или для сохранения в файл на клиенте</li>
      <li>Диалог сохранения blob на клиенте</li>
      <li><a href='http://jsfiddle.net/DenVdmj/go2vpknb/'>saveFileDialog(blob)</a></li>
    </ul>
    <div>
      <input id='file-name' type='text' value='generated-image.png'>
      <button id='save-dialog'>Сохранить изображение на диск</button>
    </div>
    <div>
      <div id='canvasContainer'>
        <div>Canvas:</div>
      </div>
      <div id='imageContainer'>
        <div>Image:</div>
      </div>
    </div>

CSS

body {
  background: #282828;
  color: #ddc;
  font: 14px/130% Verdana;
  min-width: 20em;
  margin: auto;
  padding: 1em 4em;  
}
h1, h2, h3, h4, h5, h6 {
  font: 140%/110% Verdana;
}
body > ul + div {
  margin: 2em 0 1em 0;
}
body > ul + div + div {
  margin: 1em 0 1em 0;
}
a {
  color: #aae;
}
body > ul + div + div > div {
  display: inline-block;
  color: #7A7;
}
body > ul + div + div > div + div {
  display: inline-block;
  color: #88C;
}
canvas, img {
  border: 4px ridge #7A7;
  margin: 10px 10px 10px 0;
  padding: 5px;

}
img {
  border: 4px ridge #88C;
}
input[type="text"] {
  box-sizing: border-box;
  display: block;
  background: linear-gradient(#aaa, #fff);
  border: none;
  font-size: 1.1em;
  padding: .3em .5em;
  margin: 5px 0 5px 5px;
  border-radius: .2em;
  width: 320px;
}
button {
  box-sizing: border-box;
  cursor: pointer;
  display: inline-block;
  vertical-align: top;
  height: 52px;
  width: 320px;
  line-height: 1.6;
  margin: 5px 0 5px 5px;
  padding: 12px 22px;
  position: relative;
  background: linear-gradient(#4d4d4d, #2f2f2f);
  border-radius: 8px;
  border: 1px solid #333;
  font-family: "Lucida Grande", "Lucida Sans Unicode", sans-serif;
  color: white;
  font-size: 1.1em;
  white-space: nowrap;
  text-shadow: 0 1px 2px #000;
  text-overflow: ellipsis;
  text-decoration: none;
  -webkit-user-select: none;
  -moz-user-select: -moz-none;
  -ms-user-select: none;  
  user-select: none;  
}
button:hover {
  background: linear-gradient(#505050, #333);
}
button:active {
  background: linear-gradient(#444444, #282828);
  margin: 6px 0 4px 5px;
}
button:focus {
  outline: 0;
}

/* ******* */
/* ************** */
::selection {
  background: #C9DBEF
}

::-webkit-scrollbar {
  width: 7px;
  height: 7px;
  background: #333;
}
::-webkit-scrollbar-thumb {
  border-radius: 4px !important;
}
::-webkit-scrollbar-thumb:vertical {
  background: linear-gradient(90deg, rgba(0,0,0,0), rgba(110,110,110,.3));
}
::-webkit-scrollbar-thumb:horizontal {
 ...

JavaScript

document.querySelector('button#save-dialog').onclick = function buttonSaveOnClick () {
  var filename = document.querySelector('input#file-name').value;
  document.querySelector('canvas').toBlob(function(blob) {
    saveFileDialog(blob, filename);
  });
};

function saveFileDialog (blob, filename, mimetype) {

  if (navigator.msSaveBlob) {
    navigator.msSaveBlob(blob, filename);
    return;
  }
  
  var a = document.createElement('a'),
      URL = window.URL,
      objectURL;

  if (mimetype) {
    a.type = mimetype;
  }

  a.download = filename;
  a.href = objectURL = window.URL.createObjectURL(blob);

  a.dispatchEvent(new MouseEvent('click'));
  setTimeout(URL.revokeObjectURL.bind(URL, objectURL), 500);
};

function createCanvasImage () {
  var canvas = document.createElement('canvas');
  var context = canvas.getContext('2d');
  canvas.width = 200;
  canvas.height = 150;
  context.fillStyle = '#009';
  canvas.getContext('2d').fillRect(5, 5, 190, 140);
  context.font = '16pt Arial';
  context.fillStyle = '#fff';
  context.fillText('hello, world.', 12, 40);
  document.querySelector('#canvasContainer').appendChild(canvas);
  return canvas;
}

function testImageBlob (canvas) {
  canvas.toBlob(function(blob) {
    // проверка, что блоб правильный
    var fr = new FileReader();
    fr.onload = function() {
      var img = new Image();
      img.src = fr.result;
      document.querySelector('#imageContainer').appendChild(img);
    };
    fr.readAsDataURL(blob);
  });
}

if (window.HTMLCanvasElement && !HTMLCanvasElement.prototype.toBlob) {
  HTMLCanvasElement.prototype.toBlob = function (cback) {
    var str = this.toDataURL();
    str = atob(str.substr(str.indexOf('base64') + 7));
    var buffer = new ArrayBuffer(str.length);
    var bytes = new Uint8Array(buffer);
    for (var i = 0; i < str.length; ++i) {
      bytes[i] = str.charCodeAt(i);
    }
    cback(new Blob([bytes]));
  };
}

testImageBlob( createCanvasImage() );