Android开源之行之走进zxing,轻松实现二维码扫描(二)

对于Zxing开源项目的简化上文已给出,源码经过测试且不断修改。众所周知,Zxing项目的扫描是横向的,这么引用的用户体验确实不好;然而盲目的修改会出现拉伸以及样本采集的偏离。所以这里说一下如何将横屏修改为竖屏扫描

解决办法引用原文:http://blog.csdn.net/aaawqqq/article/details/24804939

一、Zxing扫描框架竖屏切换

1、menifest.xml中,Activitiy必须要设为竖屏的,添加属性

  android:screenOrientation="portrait"

2、camera扫描过程中,有两个视图:当前扫描view(取景框)和预览preview。为了修正预览的90度的偏离,我们需要修正PreView。因此我们要修改CameraManager中的                        getFramingRectInPreview()的preView的边框

1 rect.left = rect.left * cameraResolution.y / screenResolution.x;
2             rect.right = rect.right * cameraResolution.y / screenResolution.x;
3             rect.top = rect.top * cameraResolution.x / screenResolution.y;
4             rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;

3、在CameraConfigurationManager中setDesiredCameraParameters()设置我们需要设置的Camera参数,设置preView大小,因此我们我们需要在这里添加                    setDisplayOrientation()来设置camera旋转90度旋转;调用位置:setDesiredCameraParameters()中camera.setParameters(parameters)之前

 1 void setDisplayOrientation(Camera camera, int angle) {
 2
 3         Method method;
 4         try {
 5             method = camera.getClass().getMethod("setDisplayOrientation",
 6                     new Class[] { int.class });
 7             if (method != null)
 8                 method.invoke(camera, new Object[] { angle });
 9         } catch (Exception e1) {
10             e1.printStackTrace();
11         }
12     }

4、在DecodeHandler中,decode(byte[] data, int width, int height)在PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height)之前添加以下代码,防止转化的bitmap与取景框得到的扫描图不一致

1 byte[] rotatedData = new byte[data.length];
2          for (int y = 0; y < height; y++) {
3          for (int x = 0; x < width; x++)
4          rotatedData[x * height + height - y - 1] = data[x + y * width];
5          }
6          int tmp = width; // Here we are swapping, that‘s the difference to #11
7          width = height;
8          height = tmp;
9          data = rotatedData;  

5、在CameraConfigurationManager中,initFromCameraParameters(Camera camera)替换为如下代码

 1 void initFromCameraParameters(Camera camera) {
 2         Camera.Parameters parameters = camera.getParameters();
 3         WindowManager manager = (WindowManager) context
 4                 .getSystemService(Context.WINDOW_SERVICE);
 5         Display display = manager.getDefaultDisplay();
 6         Point theScreenResolution = new Point(display.getWidth(),
 7                 display.getHeight());
 8         screenResolution = theScreenResolution;
 9         Log.i(TAG, "Screen resolution: " + screenResolution);
10
11         /************** 竖屏更改4 ******************/
12         Point screenResolutionForCamera = new Point();
13         screenResolutionForCamera.x = screenResolution.x;
14         screenResolutionForCamera.y = screenResolution.y;
15
16         // preview size is always something like 480*320, other 320*480
17         if (screenResolution.x < screenResolution.y) {
18             screenResolutionForCamera.x = screenResolution.y;
19             screenResolutionForCamera.y = screenResolution.x;
20         }
21
22         cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(
23                 parameters, screenResolutionForCamera);
24         Log.i(TAG, "Camera resolution: " + cameraResolution);
25
26     }

非常感谢NDK-baozi的解决方法!

二、解决自定义取景框的问题

Zxing中,在取景框中央的红色扫描线或许跟我们需要的循环移动扫描还有些出入,这就需要我们来自定义属于自己的取景框。实现自定义取景框,我们需要改写ViewfinderView来绘制自  己的View。

首先需要确定一点,在Zxing源代码中,有两个Rect:一个是frame,通过getFramingRect()取得,这是我们要的取景框的Rect;而另一个previewFrame则是预览视图。我们要做的是以frame为参照物进行我们自己的绘制。

1、绘制描述的文字,也即取景框上方的提示消息

 1 private void drawStatusText(Canvas canvas, Rect frame, int width) {
 2
 3         String statusText1 = getResources().getString(
 4                 R.string.viewfinderview_status_text1);
 5         String statusText2 = getResources().getString(
 6                 R.string.viewfinderview_status_text2);
 7         int statusTextSize = 45;
 8         int statusPaddingTop = 180;
 9
10         paint.setColor(statusColor);
11         paint.setTextSize(statusTextSize);
12
13         int textWidth1 = (int) paint.measureText(statusText1);
14         canvas.drawText(statusText1, (width - textWidth1) / 2, frame.top
15                 - statusPaddingTop, paint);
16
17         int textWidth2 = (int) paint.measureText(statusText2);
18         canvas.drawText(statusText2, (width - textWidth2) / 2, frame.top
19                 - statusPaddingTop + 60, paint);
20     }

