/******************************************************************************
* Copyright © 2013-2016 The Nxt Core Developers. *
* *
* See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* Nxt software, including this file, may be copied, modified, propagated, *
* or distributed except according to the terms contained in the LICENSE.txt *
* file. *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
package nxt.http;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import nxt.NxtException;
import nxt.util.Convert;
import nxt.util.Logger;
import org.json.simple.JSONObject;
import org.json.simple.JSONStreamAware;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* <p>The EncodeQRCode API converts a UTF-8 string to a base64-encoded
* jpeg image of a 2-D QR (Quick Response) code, using the ZXing library.</p>
*
* <p>The output qrCodeBase64 string can be incorporated into an in-line HTML
* image like this: <img src="data:image/jpeg;base64,qrCodeBase64">
* </p>
*
* <p>The output qrCodeBase64 can be input to the DecodeQRCode API to
* recover the original qrCodeData.</p>
*
* <p>Request parameters:</p>
*
* <ul>
* <li>qrCodeData - A UTF-8 text string.</li>
* <li>width - The width of the output image in pixels, optional.</li>
* <li>height - The height of the output image in pixels, optional.</li>
* </ul>
*
* <p>Notes:</p>
* <ul>
* <li>The output image consists of a centrally positioned square QR code
* with a size which is an integer multiple of the minimum size, surrounded by
* sufficient white padding to achieve the requested width/height.</li>
* <li>The default width/height of 0 results in the minimum sized output
* image, with one pixel per black/white region of the QR code and no
* extra padding.</li>
* <li>To eliminate padding, the requested width/height must be an integer
* multiple of the minimum.</li>
* </ul>
*
* <p>Response fields:</p>
*
* <ul>
* <li>qrCodeBase64 - A base64 string encoding a jpeg image of
* the QR code.</li>
* </ul>
*/
public final class EncodeQRCode extends APIServlet.APIRequestHandler {
static final EncodeQRCode instance = new EncodeQRCode();
private EncodeQRCode() {
super(new APITag[] {APITag.UTILS}, "qrCodeData", "width", "height");
}
@Override
JSONStreamAware processRequest(HttpServletRequest request)
throws NxtException {
JSONObject response = new JSONObject();
String qrCodeData = Convert.nullToEmpty(request.getParameter("qrCodeData"));
int width = ParameterParser.getInt(request, "width", 0, 5000, false);
int height = ParameterParser.getInt(request, "height", 0, 5000, false);
try {
Map hints = new HashMap();
// Error correction level: L (7%), M (15%), Q (25%), H (30%) -- Default L.
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.MARGIN, 0); // Default 4
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix matrix = new MultiFormatWriter().encode(qrCodeData,
BarcodeFormat.QR_CODE,
width,
height,
hints
);
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(matrix);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpeg", os);
byte[] bytes = os.toByteArray();
os.close();
String base64 = Base64.getEncoder().encodeToString(bytes);
response.put("qrCodeBase64", base64);
} catch(WriterException|IOException ex) {
String errorMessage = "Error creating image from qrCodeData";
Logger.logErrorMessage(errorMessage, ex);
JSONData.putException(response, ex, errorMessage);
}
return response;
}
@Override
final boolean requirePost() {
return true;
}
@Override
boolean allowRequiredBlockParameters() {
return false;
}
@Override
boolean requireBlockchain() {
return false;
}
}