Android ZXing(二维码扫描)必须远距离扫描的解决方案

只要将其中两个类替换为下面的就可以了,CameraManager,CameraConfigurationManager:

final class CameraConfigurationManager {


 private static final String TAG = CameraConfigurationManager.class.getSimpleName();


 private static final int TEN_DESIRED_ZOOM = 27;
 private static final int DESIRED_SHARPNESS = 30;


 private static final Pattern COMMA_PATTERN = Pattern.compile(",");


 private final Context context;
 private Point screenResolution;
 private Point cameraResolution;
 private int previewFormat;
 private String previewFormatString;


 CameraConfigurationManager(Context context) {
   this.context = context;
 }
 /**
  * Reads, one time, values from the camera that are needed by the app.
  */
 void initFromCameraParameters(Camera camera) {
 Camera.Parameters parameters = camera.getParameters();
 previewFormat = parameters.getPreviewFormat();
 previewFormatString = parameters.get("preview-format");
 WindowManager manager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
 Display display = manager.getDefaultDisplay();
 int width = display.getWidth();
 int height = display.getHeight();
 screenResolution = new Point(width,height);
 if(width < height)
 {
 cameraResolution = getCameraResolution(parameters, new Point(height,width));
 }else{
 cameraResolution = getCameraResolution(parameters, screenResolution);
 }
 }






 /**
  * Sets the camera up to take preview images which are used for both preview and decoding.
  * We detect the preview format here so that buildLuminanceSource() can build an appropriate
  * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
  * and the planar Y can be used for barcode scanning without a copy in some cases.
  */
 void setDesiredCameraParameters(Camera camera) {
   Camera.Parameters parameters = camera.getParameters();
List supportedPreviewSizes = parameters.getSupportedPreviewSizes();
int position =0;
if(supportedPreviewSizes.size()>2){
position=supportedPreviewSizes.size()/2+1;//supportedPreviewSizes.get();
}else {
position=supportedPreviewSizes.size()/2;
}

int width = supportedPreviewSizes.get(position).width;
int height = supportedPreviewSizes.get(position).height;
   Log.d(TAG, "Setting preview size: " + cameraResolution);
   camera.setDisplayOrientation(90);  
   cameraResolution.x=width;
   cameraResolution.y=height;
   parameters.setPreviewSize(width,height);
   setFlash(parameters);
   setZoom(parameters);
   //setSharpness(parameters);
   camera.setParameters(parameters);
 }


 Point getCameraResolution() {
   return cameraResolution;
 }


 Point getScreenResolution() {
   return screenResolution;
 }


 int getPreviewFormat() {
   return previewFormat;
 }


 String getPreviewFormatString() {
   return previewFormatString;
 }
 private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {


   String previewSizeValueString = parameters.get("preview-size-values");
   // saw this on Xperia
   if (previewSizeValueString == null) {
     previewSizeValueString = parameters.get("preview-size-value");
   }


   Point cameraResolution = null;


   if (previewSizeValueString != null) {
     Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString);
     cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
   }


   if (cameraResolution == null) {
     // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
     cameraResolution = new Point(
         (screenResolution.x >> 3) << 3,
         (screenResolution.y >> 3) << 3);
   }