2、绘制取景框边角,也即四个角的蓝色拐角

 1 private void drawFrameBounds(Canvas canvas, Rect frame) {
 2
 3         paint.setColor(Color.WHITE);
 4         paint.setStrokeWidth(2);
 5         paint.setStyle(Paint.Style.STROKE);
 6
 7         canvas.drawRect(frame, paint);
 8
 9         paint.setColor(Color.BLUE);
10         paint.setStyle(Paint.Style.FILL);
11
12         int corWidth = 15;
13         int corLength = 45;
14
15         // 左上角
16         canvas.drawRect(frame.left - corWidth, frame.top, frame.left, frame.top
17                 + corLength, paint);
18         canvas.drawRect(frame.left - corWidth, frame.top - corWidth, frame.left
19                 + corLength, frame.top, paint);
20         // 右上角
21         canvas.drawRect(frame.right, frame.top, frame.right + corWidth,
22                 frame.top + corLength, paint);
23         canvas.drawRect(frame.right - corLength, frame.top - corWidth,
24                 frame.right + corWidth, frame.top, paint);
25         // 左下角
26         canvas.drawRect(frame.left - corWidth, frame.bottom - corLength,
27                 frame.left, frame.bottom, paint);
28         canvas.drawRect(frame.left - corWidth, frame.bottom, frame.left
29                 + corLength, frame.bottom + corWidth, paint);
30         // 右下角
31         canvas.drawRect(frame.right, frame.bottom - corLength, frame.right
32                 + corWidth, frame.bottom, paint);
33         canvas.drawRect(frame.right - corLength, frame.bottom, frame.right
34                 + corWidth, frame.bottom + corWidth, paint);
35     }

3、绘制循环移动的扫描线

 1 private void drawScanLight(Canvas canvas, Rect frame) {
 2
 3         if (scanLineTop == 0) {
 4             scanLineTop = frame.top;
 5         }
 6
 7         if (scanLineTop >= frame.bottom) {
 8             scanLineTop = frame.top;
 9         } else {
10             scanLineTop += SCAN_VELOCITY;
11         }
12         Rect scanRect = new Rect(frame.left, scanLineTop, frame.right,
13                 scanLineTop + 30);
14         canvas.drawBitmap(scanLight, null, scanRect, paint);
15     }

