如何在Unity中打开摄像机、在Unity中打开本地相册,选一个照片后如何进行裁剪,最后将图片转换成Texture显示在U3D的世界当中。
首先看看Eclipse中的Android插件部分,我的包名是com.xys请大家与MOMO保持一致,Unity工程中也需要是这个包名噢。
UnityTestActivity.java 这个类是Unity的插件主类,在这里调用是打开摄像机 还是本地相册的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
com
.
xys
;
import
android
.
content
.
Context
;
import
android
.
content
.
Intent
;
import
android
.
os
.
Bundle
;
import
com
.
unity3d
.
player
.
UnityPlayerActivity
;
public
class
UnityTestActivity
extends
UnityPlayerActivity
{
//public class UnityTestActivity extends Activity {
Context
mContext
=
null
;
@
Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
)
;
mContext
=
this
;
}
//Unity中会调用这个方法,用于区分打开摄像机 开始本地相册
public
void
TakePhoto
(
String
str
)
{
Intent
intent
=
new
Intent
(
mContext
,
WebViewActivity
.
class
)
;
intent
.
putExtra
(
"type"
,
str
)
;
this
.
startActivity
(
intent
)
;
}
}
|
然后是WebViewActivity.java 这里主要处理用户打开摄像机或本地相册后如何进行裁剪图片,并且把裁剪的图片储存在本地文件中。
1
2
3
4
5
6
7
8
9
10
11
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
|
package
com
.
xys
;
import
java
.
io
.
File
;
import
java
.
io
.
FileNotFoundException
;
import
java
.
io
.
FileOutputStream
;
import
java
.
io
.
IOException
;
import
com
.
unity3d
.
player
.
UnityPlayer
;
import
android
.
app
.
Activity
;
import
android
.
content
.
Intent
;
import
android
.
graphics
.
Bitmap
;
import
android
.
net
.
Uri
;
import
android
.
os
.
Bundle
;
import
android
.
os
.
Environment
;
import
android
.
provider
.
MediaStore
;
import
android
.
view
.
KeyEvent
;
import
android
.
widget
.
ImageView
;
public
class
WebViewActivity
extends
Activity
{
ImageView
imageView
=
null
;
public
static
final
int
NONE
=
0
;
public
static
final
int
PHOTOHRAPH
=
1
;
// 拍照
public
static
final
int
PHOTOZOOM
=
2
;
// 缩放
public
static
final
int
PHOTORESOULT
=
3
;
// 结果
public
static
final
String
IMAGE_UNSPECIFIED
=
"image/*"
;
public
final
static
String
FILE_NAME
=
"image.png"
;
public
final
static
String
DATA_URL
=
"/data/data/"
;
@
Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
)
;
setContentView
(
R
.
layout
.
main
)
;
imageView
=
(
ImageView
)
this
.
findViewById
(
R
.
id
.
imageID
)
;
String
type
=
this
.
getIntent
(
)
.
getStringExtra
(
"type"
)
;
//在这里判断是打开本地相册还是直接照相
if
(
type
.
equals
(
"takePhoto"
)
)
{
Intent
intent
=
new
Intent
(
MediaStore
.
ACTION_IMAGE_CAPTURE
)
;
intent
.
putExtra
(
MediaStore
.
EXTRA_OUTPUT
,
Uri
.
fromFile
(
new
File
(
Environment
.
getExternalStorageDirectory
(
)
,
"temp.jpg"
)
)
)
;
startActivityForResult
(
intent
,
PHOTOHRAPH
)
;
}
else
{
Intent
intent
=
new
Intent
(
Intent
.
ACTION_PICK
,
null
)
;
intent
.
setDataAndType
(
MediaStore
.
Images
.
Media
.
EXTERNAL_CONTENT_URI
,
IMAGE_UNSPECIFIED
)
;
startActivityForResult
(
intent
,
PHOTOZOOM
)
;
}
}
@
Override
protected
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
if
(
resultCode
==
NONE
)
return
;
// 拍照
if
(
requestCode
==
PHOTOHRAPH
)
{
//设置文件保存路径这里放在跟目录下
File
picture
=
new
File
(
Environment
.
getExternalStorageDirectory
(
)
+
"/temp.jpg"
)
;
startPhotoZoom
(
Uri
.
fromFile
(
picture
)
)
;
}
if
(
data
==
null
)
return
;
// 读取相册缩放图片
if
(
requestCode
==
PHOTOZOOM
)
{
startPhotoZoom
(
data
.
getData
(
)
)
;
}
// 处理结果
if
(
requestCode
==
PHOTORESOULT
)
{
Bundle
extras
=
data
.
getExtras
(
)
;
if
(
extras
!=
null
)
{
Bitmap
photo
=
extras
.
getParcelable
(
"data"
)
;
imageView
.
setImageBitmap
(
photo
)
;
try
{
SaveBitmap
(
photo
)
;
}
catch
(
IOException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
(
)
;
}
}
}
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
;
}
public
void
startPhotoZoom
(
Uri
uri
)
{
Intent
intent
=
new
Intent
(
"com.android.camera.action.CROP"
)
;
intent
.
setDataAndType
(
uri
,
IMAGE_UNSPECIFIED
)
;
intent
.
putExtra
(
"crop"
,
"true"
)
;
// aspectX aspectY 是宽高的比例
intent
.
putExtra
(
"aspectX"
,
1
)
;
intent
.
putExtra
(
"aspectY"
,
1
)
;
// outputX outputY 是裁剪图片宽高
intent
.
putExtra
(
"outputX"
,
300
)
;
intent
.
putExtra
(
"outputY"
,
300
)
;
intent
.
putExtra
(
"return-data"
,
true
)
;
startActivityForResult
(
intent
,
PHOTORESOULT
)
;
}
public
void
SaveBitmap
(
Bitmap
bitmap
)
throws
IOException
{
FileOutputStream
fOut
=
null
;
//注解1
String
path
=
"/mnt/sdcard/Android/data/com.xys/files"
;
try
{
//查看这个路径是否存在,
//如果并没有这个路径,
//创建这个路径
File
destDir
=
new
File
(
path
)
;
if
(
!
destDir
.
exists
(
)
)
{
destDir
.
mkdirs
(
)
;
}
fOut
=
new
FileOutputStream
(
path
+
"/"
+
FILE_NAME
)
;
}
catch
(
FileNotFoundException
e
)
{
e
.
printStackTrace
(
)
;
}
//将Bitmap对象写入本地路径中,Unity在去相同的路径来读取这个文件
bitmap
.
compress
(
Bitmap
.
CompressFormat
.
PNG
,
100
,
fOut
)
;
try
{
fOut
.
flush
(
)
;
}
catch
(
IOException
e
)
{
e
.
printStackTrace
(
)
;
}
try
{
fOut
.
close
(
)
;
}
catch
(
IOException
e
)
{
e
.
printStackTrace
(
)
;
}
}
@
Override
public
boolean
onKeyDown
(
int
keyCode
,
KeyEvent
event
)
{
if
(
keyCode
==
KeyEvent
.
KEYCODE_BACK
&&
event
.
getRepeatCount
(
)
==
0
)
{
//当用户点击返回键是 通知Unity开始在"/mnt/sdcard/Android/data/com.xys/files";路径中读取图片资源,并且现在在Unity中
UnityPlayer
.
UnitySendMessage
(
"Main Camera"
,
"message"
,
FILE_NAME
)
;
}
return
super
.
onKeyDown
(
keyCode
,
event
)
;
}
}
|
注解1:主要是路径”/mnt/sdcard/Android/data/com.xys/files”,如下图所示,我们在这里把文件保存在这个路径下。为什么要把图片2进制文件写在这里呢? 还记得以前MOMO给大家说过在Unity中访问Android或IOS本地2进制文件时用到的这个路径,
Application.persistentDataPath 该路径等价于 /mnt/sdcard/Android/data/com.xys/files ,当然后者的包名是对应的工程包名,这样在Unity中可以找到对应裁剪后的图片文件,并且显示在Unity中。
AndroidManifest.xml 这个文件也没什么好说的,大家看看吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
manifest
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
package
=
"com.xys"
android
:
versionCode
=
"1"
android
:
versionName
=
"1.0"
>
<
uses
-
sdk
android
:
minSdkVersion
=
"10"
/
>
<
application
android
:
icon
=
"@drawable/ic_launcher"
android
:
label
=
"@string/app_name"
>
<
activity
android
:
name
=
".UnityTestActivity"
android
:
label
=
"@string/app_name"
>
<
intent
-
filter
>
<
action
android
:
name
=
"android.intent.action.MAIN"
/
>
<
category
android
:
name
=
"android.intent.category.LAUNCHER"
/
>
<
/
intent
-
filter
>
<
/
activity
>
<
activity
android
:
name
=
".WebViewActivity"
>
<
/
activity
>
<
/
application
>
<
!
--
连接互联网的权限
--
>
<
uses
-
permission
android
:
name
=
"android.permission.INTERNET"
/
>
<
!
--
SDCard中创建与删除文件权限
--
>
<
uses
-
permission
android
:
name
=
"android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
/
>
<
!
--
SDCard写入数据权限
--
>
<
uses
-
permission
android
:
name
=
"android.permission.WRITE_EXTERNAL_STORAGE"
/
>
<
/
manifest
>
|
然后把上面的Android工程打包做成插件放在Unity中。如下图所示,这个我的Unity工程中对应的路径。如果看不懂的朋友请看我之前的文章哈。
然后看Test.cs脚本,它直接挂在摄像机身上。
1
2
3
4
5
6
7
8
9
10
11
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
|
using
UnityEngine
;
using
System
.
Collections
;
using
System
.
IO
;
public
class
Test
:
MonoBehaviour
{
public
GUISkin
skin
;
Texture
texture
;
void
Update
(
)
{
if
(
Input
.
GetKeyDown
(
KeyCode
.
Escape
)
||
Input
.
GetKeyDown
(
KeyCode
.
Home
)
)
{
Application
.
Quit
(
)
;
}
}
void
OnGUI
(
)
{
GUI
.
skin
=
skin
;
if
(
GUILayout
.
Button
(
"打开手机相册"
)
)
{
//调用我们制作的Android插件打开手机相册
AndroidJavaClass
jc
=
new
AndroidJavaClass
(
"com.unity3d.player.UnityPlayer"
)
;
AndroidJavaObject
jo
=
jc
.
GetStatic
<
AndroidJavaObject
>
(
"currentActivity"
)
;
jo
.
Call
(
"TakePhoto"
,
"takeSave"
)
;
}
if
(
GUILayout
.
Button
(
"打开手机摄像机"
)
)
{
//调用我们制作的Android插件打开手机摄像机
AndroidJavaClass
jc
=
new
AndroidJavaClass
(
"com.unity3d.player.UnityPlayer"
)
;
AndroidJavaObject
jo
=
jc
.
GetStatic
<
AndroidJavaObject
>
(
"currentActivity"
)
;
jo
.
Call
(
"TakePhoto"
,
"takePhoto"
)
;
}
if
(
texture
!=
null
)
{
//注意! 我们在这里绘制Texture对象,该对象是通过
//我们制作的Android插件得到的,当这个对象不等于空的时候
//直接绘制。
GUI
.
DrawTexture
(
new
Rect
(
100
,
300
,
300
,
300
)
,
texture
)
;
}
}
void
messgae
(
string
str
)
{
//在Android插件中通知Unity开始去指定路径中找图片资源
StartCoroutine
(
LoadTexture
(
str
)
)
;
}
IEnumerator
LoadTexture
(
string
name
)
{
//注解1
string
path
=
"file://"
+
Application
.
persistentDataPath
+
"/"
+
name
;
WWW
www
=
new
WWW
(
path
)
;
while
(
!
www
.
isDone
)
{
}
yield
return
www
;
//为贴图赋值
texture
=
www
.
texture
;
}
}
|
注解1:请大家一定要注意这个路径的写法, 前面一定要加 “File://” 不然无法读取。OK说了这么多我们看看这个项目运行的效果,激动人心的时刻来临啦 嚯嚯嚯嚯!!!
1.首次进入的画面, 这里的图片是我刚刚从相册选择的
2.打开相册我们选择一张图片
3. 选择一张图片,我们进行裁剪
最后我们返回到Unity中界面。新的图片Unity已经完成读取,界面上已经修改成刚刚我裁剪的啦,哇咔咔。 怎么样,还不错啦? 哈哈后。这个做用户头像肯定给力 蛤蛤。