Android实现图片的裁剪(不调用系统功能)

            接上一篇文章:http://blog.csdn.net/kiritor/article/details/8926336

            上一篇文章提及了通过调用系统相册或拍照来实现图片的缩放\裁剪。不过这对于笔者项目的

         要求同样不适合,笔者需要的是通过对手机屏幕整个进行一个截图,并对这个截图进行裁剪操作。

         依靠系统功能确实可以实现图片的裁剪,但是不够灵活。这里笔者提供一种较为灵活的做法。

         但是这种做法的用户体验没有上篇文章的好,至于使用何种方法,读者应该自己衡量。

            同样,我们先看实际效果图。

              这里展示的是笔者项目的一小部分(阅读器):

             

           我们点击左下角的剪切按钮

             

            我们通过红色边框的四个角来控制裁剪的大小,移动红色框体来控制裁剪的位置区域。

             接下来我们看看源码的实现:

             首先点击剪切按钮的时候,我们应该生成一个Bitmap对象,传递给另一个Activty处理

             具体做法如下:  

cutP.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				//将一些按钮隐藏
				cutP.setVisibility(View.INVISIBLE);
				mTopBarSwitcher.setVisibility(View.INVISIBLE);
				mPageSlider.setVisibility(View.INVISIBLE);
				back.setVisibility(View.INVISIBLE);
				mPageNumberView.setVisibility(View.INVISIBLE);
				View view = MuPDFActivity.this.getWindow().getDecorView();
				if (false == view.isDrawingCacheEnabled()) {
					view.setDrawingCacheEnabled(true);
				}
				Bitmap bitmap = view.getDrawingCache();
				ImageView imgv = new ImageView(MuPDFActivity.this);
				imgv.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
						LayoutParams.FILL_PARENT-200));
				imgv.setImageBitmap(bitmap);
				backBitmap = bitmap;
				//传递给另一个Activity进行裁剪
				Intent intent = new Intent();
				intent.setClass(MuPDFActivity.this, CutActivity.class);
				startActivity(intent);

			}
			
		});
             Tips:这里笔者是将这个截取的Bitmap对象传递给另一个Actvity做相关处理,这里如何

         在Activity之间进行Bitmap传递呢?这里我们简单的运用java语法特性来完成具体做法如下:

             我们在ActvityA中有一个public static Bitmap bitmap对象,当ActivityA跳转到B时,我们直接

         通过ActivityA.bitmap来获取这个对象。

             之后就是如何进行裁剪的操作了。操作在另一个Activity中进行。XML配置文件信息如下:  

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
  <com.artifex.mupdf.Crop_Canvas
  		android:id="@+id/myCanvas"
  		android:layout_width="fill_parent"
  		android:layout_height="fill_parent"
	    android:background="#313131"
	    />
    <Button 
        android:id="@+id/cutCancel"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="取消"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"/>
    <Button 
        android:id="@+id/cutEnsure"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="确定"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"/>
    <Button 
        android:id="@+id/toPDF"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ToPDF"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"/>
</RelativeLayout>
             通过配置文件可以看到我们自定义了一个View(ImageView)其实现如下:
package com.artifex.mupdf;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

public class Crop_Canvas extends ImageView {

	private final static int PRESS_LB = 0;//表示左下角矩形框
	private final static int PRESS_LT = 1;//表示左上角矩形框
	private final static int PRESS_RB = 2;//表示右下角矩形框
	private final static int PRESS_RT = 3;//表示右上角矩形框

	private Bitmap bitMap = null;				//原始图片
	private RectF src = null;					//经过比例转换后的裁剪区域
	private RectF dst = null;					//图片显示区域,也就是drawBitmap函数中的目标dst
	private RectF ChooseArea = null;				//选择区域				
	private Paint mPaint = null;				//画笔
	private Matrix matrix = null;				//矩阵
	
	private int mx = 0;							//存储触笔移动时,之前�?��的触笔的x坐标
	private int my = 0;							//存储触笔移动时,之前�?��的触笔的y坐标
	private boolean touchFlag = false;			//触笔是否在屏幕之�?
	private boolean cutFlag = false;			//是否点击了menu上的裁剪按钮
	private int recFlag = -1;					//用来存储触笔点击了哪个小矩形框(改变选择区域大小的小矩形框)
	private boolean firstFlag = false;
	
	private RectF recLT = null;					//左上角的小矩形框
	private RectF recRT = null;					//右上角的小矩形框
	private RectF recLB = null;					//左下角的小矩形框
	private RectF recRB = null;					//右下角的小矩形框
	private static final int LEFT_AREA_ALPHA = 50 * 255 / 100;
	private RectF leftRectL = null;
	private RectF leftRectR = null;
	private RectF leftRectT = null;
	private RectF leftRectB = null;
	private Paint leftAreaPaint = null;
	
	public Crop_Canvas(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.init();
	}
	
	public Crop_Canvas(Context context) {
		super(context);
		this.init();
	} 
	
	public void init(){
		cutFlag = true;
		recLT = new RectF();
		recLB = new RectF();
		recRT = new RectF();
		recRB = new RectF();
		dst = new RectF();
		mPaint = new Paint();
		mPaint.setColor(Color.RED);
		mPaint.setStyle(Paint.Style.STROKE);      //将画笔的风格改为空心
		ChooseArea = new RectF();
		this.setPressRecLoc();
		src = null;
		firstFlag = true;
		
		//选择框之外的灰色区域,分成四个矩形框
		
		leftAreaPaint = new Paint();
		leftAreaPaint.setStyle(Paint.Style.FILL);
		leftAreaPaint.setAlpha(Crop_Canvas.LEFT_AREA_ALPHA);
	}
	
	public void setBitmap(Bitmap bitmap){
		BitmapDrawable bd = new BitmapDrawable(bitmap);
		src = new RectF(0,0,bd.getIntrinsicWidth(),bd.getIntrinsicHeight());
		this.bitMap = bitmap.copy(Config.ARGB_8888, true);
		
		this.setImageBitmap(bitMap);
		leftRectB = new RectF();
		leftRectL = new RectF();
		leftRectR = new RectF();
		leftRectT = new RectF();
	}
	
	public void imageScale(){
		matrix = this.getImageMatrix();
		matrix.mapRect(dst, src);
		int padding = this.getPaddingBottom();
		int width = bitMap.getWidth();
		int height = bitMap.getHeight();
		//dst.set(dst.left+padding,dst.top+padding,dst.right+padding,dst.bottom+padding);
		dst.set(dst.left+20,dst.top+20,width-20,height - 40);
		ChooseArea = new RectF(dst);
		this.setPressRecLoc();
	}
	
	public Bitmap getSubsetBitmap(){
		float ratioWidth = bitMap.getWidth()/(float)(dst.right-dst.left);
		float ratioHeight = bitMap.getHeight()/(float)(dst.bottom - dst.top);
		int left = (int)((ChooseArea.left - dst.left) * ratioWidth);
		int right = (int)(left + (ChooseArea.right - ChooseArea.left) * ratioWidth);
		int top = (int)((ChooseArea.top - dst.top) * ratioHeight);
		int bottom = (int)(top + (ChooseArea.bottom - ChooseArea.top) * ratioHeight);
		src = new RectF(left,top,right,bottom);
		firstFlag = true;
		set_LeftArea_Alpha();
		return Bitmap.createBitmap(bitMap, left, top, right-left, bottom-top);
	}
	
	//获得ChooseArea对象
	public RectF getChooseArea(){
		return ChooseArea;
	}
	
	public void moveChooseArea(int move_x,int move_y){
		if(ChooseArea.left + move_x >= dst.left && ChooseArea.right + move_x <= dst.right
		&& ChooseArea.top + move_y >= dst.top && ChooseArea.bottom + move_y <= dst.bottom){
			ChooseArea.set(ChooseArea.left + move_x,ChooseArea.top+move_y
					,ChooseArea.right + move_x,ChooseArea.bottom+move_y);
		}else{
			if(ChooseArea.left + move_x < dst.left){
				ChooseArea.set(dst.left,ChooseArea.top
						,ChooseArea.right+dst.left-ChooseArea.left,ChooseArea.bottom);
			}
			if(ChooseArea.right + move_x > dst.right){
				ChooseArea.set(ChooseArea.left+dst.right-ChooseArea.right,ChooseArea.top
						,dst.right,ChooseArea.bottom);
			}
			
			if(ChooseArea.top + move_y < dst.top){
				ChooseArea.set(ChooseArea.left,dst.top
						,ChooseArea.right,ChooseArea.bottom+dst.top-ChooseArea.top);
			}
			
			if(ChooseArea.bottom + move_y > dst.bottom){
				ChooseArea.set(ChooseArea.left,ChooseArea.top+dst.bottom-ChooseArea.bottom
						,ChooseArea.right,dst.bottom);
			}
		}
		this.setPressRecLoc();
		mPaint.setColor(Color.GREEN);
		this.invalidate();
	}
	
