プログラミング雑記

プログラミングが趣味のだらだら学生。自作したプログラムの紹介やいまハマってることなんかを適当に書いていったりいかなったり

"500px"の美しい写真をプログラムで使う!ProcessingでまなぶAPIとJSONの使い方~500px API with Processing~

今回行うこと

500pxAPIを用いてProcessingで綺麗な写真を取得し表示する。

f:id:kirari0831:20160114230702p:plain

f:id:kirari0831:20160114230717p:plain

何回かに分けて投稿していこうと思いますが、今回はその第一回目と言う事で準備~簡単な画像取得と表示まで説明していきます。

ProcessingにおけるJSONの操作法についても説明していきます。

500pxとは?

500px.com

Wikipedia大先生の言葉をかりれば、

500px(five hundred pixelsと発音)[2]とはオンライン写真コミュニティ[3][4]で写真撮影に関して趣味かプロフェッショナルの人たちが[5]自身の最も良い写真をアップロードすることを奨励することを目的に[6]、オレグ・ガットソル(Oleg Gutsol)とエフゲニー・トチェボタレフ(Evgeny Tchebotarev、イアン・ソボレフ(Ian Sobolev)としても知られる)が共同で[7]、2009年にトロントWeb 2.0ベンチャーとして設立した[8][9]。 写真を公開し、インスピレーションを探したり他の写真家を繋がるための場所と見なされており[10]、6000万枚以上の写真が投稿されている[11]。また、最も使われているカメラはキヤノン EOS 5D Mark IIである[12]。

簡単に言っちゃえばとってもオシャレな写真が世界中から集まるすごいサイトといったところでしょうか。

500pxのAPIを利用する

こちらの記事を参考にさせていただきました。

アカウント取得

500pxのアカウントを取得していない場合はアカウントを取得します。TwitterFacebookアカウントでログインしても構いません。

f:id:kirari0831:20160114222848p:plain

アプリケーションの登録

では、設定画面の中のApplicationsを開いてください。以下から飛べると思います。

500px.com

次に、設定画面の中央右にある、”Register your application”と書いてある緑色のボタンを押してください。

f:id:kirari0831:20160114223335p:plain

必要な情報を入力していきます。以下の画像の赤枠で囲ったところは入力必須な内容ですので、必ず記入してください。

f:id:kirari0831:20160114223538p:plain

必須項目の意味だけ説明すると、

  • Application Name...アプリケーションやWebサービスの名前。
  • Description...アプリの説明文。
  • Application URL...APIを利用するWebサイトなどのURLを記載。今回はProcessingでアプリを作るのでURLはどこにしようか迷ったのですが、とりあえず自分のブログのURLを載せておきました。
  • Developer's Email...自分のメールアドレス。連絡先となります。

APIキーの確認

APIを利用するためにAPIキーを確認しにいきましょう。
無事アプリが作れていると画面左にいまつくったアプリが表示されているとおもうのでそこをクリックしてください。

そうすると以下の様な画面がでてくるはずなので、Consumer Keyの欄にかいてあるものをメモしておきましょう。あとで使います。

f:id:kirari0831:20160114223823p:plain

(関係ない話) いま気付いたけど、こういうときに Boostnote 使ってメモしておくと便利なのかな~
詳しい使い方は以下の記事を参考にしてください。

niisi.hatenablog.jp

Processingで500pxAPI実装

いよいよ本題です。この記事ではProcessingで500pxのAPIを使用していきます。

Processingとは

Javaをグラフィックスに特化させ簡単にしたようなプログラミング言語です。Javaが分かればスラスラとかけますし、プログラムが全く分からんというかたでも簡単にできるので勉強しやすいものになっています。
Processingをインストールしていない方は以下のURLからダウンロードしておいてください。

Processing.org

リクエスト法

検索するための条件を指定するため以下のパラメータを適宜入力してください。

ここで必ず入力しないといけないパラメータは以下の2つです。

  • consumer_key...先程取得した自分のコンシューマキー
  • 以下の中からどれか必須
    • term...キーワードでの検索
    • tag...ハッシュタグでの検索
    • geo...位置座標から検索。緯度,経度,範囲で指定。範囲 には単位としてkmmiを記入する。

今回他に選択するパラメータは以下の通りです。

  • rpp...取得件数。デフォルトで20, 最大で100。
  • image_size...取得する画像のサイズ。IDで指定するのですが、詳しくは以下の内容を参考にしてください。

