Improvements and refinements to web site

git-svn-id: https://zxing.googlecode.com/svn/trunk@397 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2008-05-11 18:01:23 +00:00
parent 37559bac63
commit 5c705313bb
15 changed files with 235 additions and 171 deletions

View file

@ -67,14 +67,16 @@
<classes dir="web/WEB-INF/classes"/> <classes dir="web/WEB-INF/classes"/>
<fileset dir="web"> <fileset dir="web">
<include name="*.jspx"/> <include name="*.jspx"/>
<include name="*.png"/>
</fileset> </fileset>
</war> </war>
</target> </target>
<target name="clean"> <target name="clean">
<delete dir="web/WEB-INF/classes"/> <delete dir="web/WEB-INF/classes"/>
<delete file="../core/core.jar"/> <delete file="web/WEB-INF/lib/core.jar"/>
<delete file="../javase/javase.jar"/> <delete file="web/WEB-INF/lib/javase.jar"/>
<delete file="zxingorg.war"/>
</target> </target>
</project> </project>

View file

@ -38,13 +38,18 @@ import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart; import javax.mail.internet.MimeMultipart;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.util.Properties; import java.util.Properties;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* @author Sean Owen * A {@link TimerTask} which repeatedly checks an e-mail account for messages with an attached
* image. When one is found it attempts to decode the image and replies with the decoded messages
* by e-mail.
*
* @author Sean Owen (srowen@google.com)
*/ */
final class DecodeEmailTask extends TimerTask { final class DecodeEmailTask extends TimerTask {
@ -89,7 +94,6 @@ final class DecodeEmailTask extends TimerTask {
@Override @Override
public void run() { public void run() {
log.info("Checking email..."); log.info("Checking email...");
try {
Session session = Session.getInstance(sessionProperties, emailAuthenticator); Session session = Session.getInstance(sessionProperties, emailAuthenticator);
Store store = null; Store store = null;
Folder inbox = null; Folder inbox = null;
@ -105,16 +109,32 @@ final class DecodeEmailTask extends TimerTask {
for (int i = 1; i <= count; i++) { for (int i = 1; i <= count; i++) {
log.info("Processing message " + i); log.info("Processing message " + i);
Message message = inbox.getMessage(i); Message message = inbox.getMessage(i);
processMessage(session, message);
}
} catch (Throwable t) {
log.log(Level.WARNING, "Unexpected error", t);
} finally {
closeResources(store, inbox);
}
}
private void processMessage(Session session, Message message) throws MessagingException, IOException {
Object content = message.getContent(); Object content = message.getContent();
if (content instanceof MimeMultipart) { if (content instanceof MimeMultipart) {
MimeMultipart mimeContent = (MimeMultipart) content; MimeMultipart mimeContent = (MimeMultipart) content;
int numParts = mimeContent.getCount(); int numParts = mimeContent.getCount();
for (int j = 0; j < numParts; j++) { for (int j = 0; j < numParts; j++) {
MimeBodyPart part = (MimeBodyPart) mimeContent.getBodyPart(j); MimeBodyPart part = (MimeBodyPart) mimeContent.getBodyPart(j);
String contentType = part.getContentType(); processMessagePart(session, message, part);
if (!contentType.startsWith("image/")) {
continue;
} }
}
message.setFlag(Flags.Flag.DELETED, true);
}
private void processMessagePart(Session session, Message message, MimeBodyPart part)
throws MessagingException, IOException {
String contentType = part.getContentType();
if (contentType.startsWith("image/")) {
BufferedImage image = ImageIO.read(part.getInputStream()); BufferedImage image = ImageIO.read(part.getInputStream());
if (image != null) { if (image != null) {
Reader reader = new MultiFormatReader(); Reader reader = new MultiFormatReader();
@ -142,9 +162,8 @@ final class DecodeEmailTask extends TimerTask {
} }
} }
} }
message.setFlag(Flags.Flag.DELETED, true);
} private void closeResources(Store store, Folder inbox) {
} finally {
try { try {
if (inbox != null) { if (inbox != null) {
inbox.close(true); inbox.close(true);
@ -156,10 +175,6 @@ final class DecodeEmailTask extends TimerTask {
// continue // continue
} }
} }
} catch (Throwable t) {
log.log(Level.WARNING, "Unexpected error", t);
}
}
public static void main(String[] args) { public static void main(String[] args) {
String emailAddress = args[0]; String emailAddress = args[0];

View file

@ -22,6 +22,7 @@ import com.google.zxing.Reader;
import com.google.zxing.ReaderException; import com.google.zxing.ReaderException;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageMonochromeBitmapSource; import com.google.zxing.client.j2se.BufferedImageMonochromeBitmapSource;
import com.google.zxing.client.result.ParsedReaderResult;
import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory;
@ -63,7 +64,10 @@ import java.util.Timer;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* @author Sean Owen * {@link HttpServlet} which decodes images containing barcodes. Given a URL, it will
* retrieve the image and decode it. It can also process image files uploaded via POST.
*
* @author Sean Owen (srowen@google.com)
*/ */
public final class DecodeServlet extends HttpServlet { public final class DecodeServlet extends HttpServlet {
@ -114,7 +118,7 @@ public final class DecodeServlet extends HttpServlet {
} }
@Override @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String imageURIString = request.getParameter("u"); String imageURIString = request.getParameter("u");
if (imageURIString == null || imageURIString.length() == 0) { if (imageURIString == null || imageURIString.length() == 0) {
@ -149,7 +153,7 @@ public final class DecodeServlet extends HttpServlet {
log.info("Decoding " + imageURI); log.info("Decoding " + imageURI);
InputStream is = getResponse.getEntity().getContent(); InputStream is = getResponse.getEntity().getContent();
try { try {
processStream(is, response); processStream(is, request, response);
} finally { } finally {
is.close(); is.close();
} }
@ -183,12 +187,12 @@ public final class DecodeServlet extends HttpServlet {
log.info("Decoding uploaded file"); log.info("Decoding uploaded file");
InputStream is = item.getInputStream(); InputStream is = item.getInputStream();
try { try {
processStream(is, response); processStream(is, request, response);
} finally { } finally {
is.close(); is.close();
} }
} else { } else {
throw new ServletException("File is too large: " + item.getSize()); response.sendRedirect("badimage.jspx");
} }
break; break;
} }
@ -199,7 +203,8 @@ public final class DecodeServlet extends HttpServlet {
} }
private static void processStream(InputStream is, HttpServletResponse response) throws IOException { private static void processStream(InputStream is, HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BufferedImage image = ImageIO.read(is); BufferedImage image = ImageIO.read(is);
if (image == null) { if (image == null) {
response.sendRedirect("badimage.jspx"); response.sendRedirect("badimage.jspx");
@ -216,6 +221,7 @@ public final class DecodeServlet extends HttpServlet {
return; return;
} }
if (request.getParameter("full") == null) {
response.setContentType("text/plain"); response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8");
Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8"); Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
@ -224,6 +230,12 @@ public final class DecodeServlet extends HttpServlet {
} finally { } finally {
out.close(); out.close();
} }
} else {
request.setAttribute("result", result);
ParsedReaderResult parsedReaderResult = ParsedReaderResult.parseReaderResult(result);
request.setAttribute("parsedReaderResult", parsedReaderResult);
request.getRequestDispatcher("decoderesult.jspx").forward(request, response);
}
} }
private static boolean isSizeOK(HttpMessage getResponse) { private static boolean isSizeOK(HttpMessage getResponse) {

View file

@ -35,7 +35,10 @@ import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
/** /**
* @author Sean Owen * A {@link Filter} that rejects requests from hosts that are sending too many
* requests in too short a time.
*
* @author Sean Owen (srowen@google.com)
*/ */
public final class DoSFilter implements Filter { public final class DoSFilter implements Filter {

View file

@ -19,6 +19,11 @@ package com.google.zxing.web;
import javax.mail.Authenticator; import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication; import javax.mail.PasswordAuthentication;
/**
* A simple {@link Authenticator} which replies with a fixed username and password.
*
* @author Sean Owen (srowen@google.com)
*/
final class EmailAuthenticator extends Authenticator { final class EmailAuthenticator extends Authenticator {
private final String emailUsername; private final String emailUsername;

View file

@ -20,7 +20,9 @@ import java.net.InetAddress;
import java.util.Arrays; import java.util.Arrays;
/** /**
* @author Sean Owen * A trie data structure for storing a set of IP addresses efficiently.
*
* @author Sean Owen (srowen@google.com)
*/ */
final class IPTrie { final class IPTrie {

View file

@ -22,7 +22,9 @@ import java.util.logging.Handler;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
/** /**
* @author Sean Owen * A {@link Handler} that redirects log messages to the servlet container log.
*
* @author Sean Owen (srowen@google.com)
*/ */
final class ServletContextLogHandler extends Handler { final class ServletContextLogHandler extends Handler {

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2008 Google Inc.
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.
-->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output omit-xml-declaration="true"/>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-788492-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</jsp:root>

View file

@ -14,6 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1"> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output <jsp:output
omit-xml-declaration="false" doctype-root-element="html" omit-xml-declaration="false" doctype-root-element="html"
@ -23,27 +24,14 @@
<jsp:scriptlet>response.setHeader("Cache-Control", "public");</jsp:scriptlet> <jsp:scriptlet>response.setHeader("Cache-Control", "public");</jsp:scriptlet>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head> <head>
<title>No Barcode Found</title> <title>Bad Image</title>
</head> </head>
<body> <body>
<p> <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Bad Image</h1>
<b>Bad URL</b>
</p>
<p>The image you uploaded could not be decoded, or was too large. Go "Back" in your browser and try another <p>The image you uploaded could not be decoded, or was too large. Go "Back" in your browser and try another
image. image.
</p> </p>
<script type="text/javascript"> <jsp:include page="analytics.jspx"/>
var gaJsHost = (("https:" == document.location.protocol) ?
"https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
"google-analytics.com/ga.js'
type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-788492-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body> </body>
</html> </html>
</jsp:root> </jsp:root>

View file

@ -14,6 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1"> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output <jsp:output
omit-xml-declaration="false" doctype-root-element="html" omit-xml-declaration="false" doctype-root-element="html"
@ -23,27 +24,14 @@
<jsp:scriptlet>response.setHeader("Cache-Control", "public");</jsp:scriptlet> <jsp:scriptlet>response.setHeader("Cache-Control", "public");</jsp:scriptlet>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head> <head>
<title>No Barcode Found</title> <title>Bad URL</title>
</head> </head>
<body> <body>
<p> <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Bad URL</h1>
<b>Bad URL</b>
</p>
<p>You didn't specify a URL, or the URL was not valid, or did not return an image. Go "Back" in your browser and <p>You didn't specify a URL, or the URL was not valid, or did not return an image. Go "Back" in your browser and
try again. try again.
</p> </p>
<script type="text/javascript"> <jsp:include page="analytics.jspx"/>
var gaJsHost = (("https:" == document.location.protocol) ?
"https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
"google-analytics.com/ga.js'
type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-788492-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body> </body>
</html> </html>
</jsp:root> </jsp:root>

View file

@ -14,6 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1"> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output <jsp:output
omit-xml-declaration="false" doctype-root-element="html" omit-xml-declaration="false" doctype-root-element="html"
@ -26,47 +27,29 @@
<title>ZXing Decoder Online</title> <title>ZXing Decoder Online</title>
</head> </head>
<body> <body>
<h1><img src="zxing-icon.png" height="32" width="32" alt=""/> ZXing Decoder Online</h1>
<h1>ZXing Decoder Online</h1>
<p><b>Under Construction</b>: This is a simple page that will let you decode a 1D or 2D barcode found <p><b>Under Construction</b>: This is a simple page that will let you decode a 1D or 2D barcode found
in an image online. Enter a URL below. in an image online. Enter a URL below.
</p> </p>
<form action="decode" method="get"> <form action="decode" method="get">
<p> <p>
<input type="text" size="50" name="u"/> <input type="text" size="50" name="u"/>&amp;nbsp;<input type="submit"/>
<input type="submit"/> <input type="hidden" name="full" value="true"/>
</p> </p>
</form> </form>
<p>Or try uploading a file:</p> <p>Or try uploading a file:</p>
<form action="decode" method="post" enctype="multipart/form-data"> <form action="decode" method="post" enctype="multipart/form-data">
<p> <p>
<input type="file" size="50" name="f"/> <input type="file" size="50" name="f"/>&amp;nbsp;<input type="submit"/>
<input type="submit"/> <input type="hidden" name="full" value="true"/>
</p> </p>
</form> </form>
<p>See the <p>See the
<a href="http://code.google.com/p/zxing">project page</a> <a href="http://code.google.com/p/zxing">project page</a>
for details. for details.
</p> </p>
<p>Copyright (C) 2008 Google Inc.</p>
<script type="text/javascript"> <jsp:include page="analytics.jspx"/>
var gaJsHost = (("https:" == document.location.protocol) ?
"https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
"google-analytics.com/ga.js'
type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-788492-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body> </body>
</html> </html>
</jsp:root> </jsp:root>

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2008 Google Inc.
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.
-->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output
omit-xml-declaration="false" doctype-root-element="html"
doctype-public="-//WAPFORUM//DTD XHTML Mobile 1.1//EN"
doctype-system="http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd"/>
<jsp:directive.page contentType="application/xhtml+xml" session="false"/>
<jsp:scriptlet>response.setHeader("Cache-Control", "no-cache");</jsp:scriptlet>
<jsp:useBean id="result" scope="request" type="com.google.zxing.Result"/>
<jsp:useBean id="parsedReaderResult" scope="request" type="com.google.zxing.client.result.ParsedReaderResult"/>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Decode Succeeded</title>
<style type="text/css">
td { vertical-align: top; padding: 0.1in; background-color: #EEEEEE; font-family: monospace; }
</style>
</head>
<body>
<h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Decode Succeeded</h1>
<table>
<tr>
<td>Raw text</td>
<td>${result.text}</td>
</tr>
<tr>
<td>Barcode format</td>
<td>${result.barcodeFormat}</td>
</tr>
<tr>
<td>Parsed Result Type</td>
<td>${parsedReaderResult.type}</td>
</tr>
<tr>
<td>Parsed Result</td>
<td>${parsedReaderResult.displayResult}</td>
</tr>
</table>
<p>Copyright (C) 2008 Google Inc.</p>
<jsp:include page="analytics.jspx"/>
</body>
</html>
</jsp:root>

View file

@ -14,6 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1"> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output <jsp:output
omit-xml-declaration="false" doctype-root-element="html" omit-xml-declaration="false" doctype-root-element="html"
@ -26,9 +27,7 @@
<title>Download ZXing Reader</title> <title>Download ZXing Reader</title>
</head> </head>
<body> <body>
<p> <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Download ZXing Reader</h1>
<strong>Welcome to zxing!</strong>
</p>
<p> <p>
<a href="BarcodeReader.jad">Download</a> <a href="BarcodeReader.jad">Download</a>
the ZXing Barcode Reader. the ZXing Barcode Reader.
@ -47,18 +46,8 @@
<a href="BarcodeReader.apk">Download</a> <a href="BarcodeReader.apk">Download</a>
the Android client. the Android client.
</p> </p>
<script type="text/javascript"> <p>Copyright (C) 2008 Google Inc.</p>
var gaJsHost = (("https:" == document.location.protocol) ? <jsp:include page="analytics.jspx"/>
"https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
"google-analytics.com/ga.js'
type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-788492-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body> </body>
</html> </html>
</jsp:root> </jsp:root>

View file

@ -14,6 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<!-- Author: Sean Owen (srowen@google.com) -->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1"> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
<jsp:output <jsp:output
omit-xml-declaration="false" doctype-root-element="html" omit-xml-declaration="false" doctype-root-element="html"
@ -26,24 +27,11 @@
<title>No Barcode Found</title> <title>No Barcode Found</title>
</head> </head>
<body> <body>
<p> <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> No Barcode Found</h1>
<b>No Barcode Found</b>
</p>
<p>No barcode was found in this image. Either it did not contain a barcode, or did not contain one in a <p>No barcode was found in this image. Either it did not contain a barcode, or did not contain one in a
supported format, or the software was simply unable to find it. Go "Back" in your browser and try another image. supported format, or the software was simply unable to find it. Go "Back" in your browser and try another image.
</p> </p>
<script type="text/javascript"> <jsp:include page="analytics.jspx"/>
var gaJsHost = (("https:" == document.location.protocol) ?
"https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
"google-analytics.com/ga.js'
type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-788492-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body> </body>
</html> </html>
</jsp:root> </jsp:root>

BIN
zxingorg/web/zxing-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB