頭の中は異空間

生活を日々ハックしてよりよくするブログ

インラインイメージ生成と画像リアルタイムアップロード

どうも。

 

画像のアップロード機能って便利ですよね。そして、画像を表示する時のinline imageも合わせて使えると、サイトが大規模化した時に対処しやすい。一度に表示する画像数が増えると、レスポンスひどいですからね。

でも一から作り直そうとするとやっぱり書式とか覚えてないだろうし、いちいち調べ直すのも面倒。ということで、いっそのことメモでも作ってしまえ、と思ったのでJSとRailsで書いてみました。inline imageをRailsで実現したいぞって思ったら、結構手軽にできるようなのでトライしてみました。

面倒なので細かいvalidationは省きます。

 

表示

Model

class Image < ActiveRecord::Base
  BASE64 = 'data:image/png;base64,'

  class << self
    def image_src_base64(img_path)
       BASE64 + Base64.encode64(File.new(img_path).read).gsub(/(\s)/,'')
    end
  end
end

View

~~
    = image_tag Image.image_src_base64("画像path"), alt: "base64画像" ~~

 

単純ですね。やってることは、base64のヘッダ部分にあたる文字列と画像のパスをencodingして結合するだけ。これでimg srcが完成します。責任をもたせたいmodelのクラスメソッドにでもしておけば良いでしょう。

 

他所のサイトであらかじめinline imageにしてからその文字列をimg src属性に設定しても良いし、cssのbackground imageって方法もある。ただ、そちらは手動で2,3の画像に対してならまだしも、何らかのサービス上で動かしたいならナンセンス。また、画面のレンダリング時間は間違いなく減るので、CDNとかのリソースの問題ならこれで解決できるでしょう。

 

画像Upload

ここでは、JSと連携してリアルタイムに画像をアップロードする場合を考慮します。ドラッグ&ドロップでアップロードするとします。

 

Model

class Test < ActiveRecord::Base
  def upload_image_for_ajax(params)
    path = params["path"]
    filename = params["filename"]
    image = params["image_link"]
    File.open("#{path}/#{filename}", 'wb') do |f|
    f.write(Base64::decode64(image))
  end
end

 

JavaScript

$(function() {
  var upload_file = function(files) {
    var reader = new FileReader();

    reader.readAsDataURL(files[0]);

    reader.onload = function() {
    var dataUrl = reader.result;
      var url = 'upload_image_for_ajax';
      var filename = files[0].name;
      var path = upload_path;
      var param = {
        filename: filename, path: path, image_link: dataUrl.replace(/^.*,/, ''), authenticity_token: $("input[name='authenticity_token']").val();
      };
      $.ajax({url: url,
        type: 'post',
        data: param,
        success: function(data) {
          if (data.uploaded) {
            alert("ファイルアップロードしました。");
          }
        },
        error: function(e) {
          alert(e.message);
          alert("ファイルアップロードできませんでした");
        }
      });
    };

    return true;
  };

  $("#drag_area").on("drop", function(e) {
    $("#drag_area").hide();
    e.preventDefault();

    var files = e.originalEvent.dataTransfer.files;

    upload_file(files);
  }).on("dragenter", function() {
    return false;
  }).on("dragover", function() {
    return false;
  });
});

 

View

<div id="drag_area" class="drag_area">
  <div class="file_uploader">
    <p>ファイルをアップロード</p>
  </div>
</div>

 

これは、アップロード画面から画像をアップロードして、ローカル環境に配備(実際にはimageサーバ等に配備させると思いますが)の想定です。やっぱりいちいちファイルダイアログ開くの面倒ですしw

GithubかCodepenにでも保存しとけば後々便利な武器になるでしょう。普通にライブラリとして使えるはずなので、今後はほとんど似たコードを書かなくて良くなると思います。

 

今回はこの辺で!