/* * Copyright (C) 2010 ZXing authors * Copyright 2011 Robert Theis * * 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.moob.ocrdnitest; import android.graphics.Bitmap; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import com.googlecode.leptonica.android.ReadFile; import com.googlecode.tesseract.android.TessBaseAPI; /** * Class to send bitmap data for OCR. * * The code for this class was adapted from the ZXing project: http://code.google.com/p/zxing/ */ final class DecodeHandler extends Handler { private final CaptureActivity activity; private boolean running = true; private final TessBaseAPI baseApi; private BeepManager beepManager; private Bitmap bitmap; private static boolean isDecodePending; private long timeRequired; DecodeHandler(CaptureActivity activity) { this.activity = activity; baseApi = activity.getBaseApi(); beepManager = new BeepManager(activity); beepManager.updatePrefs(); } @Override public void handleMessage(Message message) { if (!running) { return; } switch (message.what) { case R.id.ocr_continuous_decode: // Only request a decode if a request is not already pending. if (!isDecodePending) { isDecodePending = true; ocrContinuousDecode((byte[]) message.obj, message.arg1, message.arg2); } break; case R.id.ocr_decode: ocrDecode((byte[]) message.obj, message.arg1, message.arg2); break; case R.id.quit: running = false; Looper.myLooper().quit(); break; } } static void resetDecodeState() { isDecodePending = false; } /** * Launch an AsyncTask to perform an OCR decode for single-shot mode. * * @param data Image data * @param width Image width * @param height Image height */ private void ocrDecode(byte[] data, int width, int height) { beepManager.playBeepSoundAndVibrate(); activity.displayProgressDialog(); // Launch OCR asynchronously, so we get the dialog box displayed immediately new OcrRecognizeAsyncTask(activity, baseApi, data, width, height).execute(); } /** * Perform an OCR decode for realtime recognition mode. * * @param data Image data * @param width Image width * @param height Image height */ private void ocrContinuousDecode(byte[] data, int width, int height) { PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height); if (source == null) { sendContinuousOcrFailMessage(); return; } bitmap = source.renderCroppedGreyscaleBitmap(); OcrResult ocrResult = getOcrResult(); Handler handler = activity.getHandler(); if (handler == null) { return; } if (ocrResult == null) { try { sendContinuousOcrFailMessage(); } catch (NullPointerException e) { activity.stopHandler(); } finally { bitmap.recycle(); baseApi.clear(); } return; } try { Message message = Message.obtain(handler, R.id.ocr_continuous_decode_succeeded, ocrResult); message.sendToTarget(); } catch (NullPointerException e) { activity.stopHandler(); } finally { baseApi.clear(); } } @SuppressWarnings("unused") private OcrResult getOcrResult() { OcrResult ocrResult; String textResult; long start = System.currentTimeMillis(); try { baseApi.setImage(ReadFile.readBitmap(bitmap)); textResult = baseApi.getUTF8Text(); timeRequired = System.currentTimeMillis() - start; // Check for failure to recognize text if (textResult == null || textResult.equals("")) { return null; } ocrResult = new OcrResult(); ocrResult.setWordConfidences(baseApi.wordConfidences()); ocrResult.setMeanConfidence( baseApi.meanConfidence()); if (ViewfinderView.DRAW_REGION_BOXES) { ocrResult.setRegionBoundingBoxes(baseApi.getRegions().getBoxRects()); } if (ViewfinderView.DRAW_TEXTLINE_BOXES) { ocrResult.setTextlineBoundingBoxes(baseApi.getTextlines().getBoxRects()); } if (ViewfinderView.DRAW_STRIP_BOXES) { ocrResult.setStripBoundingBoxes(baseApi.getStrips().getBoxRects()); } // Always get the word bounding boxes--we want it for annotating the bitmap after the user // presses the shutter button, in addition to maybe wanting to draw boxes/words during the // continuous mode recognition. ocrResult.setWordBoundingBoxes(baseApi.getWords().getBoxRects()); if (ViewfinderView.DRAW_CHARACTER_BOXES || ViewfinderView.DRAW_CHARACTER_TEXT) { ocrResult.setCharacterBoundingBoxes(baseApi.getCharacters().getBoxRects()); } } catch (RuntimeException e) { Log.e("OcrRecognizeAsyncTask", "Caught RuntimeException in request to Tesseract. Setting state to CONTINUOUS_STOPPED."); e.printStackTrace(); try { baseApi.clear(); activity.stopHandler(); } catch (NullPointerException e1) { // Continue } return null; } timeRequired = System.currentTimeMillis() - start; ocrResult.setBitmap(bitmap); ocrResult.setText(textResult); ocrResult.setRecognitionTimeRequired(timeRequired); return ocrResult; } private void sendContinuousOcrFailMessage() { Handler handler = activity.getHandler(); if (handler != null) { Message message = Message.obtain(handler, R.id.ocr_continuous_decode_failed, new OcrResultFailure(timeRequired)); message.sendToTarget(); } } }