mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
On scan we pass a grayscale image of the scanned image, which is used as a thumbnail. These days this is getting to be 2MB of data to bundle to copy around in memory. Instead scale by 50% and JPEG-encode. This saves some memory and paves the way for later perhaps saving the image data with history.
git-svn-id: https://zxing.googlecode.com/svn/trunk@2561 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
434a1bb6c5
commit
90e1822928
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DecodeHintType,Object> hints;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue