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 @Override 24 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 @Override 32 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 @Override 40 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_GALLERY 55 startActivityForResult(intent, 112); 56 } 57 58 @Override 59 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 block 73 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 = 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 = 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 = 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 = 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.right 128 && ChooseArea.top + move_y >= dst.top && ChooseArea.bottom + move_y <= dst.bottom){ 129 ChooseArea.set(ChooseArea.left + move_x,ChooseArea.top+move_y 130 ,ChooseArea.right + move_x,ChooseArea.bottom+move_y); 131 }else{ 132 if(ChooseArea.left + move_x < dst.left){ 133 ChooseArea.set(dst.left,ChooseArea.top 134 ,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.top 138 ,dst.right,ChooseArea.bottom); 139 } 140 141 if(ChooseArea.top + move_y < dst.top){ 142 ChooseArea.set(ChooseArea.left,dst.top 143 ,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.bottom 148 ,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和bottom 269 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和top 299 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和top 329 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和bottom 360 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 //每次改变选择区域矩形的大小或者移动,各角落上的小矩形也要改变它的Location 390 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