Android實現(xiàn)圖片的裁剪(不調用系統(tǒng)功能)
接上一篇文章:Android實現(xiàn)圖片區(qū)域裁剪功能
上一篇文章提及了通過調用系統(tǒng)相冊或拍照來實現(xiàn)圖片的縮放\裁剪。不過這對于筆者項目的要求同樣不適合,筆者需要的是通過對手機屏幕整個進行一個截圖,并對這個截圖進行裁剪操作。
依靠系統(tǒng)功能確實可以實現(xiàn)圖片的裁剪,但是不夠靈活。這里筆者提供一種較為靈活的做法。
但是這種做法的用戶體驗沒有上篇文章的好,至于使用何種方法,讀者應該自己衡量。
同樣,我們先看實際效果圖。
這里展示的是筆者項目的一小部分(閱讀器):

我們點擊左下角的剪切按鈕

我們通過紅色邊框的四個角來控制裁剪的大小,移動紅色框體來控制裁剪的位置區(qū)域。
接下來我們看看源碼的實現(xiàn):
首先點擊剪切按鈕的時候,我們應該生成一個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)其實現(xiàn)如下:
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; //經過比例轉換后的裁剪區(qū)域
private RectF dst = null; //圖片顯示區(qū)域,也就是drawBitmap函數(shù)中的目標dst
private RectF ChooseArea = null; //選擇區(qū)域
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; //用來存儲觸筆點擊了哪個小矩形框(改變選擇區(qū)域大小的小矩形框)
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;
//選擇框之外的灰色區(qū)域,分成四個矩形框
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;
}
//如果選擇區(qū)域大小跟圖像大小一樣時,就不能移動
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();
}
//每次改變選擇區(qū)域矩形的大小或者移動,各角落上的小矩形也要改變它的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,并以附件的形似發(fā)送郵件
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,不依靠系統(tǒng)的簡單裁剪功能就實現(xiàn)了,這里筆者就不給出源代碼下載了,上述代碼讀者只要自己改改就可以用了。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android?如何獲取傳感器的數(shù)據(jù)方法詳解
這篇文章主要介紹了Android?如何獲取傳感器的數(shù)據(jù),傳感器?Sensor?是一種檢測裝置,能感受到被測量的信息,并能將感受到的信息,按一定規(guī)律變換成為電信號或其他所需形式的信息輸出,以滿足信息的傳輸、處理、存儲、顯示、記錄和控制等要求2022-07-07
Android使用ViewFlipper實現(xiàn)上下滾動消息
這篇文章主要為大家詳細介紹了Android使用ViewFlipper實現(xiàn)上下滾動消息,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-07-07
Android開源項目PullToRefresh下拉刷新功能詳解
這篇文章主要為大家詳細介紹了Android開源項目PullToRefresh下拉刷新功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09
Android編程之Application設置全局變量及傳值用法實例分析
這篇文章主要介紹了Android編程之Application設置全局變量及傳值用法,結合實例形式較為詳細的分析了全局變量及傳值的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-12-12

