Canvas Text to PNG

Canvasで文字描画

アスキーアートの画像化 テキスト画像生成ツール

WxH: x autoWidth:
X,Y: x SCALE X,Y: x
FontSize: font: bold: color:
textAlign: textBaseLine: taegaki:
  • Input

  • Canvas

    canvas
  • PNG (DL)

    canvasText.png

JavaScript

$(function(){
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');

  var e = {};
  e.textarea = $('#textarea');
  e.canvas = $('#canvas');
  e.a = $('#imgLink');
  e.img = $('#img');

  var o = [];
  //o.fontFamily = 'MS PGothic';

  function readyEvent(){
    //イベント監視
    $('input').on('change', function(){
      //resizeCanvas();
    });
    $('input,select,textarea').each(function(){
      var name = $(this).attr('name');
      var type = $(this).attr('type');
      var val = $(this).val();
      e[name] = $(this);
      o[name] = val;
      if(type === 'checkbox'){
        o[name] = $(this).prop('checked');
      }
      console.log(o[name]);
    });
    $('input,select,textarea').on('change', function(){
      var name = $(this).attr('name');
      var type = $(this).attr('type');
      var val = $(this).val();
      o[name] = val;
      if(type === 'checkbox'){
        o[name] = $(this).prop('checked');
      }
      if($(this).hasClass('css')){
        var hash = {};
        hash[name] = val;
        e.textarea.css(hash);
      }
      console.log(o);
    });

    $('input[name="w"]').on('focus', function(){
      $('[name="isAutoWidth"]').prop('checked', false).change();
    });
    $('.css').on('change', function(){
      var name = $(this).attr('name');
      var val = $(this).val();
    });

    $('#clear').click(function(){
      ctx.clearRect(o.x, o.y, o.w, o.h);
      drawWhite();
      toPng();
    });
    $('#overlay').click(function(){
      drawText(o.text);
      toPng();
    });
    $('#reload').click(function(){
      var text = e.textarea.val();
      ctx.clearRect(o.x, o.y, o.w, o.h);
      drawText();
      toPng();
    });

    e.isAutoWidth.prop('checked', true).change();
  }
  readyEvent();
  console.log(o);
  resizeCanvas();

  //画像変換
  function toPng(){
    var url = canvas.toDataURL();

    //圧縮 canvastool.pngencoder.min.js
    var encoder = new CanvasTool.PngEncoder(
        canvas,
        {
/*
            bitDepth: 8,
            colourType: CanvasTool.PngEncoder.ColourType.INDEXED_COLOR
*/
        }
    );
    var png = encoder.convert();
    url = 'data:image/png;base64,' + window.btoa(png);


    var link = url.replace('image/png', 'application/octet-stream');
    e.a.attr({'href': link, 'download': 'text-' + o.text.substr(0,9) + '.png'});
    e.img.attr({'src': url});
  }

  //サイズ変更
  function resizeCanvas(){
    e.w.val(o.w).change();
    e.h.val(o.h).change();
    canvas.width = o.w;
    canvas.height = o.h;
    fontSize = o.fontSize || 9;
    ctx = canvas.getContext('2d');

    var attr = {
      width: o.w,
      height:o.h
    };
    e.textarea.css(attr);
    e.canvas.css(attr);
    e.img.css(attr);
  }

  //テキスト描画
  function drawText() {
    ctx.beginPath();
    textList = o.text.split('\n');
    //自動サイズ変更チェック
    console.log(o.isAutoWidth);
    if(o.isAutoWidth){
      autoResize(textList);
    }
    resizeCanvas();
    setFontStyle();

    //ctx.fillText(text, x, y, 200);
    //UnToDo:自動改行はめんどくさい
    //ctx.measureText(v).height は存在しない 
    var lineHeight = 2;
    o.text.split('').forEach(function(v){
      if(ctx.measureText(v).width > lineHeight){
        lineHeight = ctx.measureText(v).width;
        console.log(lineHeight);
      }
    });


    var xAlign = {
      'left' : 0,
      'center' : o.w/2 - o.textLength/2,
      'right' : o.w - o.textLength,
    };
    var textX = xAlign[o.textAlign] || 0;

    ctx.scale(o.scaleX, o.scaleY);
    if(o.Tategaki){
      tategaki(ctx, o.text, 0,0)
    } else {
      textList.forEach(function(text, i) {
        ctx.fillText(o.text, o.x + textX, o.y+lineHeight*i);
        ctx.scale(o.scaleX, o.scaleY);
      });
    }


  }
    
  var tategaki = function(context, text) {
    var textList = o.text.split('\n');
    var lineHeight = context.measureText("あ").width;
    textList.forEach(function(elm, i) {
      Array.prototype.forEach.call(elm, function(ch, j) {
        context.fillText(ch, o.x-lineHeight*i, o.y+lineHeight*j);
      });
    });
  };

  //自動サイズ変更
  function autoResize(){
    console.log('????');
    var maxLineText = 0;
    var maxLength = 0;
    var textList = o.text.split('\n');
    textList.forEach(function(text, i) {
      var textListWidth = ctx.measureText(text).width;
      if(textListWidth > maxLineText){
        maxLineText = textListWidth;
      }
      if(o.text.length > maxLength){
        maxLength = o.text.length;
      }
    });
    o.textLength = maxLength;
    console.log(maxLineText);
    o.w = Math.ceil(maxLineText);
    o.h = textList.length * fontSize;
    if(o.isTategaki){
      o.w = Math.ceil(o.fontSize);
      o.h = Math.ceil(o.fontSize) * maxLength;
    }
    o.w *= o.scaleX;
    o.h *= o.scaleY;
    console.log([o.w, o.h]);
  }

  function setFontStyle(){
    ctx.fillStyle = o.color;  
    var fontWeight =  o.isBold ? 'bold' : 'normal';
    var font = fontWeight + ' '+ o.fontSize + 'px' + ' ' + '"' + o.fontFamily + '"';//"MS ゴシック"
    console.log(font);
    ctx.font = font
    ctx.textAlign = o.textAlign;
    ctx.textBaseline = o.textBaseline;
  }

  function drawWhite(){
    ctx.fillStyle = "rgba(255, 255, 255, 1)";
    ctx.fillRect (o.x, o.y, o.w, o.h);
  }

});

