之前介紹過一個截圖的辦法(http://www.cnblogs.com/tianzhijiexian/p/3900241.html),這里再分享個開源項目。它也是截圖,但是效果不是很好,首先還是對於小圖片沒有進行考慮,然后裁剪框也沒有正對圖片的大小做適配。雖然其代碼比較簡單,但我還是不推薦用這個做復雜的裁剪。然而里面有個“裁剪框不動,圖片可縮放”的效果還是很實用的。因此,我還是來介紹一下。
首先還是導入項目,然后在項目中新建一個類,主要是用來繼承Application。便於以后保存到sd卡中
package com.kale.cropimagetest; import android.app.Application; /** * @author:Jack Tony * @tips :在application標簽下要有這個內部類的名字 * 如:android:name="com.kale.cropimagetest.DemoApp" * <application android:name="com.kale.cropimagetest.DemoApp" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > * @date :2014-8-9 */ public class App extends Application { private static App instance; @Override public void onCreate() { super.onCreate(); instance = this; } public static App getInstance() { return instance; } }
寫好后,在manifest中的application中寫上這個類
android:name="com.kale.cropimagetest.App"
<application android:allowBackup="true" android:name="com.kale.cropimagetest.App" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
……
然后在建立一個類,用來保存截圖。根據實際需要可以自行修改
package com.kale.cropimagetest; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import android.graphics.Bitmap; import android.os.Environment; /** * * 與文件相關的類,主要負責文件的讀寫 * * @author 楊龍輝 2012.04.07 * */ /** * @author:Jack Tony * @tips : 需要有讀取sd卡的權限 * @date :2014-8-9 */ public final class FileUtil { // ------------------------------ 手機系統相關 ------------------------------ public static final String NEWLINE = System.getProperty("line.separator");// 系統的換行符 public static final String APPROOT = "UMMoka";// 程序的根目錄 public static final String ASSERT_PATH="file:///android_asset";//apk的assert目錄 public static final String RES_PATH="file:///android_res";//apk的assert目錄 //----------------------------------存放文件的路徑后綴------------------------------------ public static final String CACHE_IMAGE_SUFFIX=File.separator + APPROOT+ File.separator + "images" + File.separator; public static final String CACHE_VOICE_SUFFIX=File.separator + APPROOT+ File.separator + "voice" + File.separator; public static final String CACHE_MATERIAL_SUFFIX=File.separator + APPROOT + File.separator + "material" + File.separator; public static final String LOG_SUFFIX=File.separator + APPROOT + File.separator + "Log" + File.separator; // ------------------------------------數據的緩存目錄------------------------------------------------------- public static String SDCARD_PAHT ;// SD卡路徑 public static String LOCAL_PATH ;// 本地路徑,即/data/data/目錄下的程序私有目錄 public static String CURRENT_PATH = "";// 當前的路徑,如果有SD卡的時候當前路徑為SD卡,如果沒有的話則為程序的私有目錄 static { init(); } public static void init() { SDCARD_PAHT = Environment.getExternalStorageDirectory().getPath();// SD卡路徑 LOCAL_PATH = App.getInstance().getApplicationContext().getFilesDir().getAbsolutePath();// 本地路徑,即/data/data/目錄下的程序私有目錄 if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { CURRENT_PATH = SDCARD_PAHT; } else { CURRENT_PATH = LOCAL_PATH; } } /** * 得到與當前存儲路徑相反的路徑(當前為/data/data目錄,則返回/sdcard目錄;當前為/sdcard,則返回/data/data目錄) * @return */ public static String getDiffPath() { if(CURRENT_PATH.equals(SDCARD_PAHT)) { return LOCAL_PATH; } return SDCARD_PAHT; } public static String getDiffPath(String pathIn) { return pathIn.replace(CURRENT_PATH, getDiffPath()); } // ------------------------------------文件的相關方法-------------------------------------------- /** * 將數據寫入一個文件 * * @param destFilePath * 要創建的文件的路徑 * @param data * 待寫入的文件數據 * @param startPos * 起始偏移量 * @param length * 要寫入的數據長度 * @return 成功寫入文件返回true,失敗返回false */ public static boolean writeFile(String destFilePath, byte[] data, int startPos, int length) { try { if (!createFile(destFilePath)) { return false; } FileOutputStream fos = new FileOutputStream(destFilePath); fos.write(data, startPos, length); fos.flush(); if (null != fos) { fos.close(); fos = null; } return true; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } /** * 從一個輸入流里寫文件 * * @param destFilePath * 要創建的文件的路徑 * @param in * 要讀取的輸入流 * @return 寫入成功返回true,寫入失敗返回false */ public static boolean writeFile(String destFilePath, InputStream in) { try { if (!createFile(destFilePath)) { return false; } FileOutputStream fos = new FileOutputStream(destFilePath); int readCount = 0; int len = 1024; byte[] buffer = new byte[len]; while ((readCount = in.read(buffer)) != -1) { fos.write(buffer, 0, readCount); } fos.flush(); if (null != fos) { fos.close(); fos = null; } if (null != in) { in.close(); in = null; } return true; } catch (IOException e) { e.printStackTrace(); } return false; } public static boolean appendFile(String filename,byte[]data,int datapos,int datalength) { try { createFile(filename); RandomAccessFile rf= new RandomAccessFile(filename, "rw"); rf.seek(rf.length()); rf.write(data, datapos, datalength); if(rf!=null) { rf.close(); } } catch (Exception e) { e.printStackTrace(); } return true; } /** * 讀取文件,返回以byte數組形式的數據 * * @param filePath * 要讀取的文件路徑名 * @return */ public static byte[] readFile(String filePath) { try { if (isFileExist(filePath)) { FileInputStream fi = new FileInputStream(filePath); return readInputStream(fi); } } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } /** * 從一個數量流里讀取數據,返回以byte數組形式的數據。 * </br></br> * 需要注意的是,如果這個方法用在從本地文件讀取數據時,一般不會遇到問題,但如果是用於網絡操作,就經常會遇到一些麻煩(available()方法的問題)。所以如果是網絡流不應該使用這個方法。 * @param in * 要讀取的輸入流 * @return * @throws IOException */ public static byte[] readInputStream(InputStream in) { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] b = new byte[in.available()]; int length = 0; while ((length = in.read(b)) != -1) { os.write(b, 0, length); } b = os.toByteArray(); in.close(); in = null; os.close(); os = null; return b; } catch (IOException e) { e.printStackTrace(); } return null; } /** * 讀取網絡流 * @param in * @return */ public static byte[] readNetWorkInputStream(InputStream in) { ByteArrayOutputStream os=null; try { os = new ByteArrayOutputStream(); int readCount = 0; int len = 1024; byte[] buffer = new byte[len]; while ((readCount = in.read(buffer)) != -1) { os.write(buffer, 0, readCount); } in.close(); in = null; return os.toByteArray(); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=os) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } os = null; } } return null; } /** * 將一個文件拷貝到另外一個地方 * @param sourceFile 源文件地址 * @param destFile 目的地址 * @param shouldOverlay 是否覆蓋 * @return */ public static boolean copyFiles(String sourceFile, String destFile,boolean shouldOverlay) { try { if(shouldOverlay) { deleteFile(destFile); } FileInputStream fi = new FileInputStream(sourceFile); writeFile(destFile, fi); return true; } catch (FileNotFoundException e) { e.printStackTrace(); } return false; } /** * 判斷文件是否存在 * * @param filePath * 路徑名 * @return */ public static boolean isFileExist(String filePath) { File file = new File(filePath); return file.exists(); } /** * 創建一個文件,創建成功返回true * * @param filePath * @return */ public static boolean createFile(String filePath) { try { File file = new File(filePath); if (!file.exists()) { if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } return file.createNewFile(); } } catch (IOException e) { e.printStackTrace(); } return true; } /** * 刪除一個文件 * * @param filePath * 要刪除的文件路徑名 * @return true if this file was deleted, false otherwise */ public static boolean deleteFile(String filePath) { try { File file = new File(filePath); if (file.exists()) { return file.delete(); } } catch (Exception e) { e.printStackTrace(); } return false; } /** * 刪除 directoryPath目錄下的所有文件,包括刪除刪除文件夾 * @param directoryPath */ public static void deleteDirectory(File dir) { if (dir.isDirectory()) { File[] listFiles = dir.listFiles(); for (int i = 0; i < listFiles.length ; i++) { deleteDirectory(listFiles[i]); } } dir.delete(); } /** * 字符串轉流 * @param str * @return */ public static InputStream String2InputStream(String str) { ByteArrayInputStream stream = new ByteArrayInputStream(str.getBytes()); return stream; } /** * 流轉字符串 * @param is * @return */ public static String inputStream2String(InputStream is) { BufferedReader in = new BufferedReader(new InputStreamReader(is)); StringBuffer buffer = new StringBuffer(); String line = ""; try { while ((line = in.readLine()) != null) { buffer.append(line); } } catch (IOException e) { e.printStackTrace(); } return buffer.toString(); } //批量更改文件后綴 public static void reNameSuffix(File dir,String oldSuffix,String newSuffix) { if (dir.isDirectory()) { File[] listFiles = dir.listFiles(); for (int i = 0; i < listFiles.length ; i++) { reNameSuffix(listFiles[i],oldSuffix,newSuffix); } } else { dir.renameTo(new File(dir.getPath().replace(oldSuffix, newSuffix))); } } public static void writeImage(Bitmap bitmap,String destPath,int quality) { try { FileUtil.deleteFile(destPath); if (FileUtil.createFile(destPath)) { FileOutputStream out = new FileOutputStream(destPath); if (bitmap.compress(Bitmap.CompressFormat.JPEG,quality, out)) { out.flush(); out.close(); out = null; } } } catch (IOException e) { e.printStackTrace(); } } }
這樣准備工作就做好了。下面就是項目的使用了~
1.建立布局文件
注意:<com.open.crop.CropImageView ……/>,不同的效果要用不同的控件來實現。如:CropImageView ,CropImageView2,CropImageView3,CropImageView4
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.open.crop.CropImageView android:id="@+id/cropImg" android:layout_weight="1.0" android:layout_width="match_parent" android:layout_height="0dp"/> <Button android:id="@+id/save" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="save"/> </LinearLayout>
2.處理裁剪事務。
想用別的控件的話,這里用到的類的名字換一下就行,比如
final CropImageView mCropImage=(CropImageView)findViewById(R.id.cropImg);
final CropImageView2 mCropImage=(CropImageView2)findViewById(R.id.cropImg);
final CropImageView3 mCropImage=(CropImageView3)findViewById(R.id.cropImg);
final CropImageView4 mCropImage=(CropImageView4)findViewById(R.id.cropImg);
package com.kale.cropimagetest; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import com.open.crop.CropImageView; public class CropImageTest01 extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { // TODO 自動生成的方法存根 super.onCreate(savedInstanceState); setContentView(R.layout.test01); final CropImageView mCropImage=(CropImageView)findViewById(R.id.cropImg); //設置要裁剪的圖片和默認的裁剪區域 mCropImage.setDrawable(getResources().getDrawable(R.drawable.right),300,300); findViewById(R.id.save).setOnClickListener(new OnClickListener() { /* (非 Javadoc) * @see android.view.View.OnClickListener#onClick(android.view.View) * 開啟一個新線程來保存圖片 */ @Override public void onClick(View v) { new Thread(new Runnable(){ @Override public void run() { //得到裁剪好的圖片 Bitmap bitmap = mCropImage.getCropImage(); FileUtil.writeImage(bitmap, FileUtil.SDCARD_PAHT+"/crop.png", 100); Intent mIntent=new Intent(); mIntent.putExtra("cropImagePath", FileUtil.SDCARD_PAHT+"/crop.png"); setResult(RESULT_OK, mIntent); finish(); } }).start(); } }); } }
最后在主Activity中接收圖片的路徑,載入顯示截圖即可。
package com.kale.cropimagetest; import android.app.Activity; import android.content.Intent; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.view.View; import android.widget.ImageView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void buttonListener(View v) { Intent intent = new Intent(); Class<?> cls = null; switch (v.getId()) { case R.id.crop01_button: cls = CropImageTest01.class; break; case R.id.crop02_button: cls = CropImageTest02.class; break; case R.id.crop03_button: cls = CropImageTest03.class; break; case R.id.crop04_button: cls = CropImageTest04.class; break; default: break; } intent.setClass(getApplicationContext(), cls); startActivityForResult(intent, 100); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { ImageView iv = (ImageView) findViewById(R.id.imageView); if (requestCode == 100 && resultCode == RESULT_OK) { String path = data.getStringExtra("cropImagePath"); iv.setImageDrawable(BitmapDrawable.createFromPath(path)); } super.onActivityResult(requestCode, resultCode, data); } }
源碼下載:http://download.csdn.net/detail/shark0017/7733207