1. 程式人生 > >android基礎--自定義圖片剪輯頭像

android基礎--自定義圖片剪輯頭像

裁剪介面效果圖

點選相簿後返回的圖片效果圖

主控制類程式碼,如下:

10

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

import java.io.File;

import android.app.Activity;

import android.app.AlertDialog;

import android.content.DialogInterface;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.drawable.BitmapDrawable;

import android.graphics.drawable.Drawable;

import android.net.Uri;

import android.os.Bundle;

import android.os.Environment;

import android.provider.MediaStore;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.ImageButton;

import android.widget.ImageView;

/**

* @Title: PicCutDemoActivity.java

* @Description: 圖片裁剪功能測試

*/

public class PicCutDemoActivity extends Activity implements OnClickListener {  

 

    private ImageButton ib = null;

    private ImageView iv = null;

    private Button btn = null;

    private String tp = null;  

 

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        //初始化

        init();

    }  

 

    /**

     * 初始化方法實現

     */

    private void init() {

        ib = (ImageButton) findViewById(R.id.imageButton1);

        iv = (ImageView) findViewById(R.id.imageView1);

        btn = (Button) findViewById(R.id.button1);

        ib.setOnClickListener(this);

        iv.setOnClickListener(this);

        btn.setOnClickListener(this);

    }  

 

    /**

     * 控制元件點選事件實現

     *

     * 因為有朋友問不同控制元件的背景圖裁剪怎麼實現,

     * 我就在這個地方用了三個控制元件,只為了自己記錄學習

     * 大家覺得沒用的可以跳過啦

     */

    @Override

    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.imageButton1:

                ShowPickDialog();

                break;

            case R.id.imageView1:

                ShowPickDialog();

                break;

            case R.id.button1:

                ShowPickDialog();

                break;  

 

            default:

                break;

        }

    }  

 

    /**

     * 選擇提示對話方塊

     */

    private void ShowPickDialog() {

        new AlertDialog.Builder(this).setTitle("設定頭像...")

                .setNegativeButton("相簿", new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int which) {

                        dialog.dismiss();

 

                        Intent intent = new Intent(Intent.ACTION_PICK, null);  

 

                        /**

                         * 如果朋友們要限制上傳到伺服器的圖片型別時可以直接寫如:"image/jpeg 、 image/png等的型別"

                         * 這裡有個疑問,希望高手解答下:就是這個資料URI與型別為什麼要分兩種形式來寫呀?有什麼區別?

                         */

                        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");

                        startActivityForResult(intent, 1);  

                    }

                })

                .setPositiveButton("拍照", new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int whichButton) {

                        dialog.dismiss();

                        /**

                         * 下面是呼叫快速拍照功能,大家可以參考如下官方

                         * 文件,your_sdk_path/docs/guide/topics/media/camera.html

                         * 這個裡面有用的太多了

                         */

                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                        //下面這句指定呼叫相機拍照後的照片儲存的路徑

                        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment

                                        .getExternalStorageDirectory(),"xxxxx.jpg")));

                        startActivityForResult(intent, 2);

                    }

                }).show();

    }  

 

    @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        switch (requestCode) {

            // 直接從相簿獲取

            case 1:

                startPhotoZoom(data.getData());

                break;

            // 呼叫相機拍照時

            case 2:

                File temp = new File(Environment.getExternalStorageDirectory()+ "/xxxxx.jpg");

                startPhotoZoom(Uri.fromFile(temp));

                break;

            // 取得裁剪後的圖片

            case 3:

                /**

                 * 非空判斷大家一定要驗證,如果不驗證的話,在剪裁之後如果發現不滿意,要重新裁剪,丟棄

                 * 當前功能時,會報NullException,大家可以根據不同情況在合適的地方做判斷處理類似情況

                 */

                if(data != null){

                    setPicToView(data);

                }

                break;

            default:

                break;  

            }

            super.onActivityResult(requestCode, resultCode, data);

    }  

 

    /**

     * 裁剪圖片方法實現

     * @param uri

     */

    public void startPhotoZoom(Uri uri) {

        /*

         * 至於下面這個Intent的ACTION是怎麼知道的,大家可以看下自己Sdk路徑下的如下文件

         * your_sdk_path/docs/reference/android/content/Intent.html

         * 直接在裡面Ctrl+F搜:CROP ,其實安卓系統早已經有自帶圖片裁剪功能,是直接調本地庫的

         */

        Intent intent = new Intent("com.android.camera.action.CROP");

        intent.setDataAndType(uri, "image/*");

        //下面這個crop=true是設定在開啟的Intent中設定顯示的VIEW可裁剪

        intent.putExtra("crop", "true");

        // aspectX aspectY 是寬高的比例

        intent.putExtra("aspectX", 1);

        intent.putExtra("aspectY", 1);

        // outputX outputY 是裁剪圖片寬高

        intent.putExtra("outputX", 150);

        intent.putExtra("outputY", 150);

        intent.putExtra("return-data", true);

        startActivityForResult(intent, 3);

    }  

 

    /**

     * 儲存裁剪之後的圖片資料

     * @param picdata

     */

    private void setPicToView(Intent picdata) {

        Bundle extras = picdata.getExtras();

        if (extras != null) {

            Bitmap photo = extras.getParcelable("data");

            Drawable drawable = new BitmapDrawable(photo);  

 

            /**

             * 下面註釋的方法是將裁剪之後的圖片以Base64Coder的字元方式上

             * 傳到伺服器,QQ頭像上傳採用的方法跟這個類似

             */

 

            /*ByteArrayOutputStream stream = new ByteArrayOutputStream();

             * photo.compress(Bitmap.CompressFormat.JPEG, 60, stream);

             * byte[] b = stream.toByteArray();

             * 將圖片流以字串形式儲存下來 

 

             * tp = new String(Base64Coder.encodeLines(b));

             * 這個地方大家可以寫下給伺服器上傳圖片的實現,直接把tp直接上傳就可以了,

             * 伺服器處理的方法是伺服器那邊的事了,吼吼  

 

             * 如果下載到的伺服器的資料還是以Base64Coder的形式的話,可以用以下方式轉換

             * 為我們可以用的圖片型別就OK啦...吼吼

             * Bitmap dBitmap = BitmapFactory.decodeFile(tp);

             * Drawable drawable = new BitmapDrawable(dBitmap);

            */

            ib.setBackgroundDrawable(drawable);

            iv.setBackgroundDrawable(drawable);

        }

    }  

 

}

