/* * Copyright 2007 ZXing authors * * 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. */ package com.google.zxing.client.j2me; import com.google.zxing.BinaryBitmap; 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.common.GlobalHistogramBinarizer; import javax.microedition.lcdui.Image; import javax.microedition.media.MediaException; import javax.microedition.media.Player; import javax.microedition.media.control.VideoControl; /** * Thread which does the work of capturing a frame and decoding it. * * @author Sean Owen */ final class SnapshotThread implements Runnable { private final ZXingMIDlet zXingMIDlet; private final Object waitLock; private volatile boolean done; private final MultimediaManager multimediaManager; private String bestEncoding; SnapshotThread(ZXingMIDlet zXingMIDlet) { this.zXingMIDlet = zXingMIDlet; waitLock = new Object(); done = false; multimediaManager = ZXingMIDlet.buildMultimediaManager(); } void continueRun() { synchronized (waitLock) { waitLock.notifyAll(); } } private void waitForSignal() { synchronized (waitLock) { try { waitLock.wait(); } catch (InterruptedException ie) { // continue } } } void stop() { done = true; continueRun(); } public void run() { Player player = zXingMIDlet.getPlayer(); do { waitForSignal(); try { multimediaManager.setFocus(player); byte[] snapshot = takeSnapshot(); Image capturedImage = Image.createImage(snapshot, 0, snapshot.length); LuminanceSource source = new LCDUIImageLuminanceSource(capturedImage); BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); Reader reader = new MultiFormatReader(); Result result = reader.decode(bitmap); zXingMIDlet.handleDecodedText(result); } 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); } } while (!done); } private byte[] takeSnapshot() throws MediaException { String bestEncoding = guessBestEncoding(); VideoControl videoControl = zXingMIDlet.getVideoControl(); byte[] snapshot = null; try { snapshot = videoControl.getSnapshot("".equals(bestEncoding) ? null : bestEncoding); } catch (MediaException me) { } if (snapshot == null) { // Fall back on JPEG; seems that some cameras default to PNG even // when PNG isn't supported! snapshot = videoControl.getSnapshot("encoding=jpeg"); if (snapshot == null) { throw new MediaException("Can't obtain a snapshot"); } } return snapshot; } private synchronized String guessBestEncoding() throws MediaException { if (bestEncoding == null) { // Check this property, present on some Nokias? String supportsVideoCapture = System.getProperty("supports.video.capture"); if ("false".equals(supportsVideoCapture)) { throw new MediaException("supports.video.capture is false"); } bestEncoding = ""; String videoSnapshotEncodings = System.getProperty("video.snapshot.encodings"); if (videoSnapshotEncodings != null) { // We know explicitly what the camera supports; see if PNG is among them since // Image.createImage() should always support it int pngEncodingStart = videoSnapshotEncodings.indexOf("encoding=png"); if (pngEncodingStart >= 0) { int space = videoSnapshotEncodings.indexOf(' ', pngEncodingStart); bestEncoding = space >= 0 ? videoSnapshotEncodings.substring(pngEncodingStart, space) : videoSnapshotEncodings.substring(pngEncodingStart); } } } return bestEncoding; } }