Skip to content

Commit f9a5196

Browse files
committed
Added QRcode decoding wrapper
1 parent bf56496 commit f9a5196

File tree

7 files changed

+227
-39
lines changed

7 files changed

+227
-39
lines changed

README

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Gear Book: Informal gear management for hackerspaces
2+
3+
The moving parts are:
4+
5+
* labels: The label generator *
6+
Produces a stak of PDFs that make it easy to print
7+
the labels needed, each label contains a QR code which links into the
8+
database and some tags, like "Do Not Hack" and "Borrowed, take extra care".
9+
10+
11+
* wiki: The database *
12+
Unlike more formal systems, the database which holds the list of equipment
13+
is simply an existing wiki system, in the case of OSAA, it's just media wiki
14+
with a bunch of infoboxen that make sense to us, YMMV and so on.
15+
16+
* server: Equipment registrator *
17+
This is a simple web application written in java which uses ZXing to recognize
18+
QR codes in photos and semi-automagically turn a stream of photos into
19+
new gear registrations.
20+

server/.classpath

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@
2323
<classpathentry kind="lib" path="lib/jetty-distribution-8.0.0.M0/lib/jetty-websocket-8.0.0.M0.jar"/>
2424
<classpathentry kind="lib" path="lib/jetty-distribution-8.0.0.M0/lib/jetty-xml-8.0.0.M0.jar"/>
2525
<classpathentry kind="lib" path="lib/jetty-distribution-8.0.0.M0/lib/servlet-api-3.0.jar"/>
26+
<classpathentry kind="lib" path="lib/zxing-1.6/core/core.jar" sourcepath="lib/zxing-1.6/core/src"/>
27+
<classpathentry kind="lib" path="lib/zxing-1.6/javase/javase.jar"/>
2628
<classpathentry kind="output" path="bin"/>
2729
</classpath>
19.8 KB
Binary file not shown.

server/src/dk/osaa/gb/GearBook.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package dk.osaa.gb;
2+
3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.FileNotFoundException;
6+
import java.util.Collection;
7+
import java.util.logging.Level;
8+
import java.util.logging.Logger;
9+
10+
import org.eclipse.jetty.server.Handler;
11+
import org.eclipse.jetty.server.Server;
12+
import org.eclipse.jetty.server.handler.DefaultHandler;
13+
import org.eclipse.jetty.server.handler.HandlerList;
14+
import org.eclipse.jetty.server.handler.ResourceHandler;
15+
16+
public class GearBook {
17+
static Logger log = Logger.getLogger(GearBook.class.getName());
18+
19+
public static void main(String[] args) {
20+
Server server = new Server(Integer.getInteger("dk.osaa.gb.port", 8000));
21+
22+
try {
23+
ResourceHandler resource_handler = new ResourceHandler();
24+
resource_handler.setDirectoriesListed(true);
25+
resource_handler.setWelcomeFiles(new String[]{ "index.html" });
26+
File root = new File(System.getProperty("dk.osaa.gb.root", "root")).getAbsoluteFile();
27+
System.err.println("Serving files out of "+root);
28+
resource_handler.setResourceBase(root.getAbsolutePath());
29+
30+
HandlerList handlers = new HandlerList();
31+
handlers.setHandlers(new Handler[] {
32+
resource_handler,
33+
new NewGearHandler(),
34+
new DefaultHandler()
35+
});
36+
server.setHandler(handlers);
37+
38+
server.start();
39+
server.join();
40+
} catch (Exception e) {
41+
e.printStackTrace();
42+
}
43+
}
44+
}

server/src/gb/osaa/dk/NewGearHandler.java renamed to server/src/dk/osaa/gb/NewGearHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package gb.osaa.dk;
1+
package dk.osaa.gb;
22

33
import java.io.IOException;
44