	public boolean onTouchEvent(MotionEvent event){
		mPaint.setColor(Color.RED);
		
		
    	if(event.getAction() == MotionEvent.ACTION_DOWN && cutFlag){
    		//System.out.println(event.getX() + "," + event.getY());
    		
    		mx = (int)event.getX();
			my = (int)event.getY();
    		if(this.judgeLocation(mx,my)){
    			touchFlag = true;
    			mPaint.setColor(Color.GREEN);
    			this.invalidate();
    			return true;
    		}else{
    		
    			if(this.findPresseddst((int)event.getX(), (int)event.getY())){
	    			touchFlag = true;
	    			mPaint.setColor(Color.RED);
	    			return true;
    			}
    		}
    	}
    	
    	if(event.getAction() == MotionEvent.ACTION_MOVE && touchFlag){
    		//判断是否点击了哪个个小矩形框
    		if(this.isOutOfArea((int)event.getX(), (int)event.getY())){
    			return true;
    		}
    		
    		//如果选择区域大小跟图像大小一样时,就不能移动
    		if(ChooseArea.left == dst.left && ChooseArea.top == dst.top &&
    		   ChooseArea.right == dst.right && ChooseArea.bottom == dst.bottom){
    		}else{
    			this.moveChooseArea((int)event.getX() - mx, (int)event.getY() - my);
    			mx = (int)event.getX();
    			my = (int)event.getY();
    		}
    	}
    	
    	
    	if(event.getAction() == MotionEvent.ACTION_UP){
    		recFlag = -1;
    		this.invalidate();
    		touchFlag = false;
    	}
    	
    	return super.onTouchEvent(event);
    }
	
	
	
	
	private boolean isOutOfArea(int x,int y){
		switch(recFlag){
		case Crop_Canvas.PRESS_LB:
			this.pressLB(x - mx, y - my);
			break;
		case Crop_Canvas.PRESS_LT:
			this.pressLT(x - mx, y - my);
			break;
		case Crop_Canvas.PRESS_RB:
			this.pressRB(x - mx, y - my);
			break;
		case Crop_Canvas.PRESS_RT:
			this.pressRT(x - mx, y - my);
			break;
		default:return false;
		}
		mx = x;
		my = y;
		this.invalidate();
		return true;
	}
	
	public boolean findPresseddst(int x,int y){
		boolean returnFlag = false;
		if(this.isInRect(x, y, recLB)){
			recFlag = Crop_Canvas.PRESS_LB;
			returnFlag = true;
		}else if(this.isInRect(x, y, recLT)){
			recFlag = Crop_Canvas.PRESS_LT;
			returnFlag = true;
		}else if(this.isInRect(x, y, recRB)){
			recFlag = Crop_Canvas.PRESS_RB;
			returnFlag = true;
		}else if(this.isInRect(x, y, recRT)){
			recFlag = Crop_Canvas.PRESS_RT;
			returnFlag = true;
		}
		
		return returnFlag;
	}
	
	public boolean isInRect(int x,int y,RectF rect){
		if(x >= rect.left -20 && x <= rect.right + 20 && y > rect.top - 20 && y < rect.bottom + 20){
			return true;
		}
		return false;
	}
	