裁剪中用到的類,大家詳細看下頭註釋:

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

//EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal

//LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html

//GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html

//AL, Apache License, V2.0 or later, http://www.apache.org/licenses

//BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php

 

/**

* A Base64 encoder/decoder.

*

* <p>

* This class is used to encode and decode data in Base64 format as described in RFC 1521.

*

* <p>

* Project home page: <a href="http://www.source-code.biz/base64coder/java/">www.source-code.biz/base64coder/java</a><br>

* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>

* Multi-licensed: EPL / LGPL / GPL / AL / BSD.

*/

 

/**

* 這個類在上面註釋的網址中有,大家可以自行下載下,也可以直接用這個,公開的Base64Coder類

* @Title: Base64Coder.java

*/

 

public class Base64Coder

{  

    //The line separator string of the operating system.

    private static final String systemLineSeparator = System.getProperty("line.separator");  

 

    //Mapping table from 6-bit nibbles to Base64 characters.

    private static char[]    map1 = new char[64];

    static {

       int i=0;

       for (char c='A'; c<='Z'; c++) map1[i++] = c;

       for (char c='a'; c<='z'; c++) map1[i++] = c;

       for (char c='0'; c<='9'; c++) map1[i++] = c;

       map1[i++] = '+'; map1[i++] = '/'; }  

 

    //Mapping table from Base64 characters to 6-bit nibbles.

    private static byte[]    map2 = new byte[128];

    static {

       for (int i=0; i<map2.length; i++) map2[i] = -1;

       for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; }  

 

/**

* Encodes a string into Base64 format.

* No blanks or line breaks are inserted.

* @param s  A String to be encoded.

* @return   A String containing the Base64 encoded data.

*/

public static String encodeString (String s)

{

    return new String(encode(s.getBytes()));

}  

 

/**

* Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters.

* This method is compatible with <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>.

* @param in  An array containing the data bytes to be encoded.

* @return    A String containing the Base64 encoded data, broken into lines.

*/

public static String encodeLines (byte[] in)

{

    return encodeLines(in, 0, in.length, 76, systemLineSeparator);

}  

 

/**

* Encodes a byte array into Base 64 format and breaks the output into lines.

* @param in            An array containing the data bytes to be encoded.

* @param iOff          Offset of the first byte in <code>in</code> to be processed.

* @param iLen          Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>.

* @param lineLen       Line length for the output data. Should be a multiple of 4.

* @param lineSeparator The line separator to be used to separate the output lines.

* @return              A String containing the Base64 encoded data, broken into lines.

*/

public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator)

{

    int blockLen = (lineLen*3) / 4;

    if (blockLen <= 0) throw new IllegalArgumentException();

    int lines = (iLen+blockLen-1) / blockLen;

    int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length();

    StringBuilder buf = new StringBuilder(bufLen);

    int ip = 0;

    while (ip < iLen)

    {

       int l = Math.min(iLen-ip, blockLen);

       buf.append (encode(in, iOff+ip, l));

       buf.append (lineSeparator);

       ip += l;

    }

    return buf.toString();

}  

 

/**

* Encodes a byte array into Base64 format.

* No blanks or line breaks are inserted in the output.

* @param in  An array containing the data bytes to be encoded.

* @return    A character array containing the Base64 encoded data.

*/

public static char[] encode (byte[] in)

{

    return encode(in, 0, in.length);

}  

 

/**

* Encodes a byte array into Base64 format.

* No blanks or line breaks are inserted in the output.

* @param in    An array containing the data bytes to be encoded.

* @param iLen  Number of bytes to process in <code>in</code>.

* @return      A character array containing the Base64 encoded data.

*/

public static char[] encode (byte[] in, int iLen)