CSS

@font-face {
  font-family: 'pixelmplus12';
  src :url('/font/PixelMplus12-Bold.ttf') format('truetype');
/*
  src:
   url('font/pixelmplus12-bold-webfont.eot') format('eot'),
   url('font/pixelmplus12-bold-webfont.ttf') format('truetype'),
   url('font/pixelmplus12-bold-webfont.woff') format('woff'),
   url('font/pixelmplus12-bold-webfont.woff2') format('woff2'),
   url('font/pixelmplus12-bold-webfont.svg') format('svg');
*/
}

@font-face {
  font-family: 'Noto JP Black';
  font-style: normal;
  font-weight: 400;
  src: url(/fonts/NotoSansJP-Black.otf) format('opentype');
}
@font-face {
  font-family: 'Noto JP Thin';
  font-style: normal;
  font-weight: 100;
  src: url(/fonts/NotoSansJP-Thin-Windows.otf) format('opentype');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 100;
  src: url(/fonts/Roboto-Black.ttf) format('truetype');
}
@font-face {
  font-family: 'MPlus';
  font-style: normal;
  font-weight: 100;
  src: url(/fonts/mplus-1c-black.ttf) format('truetype');
}
@font-face {
  font-family: 'Yourself';
  font-style: normal;
  src: url(/fonts/Yourself.ttf) format('truetype');
}
@font-face {
  font-family: 'zephyreg';
  font-style: normal;
  src: url(/fonts/zephyreg.ttf) format('truetype');
}


#inputArea{
  margin:8px 0;
}

#inputArea input{
  margin:4px 0;
}

input[type="number"]{
  width:40px;
}
input[type="text"]{
  width:60px;
}

canvas,
textarea,
#img{
  min-width:12px;
  min-height:12px;
  /*
  width:200px;
  height:200px;
  */
  border:1px solid #999999;
  font-size:12px;
}

textarea{
  min-height:28px;
  min-width:120px;
  background-color:#eeeeee;
  box-sizing:border-box;
}

.hori:after{
  display:block;
  content:"";
  clear:both;
}
.hori li{
  min-width:200px;
  float:left;
}