	private void pressLB(int x,int y){
		float left = ChooseArea.left + x;
		float right = ChooseArea.right;
		float top = ChooseArea.top;
		float bottom = ChooseArea.bottom + y;
		if(left <= right - 30 && left >= dst.left && bottom <= dst.bottom && bottom >= top + 30){
				ChooseArea.set(left,top,right,bottom);
		}else{
			if(left + x < dst.left){
				left = dst.left;
			}
			
			if(bottom + y > dst.bottom){
				bottom = dst.bottom;
			}
			
			if(ChooseArea.left + x > ChooseArea.right - 30){
				left = ChooseArea.right - 30;
			}
			
			if(ChooseArea.bottom + y < ChooseArea.top + 30){
				bottom = ChooseArea.top + 30;
			}
			ChooseArea.set(left,top,right,bottom);
		}
		this.setPressRecLoc();
	}
	
	
	private void pressLT(int x,int y){
		float left = ChooseArea.left + x;
		float right = ChooseArea.right;
		float top = ChooseArea.top + y;
		float bottom = ChooseArea.bottom;
		if(left <= right - 30 && left >= dst.left && top <= bottom - 30 && top >= dst.top){
			ChooseArea.set(left,top,right,bottom);
		}else{
			if(left < dst.left){
				left = dst.left;
			}
			
			if(top < dst.top){
				top = dst.top;
			}
			
			if(left > right - 30){
				left = right - 30;
			}
			
			if(top > bottom - 30){
				top = bottom - 30;
			}
			ChooseArea.set(left,top,right,bottom);
		}
		this.setPressRecLoc();
	}
	
	
	private void pressRT(int x,int y){
		float left = ChooseArea.left;
		float right = ChooseArea.right + x;
		float top = ChooseArea.top + y;
		float bottom = ChooseArea.bottom;
		
		if(right <= dst.right && right >= left + 30 && top <= bottom - 30 && top >= dst.top){
			ChooseArea.set(left,top,right,bottom);
		}else{
			if(right > dst.right){
				right = dst.right;
			}
			
			if(top < dst.top){
				top = dst.top;
			}
			
			if(right < left + 30){
				right = left + 30;
			}
			
			if(top > bottom - 30){
				top = bottom - 30;
			}
			ChooseArea.set(left,top,right,bottom);
		}
		this.setPressRecLoc();
	}
	
	
	private void pressRB(int x,int y){
		float left = ChooseArea.left;
		float right = ChooseArea.right + x;
		float top = ChooseArea.top;
		float bottom = ChooseArea.bottom + y;
		
		if(right<= dst.right && right >= left + 30 && bottom <= dst.bottom && bottom >= top + 30){
			ChooseArea.set(left,top,right,bottom);
		}else{
			if(right > dst.right){
				right = dst.right;
			}
			
			if(bottom > dst.bottom){
				bottom = dst.bottom;
			}
			
			if(right < left + 30){
				right = left + 30;
			}
			
			if(bottom < top + 30){
				bottom = top + 30;
			}
			ChooseArea.set(left,top,right,bottom);
		}
		this.setPressRecLoc();
	}
	
	//每次改变选择区域矩形的大小或者移动,各角落上的小矩形也要改变它的Location
	private void setPressRecLoc(){
		recLT.set(ChooseArea.left-5,ChooseArea.top-5 , ChooseArea.left+5, ChooseArea.top+5);
		recLB.set(ChooseArea.left-5,ChooseArea.bottom-5 , ChooseArea.left+5, ChooseArea.bottom+5);
		recRT.set(ChooseArea.right-5,ChooseArea.top-5 , ChooseArea.right+5, ChooseArea.top+5);
		recRB.set(ChooseArea.right-5,ChooseArea.bottom-5 , ChooseArea.right+5, ChooseArea.bottom+5);
	}
	

	public boolean judgeLocation(float x,float y){
    	float start_x = this.getChooseArea().left;
    	float start_y = this.getChooseArea().top;
    	float last_x = this.getChooseArea().right;
    	float last_y = this.getChooseArea().bottom;
    	//System.out.println("chubi:" + x + "," + y);
    	//System.out.println(start_y + "," + last_y);
    	if(x > start_x+10 && x < last_x-10 && y > start_y+10 && y < last_y-10){
    		return true;
    	}
    	return false;
    }
	