{

    return encode(in, 0, iLen);

}  

 

/**

* Encodes a byte array into Base64 format.

* No blanks or line breaks are inserted in the output.

* @param in    An array containing the data bytes to be encoded.

* @param iOff  Offset of the first byte in <code>in</code> to be processed.

* @param iLen  Number of bytes to process in <code>in</code>, starting at <code>iOff</code>.

* @return      A character array containing the Base64 encoded data.

*/

public static char[] encode (byte[] in, int iOff, int iLen)

{

    int oDataLen = (iLen*4+2)/3;       // output length without padding

    int oLen = ((iLen+2)/3)*4;         // output length including padding

    char[] out = new char[oLen];

    int ip = iOff;

    int iEnd = iOff + iLen;

    int op = 0;

    while (ip < iEnd)

    {

       int i0 = in[ip++] & 0xff;

       int i1 = ip < iEnd ? in[ip++] & 0xff : 0;

       int i2 = ip < iEnd ? in[ip++] & 0xff : 0;

       int o0 = i0 >>> 2;

       int o1 = ((i0 &   3) << 4) | (i1 >>> 4);

       int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);

       int o3 = i2 & 0x3F;

       out[op++] = map1[o0];

       out[op++] = map1[o1];

       out[op] = op < oDataLen ? map1[o2] : '='; op++;

       out[op] = op < oDataLen ? map1[o3] : '='; op++;

    }

    return out;

}  

 

/**

* Decodes a string from Base64 format.

* No blanks or line breaks are allowed within the Base64 encoded input data.

* @param s  A Base64 String to be decoded.

* @return   A String containing the decoded data.

* @throws   IllegalArgumentException If the input is not valid Base64 encoded data.

*/

public static String decodeString (String s)

{

    return new String(decode(s));

}  

 

/**

* Decodes a byte array from Base64 format and ignores line separators, tabs and blanks.

* CR, LF, Tab and Space characters are ignored in the input data.

* This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.

* @param s  A Base64 String to be decoded.

* @return   An array containing the decoded data bytes.

* @throws   IllegalArgumentException If the input is not valid Base64 encoded data.

*/

public static byte[] decodeLines (String s)

{

    char[] buf = new char[s.length()+3];

    int p = 0;

    for (int ip = 0; ip < s.length(); ip++)

    {

       char c = s.charAt(ip);

       if (c != ' ' && c != '\r' && c != '\n' && c != '\t')

          buf[p++] = c;

    }

   while ((p % 4) != 0)

       buf[p++] = '0';  

 

    return decode(buf, 0, p);

}  

 

/**

* Decodes a byte array from Base64 format.

* No blanks or line breaks are allowed within the Base64 encoded input data.

* @param s  A Base64 String to be decoded.

* @return   An array containing the decoded data bytes.

* @throws   IllegalArgumentException If the input is not valid Base64 encoded data.

*/

public static byte[] decode (String s)

{

    return decode(s.toCharArray());

}  

 

/**

* Decodes a byte array from Base64 format.

* No blanks or line breaks are allowed within the Base64 encoded input data.

* @param in  A character array containing the Base64 encoded data.

* @return    An array containing the decoded data bytes.

* @throws    IllegalArgumentException If the input is not valid Base64 encoded data.

*/

public static byte[] decode (char[] in)

{

    return decode(in, 0, in.length);

}  

 

/**

* Decodes a byte array from Base64 format.

* No blanks or line breaks are allowed within the Base64 encoded input data.

* @param in    A character array containing the Base64 encoded data.

* @param iOff  Offset of the first character in <code>in</code> to be processed.

* @param iLen  Number of characters to process in <code>in</code>, starting at <code>iOff</code>.

* @return      An array containing the decoded data bytes.

* @throws      IllegalArgumentException If the input is not valid Base64 encoded data.

*/

public static byte[] decode (char[] in, int iOff, int iLen)

{

    if (iLen%4 != 0)

        throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");

    while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--;

    int oLen = (iLen*3) / 4;

    byte[] out = new byte[oLen];

    int ip = iOff;

    int iEnd = iOff + iLen;

    int op = 0;

    while (ip < iEnd) {

       int i0 = in[ip++];

       int i1 = in[ip++];

       int i2 = ip < iEnd ? in[ip++] : 'A';

       int i3 = ip < iEnd ? in[ip++] : 'A';

       if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)

          throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");

       int b0 = map2[i0];

       int b1 = map2[i1];

       int b2 = map2[i2];

       int b3 = map2[i3];

       if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)

          throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");

       int o0 = ( b0       <<2) | (b1>>>4);

       int o1 = ((b1 & 0xf)<<4) | (b2>>>2);

       int o2 = ((b2 &   3)<<6) |  b3;

       out[op++] = (byte)o0;

       if (op<oLen) out[op++] = (byte)o1;

       if (op<oLen) out[op++] = (byte)o2;

    }

    return out; }  

 

    //Dummy constructor.

    private Base64Coder() {}  

 

 

原始碼此下載:http://mzh3344258.blog.51cto.com/blog/1823534/808837