最近做的一個小App中的一個功能, 把ImageView中的圖片儲存為一個 jpg檔案。
如果裝置上有SDCard,圖片會被儲存到SD卡上,如果沒有則儲存在裝置的儲存空間中。
這裡主要包含了兩個要點,一是 Android檔案儲存時資料夾的建立;二是 ImageView中圖片提取並儲存為圖片。
感覺今後還會用到,這裡總結一下以後方便查詢。
程式執行介面:
使用類的說明
關於Android 的檔案系統
android 檔案儲存可以分兩部分 一個是裝置的flash,一個是SDCard。感覺android 對APP對檔案的訪問許可權控制的比較嚴。
一個App比較肯定的可以自由訪問(讀 寫 建立 刪除檔案 或資料夾 )的位置有2個,其他的位置就未必了,有的可能可以讀,但無法寫入或建立資料夾。
(1) SDCard
在解除安裝了App後,相關的檔案還在,不會被刪除。
(2) /data/data/[your_project]/ 在裝置自帶的RAM上。app的許可權各自獨立,即每個app 預設只能讀寫自己資料夾下的檔案, your_project: 是app的包的名字。
在解除安裝了App後,相關的檔案可能會被刪除,但沒有嘗試過。
但操作sdcard需要許可權,我們必須在AndroidManifest.xml中進行配置
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
開啟/關閉sdcard的許可權
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
Android_Manifest.xml
-
<?xml version="1.0" encoding="utf-8"?>
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-
package="com.example.imageviewsave2bitmap"
-
android:versionCode="1"
-
android:versionName="1.0" >
-
-
<uses-sdk
-
android:minSdkVersion="8"
-
android:targetSdkVersion="17" />
-
-
<application
-
android:allowBackup="true"
-
android:icon="@drawable/ic_launcher"
-
android:label="@string/app_name"
-
android:theme="@style/AppTheme" >
-
<activity
-
android:name="com.example.imageviewsave2bitmap.MainActivity"
-
android:label="@string/app_name" >
-
<intent-filter>
-
<action android:name="android.intent.action.MAIN" />
-
-
<category android:name="android.intent.category.LAUNCHER" />
-
</intent-filter>
-
</activity>
-
</application>
-
-
-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
-
-
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
-
-
</manifest>
Android 系統中關於一些資料夾的資訊被儲存在環境資訊中,例如SDCard的路徑可能是 /mnt/SDCard 或 /SDCard,當不確定時最好還是通過環境變數把他們提取出來。這一步主要通過 Environment 類 實現的。
例如:一個簡單的小函式就能取得SDCard的資訊,先判斷SDCard是否存在,如果存在則返回路徑。
-
public static String getSDPath()
-
{
-
boolean hasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
-
if(hasSDCard)
-
{
-
return Environment.getExternalStorageDirectory().toString() + "/saving_picture";
-
}
-
else
-
return "/data/data/com.example.imageviewsave2bitmap/saving_picture";
-
}
更詳細的資訊最好還是參考 Google的Android SDK文件。
提取-儲存影象檔案
Android ImageView 儲存到檔案
從ImageView中儲存影象檔案大概可以分3個步驟:
1) 從ImageView中取得快取資料,並用這些資料建立一個新的Bitmap物件
-
public static Bitmap convertViewToBitmap(View view)
-
{
-
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
-
view.buildDrawingCache();
-
Bitmap bitmap = view.getDrawingCache();
-
-
return bitmap;
-
}
關於view.measure,當我們要從view中提取圖片時,系統給了我們一些選擇,首先最容易想到的就是我們要把view中整個圖片都儲存下來,但有時候圖片較大,當然我們也可以只儲存當前我們看到的這部分。我們還可以儲存指定大小的圖片。
這就是MeasureSpec.UNSPECIFIED可以幫指定儲存的模式。這裡一共有三種模式
- AT_MOST Measure specification mode: The child can be as large as it wants up to the specified size.
- EXACTLY Measure specification mode: The parent has determined an exact size for the child.
- UNSPECIFIED Measure specification mode: The parent has not imposed any constraint on the child.
白話解釋一下:
AT_MOST:我們可以指定一個上限,要儲存的圖片的大小不會超過它。
EXACTLY:我們指定了一個明確的大小,要求圖片儲存時滿足這個條件。
UNSPECIFIED:圖片多大,我們就儲存多大。
函式convertViewToBitmap就是從View中取得了圖片的大小,然後按照這個尺寸建立了一個Bitmap物件,再把cache中的內容儲存在Bitmap物件中。
2) 建立一個FileOutputStream 物件,並用新的Bitmap物件來進行初始化。
-
File imageFile = new File(strPath + "/" + strFileName);
-
imageFile.createNewFile();
-
FileOutputStream fos = new FileOutputStream(imageFile);
-
bitmap.compress(CompressFormat.JPEG, 50, fos);
這裡先建立了一個檔案物件 File imageFile,接著用把這個檔案和一個FileOutputStream繫結在一起,然後把圖片壓縮到這個流中,壓縮方式為JPEG。
3) 指定影象檔案的型別,儲存並且關閉FileOutputStream 。
-
fos.flush();
-
fos.close();
例項程式碼
main_layout.xml
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-
xmlns:tools="http://schemas.android.com/tools"
-
android:layout_width="fill_parent"
-
android:layout_height="fill_parent"
-
android:orientation="vertical" >
-
-
<ImageView
-
android:id="@+id/ID_ivMain"
-
android:layout_width="fill_parent"
-
android:layout_height="300dp"
-
android:background="@color/Black"
-
android:scaleType="centerInside"
-
android:src="@drawable/pic_01" />
-
-
<TextView
-
android:id="@+id/ID_tvPath"
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="儲存路徑: " />
-
-
<EditText
-
android:id="@+id/ID_etFileName"
-
android:layout_width="match_parent"
-
android:layout_height="wrap_content"
-
android:ems="10" >
-
</EditText>
-
-
<Button
-
android:id="@+id/ID_btnSave"
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="儲存" />
-
-
</LinearLayout>
MainActivity.java
-
package com.example.imageviewsave2bitmap;
-
-
import java.io.File;
-
import java.io.FileNotFoundException;
-
import java.io.FileOutputStream;
-
import java.io.IOException;
-
-
import android.os.Bundle;
-
import android.os.Environment;
-
import android.app.Activity;
-
import android.graphics.Bitmap;
-
import android.graphics.Bitmap.CompressFormat;
-
import android.util.Log;
-
import android.view.Menu;
-
import android.view.View;
-
import android.view.View.MeasureSpec;
-
import android.widget.Button;
-
import android.widget.EditText;
-
import android.widget.ImageView;
-
import android.widget.TextView;
-
-
public class MainActivity extends Activity {
-
-
private ImageView m_ivMain;
-
private Button m_btnSave;
-
private TextView m_tvPath;
-
private EditText m_etFileName;
-
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_main);
-
-
String strPath = getSDPath();
-
m_ivMain = (ImageView) findViewById(R.id.ID_ivMain);
-
m_ivMain.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
m_btnSave = (Button) findViewById(R.id.ID_btnSave);
-
m_tvPath = (TextView)findViewById(R.id.ID_tvPath);
-
m_etFileName = (EditText)findViewById(R.id.ID_etFileName);
-
-
m_tvPath.setText(strPath);
-
-
m_btnSave.setOnClickListener(new Button.OnClickListener(){
-
public void onClick(View v)
-
{
-
String strFileName = m_etFileName.getText().toString().trim();
-
saveImage(strFileName);
-
}
-
});
-
}
-
-
@Override
-
public boolean onCreateOptionsMenu(Menu menu) {
-
-
getMenuInflater().inflate(R.menu.main, menu);
-
return true;
-
}
-
-
public static String getSDPath()
-
{
-
boolean hasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
-
if(hasSDCard)
-
{
-
return Environment.getExternalStorageDirectory().toString() + "/saving_picture";
-
}
-
else
-
return "/data/data/com.example.imageviewsave2bitmap/saving_picture";
-
}
-
-
public static Bitmap convertViewToBitmap(View view)
-
{
-
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
-
view.buildDrawingCache();
-
Bitmap bitmap = view.getDrawingCache();
-
-
return bitmap;
-
}
-
-
-
-
-
public void saveImage(String strFileName)
-
{
-
Bitmap bitmap = convertViewToBitmap(m_ivMain);
-
String strPath = getSDPath();
-
-
try
-
{
-
File destDir = new File(strPath);
-
if (!destDir.exists())
-
{
-
Log.d("MagicMirror", "Dir not exist create it " + strPath);
-
destDir.mkdirs();
-
Log.d("MagicMirror", "Make dir success: " + strPath);
-
}
-
-
File imageFile = new File(strPath + "/" + strFileName);
-
imageFile.createNewFile();
-
FileOutputStream fos = new FileOutputStream(imageFile);
-
bitmap.compress(CompressFormat.JPEG, 50, fos);
-
fos.flush();
-
fos.close();
-
}
-
catch (FileNotFoundException e)
-
{
-
-
e.printStackTrace();
-
}
-
catch (IOException e)
-
{
-
-
e.printStackTrace();
-
}
-
}
-
}