canvasをSVG、EPSへベクトル情報を保持したまま変換するシステム

AWS システム開発

canvasで作った画像がそのまま印刷所へ投稿できるようになるまで

イラストレーターを使って画像を作り、印刷所へ投稿することはありますが、今回それをWEB画面上だけで完結するWebサイトを作成しました。
canvas上に写真や文字、フレームを設定して、そのcanvasデータをSVGに変換し、更にEPSへ変換することで対応できます。
ここではその仕組をご紹介します。

前提となる知識:HTML/JavaScriptがある程度自由に読み書き出来る方向けです

canvas上でベクトル画像を扱えるようにする

通常のcanvasは、お世辞にも高機能とは言えない最低限の機能しか持っていません。canvasを更に便利に、グレードアップさせるにはいくつかの選択肢がありますが、ここでは
fabric.jsを利用しました。

fabric.jsはcanvas上のデータをオブジェクトとして扱うことができるようになるcanvas用のライブラリです。
残念ながらマニュアルは非常に読みにくいです。
しかしチュートリアルを一通りやれば最低限のことは出来るようになります。

fabric.jsをダウンロードし、適当なディレクトリに解答しておきます。
使用するファイルは /dist/fabric.jsです。

html上でfabric.jsをインポートします

<head>
  <script type="text/javascript" src="./lib/fabric.js"></script>
</head>

html上にcanvasを作成する

fabric.jsの利用準備ができたので、html上にcanvasを作成しましょう。適当な場所にcanvasを作ります

   <canvas id="c" width="320" height="320" style="border:2px dashed #bbb;"></canvas>

idは c とします。キャンバスの大きさはwidthとheightで自由に変更できます。また、キャンバスの枠線はstyleで簡単に設定しました。

javascriptでcanvasを操作します。


<script type="text/javascript">
var canvas = new fabric.Canvas('c');
// 簡単な四角を書いてみる
sikaku = new fabric.Rect({left: 17,top: 80,fill: 'red', width: 20,height: 20});
canvas.add(sikaku);
</script>

これでキャンバス上に赤い四角が作成できます。

文字を入力したり、フォームから画像をセットすることも可能です。この辺のfabric.jsに関する操作については公式マニュアルを御覧ください。

canvasをSVGに変換する

fabric.jsがサポートしている機能なので、比較的簡単にSVGへ変換できます。
変換は次の1行だけです

canvas.toSVG();

しかし、canvasのデータを、SVGに変換し、これをサーバに保存するためには若干面倒な処理が必要です。
試行錯誤でやったのでもっと効率の良いやり方もあるはずです。

以下、あまり効率の良くない保存方法

<form action="転送先URL" method="post" role="form" enctype="multipart/form-data" onsubmit="return do_submit()">
    <input type="hidden" value="" name="upfile" id="upfile">
    <input type="submit" name="submit" class="btn btn-primary btn-lg" value="保存" >
</form>
<script type="text/javascript">
function do_submit() {
    $("#upfile").val(canvas.toSVG());
    document.forms.submit();
}
</script>

サブミットされるときに、upfileにsvgに変換したキャンバスのデータをセットします。svgはテキストなので、これで動きます。

ハマりポイント

  • キャンバス上にラスター型の画像(JPGやPNG)が含まれる場合、うまく反映されないことがあります。ラスタ系の画像はBase64エンコードして埋め込むことでうまく動作しました
  • 最後のSVGからEPSへ変換する際、フォントが変わってしまうことがあります。woffフォントで明示的に使用するフォントを指定する必要があるようです。
  • EPSは透過を扱えないため、写真の前に配置するフレームのような素材は注意が必要です。

JpegやPngについては、以下のような関数を用意しとくと良いでしょう。

<script type="text/javascript>

  function img2base64(imgPath){
    var deferred = new $.Deferred;
    var base64;
    fabric.Image.fromURL(imgPath , function(img){
      base64 = img.toDataURL();
      deferred.resolve(base64);
    })
    return deferred.promise();
  }

</script>

フォントについては、CSSで@font-faceを使って明示的にフォントを指示します。OSによって存在しないフォントもあるため、Web上にフォントを上げておく必要があります。
(権利関係について色々制約があることも多いので、注意して下さい)

canvasをSVGにして保存する