通过以上的三步绘制,我们就可以实现展示图的效果。整体的ViewfinderView代码:   

  1 /**
  2  * This view is overlaid on top of the camera preview. It adds the viewfinder
  3  * rectangle and partial transparency outside it, as well as the laser scanner
  4  * animation and result points. 这是一个位于相机顶部的预览view,它增加了一个外部部分透明的取景框,以及激光扫描动画和结果组件
  5  *
  6  * @author [email protected] (Daniel Switkin)
  7  */
  8 public final class ViewfinderView extends View {
  9
 10     private static final int[] SCANNER_ALPHA = { 0, 64, 128, 192, 255, 192,
 11             128, 64 };
 12     private static final long ANIMATION_DELAY = 80L;
 13     private static final int CURRENT_POINT_OPACITY = 0xA0;
 14     private static final int MAX_RESULT_POINTS = 20;
 15     private static final int POINT_SIZE = 6;
 16
 17     private CameraManager cameraManager;
 18     private final Paint paint;
 19     private Bitmap resultBitmap;
 20     private final int maskColor; // 取景框外的背景颜色
 21     private final int resultColor;// result Bitmap的颜色
 22     private final int laserColor; // 红色扫描线的颜色
 23     private final int resultPointColor; // 特征点的颜色
 24     private final int statusColor; // 提示文字颜色
 25     private int scannerAlpha;
 26     private List<ResultPoint> possibleResultPoints;
 27     private List<ResultPoint> lastPossibleResultPoints;
 28     // 扫描线移动的y
 29     private int scanLineTop;
 30     // 扫描线移动速度
 31     private final int SCAN_VELOCITY = 5;
 32     // 扫描线
 33     Bitmap scanLight;
 34
 35     public ViewfinderView(Context context, AttributeSet attrs) {
 36         super(context, attrs);
 37
 38         // Initialize these once for performance rather than calling them every
 39         // time in onDraw().
 40         paint = new Paint(Paint.ANTI_ALIAS_FLAG);
 41         Resources resources = getResources();
 42         maskColor = resources.getColor(R.color.viewfinder_mask);
 43         resultColor = resources.getColor(R.color.result_view);
 44         laserColor = resources.getColor(R.color.viewfinder_laser);
 45         resultPointColor = resources.getColor(R.color.possible_result_points);
 46         statusColor = resources.getColor(R.color.status_text);
 47         scannerAlpha = 0;
 48         possibleResultPoints = new ArrayList<ResultPoint>(5);
 49         lastPossibleResultPoints = null;
 50         scanLight = BitmapFactory.decodeResource(resources,
 51                 R.drawable.scan_light);
 52     }
 53
 54     public void setCameraManager(CameraManager cameraManager) {
 55         this.cameraManager = cameraManager;
 56     }
 57
 58     @SuppressLint("DrawAllocation")
 59     @Override
 60     public void onDraw(Canvas canvas) {
 61         if (cameraManager == null) {
 62             return; // not ready yet, early draw before done configuring
 63         }
 64
 65         // frame为取景框
 66         Rect frame = cameraManager.getFramingRect();
 67         Rect previewFrame = cameraManager.getFramingRectInPreview();
 68         if (frame == null || previewFrame == null) {
 69             return;
 70         }
 71         int width = canvas.getWidth();
 72         int height = canvas.getHeight();
 73
 74         // Draw the exterior (i.e. outside the framing rect) darkened
 75         // 绘制取景框外的暗灰色的表面,分四个矩形绘制
 76         paint.setColor(resultBitmap != null ? resultColor : maskColor);
 77         canvas.drawRect(0, 0, width, frame.top, paint);// Rect_1
 78         canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); // Rect_2
 79         canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1,
 80                 paint); // Rect_3
 81         canvas.drawRect(0, frame.bottom + 1, width, height, paint); // Rect_4
 82
 83         if (resultBitmap != null) {
 84             // Draw the opaque result bitmap over the scanning rectangle
 85             // 如果有二维码结果的Bitmap,在扫取景框内绘制不透明的result Bitmap
 86             paint.setAlpha(CURRENT_POINT_OPACITY);
 87             canvas.drawBitmap(resultBitmap, null, frame, paint);
 88         } else {
 89             // Draw a red "laser scanner" line through the middle to show
 90             // decoding is active
 91             drawFrameBounds(canvas, frame);
 92             drawStatusText(canvas, frame, width);
 93
 94             // 绘制扫描线
 95             // paint.setColor(laserColor);
 96             // paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
 97             // scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
 98             // int middle = frame.height() / 2 + frame.top;
 99             // canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1,
100             // middle + 2, paint);
101
102             drawScanLight(canvas, frame);
103
104             float scaleX = frame.width() / (float) previewFrame.width();
105             float scaleY = frame.height() / (float) previewFrame.height();
106
107             // 绘制扫描线周围的特征点
108             List<ResultPoint> currentPossible = possibleResultPoints;
109             List<ResultPoint> currentLast = lastPossibleResultPoints;
110             int frameLeft = frame.left;
111             int frameTop = frame.top;
112             if (currentPossible.isEmpty()) {
113                 lastPossibleResultPoints = null;
114             } else {
115                 possibleResultPoints = new ArrayList<ResultPoint>(5);
116                 lastPossibleResultPoints = currentPossible;
117                 paint.setAlpha(CURRENT_POINT_OPACITY);
118                 paint.setColor(resultPointColor);
119                 synchronized (currentPossible) {
120                     for (ResultPoint point : currentPossible) {
121                         canvas.drawCircle(frameLeft
122                                 + (int) (point.getX() * scaleX), frameTop
123                                 + (int) (point.getY() * scaleY), POINT_SIZE,
124                                 paint);
125                     }
126                 }
127             }
128             if (currentLast != null) {
129                 paint.setAlpha(CURRENT_POINT_OPACITY / 2);
130                 paint.setColor(resultPointColor);
131                 synchronized (currentLast) {
132                     float radius = POINT_SIZE / 2.0f;
133                     for (ResultPoint point : currentLast) {
134                         canvas.drawCircle(frameLeft
135                                 + (int) (point.getX() * scaleX), frameTop
136                                 + (int) (point.getY() * scaleY), radius, paint);
137                     }
138                 }
139             }
140
141             // Request another update at the animation interval, but only
142             // repaint the laser line,
143             // not the entire viewfinder mask.
144             postInvalidateDelayed(ANIMATION_DELAY, frame.left - POINT_SIZE,
145                     frame.top - POINT_SIZE, frame.right + POINT_SIZE,
146                     frame.bottom + POINT_SIZE);
147         }
148     }
149
150     /**
151      * 绘制取景框边框
152      *
153      * @param canvas
154      * @param frame
155      */
156     private void drawFrameBounds(Canvas canvas, Rect frame) {
157
158         paint.setColor(Color.WHITE);
159         paint.setStrokeWidth(2);
160         paint.setStyle(Paint.Style.STROKE);
161
162         canvas.drawRect(frame, paint);
163
164         paint.setColor(Color.BLUE);
165         paint.setStyle(Paint.Style.FILL);
166
167         int corWidth = 15;
168         int corLength = 45;
169
170         // 左上角
171         canvas.drawRect(frame.left - corWidth, frame.top, frame.left, frame.top
172                 + corLength, paint);
173         canvas.drawRect(frame.left - corWidth, frame.top - corWidth, frame.left
174                 + corLength, frame.top, paint);
175         // 右上角
176         canvas.drawRect(frame.right, frame.top, frame.right + corWidth,
177                 frame.top + corLength, paint);
178         canvas.drawRect(frame.right - corLength, frame.top - corWidth,
179                 frame.right + corWidth, frame.top, paint);
180         // 左下角
181         canvas.drawRect(frame.left - corWidth, frame.bottom - corLength,
182                 frame.left, frame.bottom, paint);
183         canvas.drawRect(frame.left - corWidth, frame.bottom, frame.left
184                 + corLength, frame.bottom + corWidth, paint);
185         // 右下角
186         canvas.drawRect(frame.right, frame.bottom - corLength, frame.right
187                 + corWidth, frame.bottom, paint);
188         canvas.drawRect(frame.right - corLength, frame.bottom, frame.right
189                 + corWidth, frame.bottom + corWidth, paint);
190     }
191
192     /**
193      * 绘制提示文字
194      *
195      * @param canvas
196      * @param frame
197      * @param width
198      */
199     private void drawStatusText(Canvas canvas, Rect frame, int width) {
200
201         String statusText1 = getResources().getString(
202                 R.string.viewfinderview_status_text1);
203         String statusText2 = getResources().getString(
204                 R.string.viewfinderview_status_text2);
205         int statusTextSize = 45;
206         int statusPaddingTop = 180;
207
208         paint.setColor(statusColor);
209         paint.setTextSize(statusTextSize);
210
211         int textWidth1 = (int) paint.measureText(statusText1);
212         canvas.drawText(statusText1, (width - textWidth1) / 2, frame.top
213                 - statusPaddingTop, paint);
214
215         int textWidth2 = (int) paint.measureText(statusText2);
216         canvas.drawText(statusText2, (width - textWidth2) / 2, frame.top
217                 - statusPaddingTop + 60, paint);
218     }
219
220     /**
221      * 绘制移动扫描线
222      *
223      * @param canvas
224      * @param frame
225      */
226     private void drawScanLight(Canvas canvas, Rect frame) {
227
228         if (scanLineTop == 0) {
229             scanLineTop = frame.top;
230         }
231
232         if (scanLineTop >= frame.bottom) {
233             scanLineTop = frame.top;
234         } else {
235             scanLineTop += SCAN_VELOCITY;
236         }
237         Rect scanRect = new Rect(frame.left, scanLineTop, frame.right,
238                 scanLineTop + 30);
239         canvas.drawBitmap(scanLight, null, scanRect, paint);
240     }
241
242     public void drawViewfinder() {
243         Bitmap resultBitmap = this.resultBitmap;
244         this.resultBitmap = null;
245         if (resultBitmap != null) {
246             resultBitmap.recycle();
247         }
248         invalidate();
249     }
250
251     /**
252      * Draw a bitmap with the result points highlighted instead of the live
253      * scanning display.
254      *
255      * @param barcode
256      *            An image of the decoded barcode.
257      */
258     public void drawResultBitmap(Bitmap barcode) {
259         resultBitmap = barcode;
260         invalidate();
261     }
262
263     public void addPossibleResultPoint(ResultPoint point) {
264         List<ResultPoint> points = possibleResultPoints;
265         synchronized (points) {
266             points.add(point);
267             int size = points.size();
268             if (size > MAX_RESULT_POINTS) {
269                 // trim it
270                 points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
271             }
272         }
273     }
274
275 }

