// L2 distance private static int distance(ResultPoint a, ResultPoint b) { return round( (float) Math.sqrt( (a.getX() - b.getX()) * (a.getX() - b.getX()) + (a.getY() - b.getY()) * (a.getY() - b.getY()))); }
private static BitMatrix sampleGrid( BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topRight, int dimension) throws NotFoundException { GridSampler sampler = GridSampler.getInstance(); return sampler.sampleGrid( image, dimension, 0.5f, 0.5f, dimension - 0.5f, 0.5f, dimension - 0.5f, dimension - 0.5f, 0.5f, dimension - 0.5f, topLeft.getX(), topLeft.getY(), topRight.getX(), topRight.getY(), bottomRight.getX(), bottomRight.getY(), bottomLeft.getX(), bottomLeft.getY()); }
private static BitMatrix sampleGrid( BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int dimension) throws NotFoundException { // Note that unlike the QR Code sampler, we didn't find the center of // modules, but the // very corners. So there is no 0.5f here; 0.0f is right. GridSampler sampler = GridSampler.getInstance(); return sampler.sampleGrid( matrix, dimension, dimension, 0.0f, // p1ToX 0.0f, // p1ToY dimension, // p2ToX 0.0f, // p2ToY dimension, // p3ToX dimension, // p3ToY 0.0f, // p4ToX dimension, // p4ToY topLeft.getX(), // p1FromX topLeft.getY(), // p1FromY topRight.getX(), // p2FromX topRight.getY(), // p2FromY bottomRight.getX(), // p3FromX bottomRight.getY(), // p3FromY bottomLeft.getX(), // p4FromX bottomLeft.getY()); // p4FromY }
@Override public void onDraw(Canvas canvas) { // 中间的扫描框,你要修改扫描框的大小,去CameraManager里面修改 frame = CameraManager.get().getFramingRect(); if (frame == null) { return; } if (!isFirst) { isFirst = true; slideBottom = START_SCAN_Y + frame.width(); } paint.setColor(resultBitmap != null ? resultColor : maskColor); // 绘制扫描区域外的阴影 drawScanArea(canvas); if (resultBitmap != null) { // Draw the opaque result bitmap over the scanning rectangle paint.setAlpha(OPAQUE); canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint); } else { // 绘制扫描区域的四角 drawArc(canvas); // 绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE slideTop += SPEEN_DISTANCE; if (slideTop >= slideBottom) { slideTop = START_SCAN_Y; } canvas.drawRect( frame.left + MIDDLE_LINE_PADDING, slideTop - MIDDLE_LINE_WIDTH / 2, frame.right - MIDDLE_LINE_PADDING, slideTop + MIDDLE_LINE_WIDTH / 2, paint); // 画扫描框下面的字 drawText(canvas); Collection<ResultPoint> currentPossible = possibleResultPoints; Collection<ResultPoint> currentLast = lastPossibleResultPoints; if (currentPossible.isEmpty()) { lastPossibleResultPoints = null; } else { possibleResultPoints = new HashSet<ResultPoint>(5); lastPossibleResultPoints = currentPossible; paint.setAlpha(OPAQUE); paint.setColor(resultPointColor); for (ResultPoint point : currentPossible) { canvas.drawCircle(frame.left + point.getX(), START_SCAN_Y + point.getY(), 6.0f, paint); } } if (currentLast != null) { paint.setAlpha(OPAQUE / 2); paint.setColor(resultPointColor); for (ResultPoint point : currentLast) { canvas.drawCircle(frame.left + point.getX(), START_SCAN_Y + point.getY(), 3.0f, paint); } } // 只刷新扫描框的内容,其他地方不刷新 postInvalidateDelayed(ANIMATION_DELAY, frame.left, START_SCAN_Y, frame.right, slideBottom); } }
private static void drawLine( Canvas canvas, Paint paint, ResultPoint a, ResultPoint b, int scaleFactor) { if (a != null && b != null) { canvas.drawLine( a.getX() / scaleFactor, a.getY() / scaleFactor, b.getX() / scaleFactor, b.getY() / scaleFactor, paint); } }
private static void drawLine( Canvas canvas, Paint paint, ResultPoint a, ResultPoint b, float scaleFactor) { if (a != null && b != null) { canvas.drawLine( scaleFactor * a.getX(), scaleFactor * a.getY(), scaleFactor * b.getX(), scaleFactor * b.getY(), paint); } }
protected void drawResultPoints(Bitmap barcode, Result rawResult) { ResultPoint[] points = rawResult.getResultPoints(); if (points != null && points.length > 0) { Canvas canvas = new Canvas(barcode); Paint paint = new Paint(); paint.setColor(getResources().getColor(R.color.result_image_border)); paint.setStrokeWidth(3.0f); paint.setStyle(Paint.Style.STROKE); Rect border = new Rect(2, 2, barcode.getWidth() - 2, barcode.getHeight() - 2); canvas.drawRect(border, paint); paint.setColor(getResources().getColor(R.color.result_points)); if (points.length == 2) { paint.setStrokeWidth(4.0f); drawLine(canvas, paint, points[0], points[1]); } 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]); } else { paint.setStrokeWidth(10.0f); for (ResultPoint point : points) { canvas.drawPoint(point.getX(), point.getY(), paint); } } } }
/** * @param color Color of result points * @return {@link Bitmap} with result points on it, or plain bitmap, if no result points */ public Bitmap getBitmapWithResultPoints(int color) { Bitmap bitmap = getBitmap(); Bitmap barcode = bitmap; ResultPoint[] points = mResult.getResultPoints(); if (points != null && points.length > 0 && bitmap != null) { barcode = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(barcode); canvas.drawBitmap(bitmap, 0, 0, null); Paint paint = new Paint(); paint.setColor(color); if (points.length == 2) { paint.setStrokeWidth(PREVIEW_LINE_WIDTH); drawLine(canvas, paint, points[0], points[1], mScaleFactor); } else if (points.length == 4 && (mResult.getBarcodeFormat() == BarcodeFormat.UPC_A || mResult.getBarcodeFormat() == BarcodeFormat.EAN_13)) { // Hacky special case -- draw two lines, for the barcode and metadata drawLine(canvas, paint, points[0], points[1], mScaleFactor); drawLine(canvas, paint, points[2], points[3], mScaleFactor); } else { paint.setStrokeWidth(PREVIEW_DOT_WIDTH); for (ResultPoint point : points) { if (point != null) { canvas.drawPoint(point.getX() / mScaleFactor, point.getY() / mScaleFactor, paint); } } } } return barcode; }
/** * 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, float scaleFactor, Result rawResult) { ResultPoint[] points = rawResult.getResultPoints(); if (points != null && points.length > 0) { Canvas canvas = new Canvas(barcode); Paint paint = new Paint(); paint.setColor(getResources().getColor(R.color.result_points)); if (points.length == 2) { paint.setStrokeWidth(4.0f); 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], scaleFactor); drawLine(canvas, paint, points[2], points[3], scaleFactor); } else { paint.setStrokeWidth(10.0f); for (ResultPoint point : points) { if (point != null) { canvas.drawPoint(scaleFactor * point.getX(), scaleFactor * point.getY(), paint); } } } } }
public void handleResult( final Result scanResult, final Bitmap thumbnailImage, final float thumbnailScaleFactor) { vibrator.vibrate(VIBRATE_DURATION); // superimpose dots to highlight the key features of the qr code final ResultPoint[] points = scanResult.getResultPoints(); if (points != null && points.length > 0) { final Paint paint = new Paint(); paint.setColor(getResources().getColor(R.color.scan_result_dots)); paint.setStrokeWidth(10.0f); final Canvas canvas = new Canvas(thumbnailImage); canvas.scale(thumbnailScaleFactor, thumbnailScaleFactor); for (final ResultPoint point : points) canvas.drawPoint(point.getX(), point.getY(), paint); } scannerView.drawResultBitmap(thumbnailImage); final Intent result = new Intent(); result.putExtra(INTENT_EXTRA_RESULT, scanResult.getText()); setResult(RESULT_OK, result); // delayed finish new Handler() .post( new Runnable() { @Override public void run() { finish(); } }); }
private static Result translateResultPoints(Result result, int xOffset, int yOffset) { ResultPoint[] oldResultPoints = result.getResultPoints(); ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.length]; for (int i = 0; i < oldResultPoints.length; i++) { ResultPoint oldPoint = oldResultPoints[i]; newResultPoints[i] = new ResultPoint(oldPoint.getX() + xOffset, oldPoint.getY() + yOffset); } return new Result( result.getText(), result.getRawBytes(), newResultPoints, result.getBarcodeFormat()); }
/** * Counts the number of black/white transitions between two points, using something like * Bresenham's algorithm. */ private ResultPointsAndTransitions transitionsBetween(ResultPoint from, ResultPoint to) { // See QR Code Detector, sizeOfBlackWhiteBlackRun() int fromX = (int) from.getX(); int fromY = (int) from.getY(); int toX = (int) to.getX(); int toY = (int) to.getY(); boolean steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); if (steep) { int temp = fromX; fromX = fromY; fromY = temp; temp = toX; toX = toY; toY = temp; } int dx = Math.abs(toX - fromX); int dy = Math.abs(toY - fromY); int error = -dx >> 1; int ystep = fromY < toY ? 1 : -1; int xstep = fromX < toX ? 1 : -1; int transitions = 0; boolean inBlack = image.get(steep ? fromY : fromX, steep ? fromX : fromY); for (int x = fromX, y = fromY; x != toX; x += xstep) { boolean isBlack = image.get(steep ? y : x, steep ? x : y); if (isBlack != inBlack) { transitions++; inBlack = isBlack; } error += dy; if (error > 0) { if (y == toY) { break; } y += ystep; error -= dx; } } return new ResultPointsAndTransitions(from, to, transitions); }
/** * 绘制可疑点 * * @param canvas */ private void drawPossibleResult(Canvas canvas) { Collection<ResultPoint> currentPossible = possibleResultPoints; Collection<ResultPoint> currentLast = lastPossibleResultPoints; if (currentPossible.isEmpty()) { lastPossibleResultPoints = null; } else { possibleResultPoints = new HashSet<ResultPoint>(5); lastPossibleResultPoints = currentPossible; paint.setAlpha(OPAQUE); paint.setColor(getResultPointColor()); for (ResultPoint point : currentPossible) { canvas.drawCircle(point.getX(), point.getY(), getNewResultPointRadius(), paint); } } if (currentLast != null) { paint.setAlpha(OPAQUE / 2); paint.setColor(resultPointColor); for (ResultPoint point : currentLast) { canvas.drawCircle(point.getX(), point.getY(), getLastResultPointRadius(), paint); } } }
private ResultPoint[] centerEdges(ResultPoint resultpoint, ResultPoint resultpoint1, ResultPoint resultpoint2, ResultPoint resultpoint3) { float f = resultpoint.getX(); float f1 = resultpoint.getY(); float f2 = resultpoint1.getX(); float f3 = resultpoint1.getY(); float f4 = resultpoint2.getX(); float f5 = resultpoint2.getY(); float f6 = resultpoint3.getX(); float f7 = resultpoint3.getY(); if (f < (float)width / 2.0F) { return (new ResultPoint[] { new ResultPoint(f6 - 1.0F, 1.0F + f7), new ResultPoint(1.0F + f2, 1.0F + f3), new ResultPoint(f4 - 1.0F, f5 - 1.0F), new ResultPoint(1.0F + f, f1 - 1.0F) }); } else { return (new ResultPoint[] { new ResultPoint(1.0F + f6, 1.0F + f7), new ResultPoint(1.0F + f2, f3 - 1.0F), new ResultPoint(f4 - 1.0F, 1.0F + f5), new ResultPoint(f - 1.0F, f1 - 1.0F) }); } }
// TODO maybe we should add missing codewords to store the correct row number to make // finding row numbers for other columns easier // use row height count to make detection of invalid row numbers more reliable int adjustIncompleteIndicatorColumnRowNumbers(BarcodeMetadata barcodeMetadata) { BoundingBox boundingBox = getBoundingBox(); ResultPoint top = isLeft ? boundingBox.getTopLeft() : boundingBox.getTopRight(); ResultPoint bottom = isLeft ? boundingBox.getBottomLeft() : boundingBox.getBottomRight(); int firstRow = imageRowToCodewordIndex((int) top.getY()); int lastRow = imageRowToCodewordIndex((int) bottom.getY()); float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount(); Codeword[] codewords = getCodewords(); int barcodeRow = -1; int maxRowHeight = 1; int currentRowHeight = 0; for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { if (codewords[codewordsRow] == null) { continue; } Codeword codeword = codewords[codewordsRow]; codeword.setRowNumberAsRowIndicatorColumn(); int rowDifference = codeword.getRowNumber() - barcodeRow; // TODO improve handling with case where first row indicator doesn't start with 0 if (rowDifference == 0) { currentRowHeight++; } else if (rowDifference == 1) { maxRowHeight = Math.max(maxRowHeight, currentRowHeight); currentRowHeight = 1; barcodeRow = codeword.getRowNumber(); } else if (codeword.getRowNumber() >= barcodeMetadata.getRowCount()) { codewords[codewordsRow] = null; } else { barcodeRow = codeword.getRowNumber(); currentRowHeight = 1; } } return (int) (averageRowHeight + 0.5); }
/** * Transform result to surfaceView coordinates * * <p>This method is needed because coordinates are given in landscape camera coordinates. Now is * working but transform operations aren't very explained * * <p>TODO re-write this method explaining each single value * * @return a new PointF array with transformed points */ private PointF[] transformToViewCoordinates(ResultPoint[] resultPoints) { PointF[] transformedPoints = new PointF[resultPoints.length]; int index = 0; if (resultPoints != null) { float previewX = mCameraManager.getPreviewSize().x; float previewY = mCameraManager.getPreviewSize().y; float scaleX = this.getWidth() / previewY; float scaleY = this.getHeight() / previewX; for (ResultPoint point : resultPoints) { PointF tmppoint = new PointF((previewY - point.getY()) * scaleX, point.getX() * scaleY); transformedPoints[index] = tmppoint; index++; } } return transformedPoints; }
private ResultPoint correctTopRight(ResultPoint resultpoint, ResultPoint resultpoint1, ResultPoint resultpoint2, ResultPoint resultpoint3, int i) { ResultPoint resultpoint4; float f = (float)distance(resultpoint, resultpoint1) / (float)i; int j = distance(resultpoint2, resultpoint3); float f1 = (resultpoint3.getX() - resultpoint2.getX()) / (float)j; float f2 = (resultpoint3.getY() - resultpoint2.getY()) / (float)j; resultpoint4 = new ResultPoint(resultpoint3.getX() + f * f1, resultpoint3.getY() + f * f2); f = (float)distance(resultpoint, resultpoint2) / (float)i; i = distance(resultpoint1, resultpoint3); f1 = (resultpoint3.getX() - resultpoint1.getX()) / (float)i; f2 = (resultpoint3.getY() - resultpoint1.getY()) / (float)i; resultpoint3 = new ResultPoint(resultpoint3.getX() + f * f1, resultpoint3.getY() + f * f2); if (isValid(resultpoint4)) goto _L2; else goto _L1
/** * Calculates the position of the white top right module using the output of the rectangle * detector */ private ResultPoint correctTopRight( ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topLeft, ResultPoint topRight, int dimension) { float corr = distance(bottomLeft, bottomRight) / (float) dimension; int norm = distance(topLeft, topRight); float cos = (topRight.getX() - topLeft.getX()) / norm; float sin = (topRight.getY() - topLeft.getY()) / norm; ResultPoint c1 = new ResultPoint(topRight.getX() + corr * cos, topRight.getY() + corr * sin); corr = distance(bottomLeft, bottomRight) / (float) dimension; norm = distance(bottomRight, topRight); cos = (topRight.getX() - bottomRight.getX()) / norm; sin = (topRight.getY() - bottomRight.getY()) / norm; ResultPoint c2 = new ResultPoint(topRight.getX() + corr * cos, topRight.getY() + corr * sin); if (!isValid(c1)) { if (isValid(c2)) { return c2; } return null; } else if (!isValid(c2)) { return c1; } int l1 = Math.abs( transitionsBetween(topLeft, c1).getTransitions() - transitionsBetween(bottomRight, c1).getTransitions()); int l2 = Math.abs( transitionsBetween(topLeft, c2).getTransitions() - transitionsBetween(bottomRight, c2).getTransitions()); if (l1 <= l2) { return c1; } return c2; }
/** * 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 rawResult The decoded results which contains the points to draw. */ private void drawResultPoints(Bitmap barcode, Result rawResult) { ResultPoint[] points = rawResult.getResultPoints(); if (points != null && points.length > 0) { Canvas canvas = new Canvas(barcode); Paint paint = new Paint(); paint.setColor(getResources().getColor(R.color.result_image_border)); paint.setStrokeWidth(3.0f); paint.setStyle(Paint.Style.STROKE); Rect border = new Rect(2, 2, barcode.getWidth() - 2, barcode.getHeight() - 2); canvas.drawRect(border, paint); paint.setColor(getResources().getColor(R.color.result_points)); if (points.length == 2) { paint.setStrokeWidth(4.0f); canvas.drawLine( points[0].getX(), points[0].getY(), points[1].getX(), points[1].getY(), paint); } else { paint.setStrokeWidth(10.0f); for (ResultPoint point : points) { canvas.drawPoint(point.getX(), point.getY(), paint); } } } }
@Override public void onDraw(Canvas canvas) { if (cameraManager == null) { return; // not ready yet, early draw before done configuring } Rect frame = cameraManager.getFramingRect(); Rect previewFrame = cameraManager.getFramingRectInPreview(); if (frame == null || previewFrame == null) { return; } int width = canvas.getWidth(); int height = canvas.getHeight(); // Draw the exterior (i.e. outside the framing rect) darkened paint.setColor(resultBitmap != null ? resultColor : maskColor); canvas.drawRect(0, 0, width, frame.top, paint); canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint); canvas.drawRect(0, frame.bottom + 1, width, height, paint); if (resultBitmap != null) { // Draw the opaque result bitmap over the scanning rectangle paint.setAlpha(CURRENT_POINT_OPACITY); canvas.drawBitmap(resultBitmap, null, frame, paint); } else { // Draw a red "laser scanner" line through the middle to show decoding is active paint.setColor(laserColor); paint.setAlpha(SCANNER_ALPHA[scannerAlpha]); scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length; int middle = frame.height() / 2 + frame.top; canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint); float scaleX = frame.width() / (float) previewFrame.width(); float scaleY = frame.height() / (float) previewFrame.height(); List<ResultPoint> currentPossible = possibleResultPoints; List<ResultPoint> currentLast = lastPossibleResultPoints; int frameLeft = frame.left; int frameTop = frame.top; if (currentPossible.isEmpty()) { lastPossibleResultPoints = null; } else { possibleResultPoints = new ArrayList<ResultPoint>(5); lastPossibleResultPoints = currentPossible; paint.setAlpha(CURRENT_POINT_OPACITY); paint.setColor(resultPointColor); synchronized (currentPossible) { for (ResultPoint point : currentPossible) { canvas.drawCircle( frameLeft + (int) (point.getX() * scaleX), frameTop + (int) (point.getY() * scaleY), POINT_SIZE, paint); } } } if (currentLast != null) { paint.setAlpha(CURRENT_POINT_OPACITY / 2); paint.setColor(resultPointColor); synchronized (currentLast) { float radius = POINT_SIZE / 2.0f; for (ResultPoint point : currentLast) { canvas.drawCircle( frameLeft + (int) (point.getX() * scaleX), frameTop + (int) (point.getY() * scaleY), radius, paint); } } } // Request another update at the animation interval, but only repaint the laser line, // not the entire viewfinder mask. postInvalidateDelayed( ANIMATION_DELAY, frame.left - POINT_SIZE, frame.top - POINT_SIZE, frame.right + POINT_SIZE, frame.bottom + POINT_SIZE); } }
@SuppressWarnings("unchecked") private void doDecodeMultiple( BinaryBitmap image, @SuppressWarnings("rawtypes") Hashtable hints, @SuppressWarnings("rawtypes") Vector results, int xOffset, int yOffset) { Result result; try { result = delegate.decode(image, hints); } catch (ReaderException re) { return; } boolean alreadyFound = false; for (int i = 0; i < results.size(); i++) { Result existingResult = (Result) results.elementAt(i); if (existingResult.getText().equals(result.getText())) { alreadyFound = true; break; } } if (alreadyFound) { return; } results.addElement(translateResultPoints(result, xOffset, yOffset)); ResultPoint[] resultPoints = result.getResultPoints(); if (resultPoints == null || resultPoints.length == 0) { return; } int width = image.getWidth(); int height = image.getHeight(); float minX = width; float minY = height; float maxX = 0.0f; float maxY = 0.0f; for (int i = 0; i < resultPoints.length; i++) { ResultPoint point = resultPoints[i]; float x = point.getX(); float y = point.getY(); if (x < minX) { minX = x; } if (y < minY) { minY = y; } if (x > maxX) { maxX = x; } if (y > maxY) { maxY = y; } } // Decode left of barcode if (minX > MIN_DIMENSION_TO_RECUR) { doDecodeMultiple(image.crop(0, 0, (int) minX, height), hints, results, xOffset, yOffset); } // Decode above barcode if (minY > MIN_DIMENSION_TO_RECUR) { doDecodeMultiple(image.crop(0, 0, width, (int) minY), hints, results, xOffset, yOffset); } // Decode right of barcode if (maxX < width - MIN_DIMENSION_TO_RECUR) { doDecodeMultiple( image.crop((int) maxX, 0, width - (int) maxX, height), hints, results, xOffset + (int) maxX, yOffset); } // Decode below barcode if (maxY < height - MIN_DIMENSION_TO_RECUR) { doDecodeMultiple( image.crop(0, (int) maxY, width, height - (int) maxY), hints, results, xOffset, yOffset + (int) maxY); } }
@Override public void onDraw(Canvas canvas) { Rect frame = CameraManager.get().getFramingRect(); if (frame == null) { return; } int width = canvas.getWidth(); int height = canvas.getHeight(); // Draw the exterior (i.e. outside the framing rect) darkened paint.setColor(resultBitmap != null ? resultColor : maskColor); canvas.drawRect(0, 0, width, frame.top, paint); canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint); canvas.drawRect(0, frame.bottom + 1, width, height, paint); if (resultBitmap != null) { // Draw the opaque result bitmap over the scanning rectangle paint.setAlpha(OPAQUE); canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint); } else { // Draw a two pixel solid black border inside the framing rect paint.setColor(frameColor); canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint); canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint); canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint); canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint); // Draw a red "laser scanner" line through the middle to show decoding is active paint.setColor(laserColor); paint.setAlpha(SCANNER_ALPHA[scannerAlpha]); scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length; int middle = frame.height() / 2 + frame.top; canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint); Collection<ResultPoint> currentPossible = possibleResultPoints; Collection<ResultPoint> currentLast = lastPossibleResultPoints; if (currentPossible.isEmpty()) { lastPossibleResultPoints = null; } else { possibleResultPoints = new HashSet<ResultPoint>(5); lastPossibleResultPoints = currentPossible; paint.setAlpha(OPAQUE); paint.setColor(resultPointColor); for (ResultPoint point : currentPossible) { canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint); } } if (currentLast != null) { paint.setAlpha(OPAQUE / 2); paint.setColor(resultPointColor); for (ResultPoint point : currentLast) { canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint); } } // Request another update at the animation interval, but only repaint the laser line, // not the entire viewfinder mask. postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom); } }
private boolean isValid(ResultPoint p) { return (p.getX() >= 0 && p.getX() < image.width && p.getY() > 0 && p.getY() < image.height); }
@Override public void onDraw(Canvas canvas) { // 中间的扫描框,你要修改扫描框的大小,去CameraManager里面修改 Rect frame = CameraManager.get().getFramingRect(); if (frame == null) { return; } // 初始化中间线滑动的最上边和最下边 if (!isFirst) { isFirst = true; slideTop = frame.top; slideBottom = frame.bottom; } // 获取屏幕的宽和高 int width = canvas.getWidth(); int height = canvas.getHeight(); paint.setColor(resultBitmap != null ? resultColor : maskColor); // 画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面 // 扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边 canvas.drawRect(0, 0, width, frame.top, paint); canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint); canvas.drawRect(0, frame.bottom + 1, width, height, paint); if (resultBitmap != null) { // Draw the opaque result bitmap over the scanning rectangle paint.setAlpha(OPAQUE); canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint); } else { // 画扫描框边上的角,总共8个部分 paint.setColor(Color.GREEN); canvas.drawRect( frame.left, frame.top, frame.left + ScreenRate, frame.top + CORNER_WIDTH, paint); canvas.drawRect( frame.left, frame.top, frame.left + CORNER_WIDTH, frame.top + ScreenRate, paint); canvas.drawRect( frame.right - ScreenRate, frame.top, frame.right, frame.top + CORNER_WIDTH, paint); canvas.drawRect( frame.right - CORNER_WIDTH, frame.top, frame.right, frame.top + ScreenRate, paint); canvas.drawRect( frame.left, frame.bottom - CORNER_WIDTH, frame.left + ScreenRate, frame.bottom, paint); canvas.drawRect( frame.left, frame.bottom - ScreenRate, frame.left + CORNER_WIDTH, frame.bottom, paint); canvas.drawRect( frame.right - ScreenRate, frame.bottom - CORNER_WIDTH, frame.right, frame.bottom, paint); canvas.drawRect( frame.right - CORNER_WIDTH, frame.bottom - ScreenRate, frame.right, frame.bottom, paint); // 绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE slideTop += SPEEN_DISTANCE; if (slideTop >= frame.bottom) { slideTop = frame.top; } Rect lineRect = new Rect(); lineRect.left = frame.left; lineRect.right = frame.right; lineRect.top = slideTop; lineRect.bottom = slideTop + 18; canvas.drawBitmap( ((BitmapDrawable) (getResources().getDrawable(R.drawable.qrcode_scan_line))).getBitmap(), null, lineRect, paint); // 画扫描框下面的字 paint.setColor(Color.WHITE); paint.setTextSize(TEXT_SIZE * density); paint.setAlpha(0x40); paint.setTypeface(Typeface.create("System", Typeface.BOLD)); String text = getResources().getString(R.string.scan_text); float textWidth = paint.measureText(text); canvas.drawText( text, (width - textWidth) / 2, (float) (frame.bottom + (float) TEXT_PADDING_TOP * density), paint); Collection<ResultPoint> currentPossible = possibleResultPoints; Collection<ResultPoint> currentLast = lastPossibleResultPoints; if (currentPossible.isEmpty()) { lastPossibleResultPoints = null; } else { possibleResultPoints = new HashSet<ResultPoint>(5); lastPossibleResultPoints = currentPossible; paint.setAlpha(OPAQUE); paint.setColor(resultPointColor); for (ResultPoint point : currentPossible) { canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint); } } if (currentLast != null) { paint.setAlpha(OPAQUE / 2); paint.setColor(resultPointColor); for (ResultPoint point : currentLast) { canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint); } } // 只刷新扫描框的内容,其他地方不刷新 postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom); } }
protected static void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b) { canvas.drawLine(a.getX(), a.getY(), b.getX(), b.getY(), paint); }
// TODO implement properly // TODO maybe we should add missing codewords to store the correct row number to make // finding row numbers for other columns easier // use row height count to make detection of invalid row numbers more reliable int adjustCompleteIndicatorColumnRowNumbers(BarcodeMetadata barcodeMetadata) { Codeword[] codewords = getCodewords(); setRowNumbers(); removeIncorrectCodewords(codewords, barcodeMetadata); BoundingBox boundingBox = getBoundingBox(); ResultPoint top = isLeft ? boundingBox.getTopLeft() : boundingBox.getTopRight(); ResultPoint bottom = isLeft ? boundingBox.getBottomLeft() : boundingBox.getBottomRight(); int firstRow = imageRowToCodewordIndex((int) top.getY()); int lastRow = imageRowToCodewordIndex((int) bottom.getY()); // We need to be careful using the average row height. Barcode could be skewed so that we have // smaller and // taller rows float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount(); int barcodeRow = -1; int maxRowHeight = 1; int currentRowHeight = 0; for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { if (codewords[codewordsRow] == null) { continue; } Codeword codeword = codewords[codewordsRow]; // float expectedRowNumber = (codewordsRow - firstRow) / averageRowHeight; // if (Math.abs(codeword.getRowNumber() - expectedRowNumber) > 2) { // SimpleLog.log(LEVEL.WARNING, // "Removing codeword, rowNumberSkew too high, codeword[" + codewordsRow + "]: // Expected Row: " + // expectedRowNumber + ", RealRow: " + codeword.getRowNumber() + ", value: " + // codeword.getValue()); // codewords[codewordsRow] = null; // } int rowDifference = codeword.getRowNumber() - barcodeRow; // TODO improve handling with case where first row indicator doesn't start with 0 if (rowDifference == 0) { currentRowHeight++; } else if (rowDifference == 1) { maxRowHeight = Math.max(maxRowHeight, currentRowHeight); currentRowHeight = 1; barcodeRow = codeword.getRowNumber(); } else if (rowDifference < 0 || codeword.getRowNumber() >= barcodeMetadata.getRowCount() || rowDifference > codewordsRow) { codewords[codewordsRow] = null; } else { int checkedRows; if (maxRowHeight > 2) { checkedRows = (maxRowHeight - 2) * rowDifference; } else { checkedRows = rowDifference; } boolean closePreviousCodewordFound = checkedRows >= codewordsRow; for (int i = 1; i <= checkedRows && !closePreviousCodewordFound; i++) { // there must be (height * rowDifference) number of codewords missing. For now we assume // height = 1. // This should hopefully get rid of most problems already. closePreviousCodewordFound = codewords[codewordsRow - i] != null; } if (closePreviousCodewordFound) { codewords[codewordsRow] = null; } else { barcodeRow = codeword.getRowNumber(); currentRowHeight = 1; } } } return (int) (averageRowHeight + 0.5); }