среда, 18 июля 2012 г.

Сервлет для генерации QR-кодов

Раньше я описывал, как используя библиотеку ZXing можно сделать Android-приложение для генерации QR-кода. Теперь то же самое давайте сделаем на серверной стороне. Напишем сервлет, который в ответ на get-запрос с текстом получает изображение в котором этот текст будет закодирован. Такой сервис можно использовать чтобы разместить у себя на сайте любой qr-код картинкой с src="url_сервиса/?code=текст".
Особенных открытий в такой реализации нет, разве что преобразование двумерной матрицы в картинку делаем иначе чем в Android, используя java.awt.* классы.



import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import javax.servlet.annotation.WebServlet;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
 
@WebServlet(name = "GetQrServlet", urlPatterns = {"/getqr"})
public class GetQrServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        if (request.getParameterMap().containsKey("code")) {
            String code = request.getParameter("code");
            Map<EncodeHintType,Object> hints = new HashMap<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix matrix = null;
            try {
                matrix = new QRCodeWriter().encode(code, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300, hints);
            } catch (WriterException e) {
                e.printStackTrace();
            }
            response.setContentType("image/jpeg");
            ImageIO.write(matrixToImage(matrix), "jpg", response.getOutputStream());
        } else {
            PrintWriter w = response.getWriter();
            w.print("parameter code not found!");
            w.flush();
            w.close();
        }
    }
 
    private BufferedImage matrixToImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        int[] pixels = new int[width*height];
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {
                pixels[j*width + i] = matrix.get(j, i) ? Color.BLACK.getRGB() : Color.WHITE.getRGB();
            }
        }
        image.setRGB(0, 0, width, height, pixels, 0, width);
        return image;
    }
 
    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        doPost(request, response);
    }
}
На что тут обратить внимание? Мы в этом примере задаём не просто текст для кодирования, но и уровень избыточности для коррекции ошибок и кодировку текста (закомментированная строка), что может быть полезно для корректного кодирования кириллицы.

2 комментария:

  1. А вот эту: net.glxn.qrgen.* не пробовали? Или она хуже?

    ОтветитьУдалить
    Ответы
    1. Это просто "обёртка" над ZXing. Учитывая то, что генерация кода с помощью ZXing это всего лишь 3-4 строки кода, не вижу особой пользы от ещё одного уровня абстракции

      Удалить