01.package demo.camera;
02.import java.io.FileNotFoundException;
03.import android.app.Activity;
04.import android.content.Intent;
05.import android.graphics.Bitmap;
06.import android.graphics.BitmapFactory;
07.import android.graphics.Canvas;
08.import android.graphics.ColorMatrix;
09.import android.graphics.ColorMatrixColorFilter;
10.import android.graphics.Matrix;
11.import android.graphics.Paint;
12.import android.graphics.PorterDuff;
13.import android.graphics.PorterDuffXfermode;
14.import android.net.Uri;
15.import android.os.Bundle;
16.import android.provider.MediaStore;
17.import android.util.Log;
18.import android.view.Menu;
19.import android.view.MenuItem;
20.import android.view.View;
21.import android.widget.Button;
22.import android.widget.ImageView;
23./**
24. * 在Android中我们可以对图像进行编辑处理等操作
25. * 包括放大缩小,旋转,偏移,裁剪,以及更改亮度,饱和度等
26. *
27. * 1、首先,从SDCard中选择图片,采用Android自带的Callery应用获得
28. * Gallery是Android自带的图片和视频管理应用
29. * 使用Intent来启动Gallery应用,需要指定两个参数,一个是Action,另一个是多媒体存放的URI
30. * Action是一个通用的Action叫ACTION_PICK,来告诉Gallery,我们想检索数据。
31. * 第二个是Data,是一个URI,这里当然是MediaStore.Images.Media.EXTERNAL_CONTENT_URI
32. * 当在Gallery中选择了一个图片的时候,返回的Intent中的Data域就是所选图片对应的URI
33. *
34. * @author Administrator
35. *
36. */
37.public class PhotoProcess extends Activity{
38. public static final int FIRST_PIC = 0;
39. public static final int SECOND_PIC = 1;
40. public static final int MAX_WIDTH = 240;
41. public static final int MAX_HEIGHT = 180;
42. private Button btnSelect,btnSelect2;
43. private ImageView srcImageView, dstImageView;
44.
45. private Bitmap srcBitmap, dstBitmap;
46. private Uri imageUri;
47.
48.
49. public void onCreate(Bundle savedInstanceState){
50. super.onCreate(savedInstanceState);
51. this.setContentView(R.layout.process);
52.
53. this.btnSelect = (Button)this.findViewById(R.id.btn_select);
54. btnSelect.setOnClickListener(clickListener);
55. this.btnSelect2 = (Button)this.findViewById(R.id.btn_select2);
56. btnSelect2.setOnClickListener(clickListener2);
57. srcImageView = (ImageView)this.findViewById(R.id.img_src);
58. dstImageView = (ImageView)this.findViewById(R.id.img_dst);
59. }
60.
61. private View.OnClickListener clickListener = new View.OnClickListener() {
62.
63. @Override
64. public void onClick(View arg0) {
65. // 启动Gallery应用
66. Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
67. startActivityForResult(intent, FIRST_PIC);
68. }
69. };
70. private View.OnClickListener clickListener2 = new View.OnClickListener() {
71.
72. @Override
73. public void onClick(View arg0) {
74. // 启动Gallery应用
75. Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
76. startActivityForResult(intent, SECOND_PIC);
77.
78. }
79. };
80.
81. public boolean onCreateOptionsMenu(Menu menu){
82. //super.onCreateOptionsMenu(menu);
83. //MenuInflater menuInflater = new MenuInflater(this);
84. //menuInflater.inflate(R.layout.image, menu)
85. menu.add(Menu.NONE,1,Menu.NONE,"复制");
86. menu.add(Menu.NONE,2,Menu.NONE,"变换");
87. menu.add(Menu.NONE,3,Menu.NONE,"亮度");
88. menu.add(Menu.NONE,4,Menu.NONE,"合成");
89. return super.onCreateOptionsMenu(menu);
90. }
91.
92. public boolean onOptionsItemSelected(MenuItem item){
93. int id = item.getItemId();
94. switch(id){
95. case 1:
96. //复制一个图像
97. if(srcBitmap != null){
98. dstBitmap = getDstImage(null);//这里没有变换
99. dstImageView.setImageBitmap(dstBitmap);
100. }
101. break;
102. case 2:
103. //对复制后的图像进行变换
104. if(srcBitmap != null){
105. dstBitmap = transferImage();
106. dstImageView.setImageBitmap(dstBitmap);
107. }
108. break;
109. case 3:
110. //改变图像的色彩
111. if(srcBitmap != null){
112. dstBitmap = ajustImage();
113. dstImageView.setImageBitmap(dstBitmap);
114. }
115. break;
116. case 4:
117. if(srcBitmap != null && dstBitmap != null){
118. dstBitmap = compositeImages();
119. dstImageView.setImageBitmap(dstBitmap);
120. }
121. break;
122. }
123. return true;
124. }
125.
126. /**
127. * 为了创建一个图像的副本,我们可以在创建一个新的空的Bitmap,然后在这个Bitmap上绘制一个Bitmap
128. * 这个空的Bitmap应该和已存在的Bitmap具有相同的尺寸和颜色深度
129. *
130. * 然后我们需要一个Canvas对象,一个Canvas简单说,就是一个画布,存放Bitmap,在构造时,就可以传入Bitmap对象
131. * 同时,Canvas中定义了很多便捷的画图方法,方便我们绘制各种图形
132. * 接下来,如果我们需要处理颜色和对比度,我们需要一个Paint对象,通过Paint我们可以设置画笔的各种特性。
133. *
134. * 最后,我们调用Canvas的drawBitmap就可以将原Bitmap绘制在dstBitmap上了
135. *
136. */
137. private Bitmap getDstImage(Matrix matrix){
138.
139. Bitmap bmp = null;
140. //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
141. //返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了
142. bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
143. //创建Canvas对象,
144. Canvas canvas = new Canvas(bmp);
145. //创建Paint对象,这里先不用
146. Paint paint = new Paint();
147. //在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了
148.
149. if(matrix != null){
150. //如果matrix存在,则采用变换
151. canvas.drawBitmap(dstBitmap, matrix, paint);
152. }else{
153. canvas.drawBitmap(srcBitmap, 0, 0, paint);
154. }
155.
156.
157. return bmp;
158.
159. }
160.
161.
162. /**
163. * 重载getDstImage函数,传入定制的Paint对象
164. * @param matrix
165. * @param paint
166. * @return
167. */
168. private Bitmap getDstImage(Matrix matrix, Paint paint){
169.
170. Bitmap bmp = null;
171. //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
172. //返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了
173. bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
174. //创建Canvas对象,
175. Canvas canvas = new Canvas(bmp);
176.
177. //在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了
178.
179. if(matrix != null){
180. //如果matrix存在,则采用变换
181. canvas.drawBitmap(dstBitmap, matrix, paint);
182. }else{
183. canvas.drawBitmap(srcBitmap, 0, 0, paint);
184. }
185.
186.
187. return bmp;
188.
189. }
190.
191. /**
192. * 为了放大缩小、旋转图像,我们要使用Matrix类。Matrix类是一个三维矩阵。
193. * 在Android屏幕中,图像的每个像素对应都是一个坐标,一个坐标由x/y/z组成
194. * ------------------------
195. * cosX -sinX translateX
196. * sinX cosX translateY
197. * 0 0 scale
198. * ------------------------
199. * 第一行的值,影响着x坐标。比如 1 0 0 =>x = 1*x + 0*y + 0*z
200. * 第二行的值,影响着y坐标。比如0 1 0 => y = 0*x + 1*y + 0*z
201. * 第三行的值,影响着z坐标。比如 0 0 1 => z = 0*x + 0*y + 1*z
202. *
203. * 我们自己计算一个矩阵然后通过Matrax.setValues设置。
204. * 这样,在调用canvas的drawBitmap方法时,传入matrix
205. *
206. * Matrix类并不提倡我们使用这种方式来操作变换,Matrix针对不同的变换都相应的有pre,set,post三种方法
207. * 可以使用。
208. * pre是矩阵前乘
209. * set是直接设置
210. * post是矩阵后乘
211. */
212. private Bitmap transferImage(){
213. Matrix matrix = new Matrix();
214. matrix.setValues(new float[]{
215. .5f,0,0,//这里只会影响到x轴,所以,图片的长度将是原来的一半
216. 0,1,0,
217. 0,0,1
218. });
219. return this.getDstImage(matrix);
220. }
221.
222. /**
223. * 该方法中我们将对图像的颜色,亮度,对比度等进行设置
224. * 需要用到ColorMatrix类。ColorMatrix类是一个四行五列的矩阵
225. * 每一行影响着[R,G,B,A]中的一个
226. * -------------------------
227. * a1 b1 c1 d1 e1
228. * a2 b2 c2 d2 e2
229. * a3 b3 c3 d3 e3
230. * a4 b4 c4 d4 e4
231. * -------------------------
232. * Rnew => a1*R+b1*G+c1*B+d1*A+e1
233. * Gnew => a2*R+b2*G+c2*B+d2*A+e2
234. * Bnew => a3*R+b3*G+c3*B+d3*A+e3
235. * Gnew => a4*R+b4*G+c4*B+d4*A+e4
236. * 其中R,G,B的值是128,A的值是0
237. *
238. * 最后将颜色的修改,通过Paint.setColorFilter应用到Paint对象中。
239. * 主要对于ColorMatrix,需要将其包装成ColorMatrixColorFilter对象,再传给Paint对象
240. *
241. * 同样的,ColorMatrix提供给我们相应的方法,setSaturation()就可以设置一个饱和度
242. */
243. private Bitmap ajustImage(){
244. ColorMatrix cMatrix = new ColorMatrix();
245.// int brightIndex = -25;
246.// int doubleColor = 2;
247.// cMatrix.set(new float[]{
248.// doubleColor,0,0,0,brightIndex, //这里将1改为2则我们让Red的值为原来的两倍
249.// 0,doubleColor,0,0,brightIndex,//改变最后一列的值,我们可以不改变RGB同道颜色的基础上,改变亮度
250.// 0,0,doubleColor,0,brightIndex,
251.// 0,0,0,doubleColor,0
252.// });
253. //cMatrix.setSaturation(2.0f);//设置饱和度
254. cMatrix.setScale(2.0f, 2.0f, 2.0f, 2.0f);//设置颜色同道色彩缩放
255. Paint paint = new Paint();
256. paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));
257. return this.getDstImage(null, paint);
258. }
259.
260. /**
261. * 图像的合成,可以通过在同一个Canvas中绘制两张图片。
262. * 只是在绘制第二章图片的时候,需要给Paint指定一个变幻模式TransferMode。
263. * 在Android中有一个XFermode所有的变幻模式都是这个类的子类
264. * 我们需要用到它的一个子类PorterDuffXfermode,关于这个类,其中用到PorterDuff类
265. * 这个类很简单,就包含一个Enum是Mode,其中定义了一组规则,这组规则就是如何将
266. * 一张图像和另一种图像进行合成
267. * 关于图像合成有四种模式,LIGHTEN,DRAKEN,MULTIPLY,SCREEN
268. */
269. private Bitmap compositeImages(){
270.
271. Bitmap bmp = null;
272. //下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
273. bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
274. Paint paint = new Paint();
275. Canvas canvas = new Canvas(bmp);
276. //首先绘制第一张图片,很简单,就是和方法中getDstImage一样
277. canvas.drawBitmap(srcBitmap, 0, 0, paint);
278.
279. //在绘制第二张图片的时候,我们需要指定一个Xfermode
280. //这里采用Multiply模式,这个模式是将两张图片的对应的点的像素相乘
281. //,再除以255,然后以新的像素来重新绘制显示合成后的图像
282. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
283. canvas.drawBitmap(dstBitmap, 0, 0, paint);
284.
285. return bmp;
286. }
287. public void onActivityResult(int requestCode, int resultCode, Intent data){
288. super.onActivityResult(requestCode, resultCode, data);
289.
290. Log.v("Result OK Value:", resultCode+"");
291. Log.v("RequestCode Value", requestCode+"");
292.
293. if(resultCode == RESULT_OK){
294. imageUri = data.getData();
295. if(requestCode == FIRST_PIC){
296. //在Gallery中选中一个图片时,返回来的Intent中的Data就是选择图片的Uri
297. srcBitmap = getSrcImage(imageUri);
298. srcImageView.setImageBitmap(srcBitmap);
299. }else if(requestCode == SECOND_PIC){
300. //这里处理用户选择的第二张图片
301.
302. dstBitmap = getSrcImage(imageUri);
303. dstImageView.setImageBitmap(dstBitmap);
304. }
305. }
306. }
307.
308. /**
309. * 需要加载的图片可能是大图,我们需要对其进行合适的缩小处理
310. * @param imageUri
311. */
312. private Bitmap getSrcImage(Uri imageUri){
313. //Display display = this.getWindowManager().getDefaultDisplay();
314. try {
315. BitmapFactory.Options ops = new BitmapFactory.Options();
316. ops.inJustDecodeBounds = true;
317. Bitmap bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);
318. int wRatio = (int)Math.ceil(ops.outWidth/(float)MAX_WIDTH);
319. int hRatio = (int)Math.ceil(ops.outHeight/(float)MAX_HEIGHT);
320.
321. if(wRatio > 1 && hRatio > 1){
322. if(wRatio > hRatio){
323. ops.inSampleSize = wRatio;
324. }else{
325. ops.inSampleSize = hRatio;
326. }
327. }
328.
329. ops.inJustDecodeBounds = false;
330. bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);
331.
332. return bmp;
333.
334. } catch (FileNotFoundException e) {
335. // TODO Auto-generated catch block
336. e.printStackTrace();
337. Log.e(this.getClass().getName(), e.getMessage());
338. }
339.
340. return null;
341. }
342.}
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/chenjie19891104/archive/2011/04/14/6323423.aspx