AnyWrite/ATakePhoto.java
Retired DISLab
Preview로 내용을 보고 사진을 촬영하는 클래스이다. 그리고 DrawOnTop 클래스는 View 클래스로서 Preview 화면에 내용을 그려넣는 역할을 한다.
package hufs.dislab.anywrite; import hufs.dislab.util.ImageUtil; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Bitmap.CompressFormat; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.ShutterCallback; import android.hardware.Camera.Size; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.widget.Toast; /** * 사진을 촬영하는 액티비티이다. * 사진을 촬영한 다음 그 결과인 파일에 대한 노트를 설정하기 위하여 * AddPhotoActivity를 호출한다. * @author swpark * */ public class ATakePhoto extends Activity { //private static final String TAG = "AnyWrite Camera"; private Camera mCamera = null; private MySurfaceView mSurface = null; private DrawOnTop mDraw = null; private String mImageFile = null; private long mCurrentFolder; public static final int REQ_ADD_PHOTO = 1; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { //Log.i(TAG, "onCreate"); super.onCreate(savedInstanceState); Intent intent = getIntent(); mCurrentFolder = intent.getLongExtra(AMainList.PARENT, AMainList.NO_SELECTED); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); if (mSurface == null) { mSurface = new MySurfaceView(this); setContentView(mSurface); } if (mDraw == null) { mDraw = new DrawOnTop(this); addContentView(mDraw, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } if (mSurface != null) mSurface.setOnClickListener(listener); } @Override public void onBackPressed() { //Log.d(TAG, "onBackPressed"); if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mCamera = null; } Toast.makeText(ATakePhoto.this, R.string.canceled, Toast.LENGTH_SHORT) .show(); setResult(Activity.RESULT_CANCELED); finish(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { setResult(resultCode); finish(); } OnClickListener listener = new OnClickListener() { public void onClick(View v) { //Log.d(TAG, "TakePhotoActivity.OnClickListener.onClick"); try { mCamera.takePicture(shutterCallback, rawCallback, jpegCallback); } catch (NullPointerException e) { String error = getResources().getString(R.string.camera_error) + ": Null Pointer"; Toast.makeText(ATakePhoto.this, error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } } }; ShutterCallback shutterCallback = new ShutterCallback() { public void onShutter() { //Log.d(TAG, "TakePhotoActivity.ShutterCallback.onShutter"); } }; /** Handles data for raw picture */ PictureCallback rawCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { //Log.d(TAG, "rawCallback.PictureCallback.onPictureTaken"); } }; /** Handles data for jpeg picture */ PictureCallback jpegCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { //Log.d(TAG, "jpegCallback.PictureCallback.onPictureTaken"); FileOutputStream outStream = null; try { SharedPreferences pref = getSharedPreferences(Preferences.PREF_NAME, Activity.MODE_PRIVATE); String imageFolder = pref.getString(Preferences.IMAGE_FOLDER, Preferences.DEFAULT_IMAGE_FOLDER); String tempFile = Note.strGetCurrentTime(); tempFile = tempFile.replace(':', '.'); mImageFile = imageFolder + "/" + tempFile + ".jpg"; outStream = new FileOutputStream(mImageFile); outStream.write(data); outStream.close(); // Thumbnail을 만든다. Bitmap bitmap = ImageUtil.getThumbnail(ATakePhoto.this, mImageFile, AMainList.THUMBNAIL_SIZE); String thumnail = imageFolder + "/" + tempFile + ".thumb.jpg"; outStream = new FileOutputStream(thumnail); bitmap.compress(CompressFormat.JPEG, 50, outStream); outStream.flush(); outStream.close(); // 삽입하기 위하여 AddPhotoActivity를 띄운다. Intent intent = new Intent(ATakePhoto.this, AAddPhoto.class); intent.putExtra(AMainList.PARENT, mCurrentFolder); intent.putExtra(PNotes.KEY_IMAGE_PATH, mImageFile); startActivityForResult(intent, REQ_ADD_PHOTO); } catch (NullPointerException e) { String error = getResources().getString(R.string.camera_error) + ": Null Pointer"; Toast.makeText(ATakePhoto.this, error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } catch (FileNotFoundException e) { String error = getResources().getString(R.string.camera_error) + ": File not found"; Toast.makeText(ATakePhoto.this, error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } catch (IOException e) { String error = getResources().getString(R.string.camera_error) + ": IO"; Toast.makeText(ATakePhoto.this, error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } } }; /** * 사진을 찍기 위하여 등장하는 Preview를 핸들링하는 뷰이다. * @author swpark * */ class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; public MySurfaceView(Context context) { super(context); //Log.i(TAG, "MySurfaceView"); try { holder = getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } catch (NullPointerException e) { Toast.makeText(ATakePhoto.this, R.string.camera_error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } } @Override public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, acquire the camera and tell it where // to draw. //Log.i(TAG, "surfaceCreated"); try { mCamera = Camera.open(); mCamera.setPreviewDisplay(holder); } catch (NullPointerException e) { Toast.makeText(ATakePhoto.this, R.string.camera_error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } catch (IOException e) { mCamera.release(); mCamera = null; Toast.makeText(ATakePhoto.this, R.string.camera_error, Toast.LENGTH_SHORT).show(); setResult(Activity.RESULT_CANCELED); finish(); } } public void surfaceDestroyed(SurfaceHolder holder) { //Log.i(TAG, "surfaceDestroyed"); if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mCamera = null; } } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.05; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { //Log.i(TAG, "surfaceChanged"); if (mCamera != null) { Camera.Parameters parameters = mCamera.getParameters(); try { List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, width, height); parameters.setPreviewSize(optimalSize.width, optimalSize.height); mCamera.setParameters(parameters); mCamera.startPreview(); } catch (NullPointerException e) { Toast.makeText(ATakePhoto.this, R.string.camera_error, Toast.LENGTH_SHORT).show(); ATakePhoto.this.finish(); return; } } } } /** * Preview 화면에 오버레이를 하기 위하여 만든 뷰로서 단순히 화면 * 중앙에 클릭하라는 메시지를 출력한다. * @author swpark * */ class DrawOnTop extends View { public DrawOnTop(Context context) { super(context); //Log.i(TAG, "DrawOnTop"); } @Override protected void onDraw(Canvas canvas) { //Log.d(TAG, "draw"); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setShadowLayer(1, 1, 1, Color.YELLOW); paint.setAlpha(100); paint.setTextSize(25); String msg = getResources().getString(R.string.click_to_take_picture); Rect bounds = new Rect(); paint.getTextBounds(msg, 0, msg.length(), bounds); canvas.drawText( msg, canvas.getWidth() / 2 - bounds.right / 2, canvas.getHeight() / 2 - bounds.bottom / 2, paint); } } }