server/src/dk/osaa/gb/QRDecoder.java

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package dk.osaa.gb;
2+
3+
import java.awt.image.BufferedImage;
4+
import java.io.File;
5+
import java.io.FileInputStream;
6+
import java.io.FileNotFoundException;
7+
import java.io.InputStream;
8+
import java.util.ArrayList;
9+
import java.util.Arrays;
10+
import java.util.Collection;
11+
import java.util.Hashtable;
12+
import java.util.Vector;
13+
import java.util.logging.Level;
14+
import java.util.logging.Logger;
15+
16+
import javax.imageio.ImageIO;
17+
18+
import com.google.zxing.BarcodeFormat;
19+
import com.google.zxing.BinaryBitmap;
20+
import com.google.zxing.DecodeHintType;
21+
import com.google.zxing.LuminanceSource;
22+
import com.google.zxing.MultiFormatReader;
23+
import com.google.zxing.Reader;
24+
import com.google.zxing.ReaderException;
25+
import com.google.zxing.Result;
26+
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
27+
import com.google.zxing.common.GlobalHistogramBinarizer;
28+
import com.google.zxing.common.HybridBinarizer;
29+
import com.google.zxing.multi.GenericMultipleBarcodeReader;
30+
import com.google.zxing.multi.MultipleBarcodeReader;
31+
32+
/**
33+
* Wrapper for ZXing, which allows mortals to use the library.
34+
*/
35+
public class QRDecoder {
36+
37+
private static Logger log = Logger.getLogger(QRDecoder.class.getName());
38+
39+
private static final Hashtable<DecodeHintType, Object> HINTS;
40+
private static final Hashtable<DecodeHintType, Object> HINTS_PURE;
41+
42+
static {
43+
HINTS = new Hashtable<DecodeHintType, Object>(5);
44+
HINTS.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
45+
Collection<BarcodeFormat> possibleFormats = new Vector<BarcodeFormat>(17);
46+
possibleFormats.add(BarcodeFormat.QR_CODE);
47+
HINTS.put(DecodeHintType.POSSIBLE_FORMATS, possibleFormats);
48+
HINTS_PURE = new Hashtable<DecodeHintType, Object>(HINTS);
49+
HINTS_PURE.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
50+
}
51+
52+
/**
53+
* Simple QR decoding routing, will try very hard to find one or more QR codes in the image and return them.
54+
* @param is The input stream where the image can be read from
55+
* @return The results, might be 0 long.
56+
*/
57+
public static Collection<Result> decodeImage(InputStream is) {
58+
59+
Collection<Result> results = new ArrayList<Result>(1);
60+
61+
BufferedImage image;
62+
try {
63+
image = ImageIO.read(is);
64+
} catch (Exception e) {
65+
log.log(Level.INFO, "Got exception while reading image from strea, perhaps it's corrupt", e);
66+
return results;
67+
}
68+
69+
if (image == null) {
70+
log.log(Level.INFO, "bad image");
71+
return results;
72+
}
73+
74+
Reader reader = new MultiFormatReader();
75+
LuminanceSource source = new BufferedImageLuminanceSource(image);
76+
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
77+
78+
try {
79+
// Look for multiple barcodes
80+
MultipleBarcodeReader multiReader = new GenericMultipleBarcodeReader(reader);
81+
Result[] theResults = multiReader.decodeMultiple(bitmap, HINTS);
82+
if (theResults != null) {
83+
results.addAll(Arrays.asList(theResults));
84+
}
85+
} catch (ReaderException re) {
86+
}
87+
88+
if (results.isEmpty()) {
89+
try {
90+
// Look for pure barcode
91+
Result theResult = reader.decode(bitmap, HINTS_PURE);
92+
if (theResult != null) {
93+
results.add(theResult);
94+
}
95+
} catch (ReaderException re) {
96+
}
97+
}
98+
99+
if (results.isEmpty()) {
100+
try {
101+
// Look for normal barcode in photo
102+
Result theResult = reader.decode(bitmap, HINTS);
103+
if (theResult != null) {
104+
results.add(theResult);
105+
}
106+
} catch (ReaderException re) {
107+
}
108+
}
109+
110+
if (results.isEmpty()) {
111+
try {
112+
// Try again with other binarizer
113+
BinaryBitmap hybridBitmap = new BinaryBitmap(new HybridBinarizer(source));
114+
Result theResult = reader.decode(hybridBitmap, HINTS);
115+
if (theResult != null) {
116+
results.add(theResult);
117+
}
118+
} catch (ReaderException re) {
119+
}
120+
}
121+
122+
if (results.isEmpty()) {
123+
log.fine("Failed to find any barcode in image");
124+
return results;
125+
}
126+
127+
if (log.isLoggable(Level.FINE)) {
128+
for (Result result : results) {
129+
log.fine(result.getText());
130+
}
131+
}
132+
133+
return results;
134+
}
135+
136+
/**
137+
* Just a small bit of test code, not really suitable for anything.
138+
* @param args Ignored
139+
*/
140+
public static void main(String[] args) {
141+
142+
File td = new File("/home/ff/projects/osaa/GearBook/testdata");
143+
for (File f : td.listFiles()) {
144+
145+
log.info("Reading: "+f);
146+
try {
147+
Collection<Result> results = QRDecoder.decodeImage(new FileInputStream(f));
148+
for (Result r : results) {
149+
log.info("Found: "+r);
150+
}
151+
152+
} catch (FileNotFoundException e) {
153+
log.log(Level.SEVERE, "Urgh: "+f, e);
154+
continue;
155+
}
156+
157+
}
158+
System.exit(0);
159+
}
160+
}

server/src/gb/osaa/dk/GearBook.java

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)