com.google.zxing.web.ChartServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.google.zxing.web.ChartServlet.java

Source

/*
 * Copyright 2013 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.web;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.CharStreams;
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;

import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Map;

/**
 * A reimplementation of the
 * <a href="https://google-developers.appspot.com/chart/infographics/docs/qr_codes">
 *   Google Chart Server's QR code encoder</a>, which is now deprecated.
 *
 * @author Sean Owen
 */
@WebServlet("/w/chart")
public final class ChartServlet extends HttpServlet {

    private static final int MAX_DIMENSION = 4096;
    private static final Collection<Charset> SUPPORTED_OUTPUT_ENCODINGS = ImmutableSet.<Charset>builder()
            .add(StandardCharsets.UTF_8).add(StandardCharsets.ISO_8859_1).add(Charset.forName("Shift_JIS")).build();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doEncode(request, response, false);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doEncode(request, response, true);
    }

    private static void doEncode(ServletRequest request, HttpServletResponse response, boolean isPost)
            throws IOException {

        ChartServletRequestParameters parameters;
        try {
            parameters = doParseParameters(request, isPost);
        } catch (IllegalArgumentException | NullPointerException e) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.toString());
            return;
        }

        Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
        hints.put(EncodeHintType.MARGIN, parameters.getMargin());
        if (!StandardCharsets.ISO_8859_1.equals(parameters.getOutputEncoding())) {
            // Only set if not QR code default
            hints.put(EncodeHintType.CHARACTER_SET, parameters.getOutputEncoding().name());
        }
        hints.put(EncodeHintType.ERROR_CORRECTION, parameters.getEcLevel());

        BitMatrix matrix;
        try {
            matrix = new QRCodeWriter().encode(parameters.getText(), BarcodeFormat.QR_CODE, parameters.getWidth(),
                    parameters.getHeight(), hints);
        } catch (WriterException we) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, we.toString());
            return;
        }

        ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(matrix, "PNG", pngOut);
        byte[] pngData = pngOut.toByteArray();

        response.setContentType("image/png");
        response.setContentLength(pngData.length);
        response.setHeader("Cache-Control", "public");
        response.getOutputStream().write(pngData);
    }

    private static ChartServletRequestParameters doParseParameters(ServletRequest request, boolean readBody)
            throws IOException {

        Preconditions.checkArgument("qr".equals(request.getParameter("cht")), "Bad type");

        String widthXHeight = request.getParameter("chs");
        Preconditions.checkNotNull(widthXHeight, "No size");
        int xIndex = widthXHeight.indexOf('x');
        Preconditions.checkArgument(xIndex >= 0, "Bad size");

        int width = Integer.parseInt(widthXHeight.substring(0, xIndex));
        int height = Integer.parseInt(widthXHeight.substring(xIndex + 1));
        Preconditions.checkArgument(width > 0 && height > 0, "Bad size");
        Preconditions.checkArgument(width <= MAX_DIMENSION && height <= MAX_DIMENSION, "Bad size");

        String outputEncodingName = request.getParameter("choe");
        Charset outputEncoding = StandardCharsets.UTF_8;
        if (outputEncodingName != null) {
            outputEncoding = Charset.forName(outputEncodingName);
            Preconditions.checkArgument(SUPPORTED_OUTPUT_ENCODINGS.contains(outputEncoding), "Bad output encoding");
        }

        ErrorCorrectionLevel ecLevel = ErrorCorrectionLevel.L;
        int margin = 4;

        String ldString = request.getParameter("chld");
        if (ldString != null) {
            int pipeIndex = ldString.indexOf('|');
            if (pipeIndex < 0) {
                // Only an EC level
                ecLevel = ErrorCorrectionLevel.valueOf(ldString);
            } else {
                ecLevel = ErrorCorrectionLevel.valueOf(ldString.substring(0, pipeIndex));
                margin = Integer.parseInt(ldString.substring(pipeIndex + 1));
                Preconditions.checkArgument(margin > 0, "Bad margin");
            }
        }

        String text;
        if (readBody) {
            text = CharStreams.toString(request.getReader());
        } else {
            text = request.getParameter("chl");
        }
        Preconditions.checkArgument(text != null && !text.isEmpty(), "No input");

        return new ChartServletRequestParameters(width, height, outputEncoding, ecLevel, margin, text);
    }

}