Skip to content

Commit 70f4bbb

Browse files
authored
Merge pull request #493 from journeyapps/preview-sizing
Fix preview sizing & fix ResultPoints for front camera
2 parents 1a1c8d0 + 62547c1 commit 70f4bbb

File tree

8 files changed

+266
-144
lines changed

8 files changed

+266
-144
lines changed

zxing-android-embedded/src/com/journeyapps/barcodescanner/BarcodeResult.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
import com.google.zxing.ResultMetadataType;
1111
import com.google.zxing.ResultPoint;
1212

13+
import java.util.ArrayList;
14+
import java.util.Arrays;
15+
import java.util.Collections;
16+
import java.util.List;
1317
import java.util.Map;
1418

1519
/**
@@ -54,7 +58,14 @@ public Result getResult() {
5458
* @see #getBitmapWithResultPoints(int)
5559
*/
5660
public Bitmap getBitmap() {
57-
return sourceData.getBitmap(mScaleFactor);
61+
return sourceData.getBitmap(null, mScaleFactor);
62+
}
63+
64+
public List<ResultPoint> getTransformedResultPoints() {
65+
if (this.mResult.getResultPoints() == null) {
66+
return Collections.emptyList();
67+
}
68+
return transformResultPoints(Arrays.asList(this.mResult.getResultPoints()), this.sourceData);
5869
}
5970

6071
/**
@@ -64,23 +75,23 @@ public Bitmap getBitmap() {
6475
public Bitmap getBitmapWithResultPoints(int color) {
6576
Bitmap bitmap = getBitmap();
6677
Bitmap barcode = bitmap;
67-
ResultPoint[] points = mResult.getResultPoints();
78+
List<ResultPoint> points = getTransformedResultPoints();
6879

69-
if (points != null && points.length > 0 && bitmap != null) {
80+
if (!points.isEmpty() && bitmap != null) {
7081
barcode = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
7182
Canvas canvas = new Canvas(barcode);
7283
canvas.drawBitmap(bitmap, 0, 0, null);
7384
Paint paint = new Paint();
7485
paint.setColor(color);
75-
if (points.length == 2) {
86+
if (points.size() == 2) {
7687
paint.setStrokeWidth(PREVIEW_LINE_WIDTH);
77-
drawLine(canvas, paint, points[0], points[1], mScaleFactor);
78-
} else if (points.length == 4 &&
88+
drawLine(canvas, paint, points.get(0), points.get(1), mScaleFactor);
89+
} else if (points.size() == 4 &&
7990
(mResult.getBarcodeFormat() == BarcodeFormat.UPC_A ||
8091
mResult.getBarcodeFormat() == BarcodeFormat.EAN_13)) {
8192
// Hacky special case -- draw two lines, for the barcode and metadata
82-
drawLine(canvas, paint, points[0], points[1], mScaleFactor);
83-
drawLine(canvas, paint, points[2], points[3], mScaleFactor);
93+
drawLine(canvas, paint, points.get(0), points.get(1), mScaleFactor);
94+
drawLine(canvas, paint, points.get(2), points.get(3), mScaleFactor);
8495
} else {
8596
paint.setStrokeWidth(PREVIEW_DOT_WIDTH);
8697
for (ResultPoint point : points) {
@@ -153,4 +164,13 @@ public long getTimestamp() {
153164
public String toString() {
154165
return mResult.getText();
155166
}
167+
168+
169+
public static List<ResultPoint> transformResultPoints(List<ResultPoint> resultPoints, SourceData sourceData) {
170+
List<ResultPoint> scaledPoints = new ArrayList<>(resultPoints.size());
171+
for (ResultPoint point : resultPoints) {
172+
scaledPoints.add(sourceData.translateResultPoint(point));
173+
}
174+
return scaledPoints;
175+
}
156176
}

zxing-android-embedded/src/com/journeyapps/barcodescanner/CameraPreview.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ public void surfaceChanged(SurfaceHolder holder, int format, int width, int heig
197197
@Override
198198
public boolean handleMessage(Message message) {
199199
if (message.what == R.id.zxing_prewiew_size_ready) {
200+
// At this point, we have the camera preview size, and should have containerSize and
201+
// surfaceRect.
200202
previewSized((Size) message.obj);
201203
return true;
202204
} else if (message.what == R.id.zxing_camera_error) {
@@ -375,7 +377,13 @@ private void calculateFrames() {
375377
int width = containerSize.width;
376378
int height = containerSize.height;
377379

378-
surfaceRect = displayConfiguration.scalePreview(previewSize);
380+
Rect scaledPreview = displayConfiguration.scalePreview(previewSize);
381+
if (scaledPreview.width() <= 0 || scaledPreview.height() <= 0) {
382+
// Something is not ready yet - we can't start the preview.
383+
return;
384+
}
385+
386+
surfaceRect = scaledPreview;
379387

380388
Rect container = new Rect(0, 0, width, height);
381389
framingRect = calculateFramingRect(container, surfaceRect);
@@ -387,16 +395,6 @@ private void calculateFrames() {
387395
frameInPreview.right * previewWidth / surfaceRect.width(),
388396
frameInPreview.bottom * previewHeight / surfaceRect.height());
389397

390-
if (surfaceRect.width() != 0 && surfaceRect.height() != 0) {
391-
previewFramingRect = new Rect(frameInPreview.left * previewWidth / surfaceRect.width(),
392-
frameInPreview.top * previewHeight / surfaceRect.height(),
393-
frameInPreview.right * previewWidth / surfaceRect.width(),
394-
frameInPreview.bottom * previewHeight / surfaceRect.height());
395-
396-
} else {
397-
previewFramingRect = null;
398-
}
399-
400398
if (previewFramingRect == null || previewFramingRect.width() <= 0 || previewFramingRect.height() <= 0) {
401399
previewFramingRect = null;
402400
framingRect = null;
@@ -583,6 +581,10 @@ public Rect getPreviewFramingRect() {
583581
return previewFramingRect;
584582
}
585583

584+
public Size getPreviewSize() {
585+
return previewSize;
586+
}
587+
586588
/**
587589
* @return the CameraSettings currently in use
588590
*/

