指定した文字列からQRコードを生成する

# 概要

QRコードの画像データを返すWeb APIのサンプルコードです。ライブラリには[zxing] (https://github.com/zxing/zxing)を利用しました。

**環境**

* Windows7 (64bit)
* Java 1.8.0_65
* Spring-Boot 1.3.0
* zxing 3.2.1

## 準備

プロジェクトにzxingライブラリを加えます。

```xml
<dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>3.2.1</version>
</dependency>
<dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>javase</artifactId>
  <version>3.2.1</version>
</dependency>
```

## サンプルコード

### API

リクエストパラメータで指定された文字列をQRコードにした画像データを返すAPIバージョンです。

```java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Hashtable;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

@Controller
@RequestMapping(value = "/image")
public class ImageController {
  @RequestMapping(value = "/qr/{contents}", method = RequestMethod.GET)
  public ResponseEntity<byte[]> qr(@PathVariable(value="contents") String contents) {
    try {
      byte[] res = toByteArray(contents);
      final HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.IMAGE_PNG);
      return new ResponseEntity<byte[]>(res, headers, HttpStatus.CREATED);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  private byte[] toByteArray(String contents) throws IOException, WriterException {
    BarcodeFormat format = BarcodeFormat.QR_CODE;
    int width = 160;
    int height = 160;

    Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);

    try (ByteArrayOutputStream output = new ByteArrayOutputStream()){
      QRCodeWriter writer = new QRCodeWriter();
      BitMatrix bitMatrix = writer.encode(contents, format, width, height, hints);
      MatrixToImageWriter.writeToStream(bitMatrix, "png", output);
      return output.toByteArray();
    }

  }

}
```

#### 実行

アプリケーションを実行して、下記のURLにアクセスすると`rubytomato`という文字列をQRコードにした画像データのレスポンスが得られます。

http://localhost:9000/image/qr/rubytomato

サンプル画像

![rubytomato.png](https://qiita-image-store.s3.amazonaws.com/0/22772/482f4174-9e61-9722-29db-67bf0bb2442a.png)


### dataURL

画像データをBase64エンコードすることでdataURLで表示させることができます。
Base64エンコードのライブラリにはcommons-codecを使用しました。

```xml:pom.xml
<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.10</version>
</dependency>
```

```java
@RequestMapping(value = "/data/{contents}", method = RequestMethod.GET)
public String data(@PathVariable(value="contents") String contents, Model model) {
  try {
    byte[] res = conv(contents);
    String encodedStr64 = Base64.encodeBase64String(res);
    model.addAttribute("dataUrl", encodedStr64);
  } catch (Exception e) {
    e.printStackTrace();
  }
  return "Image/data";
}
```

テンプレートのimgタグにdataスキームを指定しBase64エンコードしたデータをセットすることで画像データを表示します。

```html:template
<img th:src="|data:image/png;base64,${dataUrl}|" />
```

#### 実行

http://localhost:9000/image/data/rubytomato