ProcessingでGyazoに画像を投稿する

[Gyazo](https://gyazo.com)は画像をアップロードして共有できるサービスです。
[APIドキュメンテーション](https://gyazo.com/api/docs/image)には「multipart/form-dataを使うこと」とあります。
なんじゃそりゃ？ということで作ってみました。多分車輪の再発明。

```java
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.File;
import java.io.DataOutputStream;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.util.UUID;
import java.util.Map;

void setup() {
  PGraphics pg = createGraphics(299, 299);
  pg.beginDraw();
  pg.background(255);
  int count = 0;
  for (int r = 0; r < 256; r+=127)
    for (int g = 0; g < 256; g+=127)
      for (int b = 0; b < 256; b+=127) {
        pg.fill(r, g, b);
        pg.stroke(random(256),random(256),random(256));
        pg.rect(count/6*50, count%6*50, 50, 50);
        count++;
      }
  pg.endDraw();

  HashMap<String, Object> data = new HashMap<String, Object>();

  data.put("access_token", "enteryourtokenhere");
  data.put("title", "Sent from Processing");
  data.put("imagedata", pg);
  multipartSend("https://upload.gyazo.com/api/upload",data);
}

void multipartSend(String api, HashMap<String, Object> data) {
  final String twoHyphens = "--";
  final String boundary =  "*****"+ UUID.randomUUID().toString()+"*****";
  final String lineEnd = "\r\n";

  try {
    HttpURLConnection con = null;
    URL url = new URL(api);

    // 接続用HttpURLConnectionオブジェクト作成
    con = (HttpURLConnection)url.openConnection();
    // リクエストメソッドの設定
    con.setRequestMethod("POST");
    // リダイレクトを自動で許可しない設定
    con.setInstanceFollowRedirects(false);

    con.setRequestProperty("Connection", "Keep-Alive");
    con.setRequestProperty("Content-Type", "multipart/form-data; boundary="+boundary);
    con.setDoOutput(true);
    con.setDoInput(true);
    con.setUseCaches(false);

    DataOutputStream dos = new DataOutputStream(con.getOutputStream());

    for (Map.Entry<String, Object> entry : data.entrySet()) {
      Object value = entry.getValue();
      if (value instanceof File) {
        File file = (File)value;
        if(!file.isFile())continue;
        if(!file.canRead())continue;
        
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\""+entry.getKey()+"\";filename=\""+file.getName()+"\""+lineEnd);
        dos.writeBytes("Content-Type: application/octet-stream"+lineEnd);
        dos.writeBytes("Content-Transfer-Encoding: binary"+lineEnd);
        dos.writeBytes(lineEnd);

        final int maxBufferSize = 1024*1024*3;

        FileInputStream fileInputStream = new FileInputStream(file);
        int bytesAvailable = fileInputStream.available();
        int bufferSize = Math.min(bytesAvailable, maxBufferSize);
        byte[] buffer = new byte[bufferSize];

        int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        while (bytesRead > 0) {
          dos.write(buffer, 0, bufferSize);
          bytesAvailable = fileInputStream.available();
          bufferSize = Math.min(bytesAvailable, maxBufferSize);
          bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        }

        dos.writeBytes(lineEnd);
        fileInputStream.close();
      }
      if (value instanceof PImage) {
        PImage pi = (PImage)value;
        pi.updatePixels();
        BufferedImage bi = new BufferedImage(pi.width, pi.height, BufferedImage.TYPE_4BYTE_ABGR);
        bi.setRGB(0, 0, pi.width, pi.height, pi.pixels, 0, pi.width);

        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\""+entry.getKey()+"\";filename=\"PImage.png\""+lineEnd);
        dos.writeBytes("Content-Type: application/octet-stream"+lineEnd);
        dos.writeBytes("Content-Transfer-Encoding: binary"+lineEnd);
        dos.writeBytes(lineEnd);
        ImageIO.write(bi, "png", dos);
        dos.writeBytes(lineEnd);
      }
      if (value instanceof String) {
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\""+entry.getKey()+"\""+lineEnd);
        dos.writeBytes("Content-Type: text/plain"+lineEnd);
        dos.writeBytes(lineEnd);
        dos.writeBytes((String)value);
        dos.writeBytes(lineEnd);
      }
    }

    dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

    dos.close();

    con.connect();

    StringBuffer result = new StringBuffer();
    final int status = con.getResponseCode();
    if (status == HttpURLConnection.HTTP_OK) {
      // 通信に成功した
      // テキストを取得する
      final InputStream in = con.getInputStream();
      String encoding = con.getContentEncoding();
      if (null == encoding) {
        encoding = "UTF-8";
      }
      final InputStreamReader inReader = new InputStreamReader(in, encoding);
      final BufferedReader bufReader = new BufferedReader(inReader);
      String line = null;
      // 1行ずつテキストを読み込む
      while ((line = bufReader.readLine()) != null) {
        result.append(line);
      }
      bufReader.close();
      inReader.close();
      in.close();

      print(result);
    } else {
      print("Status:"+status);
    }
  }
  catch(Exception e) {
    e.printStackTrace();
  }
}
```


##使い方
HashMapにパラメータを入れて使ってください。
- String
- PImage
- File
に対応。

トークンは各自取得してください。

##参考
[MIME タイプ](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
[HttpURLConnectionを使用してHTTP通信を行う](https://techbooster.org/android/application/6812/)
[GyazoのAPIをRから使ってみる](http://notchained.hatenablog.com/entry/2017/02/15/174650)
[AndroidからHTTPのmultipart/form-dataを使ってデータをアップロードする](https://qiita.com/informationsea/items/778d9525c3aaded73577)

他にも色々参考にしたと思うんですが忘れました。