	public void onDraw(Canvas canvas){
		super.onDraw(canvas);
		if(firstFlag){
			this.imageScale();
			firstFlag = false;
			mPaint.setColor(Color.RED);
			System.out.println("Width: " + (dst.right - dst.left));
			System.out.println("Height: " + (dst.bottom - dst.top));
			System.out.println("Width: " + this.getDrawable().getIntrinsicWidth());
			System.out.println("Height: " + this.getDrawable().getIntrinsicHeight());
		}else{
			set_LeftArea_Alpha();
		}
		canvas.drawRect(ChooseArea, mPaint);
		mPaint.setColor(Color.BLUE);
		canvas.drawRect(recLT, mPaint);
		canvas.drawRect(recLB, mPaint);
		canvas.drawRect(recRT, mPaint);   
		canvas.drawRect(recRB, mPaint);
		
		canvas.drawRect(leftRectL, leftAreaPaint);
		canvas.drawRect(leftRectR, leftAreaPaint);
		canvas.drawRect(leftRectT, leftAreaPaint);
		canvas.drawRect(leftRectB, leftAreaPaint);
		
	}
	
	public void set_LeftArea_Alpha(){
		leftRectL.set(dst.left, dst.top, ChooseArea.left, dst.bottom);
		leftRectR.set(ChooseArea.right,dst.top,dst.right,dst.bottom);
		leftRectT.set(ChooseArea.left, dst.top, ChooseArea.right, ChooseArea.top);
		leftRectB.set(ChooseArea.left,ChooseArea.bottom,ChooseArea.right,dst.bottom);
	} 
}
          接下来直接看看Activity源码:
package com.artifex.mupdf.cut;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

import com.andorid.shu.love.R;
import com.artifex.mupdf.Crop_Canvas;
import com.artifex.mupdf.MuPDFActivity;

public class CutActivity extends Activity {
	private Crop_Canvas canvas = null;
	private Bitmap backBitmap;
	private Button cancel;
	private Button ensure;
	private Button toPDF;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.cut_image);
		backBitmap = MuPDFActivity.backBitmap;
		init();
		cancel = (Button) findViewById(R.id.cutCancel);
		cancel.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				CutActivity.this.finish();
			}
		});
		ensure = (Button) findViewById(R.id.cutEnsure);
		ensure.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				//图片保存的路径,之后将之转换为PDF,并以附件的形似发送邮件
				File tmp = new File("/sdcard/lovereader/pic");
				tmp.mkdirs();
				File f = new File("/sdcard/lovereader/pic/" + "testpic" + ".png");
		        try {
					f.createNewFile();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
		        FileOutputStream fOut = null;
		        try {
		                fOut = new FileOutputStream(f);
		        } catch (FileNotFoundException e) {
		                e.printStackTrace();
		        }
		        canvas.getSubsetBitmap().compress(Bitmap.CompressFormat.PNG, 100, fOut);
		        try {
		                fOut.flush();
		        } catch (IOException e) {
		                e.printStackTrace();
		        }
		        try {
		                fOut.close();
		        } catch (IOException e) {
		                e.printStackTrace();
		        }
			}
		});
		
		toPDF = (Button)findViewById(R.id.toPDF);
		toPDF.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				ArrayList<String> imageUrllist = new ArrayList<String>();
				imageUrllist.add("/sdcard/lovereader/pic/" + "testpic" + ".png");
				String pdfUrl = "/sdcard/lovereader/tmp/Foreverlove.pdf";
				File tmp = new File("/sdcard/lovereader/tmp");
				tmp.mkdirs();
				File file = PdfManager.Pdf(imageUrllist, pdfUrl);
				try {
					file.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		});
	}

	private void init() {
		canvas = (Crop_Canvas) findViewById(R.id.myCanvas);
		Bitmap bitmap = backBitmap;
		canvas.setBitmap(bitmap);
	}

}
              ok,不依靠系统的简单裁剪功能就实现了,这里笔者就不给出源代码下载了,

         上述代码读者只要自己改改就可以用了。


  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 46
    评论