时间: 2024-08-29 11:35:58

Android开源之行之走进zxing,轻松实现二维码扫描(二)的相关文章

Android开源之行之走进zxing,轻松实现二维码扫描(一)

现在很多App都集成了扫一扫功能,最常用的微信.QQ.手机助手等.二维码也使得生活变得更加简洁,扫一扫订餐.扫一扫下载等等.那么,说到二维码,我们不得不提Google一个开源的扫码框架:zxing. 开源下载:http://code.google.com/p/zxing/ zxing是基于多种1D/2D条码处理的开源库,是一个完整的项目.它可以通过手机摄像头实现条码的扫描以及解码,功能及其强大.那么如果要实现二维码的扫描以及解码,我们需要在该开源项目的基础上进行简化,并修改.让我们来看一下  

Android自由行之走进zxing,轻松实现二维码扫描

现在很多App都集成了扫一扫功能,最常用的微信.QQ.手机助手等.二维码也使得生活变得更加简洁,扫一扫订餐.扫一扫下载等等.那么,说到二维码,我们不得不提Google一个开源的扫码框架:zxing. 开源下载:http://code.google.com/p/zxing/ zxing是基于多种1D/2D条码处理的开源库,是一个完整的项目.它可以通过手机摄像头实现条码的扫描以及解码,功能及其强大.那么如果要实现二维码的扫描以及解码,我们需要在该开源项目的基础上进行简化,并修改.让我们来看一下  