フォームから送られてきたSVGデータを、サーバ上に保存します。受け取るファイル名はなんでもいいでしょう。このサンプルはPHPで作成されています


// svgをサーバに保存する関数
function putSvg($svg){
  $path = dirname(__FILE__);
  $filePath = $path.'/test.svg';
  if(file_put_contents($filePath , $svg) === FALSE){
    die("<div class='text-center'><h3>データ保管に失敗しました</h3></div>");
  };
  return $filePath;
}
$svgFilePath = putSvg($_POST{'upfile'});

これでデータがサーバ上に保存されます。アクセス権などに注意して下さい。 parmission なんとか〜というエラーがでたらアクセス権限が不足しています。

SVGをEPSへ変換する

SVGの保存までで良ければこれ以降の解説は不要です。しかしSVGは画像を引き伸ばしたり、回転させた情報を、何故かAdobe Illustratorでうまく読むことができません。
(ブラウザやmacのプレビューではきれいに表示できます)
そのため、EPSへ変換する必要がありました。

EPSへの変換には、インクスケープを使用します

ローカルPCで変換するのであれば別に問題は無いのですが、今回はWebサーバ上で変換が必要なため、色々面倒が多いです。
また、レンタルサーバによってはインクスケープのインストールができない可能性もあるため、レンタルサーバの規約をよく確認してください。
ここでは、AWS Amazon linuxを例にしています。

Image Magickは使えません

PHPで利用できる、各種画像の相互変換ツールに、Image Magickがありますが、
今回は選択肢から除外しました。
Image Magickは、画像をラスタライズするためのライブラリであり、せっかくのベクトル形式が
無残にも1枚のビットマップに変換されてしまうからです。

Amazon linuxにインクスケープをインストール

Amazon Linuxでは簡単にインストールができないようなので、色々遠回りが必要です。しかし簡単にインストールできるシェルを提供してくれている方がいましたので今回はありがたくそちらを拝借します。
Amazon Linuxにinkscapeをインストールするシェルをご確認下さい。

上記のshファイルをサーバ上に作成して、シェルを実行することでインストールできます。 Amazon Linux t.microでは30分ほど時間がかかりました。

インストール完了すると、
/usr/local/bin/
にインクスケープがインストールされています。

インクスケープでSVGからEPSへ変換する  CLI使用

インクスケープの優れている点として、

  • Linuxにインストールできる
  • CLI(コマンド)で実行できる

という点があります。
コマンドで実行できるため、システムに組み込んで容易にSVG to EPSという変換ができます。
その他にも、SVG to PNGなど、様々な画像に変換できます。

保存されたSVGを、EPSに変換するには、PHPのexec()関数でInkscapeのCLIを実行します。
※exec()関数はセキュリティに注意して使用する必要があります。

// 引数にsvgファイルへのパスを渡します
function svg2eps($svgPath){
  $inkscapeCmd = "/usr/local/bin/inkscape";   //Amazon Linux上のPath
  //$inkscapeCmd = "/Applications/Inkscape.app/Contents/Resources/bin/inkscape";  // macなど、ローカル上で動作確認するにはこちらのパスを使います
  $inkscapeCmd .= " -f ";
  $inkscapeCmd .= $svgPath;
  $inkscapeCmd .= " --verb EditSelectAll --verb SelectionUnGroup --verb EditSelectAll --verb ObjectToPath --verb TextToPath --verb FileSave  ";
  $inkscapeCmd .= " -E ";
  $inkscapeCmd .= $svgPath.'.eps';
  exec($inkscapeCmd,$tmp , $status);
  if($status!=0){
    die("<div class='text-center'><h3>データ変換に失敗しました</h3></div>");
  }
  
  unlink($svgPath);//変換元のSVGが不要であれば削除しちゃいましょう
  return $svgPath.'.eps'; //戻り値は作成されたEPSファイルへのパスです
}

これでEPSファイルがサーバ上に保存されました。文字データもアウトライン化されます。
あとはこのデータを、S3に保存するなり、ダウンロードさせるなりして使用します。

ハマリポイント

Amazon Linux上に使用するフォントが入っていない場合、文字化けしたりうまく変換されないことがあります。

例えば、ipaゴシックであればAmazon Linuxに簡単にインストールすることができます

sudo yum install -y ipa-gothic-fonts