zxing-android-embedded/src/com/journeyapps/barcodescanner/DecoderThread.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ private void decode(SourceData sourceData) {
164164
}
165165
}
166166
if (resultHandler != null) {
167-
List<ResultPoint> resultPoints = decoder.getPossibleResultPoints();
168-
Message message = Message.obtain(resultHandler, R.id.zxing_possible_result_points, resultPoints);
167+
List<ResultPoint> resultPoints = BarcodeResult.transformResultPoints(decoder.getPossibleResultPoints(), sourceData);
168+
Message message = Message.obtain(resultHandler, R.id.zxing_possible_result_points, resultPoints);
169169
message.sendToTarget();
170170
}
171171
requestNextPreview();

zxing-android-embedded/src/com/journeyapps/barcodescanner/DecoratedBarcodeView.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ public void initializeFromIntent(Intent intent) {
165165
barcodeView.setDecoderFactory(new DefaultDecoderFactory(decodeFormats, decodeHints, characterSet, scanType));
166166
}
167167

168+
public void setCameraSettings(CameraSettings cameraSettings) {
169+
barcodeView.setCameraSettings(cameraSettings);
170+
}
171+
172+
public void setDecoderFactory(DecoderFactory decoderFactory) {
173+
barcodeView.setDecoderFactory(decoderFactory);
174+
}
175+
176+
public DecoderFactory getDecoderFactory() {
177+
return barcodeView.getDecoderFactory();
178+
}
179+
180+
public CameraSettings getCameraSettings() {
181+
return barcodeView.getCameraSettings();
182+
}
183+
168184
public void setStatusText(String text) {
169185
// statusView is optional when using a custom layout
170186
if(statusView != null) {
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package com.journeyapps.barcodescanner;
2+
3+
import android.graphics.Rect;
4+
5+
public class RawImageData {
6+
private byte[] data;
7+
private int width;
8+
private int height;
9+
10+
public RawImageData(byte[] data, int width, int height) {
11+
this.data = data;
12+
this.width = width;
13+
this.height = height;
14+
}
15+
16+
public byte[] getData() {
17+
return data;
18+
}
19+
20+
public int getWidth() {
21+
return width;
22+
}
23+
24+
public int getHeight() {
25+
return height;
26+
}
27+
28+
public RawImageData cropAndScale(Rect cropRect, int scale) {
29+
int width = cropRect.width() / scale;
30+
int height = cropRect.height() / scale;
31+
32+
int top = cropRect.top;
33+
34+
int area = width * height;
35+
byte[] matrix = new byte[area];
36+
37+
if (scale == 1) {
38+
int inputOffset = top * this.width + cropRect.left;
39+
40+
// Copy one cropped row at a time.
41+
for (int y = 0; y < height; y++) {
42+
int outputOffset = y * width;
43+
System.arraycopy(this.data, inputOffset, matrix, outputOffset, width);
44+
inputOffset += this.width;
45+
}
46+
} else {
47+
int inputOffset = top * this.width + cropRect.left;
48+
49+
// Copy one cropped row at a time.
50+
for (int y = 0; y < height; y++) {
51+
int outputOffset = y * width;
52+
int xOffset = inputOffset;
53+
for (int x = 0; x < width; x++) {
54+
matrix[outputOffset] = this.data[xOffset];
55+
xOffset += scale;
56+
outputOffset += 1;
57+
}
58+
inputOffset += this.width * scale;
59+
}
60+
}
61+
return new RawImageData(matrix, width, height);
62+
}
63+
64+
65+
public RawImageData rotateCameraPreview(int cameraRotation) {
66+
switch (cameraRotation) {
67+
case 90:
68+
return new RawImageData(rotateCW(data, this.width, this.height), this.height, this.width);
69+
case 180:
70+
return new RawImageData(rotate180(data, this.width, this.height), this.width, this.height);
71+
case 270:
72+
return new RawImageData(rotateCCW(data, this.width, this.height), this.height, this.width);
73+
case 0:
74+
default:
75+
return this;
76+
}
77+
}
78+
79+
/**
80+
* Rotate an image by 90 degrees CW.
81+
*
82+
* @param data the image data, in with the first width * height bytes being the luminance data.
83+
* @param imageWidth the width of the image
84+
* @param imageHeight the height of the image
85+
* @return the rotated bytes
86+
*/
87+
public static byte[] rotateCW(byte[] data, int imageWidth, int imageHeight) {
88+
// Adapted from http://stackoverflow.com/a/15775173
89+
// data may contain more than just y (u and v), but we are only interested in the y section.
90+
91+
byte[] yuv = new byte[imageWidth * imageHeight];
92+
int i = 0;
93+
for (int x = 0; x < imageWidth; x++) {
94+
for (int y = imageHeight - 1; y >= 0; y--) {
95+
yuv[i] = data[y * imageWidth + x];
96+
i++;
97+
}
98+
}
99+
return yuv;
100+
}
101+
102+
/**
103+
* Rotate an image by 180 degrees.
104+
*
105+
* @param data the image data, in with the first width * height bytes being the luminance data.
106+
* @param imageWidth the width of the image
107+
* @param imageHeight the height of the image
108+
* @return the rotated bytes
109+
*/
110+
public static byte[] rotate180(byte[] data, int imageWidth, int imageHeight) {
111+
int n = imageWidth * imageHeight;
112+
byte[] yuv = new byte[n];
113+
114+
int i = n - 1;
115+
for (int j = 0; j < n; j++) {
116+
yuv[i] = data[j];
117+
i--;
118+
}
119+
return yuv;
120+
}
121+
122+
/**
123+
* Rotate an image by 90 degrees CCW.
124+
*
125+
* @param data the image data, in with the first width * height bytes being the luminance data.
126+
* @param imageWidth the width of the image
127+
* @param imageHeight the height of the image
128+
* @return the rotated bytes
129+
*/
130+
public static byte[] rotateCCW(byte[] data, int imageWidth, int imageHeight) {
131+
int n = imageWidth * imageHeight;
132+
byte[] yuv = new byte[n];
133+
int i = n - 1;
134+
for (int x = 0; x < imageWidth; x++) {
135+
for (int y = imageHeight - 1; y >= 0; y--) {
136+
yuv[i] = data[y * imageWidth + x];
137+
i--;
138+
}
139+
}
140+
return yuv;
141+
}
142+
}

0 commit comments

Comments
 (0)