【转】Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果--不错

原文网址:http://blog.csdn.net/xiaanming/article/details/10163203 转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10163203 了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现

二维码扫描开源库ZXing定制化

(抱歉文章还在修改但是不小心发布了= =) 最近在用ZXing这个开源库做二维码的扫描模块,开发过程的一些代码修改和裁剪的经验和大家分享一下. 我的代码库: https://github.com/SickWorm/ZXingDialog 代码没有在github维护,所以没有log.但是所有修改的地方我都加上了“@ch”的注释,以方便定位 官方源码: https://github.com/zxing/zxing 实现功能: 1.功能裁剪(只保留QRCode二维码扫描功能,去掉条形码等其他码扫描功能

Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果

了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能.自己感觉挺新颖的,从一张图片中扫一下居然能直接加好友,不可思议啊,那时候还不了解二维码.呵呵,然后做项目的时候.老板说要加上二维码扫描功能.然后自己的屁颠屁颠的去百度,google啥的.发现非常多朋友都有介绍二维码扫描的功能,然后我就跟着人家的介绍自己搞起了二维码扫描功能,跟着人家的帖子,非常快我的项目就增加了扫描二维码的功能,然后自己还非常开心. 随着微信的到来,二维码越来越火爆,随处能看到二维码,比方商城里面,肯德基,餐厅等等.对于

Android—ZXing二维码扫描遇到的问题

最近工作中需要开发带有二维码扫描功能的软件(基于开源项目ZXing),遇到的问题记录一下,也希望给大家带来帮助. 1.首先因为扫描要开摄像机所以加权限是一定的,不然后面什么都不能进行 <uses-permission android:name="android.permission.CAMERA" /> 2.设置扫描框的大小: 在com.zxing.camera包中查找 private static final int MIN_FRAME_WIDTH = 240;  pri

条码扫描二维码扫描—ZXing android 改进版本

看了Vurtexゞ. 文章<[Android实例] 条码扫描二维码扫描——ZXing android 源码简化 (附:支持中文) >的基础上对代码进行了修改 1.增加了将代码嵌套入自己工程后传值的办法(初学,如果有更好的方法也希望告诉我,先谢谢了) 2.扫码界面进行了处理(初步实现了现有某些软件的样子,至于长的像谁就不说了) //画四个角的代码<br>paint.setColor(frameColor); canvas.drawRect(15 + frame.left, 15 +

Zxing图片拉伸解决 Android 二维码扫描

二维码扫描  Android Zxing图片拉伸解决 Zxing是google提供的二维码扫描工程 默认是横屏的  转换成竖屏后图片出现拉伸 这里提供解决办法: Zxing  修改 CameraConfigurationManager.java文件的 void initFromCameraParameters(Camera camera)方法 在 Log.d(TAG, "Screen resolution: " + screenResolution);这句之后增加 Point scre

android 二维码扫描

了解二维码这个东西还是从微信 中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候, 老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现很多朋友都有介绍二维码扫描的功能,然后我就跟着人家的介绍自己搞起了 二维码扫描功能,跟着人家的帖子,很快我的项目就加入了扫描二维码的功能,然后自己还很开心. 随着微信的到来,二维码越来越火爆,随处能看到二维码,比如商城里面,肯德基,餐厅等等,对于