diff --git a/android/src/com/google/zxing/client/android/CaptureActivity.java b/android/src/com/google/zxing/client/android/CaptureActivity.java index 1bae65590..2fc54f953 100755 --- a/android/src/com/google/zxing/client/android/CaptureActivity.java +++ b/android/src/com/google/zxing/client/android/CaptureActivity.java @@ -399,9 +399,10 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal * A valid barcode has been found, so give an indication of success and show the results. * * @param rawResult The contents of the barcode. + * @param scaleFactor amount by which thumbnail was scaled * @param barcode A greyscale bitmap of the camera data which was decoded. */ - public void handleDecode(Result rawResult, Bitmap barcode) { + public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) { inactivityTimer.onActivity(); lastResult = rawResult; ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult); @@ -411,7 +412,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal historyManager.addHistoryItem(rawResult, resultHandler); // Then not from history, so beep/vibrate and we have an image to draw on beepManager.playBeepSoundAndVibrate(); - drawResultPoints(barcode, rawResult); + drawResultPoints(barcode, scaleFactor, rawResult); } switch (source) { @@ -445,9 +446,10 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal * Superimpose a line for 1D or dots for 2D to highlight the key features of the barcode. * * @param barcode A bitmap of the captured image. + * @param scaleFactor amount by which thumbnail was scaled * @param rawResult The decoded results which contains the points to draw. */ - private void drawResultPoints(Bitmap barcode, Result rawResult) { + private void drawResultPoints(Bitmap barcode, float scaleFactor, Result rawResult) { ResultPoint[] points = rawResult.getResultPoints(); if (points != null && points.length > 0) { Canvas canvas = new Canvas(barcode); @@ -455,24 +457,28 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal paint.setColor(getResources().getColor(R.color.result_points)); if (points.length == 2) { paint.setStrokeWidth(4.0f); - drawLine(canvas, paint, points[0], points[1]); + drawLine(canvas, paint, points[0], points[1], scaleFactor); } else if (points.length == 4 && (rawResult.getBarcodeFormat() == BarcodeFormat.UPC_A || rawResult.getBarcodeFormat() == BarcodeFormat.EAN_13)) { // Hacky special case -- draw two lines, for the barcode and metadata - drawLine(canvas, paint, points[0], points[1]); - drawLine(canvas, paint, points[2], points[3]); + drawLine(canvas, paint, points[0], points[1], scaleFactor); + drawLine(canvas, paint, points[2], points[3], scaleFactor); } else { paint.setStrokeWidth(10.0f); for (ResultPoint point : points) { - canvas.drawPoint(point.getX(), point.getY(), paint); + canvas.drawPoint(scaleFactor * point.getX(), scaleFactor * point.getY(), paint); } } } } - private static void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b) { - canvas.drawLine(a.getX(), a.getY(), b.getX(), b.getY(), paint); + private static void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b, float scaleFactor) { + canvas.drawLine(scaleFactor * a.getX(), + scaleFactor * a.getY(), + scaleFactor * b.getX(), + scaleFactor * b.getY(), + paint); } // Put up our own UI for how to handle the decoded contents. diff --git a/android/src/com/google/zxing/client/android/CaptureActivityHandler.java b/android/src/com/google/zxing/client/android/CaptureActivityHandler.java index 3e1e2e8ab..d76fe04f8 100755 --- a/android/src/com/google/zxing/client/android/CaptureActivityHandler.java +++ b/android/src/com/google/zxing/client/android/CaptureActivityHandler.java @@ -19,6 +19,7 @@ package com.google.zxing.client.android; import android.content.ActivityNotFoundException; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.graphics.BitmapFactory; import android.provider.Browser; import com.google.zxing.BarcodeFormat; import com.google.zxing.Result; @@ -82,9 +83,18 @@ public final class CaptureActivityHandler extends Handler { Log.d(TAG, "Got decode succeeded message"); state = State.SUCCESS; Bundle bundle = message.getData(); - Bitmap barcode = bundle == null ? null : - (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP); - activity.handleDecode((Result) message.obj, barcode); + Bitmap barcode = null; + float scaleFactor = 1.0f; + if (bundle != null) { + byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP); + if (compressedBitmap != null) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inMutable = true; + barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, options); + } + scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR); + } + activity.handleDecode((Result) message.obj, barcode, scaleFactor); break; case R.id.decode_failed: // We're decoding as fast as possible, so when one decode fails, start another. diff --git a/android/src/com/google/zxing/client/android/DecodeHandler.java b/android/src/com/google/zxing/client/android/DecodeHandler.java index 82a15c9ae..fa996799b 100644 --- a/android/src/com/google/zxing/client/android/DecodeHandler.java +++ b/android/src/com/google/zxing/client/android/DecodeHandler.java @@ -19,7 +19,6 @@ package com.google.zxing.client.android; import android.graphics.Bitmap; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; -import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.PlanarYUVLuminanceSource; import com.google.zxing.ReaderException; @@ -32,6 +31,7 @@ import android.os.Looper; import android.os.Message; import android.util.Log; +import java.io.ByteArrayOutputStream; import java.util.Map; final class DecodeHandler extends Handler { @@ -95,8 +95,7 @@ final class DecodeHandler extends Handler { if (handler != null) { Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult); Bundle bundle = new Bundle(); - Bitmap grayscaleBitmap = toBitmap(source, source.renderCroppedGreyscaleBitmap()); - bundle.putParcelable(DecodeThread.BARCODE_BITMAP, grayscaleBitmap); + bundleThumbnail(source, bundle); message.setData(bundle); message.sendToTarget(); } @@ -108,12 +107,15 @@ final class DecodeHandler extends Handler { } } - private static Bitmap toBitmap(LuminanceSource source, int[] pixels) { - int width = source.getWidth(); - int height = source.getHeight(); - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - bitmap.setPixels(pixels, 0, width, 0, 0, width, height); - return bitmap; + private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) { + int[] pixels = source.renderThumbnail(); + int width = source.getThumbnailWidth(); + int height = source.getThumbnailHeight(); + Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out); + bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray()); + bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth()); } } diff --git a/android/src/com/google/zxing/client/android/DecodeThread.java b/android/src/com/google/zxing/client/android/DecodeThread.java index 83ea75d19..baf60a01e 100755 --- a/android/src/com/google/zxing/client/android/DecodeThread.java +++ b/android/src/com/google/zxing/client/android/DecodeThread.java @@ -39,6 +39,7 @@ import java.util.concurrent.CountDownLatch; final class DecodeThread extends Thread { public static final String BARCODE_BITMAP = "barcode_bitmap"; + public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor"; private final CaptureActivity activity; private final Map hints; diff --git a/core/src/com/google/zxing/PlanarYUVLuminanceSource.java b/core/src/com/google/zxing/PlanarYUVLuminanceSource.java index 6b2ce5808..2049e5930 100644 --- a/core/src/com/google/zxing/PlanarYUVLuminanceSource.java +++ b/core/src/com/google/zxing/PlanarYUVLuminanceSource.java @@ -28,6 +28,8 @@ package com.google.zxing; */ public final class PlanarYUVLuminanceSource extends LuminanceSource { + private static final int THUMBNAIL_SCALE_FACTOR = 2; + private final byte[] yuvData; private final int dataWidth; private final int dataHeight; @@ -120,9 +122,9 @@ public final class PlanarYUVLuminanceSource extends LuminanceSource { false); } - public int[] renderCroppedGreyscaleBitmap() { - int width = getWidth(); - int height = getHeight(); + public int[] renderThumbnail() { + int width = getWidth() / THUMBNAIL_SCALE_FACTOR; + int height = getHeight() / THUMBNAIL_SCALE_FACTOR; int[] pixels = new int[width * height]; byte[] yuv = yuvData; int inputOffset = top * dataWidth + left; @@ -130,13 +132,27 @@ public final class PlanarYUVLuminanceSource extends LuminanceSource { for (int y = 0; y < height; y++) { int outputOffset = y * width; for (int x = 0; x < width; x++) { - int grey = yuv[inputOffset + x] & 0xff; + int grey = yuv[inputOffset + x * THUMBNAIL_SCALE_FACTOR] & 0xff; pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101); } - inputOffset += dataWidth; + inputOffset += dataWidth * THUMBNAIL_SCALE_FACTOR; } return pixels; } + + /** + * @return width of image from {@link #renderThumbnail()} + */ + public int getThumbnailWidth() { + return getWidth() / THUMBNAIL_SCALE_FACTOR; + } + + /** + * @return height of image from {@link #renderThumbnail()} + */ + public int getThumbnailHeight() { + return getHeight() / THUMBNAIL_SCALE_FACTOR; + } private void reverseHorizontal(int width, int height) { byte[] yuvData = this.yuvData;