Android實(shí)現(xiàn)圖片的裁剪(不調(diào)用系統(tǒng)功能)
接上一篇文章:Android實(shí)現(xiàn)圖片區(qū)域裁剪功能
上一篇文章提及了通過調(diào)用系統(tǒng)相冊(cè)或拍照來實(shí)現(xiàn)圖片的縮放\裁剪。不過這對(duì)于筆者項(xiàng)目的要求同樣不適合,筆者需要的是通過對(duì)手機(jī)屏幕整個(gè)進(jìn)行一個(gè)截圖,并對(duì)這個(gè)截圖進(jìn)行裁剪操作。
依靠系統(tǒng)功能確實(shí)可以實(shí)現(xiàn)圖片的裁剪,但是不夠靈活。這里筆者提供一種較為靈活的做法。
但是這種做法的用戶體驗(yàn)沒有上篇文章的好,至于使用何種方法,讀者應(yīng)該自己衡量。
同樣,我們先看實(shí)際效果圖。
這里展示的是筆者項(xiàng)目的一小部分(閱讀器):
我們點(diǎn)擊左下角的剪切按鈕
我們通過紅色邊框的四個(gè)角來控制裁剪的大小,移動(dòng)紅色框體來控制裁剪的位置區(qū)域。
接下來我們看看源碼的實(shí)現(xiàn):
首先點(diǎn)擊剪切按鈕的時(shí)候,我們應(yīng)該生成一個(gè)Bitmap對(duì)象,傳遞給另一個(gè)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; //傳遞給另一個(gè)Activity進(jìn)行裁剪 Intent intent = new Intent(); intent.setClass(MuPDFActivity.this, CutActivity.class); startActivity(intent); } });
Tips:這里筆者是將這個(gè)截取的Bitmap對(duì)象傳遞給另一個(gè)Actvity做相關(guān)處理,這里如何在Activity之間進(jìn)行Bitmap傳遞呢?這里我們簡(jiǎn)單的運(yùn)用java語法特性來完成具體做法如下:
我們?cè)贏ctvityA中有一個(gè)public static Bitmap bitmap對(duì)象,當(dāng)ActivityA跳轉(zhuǎn)到B時(shí),我們直接通過ActivityA.bitmap來獲取這個(gè)對(duì)象。
之后就是如何進(jìn)行裁剪的操作了。操作在另一個(gè)Activity中進(jìn)行。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>
通過配置文件可以看到我們自定義了一個(gè)View(ImageView)其實(shí)現(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; //經(jīng)過比例轉(zhuǎn)換后的裁剪區(qū)域 private RectF dst = null; //圖片顯示區(qū)域,也就是drawBitmap函數(shù)中的目標(biāo)dst private RectF ChooseArea = null; //選擇區(qū)域 private Paint mPaint = null; //畫筆 private Matrix matrix = null; //矩陣 private int mx = 0; //存儲(chǔ)觸筆移動(dòng)時(shí),之前�?��的觸筆的x坐標(biāo) private int my = 0; //存儲(chǔ)觸筆移動(dòng)時(shí),之前�?��的觸筆的y坐標(biāo) private boolean touchFlag = false; //觸筆是否在屏幕之�? private boolean cutFlag = false; //是否點(diǎn)擊了menu上的裁剪按鈕 private int recFlag = -1; //用來存儲(chǔ)觸筆點(diǎn)擊了哪個(gè)小矩形框(改變選擇區(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); //將畫筆的風(fēng)格改為空心 ChooseArea = new RectF(); this.setPressRecLoc(); src = null; firstFlag = true; //選擇框之外的灰色區(qū)域,分成四個(gè)矩形框 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對(duì)象 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){ //判斷是否點(diǎn)擊了哪個(gè)個(gè)小矩形框 if(this.isOutOfArea((int)event.getX(), (int)event.getY())){ return true; } //如果選擇區(qū)域大小跟圖像大小一樣時(shí),就不能移動(dòng) 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ū)域矩形的大小或者移動(dòng),各角落上的小矩形也要改變它的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) { //圖片保存的路徑,之后將之轉(zhuǎn)換為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)的簡(jiǎn)單裁剪功能就實(shí)現(xiàn)了,這里筆者就不給出源代碼下載了,上述代碼讀者只要自己改改就可以用了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android控件CardView實(shí)現(xiàn)卡片效果
這篇文章主要為大家詳細(xì)介紹了Android控件CardView實(shí)現(xiàn)卡片效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02Android?Flutter實(shí)現(xiàn)"斑馬紋"背景的示例代碼
本文將通過實(shí)現(xiàn)一個(gè)canvas繪制斑馬紋類。使用Stack布局,將斑馬紋放在下方作為背景板,需要展示的內(nèi)容在上方。從而實(shí)現(xiàn)?“斑馬紋”背景,感興趣的可以了解一下2022-06-06Android中使用PagerSlidingTabStrip實(shí)現(xiàn)導(dǎo)航標(biāo)題的示例
本篇文章主要介紹了Android中使用PagerSlidingTabStrip實(shí)現(xiàn)導(dǎo)航標(biāo)題的示例,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01Android仿網(wǎng)易客戶端頂部導(dǎo)航欄效果
這篇文章主要為大家詳細(xì)介紹了Android仿網(wǎng)易客戶端頂部導(dǎo)航欄效果,幫助大家制作網(wǎng)易客戶端導(dǎo)航欄特效,感興趣的小伙伴們可以參考一下2016-06-06Android 使用cos和sin繪制復(fù)合曲線動(dòng)畫
這篇文章主要介紹了Android 使用cos和sin繪制復(fù)合曲線動(dòng)畫的方法,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03Flutter利用注解生成可自定義的路由的實(shí)現(xiàn)
這篇文章主要介紹了Flutter利用注解生成可自定義的路由的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Android App在ViewPager中使用Fragment的實(shí)例講解
這篇文章主要介紹了Android App在ViewPager中使用Fragment的實(shí)例講解,ViewPager組件主要被用來制作滑動(dòng)切換效果,需要的朋友可以參考下2016-03-03Android 頂部標(biāo)題欄隨滑動(dòng)時(shí)的漸變隱藏和漸變顯示效果
這篇文章主要介紹了Android 頂部標(biāo)題欄隨滑動(dòng)時(shí)的漸變隱藏和漸變顯示效果,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06