   return cameraResolution;
 }


 private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
   int bestX = 0;
   int bestY = 0;
   int diff = Integer.MAX_VALUE;
   for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {


     previewSize = previewSize.trim();
     int dimPosition = previewSize.indexOf('x');
     if (dimPosition < 0) {
       Log.w(TAG, "Bad preview-size: " + previewSize);
       continue;
     }


     int newX;
     int newY;
     try {
       newX = Integer.parseInt(previewSize.substring(0, dimPosition));
       newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
     } catch (NumberFormatException nfe) {
       Log.w(TAG, "Bad preview-size: " + previewSize);
       continue;
     }


     int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
     if (newDiff == 0) {
       bestX = newX;
       bestY = newY;
       break;
     } else if (newDiff < diff) {
       bestX = newX;
       bestY = newY;
       diff = newDiff;
     }


   }
   if (bestX > 0 && bestY > 0) {
     return new Point(bestX, bestY);
   }
   return null;
 }


 private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
   int tenBestValue = 0;
   for (String stringValue : COMMA_PATTERN.split(stringValues)) {
     stringValue = stringValue.trim();
     double value;
     try {
       value = Double.parseDouble(stringValue);
     } catch (NumberFormatException nfe) {
       return tenDesiredZoom;
     }
     int tenValue = (int) (10.0 * value);
     if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
       tenBestValue = tenValue;
     }
   }
   return tenBestValue;
 }


 private void setFlash(Camera.Parameters parameters) {
   // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
   // And this is a hack-hack to work around a different value on the Behold II
   // Restrict Behold II check to Cupcake, per Samsung's advice
   //if (Build.MODEL.contains("Behold II") &&
   //    CameraManager.SDK_INT == Build.VERSION_CODES.CUPCAKE) {
   if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3 = Cupcake
     parameters.set("flash-value", 1);
   } else {
     parameters.set("flash-value", 2);
   }
   // This is the standard setting to turn the flash off that all devices should honor.
   parameters.set("flash-mode", "off");
 }


 private void setZoom(Camera.Parameters parameters) {


   String zoomSupportedString = parameters.get("zoom-supported");
   if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
     return;
   }


   int tenDesiredZoom = TEN_DESIRED_ZOOM;


   String maxZoomString = parameters.get("max-zoom");
   if (maxZoomString != null) {
     try {
       int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
       if (tenDesiredZoom > tenMaxZoom) {
         tenDesiredZoom = tenMaxZoom;
       }
     } catch (NumberFormatException nfe) {
       Log.w(TAG, "Bad max-zoom: " + maxZoomString);
     }
   }


   String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
   if (takingPictureZoomMaxString != null) {
     try {
       int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
       if (tenDesiredZoom > tenMaxZoom) {
         tenDesiredZoom = tenMaxZoom;
       }
     } catch (NumberFormatException nfe) {
       Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
     }
   }


   String motZoomValuesString = parameters.get("mot-zoom-values");
   if (motZoomValuesString != null) {
     tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
   }


   String motZoomStepString = parameters.get("mot-zoom-step");
   if (motZoomStepString != null) {
     try {
       double motZoomStep = Double.parseDouble(motZoomStepString.trim());
       int tenZoomStep = (int) (10.0 * motZoomStep);
       if (tenZoomStep > 1) {
         tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
       }
     } catch (NumberFormatException nfe) {
       // continue
     }
   }


   // Set zoom. This helps encourage the user to pull back.
   // Some devices like the Behold have a zoom parameter
   if (maxZoomString != null || motZoomValuesString != null) {
     parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
   }


   // Most devices, like the Hero, appear to expose this zoom parameter.
   // It takes on values like "27" which appears to mean 2.7x zoom
   if (takingPictureZoomMaxString != null) {
     parameters.set("taking-picture-zoom", tenDesiredZoom);
   }
 }


}


第二个类


public final class CameraManager {


 private static final String TAG = CameraManager.class.getSimpleName();  
 public static int MIN_FRAME_WIDTH = 480;
 public static int MIN_FRAME_HEIGHT = 480;  
 public static int MAX_FRAME_WIDTH = 960;     
 public static int MAX_FRAME_HEIGHT = 720;  
 private static CameraManager cameraManager;


 static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT
 static {
   int sdkInt;
   try {
     sdkInt = Integer.parseInt(Build.VERSION.SDK);
   } catch (NumberFormatException nfe) {
     // Just to be safe
     sdkInt = 10000;
   }
   SDK_INT = sdkInt;
 }


 private final Context context;
 private final CameraConfigurationManager configManager;
 private Camera camera;
 private Rect framingRect;
 private Rect framingRectInPreview;
 private boolean initialized;
 private boolean previewing;
 private final boolean useOneShotPreviewCallback;
 /**
  * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
  * clear the handler so it will only receive one message.
  */
 private final PreviewCallback previewCallback;
 /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */
 private final AutoFocusCallback autoFocusCallback;


 /**
  * Initializes this static object with the Context of the calling Activity.
  *
  * @param context The Activity which wants to use the camera.
  */
 public static void init(Context context) {
   if (cameraManager == null) {
     cameraManager = new CameraManager(context);
   }
 }


 /**
  * Gets the CameraManager singleton instance.
  *
  * @return A reference to the CameraManager singleton.
  */
 public static CameraManager get() {
   return cameraManager;
 }