实现拍照并裁剪图片功能需要以下步骤: 1. 添加权限 在AndroidManifest.xml文件中添加以下权限: ```xml <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ``` 2. 创建布局文件 创建一个布局文件camera_preview.xml,并添加一个SurfaceView和一个Button,用于显示和拍照。 ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/camera_preview" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/button_capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="拍照" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"/> </RelativeLayout> ``` 3. 实现拍照功能 在Activity中,获取Camera实例,并在SurfaceView上显示预览图像。当用户点击拍照按钮时,调用Camera.takePicture()方法拍照。拍照成功后,保存照片并显示裁剪界面。 ```java public class CameraActivity extends Activity implements SurfaceHolder.Callback { private Camera mCamera; private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private Button mButtonCapture; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera_preview); // 获取SurfaceView和Button实例 mSurfaceView = findViewById(R.id.surface_view); mButtonCapture = findViewById(R.id.button_capture); // 监听Button点击事件 mButtonCapture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 拍照 mCamera.takePicture(null, null, mPictureCallback); } }); // 获取SurfaceHolder实例,并添加回调监听 mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { // 打开摄像头并设置预览 mCamera = Camera.open(); try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d("CameraTest", "Error setting camera preview: " + e.getMessage()); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 在SurfaceView上显示预览图像 if (mSurfaceHolder.getSurface() == null) { return; } try { mCamera.stopPreview(); } catch (Exception e) { Log.d("CameraTest", "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); } catch (Exception e) { Log.d("CameraTest", "Error starting camera preview: " + e.getMessage()); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 释放摄像头资源 mCamera.stopPreview(); mCamera.release(); mCamera = null; } private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { // 保存照片 File pictureFile = getOutputMediaFile(); if (pictureFile == null) { Log.d("CameraTest", "Error creating media file, check storage permissions"); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d("CameraTest", "File not found: " + e.getMessage()); } catch (IOException e) { Log.d("CameraTest", "Error accessing file: " + e.getMessage()); } // 显示裁剪界面 Intent intent = new Intent(CameraActivity.this, CropActivity.class); intent.putExtra("image_path", pictureFile.getPath()); startActivity(intent); } }; private File getOutputMediaFile() { // 创建目录 File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("CameraTest", "failed to create directory"); return null; } } // 创建文件 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); return mediaFile; } } ``` 4. 实现裁剪功能 创建一个布局文件crop.xml,添加一个ImageView和一个Button,用于显示图片和保存裁剪后的图片。 ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/crop_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter"/> <Button android:id="@+id/button_save" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保存" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"/> </RelativeLayout> ``` 在CropActivity中,获取传递过来的图片路径,并将图片显示在ImageView上。当用户点击保存按钮时,调用Bitmap.createBitmap()方法裁剪图片,并保存到相册。 ```java public class CropActivity extends Activity { private ImageView mImageView; private Button mButtonSave; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.crop); // 获取ImageView和Button实例 mImageView = findViewById(R.id.image_view); mButtonSave = findViewById(R.id.button_save); // 获取传递过来的图片路径 Intent intent = getIntent(); String imagePath = intent.getStringExtra("image_path"); // 将图片显示在ImageView上 Bitmap bitmap = BitmapFactory.decodeFile(imagePath); mImageView.setImageBitmap(bitmap); // 监听Button点击事件 mButtonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 裁剪并保存图片 Bitmap croppedBitmap = getCroppedBitmap(bitmap); saveBitmapToGallery(croppedBitmap); Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show(); finish(); } }); } private Bitmap getCroppedBitmap(Bitmap bitmap) { // 获取ImageView的尺寸 int viewWidth = mImageView.getWidth(); int viewHeight = mImageView.getHeight(); // 获取图片的尺寸 int imageWidth = bitmap.getWidth(); int imageHeight = bitmap.getHeight(); // 计算缩放比例 float scale = Math.min((float) viewWidth / imageWidth, (float) viewHeight / imageHeight); // 计算裁剪区域 int cropWidth = (int) (viewWidth / scale); int cropHeight = (int) (viewHeight / scale); int x = (imageWidth - cropWidth) / 2; int y = (imageHeight - cropHeight) / 2; // 裁剪图片 Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, x, y, cropWidth, cropHeight); return croppedBitmap; } private void saveBitmapToGallery(Bitmap bitmap) { // 创建目录 File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("CameraTest", "failed to create directory"); return; } } // 保存图片 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imagePath = mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"; File imageFile = new File(imagePath); try { FileOutputStream fos = new FileOutputStream(imageFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.flush(); fos.close(); } catch (IOException e) { Log.d("CameraTest", "Error accessing file: " + e.getMessage()); } // 通知相册更新 MediaScannerConnection.scanFile(this, new String[]{imagePath}, null, null); } } ```
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值