├── .gitignore ├── README.md ├── RectangleCamera.iml ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── org │ │ └── itzheng │ │ └── demo │ │ └── rectanglecamera │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── org │ │ │ └── itzheng │ │ │ └── demo │ │ │ └── rectanglecamera │ │ │ ├── App.java │ │ │ ├── CameraActivity.java │ │ │ ├── MainActivity.java │ │ │ └── SensorController.java │ └── res │ │ ├── drawable │ │ └── rec_focus_shap.xml │ │ ├── layout │ │ ├── activity_camera.xml │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── org │ └── itzheng │ └── demo │ └── rectanglecamera │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── resource ├── 00.png ├── 01.png └── 02.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | *.properties 4 | .idea 5 | /build 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RectangleCamera 2 | # 拍照截取指定区域的图片 3 | *** 4 | ### 拍照前 5 | ![图片](resource/00.png "图片") 6 | 7 | ### 拍照界面 8 | ![图片](resource/01.png "图片") 9 | 10 | ### 返回结果 11 | ![图片](resource/02.png "图片") 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /RectangleCamera.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /build 4 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.2" 6 | defaultConfig { 7 | applicationId "org.itzheng.demo.rectanglecamera" 8 | minSdkVersion 14 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:24.2.0' 28 | testCompile 'junit:junit:4.12' 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/daniel/development/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/itzheng/demo/rectanglecamera/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package org.itzheng.demo.rectanglecamera; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("org.itzheng.demo.rectanglecamera", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/org/itzheng/demo/rectanglecamera/App.java: -------------------------------------------------------------------------------- 1 | package org.itzheng.demo.rectanglecamera; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | public class App extends Application { 7 | public static App app; 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | app = this; 13 | } 14 | 15 | public static App getInstance() { 16 | return app; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/org/itzheng/demo/rectanglecamera/CameraActivity.java: -------------------------------------------------------------------------------- 1 | package org.itzheng.demo.rectanglecamera; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Matrix; 8 | import android.graphics.PixelFormat; 9 | import android.graphics.Rect; 10 | import android.hardware.Camera; 11 | import android.os.AsyncTask; 12 | import android.os.Environment; 13 | import android.os.Handler; 14 | import android.support.v7.app.AppCompatActivity; 15 | import android.os.Bundle; 16 | import android.util.DisplayMetrics; 17 | import android.util.Log; 18 | import android.view.Display; 19 | import android.view.MotionEvent; 20 | import android.view.SurfaceHolder; 21 | import android.view.SurfaceView; 22 | import android.view.View; 23 | import android.view.WindowManager; 24 | import android.widget.LinearLayout; 25 | import android.widget.Toast; 26 | 27 | import java.io.BufferedOutputStream; 28 | import java.io.FileOutputStream; 29 | import java.io.IOException; 30 | import java.util.List; 31 | 32 | public class CameraActivity extends AppCompatActivity { 33 | private static final String TAG = "CameraActivity"; 34 | public static final String EXTRA_STR_FILE_PATH = "EXTRA_STR_FILE_PATH"; 35 | LinearLayout llFocus; 36 | Rect mRect = new Rect(); 37 | SensorController sensorControler; 38 | private SurfaceView surfaceView; 39 | private SurfaceHolder surfaceHolder; 40 | private Camera mCamera; 41 | private Camera.Parameters mParams; 42 | private DisplayMetrics dm = new DisplayMetrics(); 43 | private boolean mIsStop; 44 | private Handler mHandler = new Handler(); 45 | 46 | private static void saveImage(String path, Bitmap bitmap) { 47 | 48 | try { 49 | BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path)); 50 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); 51 | bos.flush(); 52 | bos.close(); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | if ((bitmap != null) && (!bitmap.isRecycled())) { 57 | bitmap.recycle(); 58 | } 59 | } 60 | 61 | /** 62 | * @param currentActivity 63 | * @param sizes 最理想的预览分辨率的宽和高 64 | * @param targetRatio 65 | * @return 获得最理想的预览尺寸 66 | */ 67 | public static Camera.Size getOptimalPreviewSize(Activity currentActivity, 68 | List sizes, double targetRatio) { 69 | // Use a very small tolerance because we want an exact match. 70 | final double ASPECT_TOLERANCE = 0.001; 71 | if (sizes == null) 72 | return null; 73 | 74 | Camera.Size optimalSize = null; 75 | double minDiff = Double.MAX_VALUE; 76 | 77 | // Because of bugs of overlay and layout, we sometimes will try to 78 | // layout the viewfinder in the portrait orientation and thus get the 79 | // wrong size of mSurfaceView. When we change the preview size, the 80 | // new overlay will be created before the old one closed, which causes 81 | // an exception. For now, just get the screen size 82 | 83 | Display display = currentActivity.getWindowManager() 84 | .getDefaultDisplay(); 85 | int targetHeight = Math.min(display.getHeight(), display.getWidth()); 86 | 87 | if (targetHeight <= 0) { 88 | // We don't know the size of SurfaceView, use screen height 89 | targetHeight = display.getHeight(); 90 | } 91 | 92 | // Try to find an size match aspect ratio and size 93 | for (Camera.Size size : sizes) { 94 | double ratio = (double) size.width / size.height; 95 | if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) 96 | continue; 97 | if (Math.abs(size.height - targetHeight) < minDiff) { 98 | optimalSize = size; 99 | minDiff = Math.abs(size.height - targetHeight); 100 | } 101 | } 102 | 103 | // Cannot find the one match the aspect ratio. This should not happen. 104 | // Ignore the requirement. 105 | if (optimalSize == null) { 106 | System.out.println("No preview size match the aspect ratio"); 107 | minDiff = Double.MAX_VALUE; 108 | for (Camera.Size size : sizes) { 109 | if (Math.abs(size.height - targetHeight) < minDiff) { 110 | optimalSize = size; 111 | minDiff = Math.abs(size.height - targetHeight); 112 | } 113 | } 114 | } 115 | return optimalSize; 116 | } 117 | 118 | @Override 119 | protected void onCreate(Bundle savedInstanceState) { 120 | super.onCreate(savedInstanceState); 121 | setContentView(R.layout.activity_camera); 122 | //设置全屏 123 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 124 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 125 | sensorControler = SensorController.getInstance(); 126 | initView(); 127 | sensorControler.setCameraFocusListener(new SensorController.CameraFocusListener() { 128 | @Override 129 | public void onFocus() { 130 | Log.d(TAG, "onFocus"); 131 | autoFocus(); 132 | } 133 | }); 134 | 135 | } 136 | 137 | private void initView() { 138 | getWindowManager().getDefaultDisplay().getMetrics(dm); 139 | surfaceView = (SurfaceView) this.findViewById(R.id.surfaceview_camera); 140 | surfaceHolder = surfaceView.getHolder(); 141 | surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 142 | surfaceHolder.addCallback(new SurfaceHolderCallBack()); 143 | llFocus = (LinearLayout) this.findViewById(R.id.llFocus); 144 | llFocus.setOnTouchListener(new View.OnTouchListener() { 145 | @Override 146 | public boolean onTouch(View view, MotionEvent motionEvent) { 147 | autoFocus(); 148 | return false; 149 | } 150 | }); 151 | } 152 | 153 | /** 154 | * 点击拍照 155 | * 156 | * @param v 157 | */ 158 | public void imgCamera(View v) { 159 | try { 160 | mIsStop = true; 161 | //将正方形的大小映射到mRect上,为了截取大小 162 | llFocus.getGlobalVisibleRect(mRect); 163 | mCamera.takePicture(null, null, null, new CropPictureCallback()); 164 | } catch (Throwable t) { 165 | t.printStackTrace(); 166 | try { 167 | mCamera.startPreview(); 168 | } catch (Throwable e) { 169 | e.printStackTrace(); 170 | } 171 | } 172 | 173 | } 174 | 175 | public Activity getActivity() { 176 | return this; 177 | } 178 | 179 | @Override 180 | protected void onPause() { 181 | super.onPause(); 182 | mIsStop = true; 183 | sensorControler.onStop(); 184 | } 185 | 186 | @Override 187 | protected void onResume() { 188 | super.onResume(); 189 | mIsStop = false; 190 | sensorControler.onStart(); 191 | } 192 | 193 | private Camera.Size getOptimalPictureSize(List pictureSizes) { 194 | Camera.Size pictureSize = null; 195 | for (int i = 0; i < pictureSizes.size(); i++) { 196 | pictureSize = pictureSizes.get(i); 197 | if (pictureSize.width == dm.widthPixels && pictureSize.height == dm.heightPixels) { 198 | return pictureSize; 199 | } 200 | } 201 | 202 | for (int i = 0; i < pictureSizes.size(); i++) { 203 | pictureSize = pictureSizes.get(i); 204 | if (pictureSize.width > dm.widthPixels && pictureSize.height > dm.heightPixels) { 205 | return pictureSize; 206 | } 207 | } 208 | return null; 209 | } 210 | 211 | /** 212 | * 按正方形裁切图片 213 | */ 214 | public void imageCrop(String filePath, Bitmap bitmap, Rect focusRect) { 215 | Log.d(TAG, "imageCrop heightPixels=" + dm.heightPixels + " widthPixels=" + dm.widthPixels); 216 | Log.d(TAG, "imageCrop bitmap w=" + bitmap.getWidth() + " h=" + bitmap.getHeight()); 217 | Log.d(TAG, "imageCrop focusRect left=" + focusRect.left + " top=" + focusRect.top); 218 | // 下面这句是关键 219 | float wScale = (float) bitmap.getWidth() / dm.heightPixels; 220 | float hScale = (float) bitmap.getHeight() / dm.widthPixels; 221 | Log.d(TAG, "imageCrop wScale=" + wScale + " hScale=" + hScale); 222 | int x = (int) (focusRect.left * wScale); 223 | int y = (int) (focusRect.top * hScale); 224 | Log.d(TAG, "imageCrop x=" + x + " y=" + y); 225 | int width = focusRect.width(); 226 | int height = focusRect.height(); 227 | Log.d(TAG, "imageCrop width=" + width + " height=" + height); 228 | // Camera.Size size = mCamera.getParameters().getPreviewSize(); 229 | Bitmap bitmapTemp = Bitmap.createBitmap(bitmap, focusRect.left, focusRect.top, width, height); 230 | //saveImage(filePath, toGrayscale(bitmapTemp)); 231 | saveImage(filePath, bitmapTemp); 232 | } 233 | 234 | /** 235 | * @return ${return_type} 返回类型 236 | * @throws 237 | * @Title: 关闭相机 238 | * @Description: 释放相机资源 239 | */ 240 | public Camera closeCamera(Camera camera) { 241 | try { 242 | if (camera != null) { 243 | mParams = null; 244 | camera.setPreviewCallback(null); 245 | camera.stopPreview(); 246 | camera.release(); 247 | camera = null; 248 | } 249 | } catch (Exception e) { 250 | Log.i("TAG", e.getMessage()); 251 | } 252 | return camera; 253 | } 254 | 255 | /** 256 | * 打开闪光灯 257 | */ 258 | public void openLight() { 259 | if (mCamera != null) { 260 | Camera.Parameters parameter = mCamera.getParameters(); 261 | parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 262 | mCamera.setParameters(parameter); 263 | } 264 | } 265 | 266 | /** 267 | * 关闭闪光灯 268 | */ 269 | public void offLight() { 270 | if (mCamera != null) { 271 | Camera.Parameters parameter = mCamera.getParameters(); 272 | parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 273 | mCamera.setParameters(parameter); 274 | } 275 | } 276 | 277 | @Override 278 | protected void onDestroy() { 279 | super.onDestroy(); 280 | closeCamera(mCamera); 281 | } 282 | 283 | public void autoFocus() { 284 | if (mCamera != null) { 285 | try { 286 | if (mCamera.getParameters().getSupportedFocusModes() != null && mCamera.getParameters() 287 | .getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) { 288 | mCamera.autoFocus(new Camera.AutoFocusCallback() { 289 | public void onAutoFocus(boolean success, Camera camera) { 290 | mIsStop = success; 291 | } 292 | }); 293 | } else { 294 | // Log.e(TAG, getString(R.string.unsupport_auto_focus)); 295 | } 296 | } catch (Exception e) { 297 | e.printStackTrace(); 298 | mCamera.stopPreview(); 299 | mCamera.startPreview(); 300 | // Log.e(TAG, getString(R.string.toast_autofocus_failure)); 301 | } 302 | } 303 | } 304 | 305 | /** 306 | * 拍照完成的回调 307 | */ 308 | private final class CropPictureCallback implements Camera.PictureCallback { 309 | 310 | @Override 311 | public void onPictureTaken(byte[] data, Camera camera) { 312 | new SavePicTask(data).execute(); 313 | try { 314 | mIsStop = false; 315 | camera.startPreview(); // 拍完照后,重新开始预览 316 | } catch (Exception e) { 317 | e.printStackTrace(); 318 | } 319 | 320 | } 321 | } 322 | 323 | private class SavePicTask extends AsyncTask { 324 | long currentTime = 0; 325 | private byte[] data; 326 | 327 | SavePicTask(byte[] data) { 328 | this.data = data; 329 | } 330 | 331 | protected void onPreExecute() { 332 | // showProgressDialog("处理中"); 333 | } 334 | 335 | @Override 336 | protected String doInBackground(Void... params) { 337 | Bitmap bitmap = null; 338 | try { 339 | bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 340 | } catch (OutOfMemoryError e) { 341 | e.printStackTrace(); 342 | } 343 | String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myPhoto.jpg"; 344 | if (bitmap != null) { 345 | if (bitmap.getWidth() > dm.widthPixels && bitmap.getHeight() > dm.heightPixels) { 346 | //获取宽高比 347 | Matrix matrix = new Matrix(); 348 | int width = bitmap.getWidth();//获取资源位图的宽 349 | int height = bitmap.getHeight();//获取资源位图的高 350 | int newWidth = dm.widthPixels; 351 | int newHeight = dm.heightPixels; 352 | 353 | float scaleW = (float) newWidth / (float) width; 354 | float scaleH = (float) newHeight / (float) height; 355 | if (scaleW < 1 && scaleH < 1) {//需要裁剪才裁剪 356 | //避免图片变形,缩放比例保持一致 357 | if (scaleW > scaleH) { 358 | matrix.postScale(scaleW, scaleW);//获取缩放比例 359 | } else { 360 | matrix.postScale(scaleH, scaleH);//获取缩放比例 361 | } 362 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, 363 | width, height, matrix, true); //根据缩放比例获取新的位图 364 | } 365 | // 366 | int left = (bitmap.getWidth() - newWidth) / 2; 367 | int top = (bitmap.getHeight() - newHeight) / 2; 368 | bitmap = Bitmap.createBitmap(bitmap, 0, top, newWidth, newHeight); 369 | Log.d(TAG, "doInBackground DisplayMetrics" + "newWidth " + newWidth + " newHeight" + newHeight); 370 | } 371 | imageCrop(filePath, bitmap, mRect); 372 | Intent intent = new Intent(); 373 | intent.putExtra(EXTRA_STR_FILE_PATH, filePath); 374 | setResult(Activity.RESULT_OK, intent); 375 | finish(); 376 | } 377 | return filePath; 378 | } 379 | 380 | @Override 381 | protected void onPostExecute(final String result) { 382 | super.onPostExecute(result); 383 | 384 | } 385 | } 386 | 387 | public class SurfaceHolderCallBack implements SurfaceHolder.Callback { 388 | 389 | @Override 390 | public void surfaceCreated(SurfaceHolder surfaceHolder) { 391 | try { 392 | if (null == mCamera) { 393 | mCamera = Camera.open(); 394 | } 395 | mHandler.postDelayed(new Runnable() { 396 | @Override 397 | public void run() { 398 | if (!mIsStop) { 399 | autoFocus(); 400 | mHandler.postDelayed(this, 2500); 401 | } 402 | 403 | } 404 | }, 1000); 405 | } catch (Exception e) { 406 | Toast.makeText(App.getInstance(), "暂未获取到拍照权限", Toast.LENGTH_SHORT).show(); 407 | e.printStackTrace(); 408 | } 409 | } 410 | 411 | 412 | @Override 413 | public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { 414 | if (mCamera != null) { 415 | mParams = mCamera.getParameters(); 416 | mParams.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式 417 | //设置PreviewSize和PictureSize 418 | List pictureSizes = mParams.getSupportedPictureSizes(); 419 | Camera.Size size = getOptimalPictureSize(pictureSizes); 420 | if (size == null) { 421 | Toast.makeText(getApplication(), "相机出错,请尝试换一台手机!", Toast.LENGTH_SHORT).show(); 422 | } else { 423 | System.out.println("surfaceChanged picture size width=" + size.width + " height=" + size.height); 424 | mParams.setPictureSize(size.width, size.height); 425 | } 426 | if (mParams.getSupportedFocusModes().contains( 427 | mParams.FOCUS_MODE_AUTO)) { 428 | mParams.setFocusMode(mParams.FOCUS_MODE_AUTO); 429 | } 430 | Log.d("surfaceChanged", "widthPixels=" + dm.widthPixels + " heightPixels=" + dm.heightPixels); 431 | Camera.Size optimalPreviewSize = getOptimalPreviewSize(getActivity(), 432 | mParams.getSupportedPreviewSizes(), 433 | (float) dm.widthPixels / dm.heightPixels); 434 | mParams.setPreviewSize(optimalPreviewSize.width, 435 | optimalPreviewSize.height); 436 | try { 437 | mCamera.setPreviewDisplay(surfaceHolder); 438 | } catch (IOException e) { 439 | // TODO Auto-generated catch block 440 | e.printStackTrace(); 441 | } 442 | mCamera.setParameters(mParams); 443 | try { 444 | // mCamera.setParameters(mParams); 445 | } catch (Exception e) { 446 | e.printStackTrace(); 447 | } 448 | mCamera.startPreview(); 449 | Log.d(TAG, "mParams heightPixels=" + mParams.getPictureSize().height + " widthPixels=" + mParams.getPictureSize().width); 450 | } 451 | } 452 | 453 | @Override 454 | public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 455 | 456 | } 457 | } 458 | } 459 | -------------------------------------------------------------------------------- /app/src/main/java/org/itzheng/demo/rectanglecamera/MainActivity.java: -------------------------------------------------------------------------------- 1 | package org.itzheng.demo.rectanglecamera; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.text.TextUtils; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.ImageView; 13 | 14 | import java.io.FileInputStream; 15 | import java.io.FileNotFoundException; 16 | 17 | public class MainActivity extends AppCompatActivity { 18 | private static final String TAG = "MainActivity"; 19 | private static final int REQUEST_CODE = 0x0001; 20 | private ImageView imgMyPhoto; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | imgMyPhoto = (ImageView) findViewById(R.id.imgMyPhoto); 27 | setTitle("this is title"); 28 | } 29 | 30 | public void takePic(View view) { 31 | startActivityForResult(new Intent(this, CameraActivity.class), REQUEST_CODE); 32 | } 33 | 34 | @Override 35 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 36 | super.onActivityResult(requestCode, resultCode, data); 37 | if (REQUEST_CODE == requestCode && resultCode == Activity.RESULT_OK) { 38 | if (data == null) { 39 | Log.e(TAG, "onActivityResult: data == null"); 40 | } else { 41 | String imgPath = data.getStringExtra(CameraActivity.EXTRA_STR_FILE_PATH); 42 | if (TextUtils.isEmpty(imgPath)) { 43 | Log.e(TAG, "onActivityResult: imgPath is Empty"); 44 | } else 45 | imgMyPhoto.setImageBitmap(getLoacalBitmap(imgPath)); 46 | } 47 | } else { 48 | Log.e(TAG, "onActivityResult: request fail"); 49 | } 50 | } 51 | 52 | 53 | /** 54 | * 加载本地图片 55 | * 56 | * @param url 57 | * @return 58 | */ 59 | public static Bitmap getLoacalBitmap(String url) { 60 | try { 61 | FileInputStream fis = new FileInputStream(url); 62 | return BitmapFactory.decodeStream(fis); ///把流转化为Bitmap图片 63 | } catch (FileNotFoundException e) { 64 | e.printStackTrace(); 65 | return null; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/org/itzheng/demo/rectanglecamera/SensorController.java: -------------------------------------------------------------------------------- 1 | package org.itzheng.demo.rectanglecamera; 2 | 3 | import android.app.Activity; 4 | import android.hardware.Sensor; 5 | import android.hardware.SensorEvent; 6 | import android.hardware.SensorEventListener; 7 | import android.hardware.SensorManager; 8 | import android.util.Log; 9 | 10 | import java.util.Calendar; 11 | 12 | /** 13 | * 加速度控制器 用来控制对焦 14 | */ 15 | public class SensorController implements SensorEventListener { 16 | private static final String TAG = "SensorController"; 17 | public static final int DELAY_DURATION = 500; 18 | public static final int STATUS_NONE = 0; 19 | public static final int STATUS_STATIC = 1; 20 | public static final int STATUS_MOVE = 2; 21 | private static SensorController mInstance; 22 | private boolean isFocusing = false; 23 | private boolean canFocusIn = false; //内部是否能够对焦控制机制 24 | private boolean canFocus = false; 25 | private SensorManager mSensorManager; 26 | private Sensor mSensor; 27 | private int mX, mY, mZ; 28 | private long lastStaticStamp = 0; 29 | private int STATUE = STATUS_NONE; 30 | private CameraFocusListener mCameraFocusListener; 31 | private int focusing = 1; //1 表示没有被锁定 0表示被锁定 32 | 33 | private SensorController() { 34 | mSensorManager = (SensorManager) App.getInstance().getSystemService(Activity.SENSOR_SERVICE); 35 | if (mSensorManager != null) { 36 | mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// TYPE_GRAVITY 37 | } 38 | } 39 | 40 | public static SensorController getInstance() { 41 | if (mInstance == null) { 42 | mInstance = new SensorController(); 43 | } 44 | return mInstance; 45 | } 46 | 47 | public void setCameraFocusListener(CameraFocusListener mCameraFocusListener) { 48 | this.mCameraFocusListener = mCameraFocusListener; 49 | } 50 | 51 | // @Override 52 | public void onStart() { 53 | restParams(); 54 | canFocus = true; 55 | if (mSensor != null) { 56 | mSensorManager.registerListener(this, mSensor, 57 | SensorManager.SENSOR_DELAY_NORMAL); 58 | } else { 59 | throw new RuntimeException("sensor is a null object"); 60 | } 61 | } 62 | 63 | // @Override 64 | public void onStop() { 65 | if (mSensor != null) { 66 | mSensorManager.unregisterListener(this, mSensor); 67 | } else { 68 | throw new RuntimeException("sensor is a null object"); 69 | } 70 | canFocus = false; 71 | } 72 | 73 | @Override 74 | public void onAccuracyChanged(Sensor sensor, int accuracy) { 75 | Log.d(TAG, "onAccuracyChanged()"); 76 | } 77 | 78 | 79 | @Override 80 | public void onSensorChanged(SensorEvent event) { 81 | // Log.d(TAG, "onSensorChanged()"); 82 | if (event.sensor == null) { 83 | return; 84 | } 85 | 86 | if (isFocusing) { 87 | restParams(); 88 | return; 89 | } 90 | 91 | if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { 92 | int x = (int) event.values[0]; 93 | int y = (int) event.values[1]; 94 | int z = (int) event.values[2]; 95 | Calendar mCalendar = Calendar.getInstance(); 96 | long stamp = mCalendar.getTimeInMillis();// 1393844912 97 | 98 | int second = mCalendar.get(Calendar.SECOND);// 53 99 | 100 | if (STATUE != STATUS_NONE) { 101 | int px = Math.abs(mX - x); 102 | int py = Math.abs(mY - y); 103 | int pz = Math.abs(mZ - z); 104 | // Log.d(TAG, "pX:" + px + " pY:" + py + " pZ:" + pz + " stamp:" 105 | // + stamp + " second:" + second); 106 | double value = Math.sqrt(px * px + py * py + pz * pz); 107 | if (value > 1) { 108 | // textviewF.setText("检测手机在移动.."); 109 | // Log.i(TAG,"mobile moving"); 110 | STATUE = STATUS_MOVE; 111 | } else { 112 | // textviewF.setText("检测手机静止.."); 113 | // Log.i(TAG,"mobile static"); 114 | //上一次状态是move,记录静态时间点 115 | if (STATUE == STATUS_MOVE) { 116 | lastStaticStamp = stamp; 117 | canFocusIn = true; 118 | } 119 | 120 | if (canFocusIn) { 121 | if (stamp - lastStaticStamp > DELAY_DURATION) { 122 | //移动后静止一段时间,可以发生对焦行为 123 | if (!isFocusing) { 124 | canFocusIn = false; 125 | // onCameraFocus(); 126 | if (mCameraFocusListener != null) { 127 | mCameraFocusListener.onFocus(); 128 | } 129 | // Log.i(TAG,"mobile focusing"); 130 | } 131 | } 132 | } 133 | 134 | STATUE = STATUS_STATIC; 135 | } 136 | } else { 137 | lastStaticStamp = stamp; 138 | STATUE = STATUS_STATIC; 139 | } 140 | 141 | mX = x; 142 | mY = y; 143 | mZ = z; 144 | } 145 | } 146 | 147 | private void restParams() { 148 | STATUE = STATUS_NONE; 149 | canFocusIn = false; 150 | mX = 0; 151 | mY = 0; 152 | mZ = 0; 153 | } 154 | 155 | /** 156 | * 对焦是否被锁定 157 | * 158 | * @return 159 | */ 160 | public boolean isFocusLocked() { 161 | if (canFocus) { 162 | return focusing <= 0; 163 | } 164 | return false; 165 | } 166 | 167 | /** 168 | * 锁定对焦 169 | */ 170 | public void lockFocus() { 171 | isFocusing = true; 172 | focusing--; 173 | Log.i(TAG, "lockFocus"); 174 | } 175 | 176 | /** 177 | * 解锁对焦 178 | */ 179 | public void unlockFocus() { 180 | isFocusing = false; 181 | focusing++; 182 | Log.i(TAG, "unlockFocus"); 183 | } 184 | 185 | public void restFoucs() { 186 | focusing = 1; 187 | } 188 | 189 | public interface CameraFocusListener { 190 | void onFocus(); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rec_focus_shap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 17 | 18 | 23 | 24 | 28 | 29 | 34 | 35 | 40 | 41 | 47 | 48 | 53 | 54 |