Skip to content

Commit

Permalink
Added QRcode decoding wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
dren-dk committed Mar 27, 2011
1 parent bf56496 commit f9a5196
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 39 deletions.
20 changes: 20 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Gear Book: Informal gear management for hackerspaces

The moving parts are:

* labels: The label generator *
Produces a stak of PDFs that make it easy to print
the labels needed, each label contains a QR code which links into the
database and some tags, like "Do Not Hack" and "Borrowed, take extra care".


* wiki: The database *
Unlike more formal systems, the database which holds the list of equipment
is simply an existing wiki system, in the case of OSAA, it's just media wiki
with a bunch of infoboxen that make sense to us, YMMV and so on.

* server: Equipment registrator *
This is a simple web application written in java which uses ZXing to recognize
QR codes in photos and semi-automagically turn a stream of photos into
new gear registrations.

2 changes: 2 additions & 0 deletions server/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@
<classpathentry kind="lib" path="lib/jetty-distribution-8.0.0.M0/lib/jetty-websocket-8.0.0.M0.jar"/>
<classpathentry kind="lib" path="lib/jetty-distribution-8.0.0.M0/lib/jetty-xml-8.0.0.M0.jar"/>
<classpathentry kind="lib" path="lib/jetty-distribution-8.0.0.M0/lib/servlet-api-3.0.jar"/>
<classpathentry kind="lib" path="lib/zxing-1.6/core/core.jar" sourcepath="lib/zxing-1.6/core/src"/>
<classpathentry kind="lib" path="lib/zxing-1.6/javase/javase.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Binary file added server/lib/zxing-1.6/javase/javase.jar
Binary file not shown.
44 changes: 44 additions & 0 deletions server/src/dk/osaa/gb/GearBook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dk.osaa.gb;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;

public class GearBook {
static Logger log = Logger.getLogger(GearBook.class.getName());

public static void main(String[] args) {
Server server = new Server(Integer.getInteger("dk.osaa.gb.port", 8000));

try {
ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[]{ "index.html" });
File root = new File(System.getProperty("dk.osaa.gb.root", "root")).getAbsoluteFile();
System.err.println("Serving files out of "+root);
resource_handler.setResourceBase(root.getAbsolutePath());

HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] {
resource_handler,
new NewGearHandler(),
new DefaultHandler()
});
server.setHandler(handlers);

server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gb.osaa.dk;
package dk.osaa.gb;

import java.io.IOException;

Expand Down
160 changes: 160 additions & 0 deletions server/src/dk/osaa/gb/QRDecoder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package dk.osaa.gb;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
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.common.GlobalHistogramBinarizer;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.multi.GenericMultipleBarcodeReader;
import com.google.zxing.multi.MultipleBarcodeReader;

/**
* Wrapper for ZXing, which allows mortals to use the library.
*/
public class QRDecoder {

private static Logger log = Logger.getLogger(QRDecoder.class.getName());

private static final Hashtable<DecodeHintType, Object> HINTS;
private static final Hashtable<DecodeHintType, Object> HINTS_PURE;

static {
HINTS = new Hashtable<DecodeHintType, Object>(5);
HINTS.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
Collection<BarcodeFormat> possibleFormats = new Vector<BarcodeFormat>(17);
possibleFormats.add(BarcodeFormat.QR_CODE);
HINTS.put(DecodeHintType.POSSIBLE_FORMATS, possibleFormats);
HINTS_PURE = new Hashtable<DecodeHintType, Object>(HINTS);
HINTS_PURE.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
}

/**
* Simple QR decoding routing, will try very hard to find one or more QR codes in the image and return them.
* @param is The input stream where the image can be read from
* @return The results, might be 0 long.
*/
public static Collection<Result> decodeImage(InputStream is) {

Collection<Result> results = new ArrayList<Result>(1);

BufferedImage image;
try {
image = ImageIO.read(is);
} catch (Exception e) {
log.log(Level.INFO, "Got exception while reading image from strea, perhaps it's corrupt", e);
return results;
}

if (image == null) {
log.log(Level.INFO, "bad image");
return results;
}

Reader reader = new MultiFormatReader();
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));

try {
// 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) {
}

if (results.isEmpty()) {
try {
// Look for pure barcode
Result theResult = reader.decode(bitmap, HINTS_PURE);
if (theResult != null) {
results.add(theResult);
}
} catch (ReaderException 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) {
}
}

if (results.isEmpty()) {
try {
// Try again with other binarizer
BinaryBitmap hybridBitmap = new BinaryBitmap(new HybridBinarizer(source));
Result theResult = reader.decode(hybridBitmap, HINTS);
if (theResult != null) {
results.add(theResult);
}
} catch (ReaderException re) {
}
}

if (results.isEmpty()) {
log.fine("Failed to find any barcode in image");
return results;
}

if (log.isLoggable(Level.FINE)) {
for (Result result : results) {
log.fine(result.getText());
}
}

return results;
}

/**
* Just a small bit of test code, not really suitable for anything.
* @param args Ignored
*/
public static void main(String[] args) {

File td = new File("/home/ff/projects/osaa/GearBook/testdata");
for (File f : td.listFiles()) {

log.info("Reading: "+f);
try {
Collection<Result> results = QRDecoder.decodeImage(new FileInputStream(f));
for (Result r : results) {
log.info("Found: "+r);
}

} catch (FileNotFoundException e) {
log.log(Level.SEVERE, "Urgh: "+f, e);
continue;
}

}
System.exit(0);
}
}
38 changes: 0 additions & 38 deletions server/src/gb/osaa/dk/GearBook.java

This file was deleted.

0 comments on commit f9a5196

Please sign in to comment.