Skip to content

Commit

Permalink
Add new endpoint at /w/chart that mimics http://chart.apis.google.com…
Browse files Browse the repository at this point in the history
…/chart QR code encoder API. To be deployed shortly to zxing.org

git-svn-id: https://zxing.googlecode.com/svn/trunk@2920 59b500cc-1b3d-0410-9834-0bbf25fbcc57
  • Loading branch information
[email protected] committed Nov 25, 2013
1 parent 65747f5 commit 52e12ee
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 4 deletions.
155 changes: 155 additions & 0 deletions zxingorg/src/main/java/com/google/zxing/web/ChartServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* 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.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
*/
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);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.nio.charset.Charset;

/**
* Parameters parsed from request for {@link ChartServlet}.
*
* @author Sean Owen
*/
final class ChartServletRequestParameters {

private final int width;
private final int height;
private final Charset outputEncoding;
private final ErrorCorrectionLevel ecLevel;
private final int margin;
private final String text;

ChartServletRequestParameters(int width,
int height,
Charset outputEncoding,
ErrorCorrectionLevel ecLevel,
int margin,
String text) {
this.width = width;
this.height = height;
this.outputEncoding = outputEncoding;
this.ecLevel = ecLevel;
this.margin = margin;
this.text = text;
}

int getWidth() {
return width;
}

int getHeight() {
return height;
}

Charset getOutputEncoding() {
return outputEncoding;
}

ErrorCorrectionLevel getEcLevel() {
return ecLevel;
}

int getMargin() {
return margin;
}

String getText() {
return text;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.google.zxing.web;

import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import com.google.common.net.HttpHeaders;
Expand Down Expand Up @@ -58,6 +57,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumMap;
Expand Down Expand Up @@ -116,7 +116,7 @@ public void init(ServletConfig servletConfig) throws ServletException {

try {
blockedURLSubstrings =
Resources.readLines(Resources.getResource("/private/uri-block-substrings.txt"), Charsets.UTF_8);
Resources.readLines(Resources.getResource("/private/uri-block-substrings.txt"), StandardCharsets.UTF_8);
} catch (IOException ioe) {
throw new ServletException(ioe);
}
Expand Down Expand Up @@ -392,8 +392,8 @@ private static void processImage(BufferedImage image,
boolean minimalOutput = fullParameter != null && !Boolean.parseBoolean(fullParameter);
if (minimalOutput) {
response.setContentType(MediaType.PLAIN_TEXT_UTF_8.toString());
response.setCharacterEncoding(Charsets.UTF_8.name());
try (Writer out = new OutputStreamWriter(response.getOutputStream(), Charsets.UTF_8)) {
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
try (Writer out = new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8)) {
for (Result result : results) {
out.write(result.getText());
out.write('\n');
Expand Down
9 changes: 9 additions & 0 deletions zxingorg/src/web/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,20 @@
<servlet-class>com.google.zxing.web.DecodeServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>ChartServlet</servlet-name>
<servlet-class>com.google.zxing.web.ChartServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>DecodeServlet</servlet-name>
<url-pattern>/w/decode</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ChartServlet</servlet-name>
<url-pattern>/w/chart</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jspx</welcome-file>
Expand Down

0 comments on commit 52e12ee

Please sign in to comment.