image_sizeに指定できるもの

リサイズ形式がcroppedのものは固定サイズになり、fitのものは元画像の縦横比を維持してくれます。
お好きなIDをimage_sizeに指定してあげてください。

ID 画像サイズ リサイズ形式
1 70px x 70px cropped
2 140px x 140px cropped
3 280px x 280px cropped
100 100px x 100px cropped
200 200px x 200px cropped
440 440px x 440px cropped
600 600px x 600px cropped
4 900px x * OR * x 900px fit
5 1170px x * OR * x 1170px fit
20 * x 300px fit
21 * x 600px fit
30 256px x * OR * x 256px fit
1,080 1080px x * OR * x 1080px fit
1,600 1600px x * OR * x 1600px fit
2,048 2048px x * OR * x 2048px fit

ソースコード①パラメータ設定法

String url = "https://api.500px.com/v1/photos/search";  //エンドポイントのURL
//{"パラメータ名", "値"}の順に追加してください。値は必ず文字列にしてください!
String[][] parameters = {
    {"consumer_key", "4GADfYKvXUwAZk5E8ZtM20p7HWpV1qy98UrGbB3Y"},   //Consumer Key
    {"term", "Japan"},      //キーワードでの検索
    //{"tag", "skyscraper"},      //タグによる検索
    //{"geo", "48.5144,2.2104,10km"}, //座標による検索。座標はパリのもの
    {"rpp", "20"},          //取得件数。default=20,max=100
    {"image_size", "600"}   //画像サイズ。600 -> 600px x 600px(固定サイズ),  1080 -> 1080px y or x 1080px(元の縦横比を保持)
};
StringDict sd = new StringDict(pairs);

パラメータの設定をおこなうためにStringDictを使います。Processingのリファレンス眺めてて私も初めて気づいたのですが、StringDictという文字列の辞書をあらわすクラスがProcessingにはあります。

二つの文字列の組み合わせがparametersのなかにありますが、左の文字列がキーとなり右の文字列がそのキーに対応するとなります。このとき、値が整数であっても必ず文字列で入力してください。文字通り文字列の辞書なのでキーも値も文字列にしてください。

いまつくったStringDictを以下の関数に代入しurlを取得してきます。

String httpBuildQuery(StringDict sd){
    String result = url + "?";
    for(String key : sd.keys()){
        String value = sd.get(key);
        result += key + "=" + value + "&";
    }
    return result.substring(0,result.length()-1);//末尾の&を削除
}

ソースコードJSONの扱い方

いま取得したURLを用いて500pxのAPIを通し画像を取得していきましょう。

ProcessingではloadJSONObject()loadJSONArray()というJSONを取得する関数があります。 名前を見ればわかりますが、前者はJSON単体を読み込むのに対して、後者はJSONの配列を取得してきます。 与える引数はdataフォルダの中にあるJSONファイルの名前か、取得してくるURLのどちらかです。今回はもちろんURLで取得します。

今回取得できるのは以下の様なJSONObject単体なのでloadJSONObjectを使います。

{
    current_page:1,     //取得したページ
    total_pages:1,      //ページの総数
    total_items:20,     //作品総数
    photos: [...]       //写真の詳細情報を詰め込んだJSONArray
}

JSONを取得してくるプログラムは以下の通りです。

String URL = httpBuildQuery(sd);
JSONObject json = loadJSONObject(URL);

では、今回のプログラムで使うプロパティを説明しておきます。

  • name...作品名
  • description...作品の説明
  • image_url...画像のURL
  • image_format...画像のフォーマット

この他にも多くのプロパティがあるのですが、全ては紹介しきれないので、日本語で説明を読みたい方は先程紹介したサイトをご覧になるとよいかと思います。詳しい情報が知りたい場合は公式のドキュメントを見るとよいでしょう。

syncer.jp

github.com

ソースコード③画像取得

では読み込んできたJSONから画像を取り出していきましょう。

ArrayList<PImage>images = new ArrayList<PImage>();
if(json == null){
    println("Failed!!");
}else{
    pictures = json.getJSONArray("photos");
    for(int i = 0; i < pictures.size(); i++){
        JSONObject picture = pictures.getJSONObject(i);
        String image_format = picture.getString("image_format","jpeg");
        String image_url = picture.getString("image_url");
        images.add(loadImage(image_url,image_format));
    }
}

以前の記事でloadImage()を使って画像を読み込む方法について説明しました。