 private CameraManager(Context context) {


   this.context = context;
   this.configManager = new CameraConfigurationManager(context);


   // Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older
   // Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use
   // the more efficient one shot callback, as the older one can swamp the system and cause it
   // to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK.
   //useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE;
   useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake


   previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback);
   autoFocusCallback = new AutoFocusCallback();
 }


 /**
  * Opens the camera driver and initializes the hardware parameters.
  *
  * @param holder The surface object which the camera will draw preview frames into.
  * @throws IOException Indicates the camera driver failed to open.
  */
 public void openDriver(SurfaceHolder holder) throws IOException {
   if (camera == null) {
     camera = Camera.open();
     if (camera == null) {
       throw new IOException();
     }
//      camera.setDisplayOrientation(90);
     camera.setPreviewDisplay(holder);
     if (!initialized) {
       initialized = true;
       configManager.initFromCameraParameters(camera);
     }
     configManager.setDesiredCameraParameters(camera);
     FlashlightManager.enableFlashlight();
   }
 }


 /**
  * Closes the camera driver if still in use.
  */
 public void closeDriver() {
   if (camera != null) {
     FlashlightManager.disableFlashlight();
     camera.release();
     camera = null;
   }
 }


 /**
  * Asks the camera hardware to begin drawing preview frames to the screen.
  */
 public void startPreview() {
   if (camera != null && !previewing) {
     camera.startPreview();
     previewing = true;
   }
 }


 /**
  * Tells the camera to stop drawing preview frames.
  */
 public void stopPreview() {
   if (camera != null && previewing) {
     if (!useOneShotPreviewCallback) {
       camera.setPreviewCallback(null);
     }
     camera.stopPreview();
     previewCallback.setHandler(null, 0);
     autoFocusCallback.setHandler(null, 0);
     previewing = false;
   }
 }


 /**
  * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
  * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
  * respectively.
  *
  * @param handler The handler to send the message to.
  * @param message The what field of the message to be sent.
  */
 public void requestPreviewFrame(Handler handler, int message) {
   if (camera != null && previewing) {
     previewCallback.setHandler(handler, message);
     if (useOneShotPreviewCallback) {
       camera.setOneShotPreviewCallback(previewCallback);
     } else {
       camera.setPreviewCallback(previewCallback);
     }
   }
 }


 /**
  * Asks the camera hardware to perform an autofocus.
  *
  * @param handler The Handler to notify when the autofocus completes.
  * @param message The message to deliver.
  */
 public void requestAutoFocus(Handler handler, int message) {
   if (camera != null && previewing) {
     autoFocusCallback.setHandler(handler, message);
     //Log.d(TAG, "Requesting auto-focus callback");
     camera.autoFocus(autoFocusCallback);
   }
 }


 /**
  * Calculates the framing rect which the UI should draw to show the user where to place the
  * barcode. This target helps with alignment as well as forces the user to hold the device
  * far enough away to ensure the image will be in focus.
  *
  * @return The rectangle to draw on screen in window coordinates.
  */
 public Rect getFramingRect() {
   Point screenResolution = configManager.getScreenResolution();
   if (framingRect == null) {
     if (camera == null) {
       return null;
     }
//      int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);


//      int height = fisndDesiredDimensionInRange(screenResolution.y,MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
     
     int width = screenResolution.x * 3 / 4;
     if (width < MIN_FRAME_WIDTH) {
       width = MIN_FRAME_WIDTH;
     } else if (width > MAX_FRAME_WIDTH) {
       width = MAX_FRAME_WIDTH;
     }
     int height = screenResolution.y * 3 / 4;
     if (height < MIN_FRAME_HEIGHT) {
       height = MIN_FRAME_HEIGHT;
     } else if (height > MAX_FRAME_HEIGHT) {
       height = MAX_FRAME_HEIGHT;
     }
     int leftOffset = (screenResolution.x - width) / 2;
     int topOffset = (screenResolution.y - height) / 2;
     framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
   }
   return framingRect;
 }


 /**
  * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
  * not UI / screen.
  */
 public Rect getFramingRectInPreview() {
   if (framingRectInPreview == null) {
     Rect rect = new Rect(getFramingRect());
     Point cameraResolution = configManager.getCameraResolution();
     Point screenResolution = configManager.getScreenResolution();
     rect.left = rect.left * cameraResolution.y / screenResolution.x;  
     rect.right = rect.right * cameraResolution.y / screenResolution.x;  
     rect.top = rect.top * cameraResolution.x / screenResolution.y;  
     rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y; 
     
     Log.e("tag","getFRIP "+rect.left +"  "+rect.right+" "+rect.top+ "  "+rect.bottom);
     framingRectInPreview = rect;
   }
   return framingRectInPreview;
 }


 /**
  * Converts the result points from still resolution coordinates to screen coordinates.
  *
  * @param points The points returned by the Reader subclass through Result.getResultPoints().
  * @return An array of Points scaled to the size of the framing rect and offset appropriately
  *         so they can be drawn in screen coordinates.
  */


 /**
  * A factory method to build the appropriate LuminanceSource object based on the format
  * of the preview buffers, as described by Camera.Parameters.
  *
  * @param data A preview frame.
  * @param width The width of the image.
  * @param height The height of the image.
  * @return A PlanarYUVLuminanceSource instance.
  */
 public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
   Rect rect = getFramingRectInPreview();
   int previewFormat = configManager.getPreviewFormat();
   String previewFormatString = configManager.getPreviewFormatString();
   switch (previewFormat) {
     // This is the standard Android format which all devices are REQUIRED to support.
     // In theory, it's the only one we should ever care about.
     case PixelFormat.YCbCr_420_SP:
     // This format has never been seen in the wild, but is compatible as we only care
     // about the Y channel, so allow it.
     case PixelFormat.YCbCr_422_SP:
//      Log.e("tag", width +" "+ height +" "+  rect.left +" "+ rect.top +" "+ rect.width() +" "+ rect.height());
       return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
           rect.width(), rect.height());
     default:
       // The Samsung Moment incorrectly uses this variant instead of the 'sp' version.
       // Fortunately, it too has all the Y data up front, so we can read it.
       if ("yuv420p".equals(previewFormatString)) {
         return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
           rect.width(), rect.height());
       }
   }
   throw new IllegalArgumentException("Unsupported picture format: " +
       previewFormat + '/' + previewFormatString);
 }


}

你可能感兴趣的:(Android)