mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Various improvements to decode speed and efficiency of J2ME client
git-svn-id: https://zxing.googlecode.com/svn/trunk@257 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
4abc8aecec
commit
8c03ed9301
|
@ -37,7 +37,7 @@ final class AdvancedMultimediaManager {
|
||||||
|
|
||||||
private static final int NO_ZOOM = 100;
|
private static final int NO_ZOOM = 100;
|
||||||
private static final int MAX_ZOOM = 200;
|
private static final int MAX_ZOOM = 200;
|
||||||
private static final long FOCUS_TIME_MS = 1000L;
|
private static final long FOCUS_TIME_MS = 750L;
|
||||||
|
|
||||||
private AdvancedMultimediaManager() {
|
private AdvancedMultimediaManager() {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|
|
@ -117,19 +117,27 @@ public final class LCDUIImageMonochromeBitmapSource implements MonochromeBitmapS
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts luminance from a pixel from this source. By default, the source is assumed to use RGB,
|
* An optimized approximation of a more proper conversion from RGB to luminance which
|
||||||
* so this implementation computes luminance is a function of a red, green and blue components as
|
* only uses shifts. See BufferedImageMonochromeBitmapSource for an original version.
|
||||||
* follows:
|
|
||||||
*
|
|
||||||
* <code>Y = 0.299R + 0.587G + 0.114B</code>
|
|
||||||
*
|
|
||||||
* where R, G, and B are values in [0,1].
|
|
||||||
*/
|
*/
|
||||||
private static int computeRGBLuminance(int pixel) {
|
private static int computeRGBLuminance(int pixel) {
|
||||||
// Coefficients add up to 1024 to make the divide into a fast shift
|
// Instead of multiplying by 306, 601, 117, we multiply by 256, 512, 256, so that
|
||||||
return (306 * ((pixel >> 16) & 0xFF) +
|
// the multiplies can be implemented as shifts.
|
||||||
601 * ((pixel >> 8) & 0xFF) +
|
//
|
||||||
117 * (pixel & 0xFF)) >> 10;
|
// Really, it's:
|
||||||
|
//
|
||||||
|
// return ((((pixel >> 16) & 0xFF) << 8) +
|
||||||
|
// (((pixel >> 8) & 0xFF) << 9) +
|
||||||
|
// (( pixel & 0xFF) << 8)) >> 10;
|
||||||
|
//
|
||||||
|
// That is, we're replacing the coefficients in the original with powers of two,
|
||||||
|
// which can be implemented as shifts, even though changing the coefficients slightly
|
||||||
|
// corrupts the conversion. Not significant for our purposes.
|
||||||
|
//
|
||||||
|
// But we can get even cleverer and eliminate a few shifts:
|
||||||
|
return (((pixel & 0x00FF0000) >> 8) +
|
||||||
|
((pixel & 0x0000FF00) << 1) +
|
||||||
|
((pixel & 0x000000FF) << 8)) >> 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -28,56 +28,64 @@ import javax.microedition.media.Player;
|
||||||
import javax.microedition.media.control.VideoControl;
|
import javax.microedition.media.control.VideoControl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Thread which does the work of capturing a frame and decoding it.
|
||||||
|
*
|
||||||
* @author Sean Owen (srowen@google.com)
|
* @author Sean Owen (srowen@google.com)
|
||||||
*/
|
*/
|
||||||
final class SnapshotThread extends Thread {
|
final class SnapshotThread extends Thread {
|
||||||
|
|
||||||
private static SnapshotThread currentThread;
|
|
||||||
|
|
||||||
private final ZXingMIDlet zXingMIDlet;
|
private final ZXingMIDlet zXingMIDlet;
|
||||||
|
private final Object waitLock;
|
||||||
|
private boolean done;
|
||||||
|
|
||||||
private SnapshotThread(ZXingMIDlet zXingMIDlet) {
|
SnapshotThread(ZXingMIDlet zXingMIDlet) {
|
||||||
this.zXingMIDlet = zXingMIDlet;
|
this.zXingMIDlet = zXingMIDlet;
|
||||||
|
waitLock = new Object();
|
||||||
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static synchronized void startThread(ZXingMIDlet zXingMIDlet) {
|
void continueRun() {
|
||||||
if (currentThread == null) {
|
synchronized (waitLock) {
|
||||||
currentThread = new SnapshotThread(zXingMIDlet);
|
waitLock.notifyAll();
|
||||||
currentThread.start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void waitForSignal() {
|
||||||
|
synchronized (waitLock) {
|
||||||
|
try {
|
||||||
|
waitLock.wait();
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
done = true;
|
||||||
|
continueRun();
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
Player player = zXingMIDlet.getPlayer();
|
Player player = zXingMIDlet.getPlayer();
|
||||||
try {
|
do {
|
||||||
AdvancedMultimediaManager.setFocus(player);
|
waitForSignal();
|
||||||
try {
|
try {
|
||||||
player.stop();
|
AdvancedMultimediaManager.setFocus(player);
|
||||||
|
byte[] snapshot = takeSnapshot();
|
||||||
|
Image capturedImage = Image.createImage(snapshot, 0, snapshot.length);
|
||||||
|
MonochromeBitmapSource source = new LCDUIImageMonochromeBitmapSource(capturedImage);
|
||||||
|
Reader reader = new MultiFormatReader();
|
||||||
|
Result result = reader.decode(source);
|
||||||
|
zXingMIDlet.handleDecodedText(result.getText());
|
||||||
|
} catch (ReaderException re) {
|
||||||
|
// Show a friendlier message on a mere failure to read the barcode
|
||||||
|
zXingMIDlet.showError("Sorry, no barcode was found.");
|
||||||
} catch (MediaException me) {
|
} catch (MediaException me) {
|
||||||
// continue
|
zXingMIDlet.showError(me);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
zXingMIDlet.showError(re);
|
||||||
}
|
}
|
||||||
byte[] snapshot = takeSnapshot();
|
} while (!done);
|
||||||
Image capturedImage = Image.createImage(snapshot, 0, snapshot.length);
|
|
||||||
MonochromeBitmapSource source = new LCDUIImageMonochromeBitmapSource(capturedImage);
|
|
||||||
Reader reader = new MultiFormatReader();
|
|
||||||
Result result = reader.decode(source);
|
|
||||||
zXingMIDlet.handleDecodedText(result.getText());
|
|
||||||
} catch (ReaderException re) {
|
|
||||||
// Show a friendlier message on a mere failure to read the barcode
|
|
||||||
zXingMIDlet.showError("Sorry, no barcode was found.");
|
|
||||||
} catch (MediaException me) {
|
|
||||||
zXingMIDlet.showError(me);
|
|
||||||
} catch (RuntimeException re) {
|
|
||||||
zXingMIDlet.showError(re);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
player.start();
|
|
||||||
} catch (MediaException me) {
|
|
||||||
// continue
|
|
||||||
}
|
|
||||||
currentThread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] takeSnapshot() throws MediaException {
|
private byte[] takeSnapshot() throws MediaException {
|
||||||
|
|
|
@ -23,6 +23,9 @@ import javax.microedition.lcdui.Displayable;
|
||||||
import javax.microedition.lcdui.Graphics;
|
import javax.microedition.lcdui.Graphics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The main {@link Canvas} onto which the camera's field of view is painted.
|
||||||
|
* This class manages decoding via {@link SnapshotThread}.
|
||||||
|
*
|
||||||
* @author Sean Owen (srowen@google.com)
|
* @author Sean Owen (srowen@google.com)
|
||||||
*/
|
*/
|
||||||
final class VideoCanvas extends Canvas implements CommandListener {
|
final class VideoCanvas extends Canvas implements CommandListener {
|
||||||
|
@ -30,11 +33,14 @@ final class VideoCanvas extends Canvas implements CommandListener {
|
||||||
private static final Command exit = new Command("Exit", Command.EXIT, 1);
|
private static final Command exit = new Command("Exit", Command.EXIT, 1);
|
||||||
|
|
||||||
private final ZXingMIDlet zXingMIDlet;
|
private final ZXingMIDlet zXingMIDlet;
|
||||||
|
private final SnapshotThread snapshotThread;
|
||||||
|
|
||||||
VideoCanvas(ZXingMIDlet zXingMIDlet) {
|
VideoCanvas(ZXingMIDlet zXingMIDlet) {
|
||||||
this.zXingMIDlet = zXingMIDlet;
|
this.zXingMIDlet = zXingMIDlet;
|
||||||
addCommand(exit);
|
addCommand(exit);
|
||||||
setCommandListener(this);
|
setCommandListener(this);
|
||||||
|
snapshotThread = new SnapshotThread(zXingMIDlet);
|
||||||
|
snapshotThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void paint(Graphics graphics) {
|
protected void paint(Graphics graphics) {
|
||||||
|
@ -44,12 +50,16 @@ final class VideoCanvas extends Canvas implements CommandListener {
|
||||||
protected void keyPressed(int keyCode) {
|
protected void keyPressed(int keyCode) {
|
||||||
// Any valid game key will trigger a capture
|
// Any valid game key will trigger a capture
|
||||||
if (getGameAction(keyCode) != 0) {
|
if (getGameAction(keyCode) != 0) {
|
||||||
SnapshotThread.startThread(zXingMIDlet);
|
snapshotThread.continueRun();
|
||||||
|
} else {
|
||||||
|
super.keyPressed(keyCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void commandAction(Command command, Displayable displayable) {
|
public void commandAction(Command command, Displayable displayable) {
|
||||||
if (command.getCommandType() == Command.EXIT || command.getCommandType() == Command.STOP) {
|
int type = command.getCommandType();
|
||||||
|
if (type == Command.EXIT || type == Command.STOP || type == Command.BACK || type == Command.CANCEL) {
|
||||||
|
snapshotThread.stop();
|
||||||
zXingMIDlet.stop();
|
zXingMIDlet.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue