X-Git-Url: http://git.rot13.org/?p=zxing.git;a=blobdiff_plain;f=zxingorg%2Fsrc%2Fcom%2Fgoogle%2Fzxing%2Fweb%2FDecodeServlet.java;h=0a26eca720591c154070da99ec5c1deece1cba03;hp=3926f0f8cbf4e7eeaea917406cd3090cbd41ab08;hb=2d9efc5f0d19d70fb4f240f506bc23992ab3fde6;hpb=ac343e4ddc7af1f54c2d2634abb1be992d183a35 diff --git a/zxingorg/src/com/google/zxing/web/DecodeServlet.java b/zxingorg/src/com/google/zxing/web/DecodeServlet.java index 3926f0f8..0a26eca7 100644 --- a/zxingorg/src/com/google/zxing/web/DecodeServlet.java +++ b/zxingorg/src/com/google/zxing/web/DecodeServlet.java @@ -28,16 +28,15 @@ import com.google.zxing.Reader; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; -import com.google.zxing.client.result.ParsedResult; -import com.google.zxing.client.result.ResultParser; import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.multi.GenericMultipleBarcodeReader; +import com.google.zxing.multi.MultipleBarcodeReader; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.apache.commons.lang.StringEscapeUtils; import org.apache.http.Header; import org.apache.http.HttpMessage; import org.apache.http.HttpResponse; @@ -57,15 +56,16 @@ import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; +import java.awt.color.CMMException; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; -import java.net.SocketException; import java.net.URI; import java.net.URISyntaxException; -import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Hashtable; import java.util.List; @@ -88,11 +88,15 @@ import javax.servlet.http.HttpServletResponse; */ public final class DecodeServlet extends HttpServlet { + // No real reason to let people upload more than a 2MB image private static final long MAX_IMAGE_SIZE = 2000000L; + // No real reason to deal with more than maybe 2 megapixels + private static final int MAX_PIXELS = 1 << 21; private static final Logger log = Logger.getLogger(DecodeServlet.class.getName()); static final Hashtable HINTS; + static final Hashtable HINTS_PURE; static { HINTS = new Hashtable(5); @@ -103,6 +107,7 @@ public final class DecodeServlet extends HttpServlet { possibleFormats.add(BarcodeFormat.EAN_8); possibleFormats.add(BarcodeFormat.EAN_13); possibleFormats.add(BarcodeFormat.CODE_39); + possibleFormats.add(BarcodeFormat.CODE_93); possibleFormats.add(BarcodeFormat.CODE_128); possibleFormats.add(BarcodeFormat.ITF); possibleFormats.add(BarcodeFormat.RSS14); @@ -110,6 +115,8 @@ public final class DecodeServlet extends HttpServlet { possibleFormats.add(BarcodeFormat.DATAMATRIX); possibleFormats.add(BarcodeFormat.PDF417); HINTS.put(DecodeHintType.POSSIBLE_FORMATS, possibleFormats); + HINTS_PURE = new Hashtable(HINTS); + HINTS_PURE.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE); } private HttpParams params; @@ -139,10 +146,13 @@ public final class DecodeServlet extends HttpServlet { throws ServletException, IOException { String imageURIString = request.getParameter("u"); if (imageURIString == null || imageURIString.length() == 0) { + log.fine("URI was empty"); response.sendRedirect("badurl.jspx"); return; } + imageURIString = imageURIString.trim(); + if (!(imageURIString.startsWith("http://") || imageURIString.startsWith("https://"))) { imageURIString = "http://" + imageURIString; } @@ -151,6 +161,7 @@ public final class DecodeServlet extends HttpServlet { try { imageURI = new URI(imageURIString); } catch (URISyntaxException urise) { + log.fine("URI was not valid: " + imageURIString); response.sendRedirect("badurl.jspx"); return; } @@ -168,25 +179,29 @@ public final class DecodeServlet extends HttpServlet { getResponse = client.execute(getRequest); } catch (IllegalArgumentException iae) { // Thrown if hostname is bad or null + log.fine(iae.toString()); getRequest.abort(); response.sendRedirect("badurl.jspx"); return; - } catch (SocketException se) { - // Thrown if hostname is bad or null - getRequest.abort(); - response.sendRedirect("badurl.jspx"); - return; - } catch (UnknownHostException uhe) { + } catch (IOException ioe) { + // Encompasses lots of stuff, including + // java.net.SocketException, java.net.UnknownHostException, + // javax.net.ssl.SSLPeerUnverifiedException, + // org.apache.http.NoHttpResponseException, + // org.apache.http.client.ClientProtocolException, + log.fine(ioe.toString()); getRequest.abort(); response.sendRedirect("badurl.jspx"); return; } if (getResponse.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK) { + log.fine("Unsuccessful return code: " + getResponse.getStatusLine().getStatusCode()); response.sendRedirect("badurl.jspx"); return; } if (!isSizeOK(getResponse)) { + log.fine("Too large"); response.sendRedirect("badimage.jspx"); return; } @@ -212,6 +227,7 @@ public final class DecodeServlet extends HttpServlet { throws ServletException, IOException { if (!ServletFileUpload.isMultipartContent(request)) { + log.fine("File upload was not multipart"); response.sendRedirect("badimage.jspx"); return; } @@ -232,12 +248,14 @@ public final class DecodeServlet extends HttpServlet { is.close(); } } else { + log.fine("Too large"); response.sendRedirect("badimage.jspx"); } break; } } } catch (FileUploadException fue) { + log.fine(fue.toString()); response.sendRedirect("badimage.jspx"); } @@ -245,74 +263,130 @@ public final class DecodeServlet extends HttpServlet { private static void processStream(InputStream is, ServletRequest request, HttpServletResponse response) throws ServletException, IOException { - BufferedImage image = ImageIO.read(is); + + BufferedImage image; + try { + image = ImageIO.read(is); + } catch (IOException ioe) { + log.fine(ioe.toString()); + // Includes javax.imageio.IIOException + response.sendRedirect("badimage.jspx"); + return; + } catch (CMMException cmme) { + log.fine(cmme.toString()); + // Have seen this in logs + response.sendRedirect("badimage.jspx"); + return; + } catch (IllegalArgumentException iae) { + log.fine(iae.toString()); + // Have seen this in logs for some JPEGs + response.sendRedirect("badimage.jspx"); + return; + } if (image == null) { + response.sendRedirect("badimage.jspx"); + return; + } + if (image.getHeight() <= 1 || image.getWidth() <= 1 || + image.getHeight() * image.getWidth() > MAX_PIXELS) { + log.fine("Dimensions too large: " + image.getWidth() + 'x' + image.getHeight()); response.sendRedirect("badimage.jspx"); return; } Reader reader = new MultiFormatReader(); - Result result; + LuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); + Collection results = new ArrayList(1); + ReaderException savedException = null; + try { - LuminanceSource source = new BufferedImageLuminanceSource(image); - BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); - result = reader.decode(bitmap, HINTS); + // Look for multiple barcodes + MultipleBarcodeReader multiReader = new GenericMultipleBarcodeReader(reader); + Result[] theResults = multiReader.decodeMultiple(bitmap, HINTS); + if (theResults != null) { + results.addAll(Arrays.asList(theResults)); + } } catch (ReaderException re) { + savedException = re; + } + + if (results.isEmpty()) { + try { + // Look for pure barcode + Result theResult = reader.decode(bitmap, HINTS_PURE); + if (theResult != null) { + results.add(theResult); + } + } catch (ReaderException re) { + savedException = re; + } + } + + if (results.isEmpty()) { + try { + // Look for normal barcode in photo + Result theResult = reader.decode(bitmap, HINTS); + if (theResult != null) { + results.add(theResult); + } + } catch (ReaderException re) { + savedException = re; + } + } + + if (results.isEmpty()) { try { // Try again with other binarizer - LuminanceSource source = new BufferedImageLuminanceSource(image); - BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); - result = reader.decode(bitmap, HINTS); - } catch (NotFoundException nfe) { - log.info("Not found: " + re.toString()); - response.sendRedirect("notfound.jspx"); - return; - } catch (FormatException fe) { - log.info("Format problem: " + re.toString()); - response.sendRedirect("format.jspx"); - return; - } catch (ChecksumException ce) { - log.info("Checksum problem: " + re.toString()); - response.sendRedirect("format.jspx"); - return; + BinaryBitmap hybridBitmap = new BinaryBitmap(new HybridBinarizer(source)); + Result theResult = reader.decode(hybridBitmap, HINTS); + if (theResult != null) { + results.add(theResult); + } + } catch (ReaderException re) { + savedException = re; } } + if (results.isEmpty()) { + handleException(savedException, response); + return; + } + if (request.getParameter("full") == null) { response.setContentType("text/plain"); response.setCharacterEncoding("UTF8"); Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF8"); try { - out.write(result.getText()); + for (Result result : results) { + out.write(result.getText()); + out.write('\n'); + } } finally { out.close(); } } else { - request.setAttribute("result", result); - byte[] rawBytes = result.getRawBytes(); - if (rawBytes != null) { - request.setAttribute("rawBytesString", arrayToString(rawBytes)); - } else { - request.setAttribute("rawBytesString", "(Not applicable)"); - } - String text = result.getText(); - if (text != null) { - request.setAttribute("text", StringEscapeUtils.escapeXml(text)); - } else { - request.setAttribute("text", "(Not applicable)"); - } - ParsedResult parsedResult = ResultParser.parseResult(result); - request.setAttribute("parsedResult", parsedResult); - String displayResult = parsedResult.getDisplayResult(); - if (displayResult != null) { - request.setAttribute("displayResult", StringEscapeUtils.escapeXml(displayResult)); - } else { - request.setAttribute("displayResult", "(Not applicable)"); - } + request.setAttribute("results", results); request.getRequestDispatcher("decoderesult.jspx").forward(request, response); } } + private static void handleException(ReaderException re, HttpServletResponse response) throws IOException { + if (re instanceof NotFoundException) { + log.info("Not found: " + re); + response.sendRedirect("notfound.jspx"); + } else if (re instanceof FormatException) { + log.info("Format problem: " + re); + response.sendRedirect("format.jspx"); + } else if (re instanceof ChecksumException) { + log.info("Checksum problem: " + re); + response.sendRedirect("format.jspx"); + } else { + log.info("Unknown problem: " + re); + response.sendRedirect("notfound.jspx"); + } + } + private static boolean isSizeOK(HttpMessage getResponse) { Header lengthHeader = getResponse.getLastHeader("Content-Length"); if (lengthHeader != null) { @@ -324,28 +398,6 @@ public final class DecodeServlet extends HttpServlet { return true; } - private static String arrayToString(byte[] bytes) { - int length = bytes.length; - StringBuilder result = new StringBuilder(length << 2); - int i = 0; - while (i < length) { - int max = Math.min(i + 8, length); - for (int j = i; j < max; j++) { - int value = bytes[j] & 0xFF; - result.append(Integer.toHexString(value / 16)); - result.append(Integer.toHexString(value % 16)); - result.append(' '); - } - result.append('\n'); - i += 8; - } - for (int j = i - 8; j < length; j++) { - result.append(Integer.toHexString(bytes[j] & 0xFF)); - result.append(' '); - } - return result.toString(); - } - @Override public void destroy() { log.config("DecodeServlet shutting down...");