niisi.hatenablog.jp

そのときはスケッチフォルダ内にあるdataフォルダのなかの自分の画像を読み込んできたのですが、
今回はURLを指定して画像を取得してきます。そこで注意しなければならないのが必ず画像のフォーマットを指定しなければならないことです。
ちなみにdataフォルダにtest.pngというファイルがあった場合は以下の様な書き方でもおっけーです。

loadImage("http://......", "png");  //オッケー!
loadImage("htpp://......");         //ダメ...

loadImage("test.png");      //オッケー!
loadImage("test", "png");   //オッケー!
loadImage("test");          //ダメ...

ほとんどの場合image_formatは設定されているはずですが、もし設定されていない時のために第2引数でデフォルト値を設定しておきます。

ソースコード④スライドショーで表示する

いままでのソースコードを全部まとめてスライドショー形式で表示するようにするよ!

JSONArray pictures;
String url = "https://api.500px.com/v1/photos/search";  //エンドポイントのURL

ArrayList<PImage>images = new ArrayList<PImage>();
PImage showImage;
int index = 0;
void setup(){
    surface.setResizable(true);
    //検索するためのパラメータを以下のparametersに追加する
   String[][] parameters = {
       {"consumer_key", "4GADfYKvXUwAZk5E8ZtM20p7HWpV1qy98UrGbB3Y"},   //Consumer Key
       {"term", "Japan"},      //キーワードでの検索
      //{"tag", "skyscraper"},      //タグによる検索
      //{"geo", "48.5144,2.2104,10km"}, //座標による検索。座標はパリのもの
       {"rpp", "20"},          //取得件数。default=20,max=100
       {"image_size", "600"}   //画像サイズ。600 -> 600px x 600px(固定サイズ),  1080 -> 1080px y or x 1080px(元の縦横比を保持)
    };
    StringDict sd = new StringDict(parameters);

    String URL = httpBuildQuery(sd);
    JSONObject json = loadJSONObject(URL);

    if(json == null){
        println("Failed!!");
    }else{
        pictures = json.getJSONArray("photos");
        for(int i = 0; i < pictures.size(); i++){
            JSONObject picture = pictures.getJSONObject(i);
            String image_format = picture.getString("image_format","null");
            String image_url = picture.getString("image_url");
            images.add(loadImage(image_url,image_format));
        }
        if(!images.isEmpty()){
            showImage = images.get(0);
            surface.setSize(showImage.width, showImage.height);
        }
    }
}
void draw(){
    if(!images.isEmpty()){
        image(showImage, 0,0);
        if(showDetail){
            JSONObject picture = pictures.getJSONObject(index);
            String photoName = picture.getString("name","null");
            String description = picture.getString("description","null");
            String userName = picture.getJSONObject("user").getString("fullname","null");
            textSize(12);
            text("Photo Name  : " + photoName,10,20);
            text("Description : " + description,10,34);
            text("photo by : " + userName,10,48);
        }
    }
}
boolean showDetail = false;
void keyPressed(){
    if(keyCode == UP){
        showDetail = true;
    }else if(keyCode == DOWN){
        showDetail = false;
    }else if(keyCode == LEFT){
        index--;
        if(index < 0){
            index = images.size()-1;
        }
        showImage = images.get(index);
        surface.setSize(showImage.width, showImage.height);
    }else if(keyCode == RIGHT){
        index++;
        if(index == images.size()){
            index = 0;
        }
        showImage = images.get(index);
        surface.setSize(showImage.width, showImage.height);
    }
}

String httpBuildQuery(StringDict sd){
    String result = url + "?";
    for(String key : sd.keys()){
        String value = sd.get(key);
        result += key + "=" + value + "&";
    }
    return result.substring(0,result.length()-1);
}

操作方法としては右矢印キーで次の画像、左矢印キーで前の画像に移動。上矢印キーで写真の名前や説明文の表示、下矢印キーでそれらの非表示をすることができます。

まとめ

実は最近までAPIとかJSONとか名前は聞いたことあるけど全然使ったことないし何なのかもよく分かってなかったです(なんという勉強不足)。
しかし、いざ触ってみるとかなり簡単に楽しい ことができたのでもっと早くに知っておけばよかったなぁとおもいました。
今回はただ画像を表示するだけのプログラムなので、そんなの500pxのサイトいって見て来いよって話になってしまうわけですが、ここからデータを色々分析したりしてデータの可視化的なことをしていけたらなとおもっています。