首页 > 代码库 > Android 相册图片选取+自定义裁剪方式(非系统裁剪)

Android 相册图片选取+自定义裁剪方式(非系统裁剪)

不多说,直接上代码(裁剪的代码摘自网络。)(项目可运行)

主要是系统自身的剪切方式在有些机型上会程序崩溃的问题。

 1 package com.jichun.activity; 2  3 import java.io.FileNotFoundException; 4  5 import com.jichun.view.CropCanvas; 6  7 import android.app.Activity; 8 import android.content.ContentResolver; 9 import android.content.Intent;10 import android.graphics.Bitmap;11 import android.graphics.BitmapFactory;12 import android.net.Uri;13 import android.os.Bundle;14 import android.view.View;15 import android.view.View.OnClickListener;16 import android.widget.ImageButton;17 import android.widget.ImageView;18 19 public class MainActivity extends Activity {20     private CropCanvas canvas = null;21     22     /** Called when the activity is first created. */23     @Override24     public void onCreate(Bundle savedInstanceState) {25         super.onCreate(savedInstanceState);26         setContentView(R.layout.main);27         //创建确定按钮28         ImageButton confirmBtn = (ImageButton) findViewById(R.id.confirm_button);29         confirmBtn.setOnClickListener(new OnClickListener() {30             31             @Override32             public void onClick(View view) {33                 confirmFunction();34             }35         });36         ImageButton exitBtn = (ImageButton) findViewById(R.id.exit_button);37         exitBtn.setOnClickListener(new OnClickListener() {38             39             @Override40             public void onClick(View view) {41                 exitFunction(view);42             }43         });44         this.gallery();45     }46     47     /*48      * 从相册获取49      */50     public void gallery() {51         // 激活系统图库,选择一张图片52         Intent intent = new Intent(Intent.ACTION_PICK);53         intent.setType("image/*");54         // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY55         startActivityForResult(intent, 112);56     }57     58     @Override59     protected void onActivityResult(int requestCode, int resultCode, Intent data) {60         super.onActivityResult(requestCode, resultCode, data);61         if (requestCode == 112) {62             // 从相册返回的数据63             if (data != null) {64                 // 得到图片的全路径65                 Uri uri = data.getData();66                 ContentResolver content_resolver = this.getContentResolver();67                 try {68                     Bitmap bmp = BitmapFactory.decodeStream(content_resolver.openInputStream(uri));69                     canvas = (CropCanvas)findViewById(R.id.myCanvas);70                     canvas.setBitmap(bmp);71                 } catch (FileNotFoundException e) {72                     // TODO Auto-generated catch block73                     e.printStackTrace();74                 }75             }76         }77         78     }79     80     public void confirmFunction(){81         canvas.setBitmap(canvas.getSubsetBitmap());82     }83     84     public void exitFunction(View view){85         this.finish();86     }87 }
  1 package com.jichun.view;  2   3 import android.content.Context;  4 import android.graphics.Bitmap;  5 import android.graphics.Canvas;  6 import android.graphics.Color;  7 import android.graphics.Matrix;  8 import android.graphics.Paint;  9 import android.graphics.Rect; 10 import android.graphics.RectF; 11 import android.graphics.Bitmap.Config; 12 import android.graphics.drawable.BitmapDrawable; 13 import android.util.AttributeSet; 14 import android.view.MotionEvent; 15 import android.widget.ImageView; 16  17 public class CropCanvas extends ImageView { 18  19     private final static int PRESS_LB = 0;//表示左下角矩形框 20     private final static int PRESS_LT = 1;//表示左上角矩形框 21     private final static int PRESS_RB = 2;//表示右下角矩形框 22     private final static int PRESS_RT = 3;//表示右上角矩形框 23  24     private Bitmap bitMap = null;                //原始图片 25     private RectF src = http://www.mamicode.com/null;                    //经过比例转换后的裁剪区域 26     private RectF dst = null;                    //图片显示区域(可被裁剪的区域大小) 27     private RectF ChooseArea = null;            //选择需要裁剪的区域                 28     private Paint mPaint = null;                //画笔 29     private Matrix matrix = null;                //矩阵 30      31     private int mx = 0;                            //存储触笔移动时,之前所在的触笔的x坐标 32     private int my = 0;                            //存储触笔移动时,之前所在的触笔的y坐标 33     private boolean touchFlag = false;            //触笔是否在屏幕之上 34     private boolean cutFlag = false;            //是否点击了menu上的裁剪按钮 35     private int recFlag = -1;                    //用来存储触笔点击了哪个小矩形框(改变选择区域大小的小矩形框) 36     private boolean firstFlag = false; 37      38     private RectF recLT = null;                    //左上角的小矩形框 39     private RectF recRT = null;                    //右上角的小矩形框 40     private RectF recLB = null;                    //左下角的小矩形框 41     private RectF recRB = null;                    //右下角的小矩形框 42     private static final int LEFT_AREA_ALPHA = 50 * 255 / 100; 43     private RectF leftRectL = null; 44     private RectF leftRectR = null; 45     private RectF leftRectT = null; 46     private RectF leftRectB = null; 47     private Paint leftAreaPaint = null; 48      49     public CropCanvas(Context context, AttributeSet attrs) { 50         super(context, attrs); 51         this.init(); 52     } 53      54     public CropCanvas(Context context) { 55         super(context); 56         this.init(); 57     }  58      59     public void init(){ 60         cutFlag = true; 61         recLT = new RectF(); 62         recLB = new RectF(); 63         recRT = new RectF(); 64         recRB = new RectF(); 65         dst = new RectF(); 66         mPaint = new Paint(); 67         mPaint.setColor(Color.RED); 68         mPaint.setStyle(Paint.Style.STROKE);      //将画笔的风格改为空心 69         mPaint.setStrokeWidth(2); 70         ChooseArea = new RectF(); 71         this.setPressRecLoc(); 72         src = http://www.mamicode.com/null; 73         firstFlag = true; 74          75         //选择框之外的灰色区域,分成四个矩形框 76          77         leftAreaPaint = new Paint(); 78         leftAreaPaint.setStyle(Paint.Style.FILL); 79         leftAreaPaint.setAlpha(CropCanvas.LEFT_AREA_ALPHA); 80     } 81      82     public void setBitmap(Bitmap bitmap){ 83         BitmapDrawable bd = new BitmapDrawable(bitmap); 84         src = http://www.mamicode.com/new RectF(0,0,bd.getIntrinsicWidth(),bd.getIntrinsicHeight()); 85         this.bitMap = bitmap.copy(Config.ARGB_8888, true); 86          87         this.setImageBitmap(bitMap); 88         leftRectB = new RectF(); 89         leftRectL = new RectF(); 90         leftRectR = new RectF(); 91         leftRectT = new RectF(); 92     } 93      94     public void imageScale(){ 95         matrix = this.getImageMatrix(); 96         matrix.mapRect(dst, src); 97         int padding = this.getPaddingBottom(); 98         dst.set(dst.left+padding,dst.top+padding,dst.right+padding,dst.bottom+padding); 99         ChooseArea = new RectF(dst.left+40,dst.top+40,dst.right-40,dst.bottom-40);100         this.setPressRecLoc();101         this.invalidate();102     }103     104     //裁剪出选择区域里的图片105     //之前要做比例转换,因为,你选择的区域是针对比例转换后的图片106     //所以要使用ChooseArea的数值做比例转换,然后,使用这些数值重新设置rec的大小107     public Bitmap getSubsetBitmap(){108         float ratioWidth = bitMap.getWidth()/(float)(dst.right-dst.left);109         float ratioHeight = bitMap.getHeight()/(float)(dst.bottom - dst.top);110         int left = (int)((ChooseArea.left - dst.left) * ratioWidth);111         int right = (int)(left + (ChooseArea.right - ChooseArea.left) * ratioWidth);112         int top = (int)((ChooseArea.top - dst.top) * ratioHeight);113         int bottom = (int)(top + (ChooseArea.bottom - ChooseArea.top) * ratioHeight);114         src = http://www.mamicode.com/new RectF(left,top,right,bottom);115         firstFlag = true;116         set_LeftArea_Alpha();117         return Bitmap.createBitmap(bitMap, left, top, right-left, bottom-top);118     }119     120     //获得ChooseArea对象121     public RectF getChooseArea(){122         return ChooseArea;123     }124     125     //移动选择区域,选择区域是不能从图片区域里移出去的126     public void moveChooseArea(int move_x,int move_y){127         if(ChooseArea.left + move_x >= dst.left && ChooseArea.right + move_x <= dst.right128         && ChooseArea.top + move_y >= dst.top && ChooseArea.bottom + move_y <= dst.bottom){129             ChooseArea.set(ChooseArea.left + move_x,ChooseArea.top+move_y130                     ,ChooseArea.right + move_x,ChooseArea.bottom+move_y);131         }else{132             if(ChooseArea.left + move_x < dst.left){133                 ChooseArea.set(dst.left,ChooseArea.top134                         ,ChooseArea.right+dst.left-ChooseArea.left,ChooseArea.bottom);135             }136             if(ChooseArea.right + move_x > dst.right){137                 ChooseArea.set(ChooseArea.left+dst.right-ChooseArea.right,ChooseArea.top138                         ,dst.right,ChooseArea.bottom);139             }140             141             if(ChooseArea.top + move_y < dst.top){142                 ChooseArea.set(ChooseArea.left,dst.top143                         ,ChooseArea.right,ChooseArea.bottom+dst.top-ChooseArea.top);144             }145             146             if(ChooseArea.bottom + move_y > dst.bottom){147                 ChooseArea.set(ChooseArea.left,ChooseArea.top+dst.bottom-ChooseArea.bottom148                         ,ChooseArea.right,dst.bottom);149             }150         }151         this.setPressRecLoc();152         mPaint.setColor(Color.GREEN);153         this.invalidate();154     }155     156     public boolean onTouchEvent(MotionEvent event){157         mPaint.setColor(Color.RED);158         159         //点击了裁剪按钮之后才会执行以下事件160         if(event.getAction() == MotionEvent.ACTION_DOWN && cutFlag){161             //System.out.println(event.getX() + "," + event.getY());162             //判断触笔是否在裁剪区域内,也就是ChooseArea内163             //如果是,整个区域随着鼠标移动而移动164             mx = (int)event.getX();165             my = (int)event.getY();166             if(this.judgeLocation(mx,my)){167                 touchFlag = true;168                 mPaint.setColor(Color.GREEN);169                 this.invalidate();170                 return true;171             }else{172                 //不在裁剪区域内,就判断触笔是否在改变区域大小的小矩形框之内173                 if(this.findPresseddst((int)event.getX(), (int)event.getY())){174                     touchFlag = true;175                     mPaint.setColor(Color.RED);176                     return true;177                 }178             }179         }180         181         if(event.getAction() == MotionEvent.ACTION_MOVE && touchFlag){182             //判断是否点击了哪个个小矩形框183             if(this.isOutOfArea((int)event.getX(), (int)event.getY())){184                 return true;185             }186             187             //如果选择区域大小跟图像大小一样时,就不能移动188             if(ChooseArea.left == dst.left && ChooseArea.top == dst.top &&189                ChooseArea.right == dst.right && ChooseArea.bottom == dst.bottom){190             }else{191                 this.moveChooseArea((int)event.getX() - mx, (int)event.getY() - my);192                 mx = (int)event.getX();193                 my = (int)event.getY();194             }195         }196         197         //触笔移出屏幕时,将一些变量设回初值198         if(event.getAction() == MotionEvent.ACTION_UP){199             recFlag = -1;200             this.invalidate();201             touchFlag = false;202         }203         204         return super.onTouchEvent(event);205     }206     207     208     209     //判断是否要超出图片区域,这个函数会调用下面四个press打头的函数210     //这个函数也会重绘整个画布,也就是选择区域会随着鼠标的移动改变211     private boolean isOutOfArea(int x,int y){212         switch(recFlag){213         case CropCanvas.PRESS_LB:214             this.pressLB(x - mx, y - my);215             break;216         case CropCanvas.PRESS_LT:217             this.pressLT(x - mx, y - my);218             break;219         case CropCanvas.PRESS_RB:220             this.pressRB(x - mx, y - my);221             break;222         case CropCanvas.PRESS_RT:223             this.pressRT(x - mx, y - my);224             break;225         default:return false;226         }227         mx = x;228         my = y;229         this.invalidate();230         return true;231     }232     233     //找到点击了哪个矩形框(改变选择区域大小的小矩形框)234     //这个是在MotionEvent.ACTION_DOWN这个动作时执行的235     //是为了在MotionEvent.ACTION_MOVE的时候,知道应该移动哪个小矩形框236     public boolean findPresseddst(int x,int y){237         boolean returnFlag = false;238         if(this.isInRect(x, y, recLB)){239             recFlag = CropCanvas.PRESS_LB;240             returnFlag = true;241         }else if(this.isInRect(x, y, recLT)){242             recFlag = CropCanvas.PRESS_LT;243             returnFlag = true;244         }else if(this.isInRect(x, y, recRB)){245             recFlag = CropCanvas.PRESS_RB;246             returnFlag = true;247         }else if(this.isInRect(x, y, recRT)){248             recFlag = CropCanvas.PRESS_RT;249             returnFlag = true;250         }251         252         return returnFlag;253     }254     255     public boolean isInRect(int x,int y,RectF rect){256         if(x >= rect.left -20 && x <= rect.right + 20 && y > rect.top - 20 && y < rect.bottom + 20){257             return true;258         }259         return false;260     }261     262     //点击角落矩形框改变选择区域大小时,不能超过图片所在的区域263     //下面以press打头的四个函数就是判断是否超出图片区域264     //如果超出了,就移动不了265     //不超出按照触笔移动的距离来移动小矩形框266     267     //pressLB是当点击左下角小矩形框改变大小时是否超出图片区域268     //如果超出就将left与bottom的值设为图片区域的left和bottom269     private void pressLB(int x,int y){270         float left = ChooseArea.left + x;271         float right = ChooseArea.right;272         float top = ChooseArea.top;273         float bottom = ChooseArea.bottom + y;274         if(left <= right - 30 && left >= dst.left && bottom <= dst.bottom && bottom >= top + 30){275                 ChooseArea.set(left,top,right,bottom);276         }else{277             if(left + x < dst.left){278                 left = dst.left;279             }280             281             if(bottom + y > dst.bottom){282                 bottom = dst.bottom;283             }284             285             if(ChooseArea.left + x > ChooseArea.right - 30){286                 left = ChooseArea.right - 30;287             }288             289             if(ChooseArea.bottom + y < ChooseArea.top + 30){290                 bottom = ChooseArea.top + 30;291             }292             ChooseArea.set(left,top,right,bottom);293         }294         this.setPressRecLoc();295     }296     297     //pressLT是当点击左上角小矩形框改变大小时是否超出图片区域298     //如果超出就将left与top的值设为图片区域的left和top299     private void pressLT(int x,int y){300         float left = ChooseArea.left + x;301         float right = ChooseArea.right;302         float top = ChooseArea.top + y;303         float bottom = ChooseArea.bottom;304         if(left <= right - 30 && left >= dst.left && top <= bottom - 30 && top >= dst.top){305             ChooseArea.set(left,top,right,bottom);306         }else{307             if(left < dst.left){308                 left = dst.left;309             }310             311             if(top < dst.top){312                 top = dst.top;313             }314             315             if(left > right - 30){316                 left = right - 30;317             }318             319             if(top > bottom - 30){320                 top = bottom - 30;321             }322             ChooseArea.set(left,top,right,bottom);323         }324         this.setPressRecLoc();325     }326     327     //pressRT是当点击右上角小矩形框改变大小时是否超出图片区域328     //如果超出就将right与top的值设为图片区域的right和top329     private void pressRT(int x,int y){330         float left = ChooseArea.left;331         float right = ChooseArea.right + x;332         float top = ChooseArea.top + y;333         float bottom = ChooseArea.bottom;334         335         if(right <= dst.right && right >= left + 30 && top <= bottom - 30 && top >= dst.top){336             ChooseArea.set(left,top,right,bottom);337         }else{338             if(right > dst.right){339                 right = dst.right;340             }341             342             if(top < dst.top){343                 top = dst.top;344             }345             346             if(right < left + 30){347                 right = left + 30;348             }349             350             if(top > bottom - 30){351                 top = bottom - 30;352             }353             ChooseArea.set(left,top,right,bottom);354         }355         this.setPressRecLoc();356     }357     358     //pressRB是当点击右下角小矩形框改变大小时是否超出图片区域359     //如果超出就将right与bottom的值设为图片区域的right和bottom360     private void pressRB(int x,int y){361         float left = ChooseArea.left;362         float right = ChooseArea.right + x;363         float top = ChooseArea.top;364         float bottom = ChooseArea.bottom + y;365         366         if(right<= dst.right && right >= left + 30 && bottom <= dst.bottom && bottom >= top + 30){367             ChooseArea.set(left,top,right,bottom);368         }else{369             if(right > dst.right){370                 right = dst.right;371             }372             373             if(bottom > dst.bottom){374                 bottom = dst.bottom;375             }376             377             if(right < left + 30){378                 right = left + 30;379             }380             381             if(bottom < top + 30){382                 bottom = top + 30;383             }384             ChooseArea.set(left,top,right,bottom);385         }386         this.setPressRecLoc();387     }388     389     //每次改变选择区域矩形的大小或者移动,各角落上的小矩形也要改变它的Location390     private void setPressRecLoc(){391         recLT.set(ChooseArea.left-8,ChooseArea.top-8 , ChooseArea.left+8, ChooseArea.top+8);392         recLB.set(ChooseArea.left-8,ChooseArea.bottom-8 , ChooseArea.left+8, ChooseArea.bottom+8);393         recRT.set(ChooseArea.right-8,ChooseArea.top-8 , ChooseArea.right+8, ChooseArea.top+8);394         recRB.set(ChooseArea.right-8,ChooseArea.bottom-8 , ChooseArea.right+8, ChooseArea.bottom+8);395     }396     397     //判断触笔是否在选择区域内398     public boolean judgeLocation(float x,float y){399         float start_x = this.getChooseArea().left;400         float start_y = this.getChooseArea().top;401         float last_x = this.getChooseArea().right;402         float last_y = this.getChooseArea().bottom;403         //System.out.println("chubi:" + x + "," + y);404         //System.out.println(start_y + "," + last_y);405         if(x > start_x+10 && x < last_x-10 && y > start_y+10 && y < last_y-10){406             return true;407         }408         return false;409     }410     411     public void onDraw(Canvas canvas){412         super.onDraw(canvas);413         if(firstFlag){414             this.imageScale();415             firstFlag = false;416             mPaint.setColor(Color.RED);417             System.out.println("Width: " + (dst.right - dst.left));418             System.out.println("Height: " + (dst.bottom - dst.top));419             System.out.println("Width: " + this.getDrawable().getIntrinsicWidth());420             System.out.println("Height: " + this.getDrawable().getIntrinsicHeight());421         }else{422             set_LeftArea_Alpha();423         }424         canvas.drawRect(ChooseArea, mPaint);425         mPaint.setColor(Color.BLUE);426         canvas.drawRect(recLT, mPaint);427         canvas.drawRect(recLB, mPaint);428         canvas.drawRect(recRT, mPaint);   429         canvas.drawRect(recRB, mPaint);430         431         canvas.drawRect(leftRectL, leftAreaPaint);432         canvas.drawRect(leftRectR, leftAreaPaint);433         canvas.drawRect(leftRectT, leftAreaPaint);434         canvas.drawRect(leftRectB, leftAreaPaint);435         436     }437     438     public void set_LeftArea_Alpha(){439         leftRectL.set(dst.left, dst.top, ChooseArea.left, dst.bottom);440         leftRectR.set(ChooseArea.right,dst.top,dst.right,dst.bottom);441         leftRectT.set(ChooseArea.left, dst.top, ChooseArea.right, ChooseArea.top);442         leftRectB.set(ChooseArea.left,ChooseArea.bottom,ChooseArea.right,dst.bottom);443     } 444 }
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/layout"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="150px"        android:layout_alignParentTop="true"        android:layout_weight="1"        android:background="#191919"        android:orientation="horizontal" >    </LinearLayout>    <com.jichun.view.CropCanvas        android:id="@+id/myCanvas"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:layout_marginBottom="5px"        android:layout_marginTop="5px"        android:layout_weight="1"        android:background="#313131"        android:padding="2dip" >    </com.jichun.view.CropCanvas>    <RelativeLayout        android:layout_width="fill_parent"        android:layout_height="150px"        android:layout_weight="1"        android:background="#191919" >        <ImageButton            android:id="@+id/confirm_button"            android:layout_width="70px"            android:layout_height="fill_parent"            android:layout_alignParentRight="true"            android:background="#00000000"            android:src="@drawable/confirmxml" >        </ImageButton>        <ImageButton             android:id="@+id/exit_button"            android:layout_width="70px"            android:layout_height="fill_parent"            android:layout_alignParentLeft="true"            android:background="#00000000"            android:src="@drawable/exitxml" >        </ImageButton>    </RelativeLayout></LinearLayout>
 1 <?xml version="1.0" encoding="utf-8" ?>  2 <selector xmlns:android="http://schemas.android.com/apk/res/android">  3     <item android:state_window_focused="false"  4         android:drawable="@drawable/confirm" />  5  6     <item android:state_focused="true" android:state_pressed="true"  7         android:drawable="@drawable/confirm_focus"  />  8     <item android:state_focused="false" android:state_pressed="true"  9         android:drawable="@drawable/confirm_focus" /> 10 11     <item android:state_focused="true" 12         android:drawable="@drawable/confirm_focus" /> 13 </selector> 

完整项目下载链接:http://pan.baidu.com/s/1c08a4Re