上一篇文章提及了通过调用系统相册或拍照来实现图片的缩放\裁剪。不过这对于笔者项目的
要求同样不适合,笔者需要的是通过对手机屏幕整个进行一个截图,并对这个截图进行裁剪操作。
依靠系统功能确实可以实现图片的裁剪,但是不够灵活。这里笔者提供一种较为灵活的做法。
但是这种做法的用户体验没有上篇文章的好,至于使用何种方法,读者应该自己衡量。
同样,我们先看实际效果图。
这里展示的是笔者项目的一小部分(阅读器):
我们点击左下角的剪切按钮
我们通过红色边框的四个角来控制裁剪的大小,移动红色框体来控制裁剪的位置区域。
接下来我们看看源码的实现:
首先点击剪切按钮的时候,我们应该生成一个Bitmap对象,传递给另一个Activty处理
具体做法如下:
1. cutP.setOnClickListener(new View.OnClickListener() {
2.
3. public void onClick(View v) {
4. //将一些按钮隐藏
5. cutP.setVisibility(View.INVISIBLE);
6. mTopBarSwitcher.setVisibility(View.INVISIBLE);
7. mPageSlider.setVisibility(View.INVISIBLE);
8. back.setVisibility(View.INVISIBLE);
9. mPageNumberView.setVisibility(View.INVISIBLE);
10. this.getWindow().getDecorView();
11. if (false == view.isDrawingCacheEnabled()) {
12. true);
13. }
14. Bitmap bitmap = view.getDrawingCache();
15. new ImageView(MuPDFActivity.this);
16. new LayoutParams(LayoutParams.FILL_PARENT,
17. 200));
18. imgv.setImageBitmap(bitmap);
19. backBitmap = bitmap;
20. //传递给另一个Activity进行裁剪
21. new Intent();
22. this, CutActivity.class);
23. startActivity(intent);
24.
25. }
26.
27. });
Tips:这里笔者是将这个截取的Bitmap对象传递给另一个Actvity做相关处理,这里如何
在Activity之间进行Bitmap传递呢?这里我们简单的运用java语法特性来完成具体做法如下:
我们在ActvityA中有一个public static Bitmap bitmap对象,当ActivityA跳转到B时,我们直接
通过ActivityA.bitmap来获取这个对象。
之后就是如何进行裁剪的操作了。操作在另一个Activity中进行。XML配置文件信息如下:
1. <?xml version="1.0" encoding="utf-8"?>
2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. "match_parent"
4. "match_parent"
5. >
6. <com.artifex.mupdf.Crop_Canvas
7. "@+id/myCanvas"
8. "fill_parent"
9. "fill_parent"
10. "#313131"
11. />
12. <Button
13. "@+id/cutCancel"
14. "wrap_content"
15. "wrap_content"
16. "取消"
17. "true"
18. "true"/>
19. <Button
20. "@+id/cutEnsure"
21. "wrap_content"
22. "wrap_content"
23. "确定"
24. "true"
25. "true"/>
26. <Button
27. "@+id/toPDF"
28. "wrap_content"
29. "wrap_content"
30. "ToPDF"
31. "true"
32. "true"/>
33. </RelativeLayout>
通过配置文件可以看到我们自定义了一个View(ImageView)其实现如下:
1. package com.artifex.mupdf;
2.
3. import android.content.Context;
4. import android.graphics.Bitmap;
5. import android.graphics.Canvas;
6. import android.graphics.Color;
7. import android.graphics.Matrix;
8. import android.graphics.Paint;
9. import android.graphics.Rect;
10. import android.graphics.RectF;
11. import android.graphics.Bitmap.Config;
12. import android.graphics.drawable.BitmapDrawable;
13. import android.util.AttributeSet;
14. import android.view.MotionEvent;
15. import android.widget.ImageView;
16.
17. public class Crop_Canvas extends ImageView {
18.
19. private final static int PRESS_LB = 0;//表示左下角矩形框
20. private final static int PRESS_LT = 1;//表示左上角矩形框
21. private final static int PRESS_RB = 2;//表示右下角矩形框
22. private final static int PRESS_RT = 3;//表示右上角矩形框
23.
24. private Bitmap bitMap = null; //原始图片
25. private RectF src = null; //经过比例转换后的裁剪区域
26. private RectF dst = null; //图片显示区域,也就是drawBitmap函数中的目标dst
27. private RectF ChooseArea = null; //选择区域
28. private Paint mPaint = null; //画笔
29. private Matrix matrix = null; //矩阵
30.
31. private int mx = 0; //存储触笔移动时,之前�?��的触笔的x坐标
32. private int my = 0; //存储触笔移动时,之前�?��的触笔的y坐标
33. private boolean touchFlag = false; //触笔是否在屏幕之�?
34. private boolean cutFlag = false; //是否点击了menu上的裁剪按钮
35. private int recFlag = -1; //用来存储触笔点击了哪个小矩形框(改变选择区域大小的小矩形框)
36. private boolean firstFlag = false;
37.
38. private RectF recLT = null; //左上角的小矩形框
39. private RectF recRT = null; //右上角的小矩形框
40. private RectF recLB = null; //左下角的小矩形框
41. private RectF recRB = null; //右下角的小矩形框
42. private static final int LEFT_AREA_ALPHA = 50 * 255 / 100;
43. private RectF leftRectL = null;
44. private RectF leftRectR = null;
45. private RectF leftRectT = null;
46. private RectF leftRectB = null;
47. private Paint leftAreaPaint = null;
48.
49. public Crop_Canvas(Context context, AttributeSet attrs) {
50. super(context, attrs);
51. this.init();
52. }
53.
54. public Crop_Canvas(Context context) {
55. super(context);
56. this.init();
57. }
58.
59. public void init(){
60. true;
61. new RectF();
62. new RectF();
63. new RectF();
64. new RectF();
65. new RectF();
66. new Paint();
67. mPaint.setColor(Color.RED);
68. //将画笔的风格改为空心
69. new RectF();
70. this.setPressRecLoc();
71. null;
72. true;
73.
74. //选择框之外的灰色区域,分成四个矩形框
75.
76. new Paint();
77. leftAreaPaint.setStyle(Paint.Style.FILL);
78. leftAreaPaint.setAlpha(Crop_Canvas.LEFT_AREA_ALPHA);
79. }
80.
81. public void setBitmap(Bitmap bitmap){
82. new BitmapDrawable(bitmap);
83. new RectF(0,0,bd.getIntrinsicWidth(),bd.getIntrinsicHeight());
84. this.bitMap = bitmap.copy(Config.ARGB_8888, true);
85.
86. this.setImageBitmap(bitMap);
87. new RectF();
88. new RectF();
89. new RectF();
90. new RectF();
91. }
92.
93. public void imageScale(){
94. this.getImageMatrix();
95. matrix.mapRect(dst, src);
96. int padding = this.getPaddingBottom();
97. int width = bitMap.getWidth();
98. int height = bitMap.getHeight();
99. //dst.set(dst.left+padding,dst.top+padding,dst.right+padding,dst.bottom+padding);
100. 20,dst.top+20,width-20,height - 40);
101. new RectF(dst);
102. this.setPressRecLoc();
103. }
104.
105. public Bitmap getSubsetBitmap(){
106. float ratioWidth = bitMap.getWidth()/(float)(dst.right-dst.left);
107. float ratioHeight = bitMap.getHeight()/(float)(dst.bottom - dst.top);
108. int left = (int)((ChooseArea.left - dst.left) * ratioWidth);
109. int right = (int)(left + (ChooseArea.right - ChooseArea.left) * ratioWidth);
110. int top = (int)((ChooseArea.top - dst.top) * ratioHeight);
111. int bottom = (int)(top + (ChooseArea.bottom - ChooseArea.top) * ratioHeight);
112. new RectF(left,top,right,bottom);
113. true;
114. set_LeftArea_Alpha();
115. return Bitmap.createBitmap(bitMap, left, top, right-left, bottom-top);
116. }
117.
118. //获得ChooseArea对象
119. public RectF getChooseArea(){
120. return ChooseArea;
121. }
122.
123. public void moveChooseArea(int move_x,int move_y){
124. if(ChooseArea.left + move_x >= dst.left && ChooseArea.right + move_x <= dst.right
125. && ChooseArea.top + move_y >= dst.top && ChooseArea.bottom + move_y <= dst.bottom){
126. ChooseArea.set(ChooseArea.left + move_x,ChooseArea.top+move_y
127. ,ChooseArea.right + move_x,ChooseArea.bottom+move_y);
128. else{
129. if(ChooseArea.left + move_x < dst.left){
130. ChooseArea.set(dst.left,ChooseArea.top
131. ,ChooseArea.right+dst.left-ChooseArea.left,ChooseArea.bottom);
132. }
133. if(ChooseArea.right + move_x > dst.right){
134. ChooseArea.set(ChooseArea.left+dst.right-ChooseArea.right,ChooseArea.top
135. ,dst.right,ChooseArea.bottom);
136. }
137.
138. if(ChooseArea.top + move_y < dst.top){
139. ChooseArea.set(ChooseArea.left,dst.top
140. ,ChooseArea.right,ChooseArea.bottom+dst.top-ChooseArea.top);
141. }
142.
143. if(ChooseArea.bottom + move_y > dst.bottom){
144. ChooseArea.set(ChooseArea.left,ChooseArea.top+dst.bottom-ChooseArea.bottom
145. ,ChooseArea.right,dst.bottom);
146. }
147. }
148. this.setPressRecLoc();
149. mPaint.setColor(Color.GREEN);
150. this.invalidate();
151. }
152.
153. public boolean onTouchEvent(MotionEvent event){
154. mPaint.setColor(Color.RED);
155.
156.
157. if(event.getAction() == MotionEvent.ACTION_DOWN && cutFlag){
158. //System.out.println(event.getX() + "," + event.getY());
159.
160. int)event.getX();
161. int)event.getY();
162. if(this.judgeLocation(mx,my)){
163. true;
164. mPaint.setColor(Color.GREEN);
165. this.invalidate();
166. return true;
167. else{
168.
169. if(this.findPresseddst((int)event.getX(), (int)event.getY())){
170. true;
171. mPaint.setColor(Color.RED);
172. return true;
173. }
174. }
175. }
176.
177. if(event.getAction() == MotionEvent.ACTION_MOVE && touchFlag){
178. //判断是否点击了哪个个小矩形框
179. if(this.isOutOfArea((int)event.getX(), (int)event.getY())){
180. return true;
181. }
182.
183. //如果选择区域大小跟图像大小一样时,就不能移动
184. if(ChooseArea.left == dst.left && ChooseArea.top == dst.top &&
185. ChooseArea.right == dst.right && ChooseArea.bottom == dst.bottom){
186. else{
187. this.moveChooseArea((int)event.getX() - mx, (int)event.getY() - my);
188. int)event.getX();
189. int)event.getY();
190. }
191. }
192.
193.
194. if(event.getAction() == MotionEvent.ACTION_UP){
195. 1;
196. this.invalidate();
197. false;
198. }
199.
200. return super.onTouchEvent(event);
201. }
202.
203.
204.
205.
206. private boolean isOutOfArea(int x,int y){
207. switch(recFlag){
208. case Crop_Canvas.PRESS_LB:
209. this.pressLB(x - mx, y - my);
210. break;
211. case Crop_Canvas.PRESS_LT:
212. this.pressLT(x - mx, y - my);
213. break;
214. case Crop_Canvas.PRESS_RB:
215. this.pressRB(x - mx, y - my);
216. break;
217. case Crop_Canvas.PRESS_RT:
218. this.pressRT(x - mx, y - my);
219. break;
220. default:return false;
221. }
222. mx = x;
223. my = y;
224. this.invalidate();
225. return true;
226. }
227.
228. public boolean findPresseddst(int x,int y){
229. boolean returnFlag = false;
230. if(this.isInRect(x, y, recLB)){
231. recFlag = Crop_Canvas.PRESS_LB;
232. true;
233. else if(this.isInRect(x, y, recLT)){
234. recFlag = Crop_Canvas.PRESS_LT;
235. true;
236. else if(this.isInRect(x, y, recRB)){
237. recFlag = Crop_Canvas.PRESS_RB;
238. true;
239. else if(this.isInRect(x, y, recRT)){
240. recFlag = Crop_Canvas.PRESS_RT;
241. true;
242. }
243.
244. return returnFlag;
245. }
246.
247. public boolean isInRect(int x,int y,RectF rect){
248. if(x >= rect.left -20 && x <= rect.right + 20 && y > rect.top - 20 && y < rect.bottom + 20){
249. return true;
250. }
251. return false;
252. }
253.
254. private void pressLB(int x,int y){
255. float left = ChooseArea.left + x;
256. float right = ChooseArea.right;
257. float top = ChooseArea.top;
258. float bottom = ChooseArea.bottom + y;
259. if(left <= right - 30 && left >= dst.left && bottom <= dst.bottom && bottom >= top + 30){
260. ChooseArea.set(left,top,right,bottom);
261. else{
262. if(left + x < dst.left){
263. left = dst.left;
264. }
265.
266. if(bottom + y > dst.bottom){
267. bottom = dst.bottom;
268. }
269.
270. if(ChooseArea.left + x > ChooseArea.right - 30){
271. 30;
272. }
273.
274. if(ChooseArea.bottom + y < ChooseArea.top + 30){
275. 30;
276. }
277. ChooseArea.set(left,top,right,bottom);
278. }
279. this.setPressRecLoc();
280. }
281.
282.
283. private void pressLT(int x,int y){
284. float left = ChooseArea.left + x;
285. float right = ChooseArea.right;
286. float top = ChooseArea.top + y;
287. float bottom = ChooseArea.bottom;
288. if(left <= right - 30 && left >= dst.left && top <= bottom - 30 && top >= dst.top){
289. ChooseArea.set(left,top,right,bottom);
290. else{
291. if(left < dst.left){
292. left = dst.left;
293. }
294.
295. if(top < dst.top){
296. top = dst.top;
297. }
298.
299. if(left > right - 30){
300. 30;
301. }
302.
303. if(top > bottom - 30){
304. 30;
305. }
306. ChooseArea.set(left,top,right,bottom);
307. }
308. this.setPressRecLoc();
309. }
310.
311.
312. private void pressRT(int x,int y){
313. float left = ChooseArea.left;
314. float right = ChooseArea.right + x;
315. float top = ChooseArea.top + y;
316. float bottom = ChooseArea.bottom;
317.
318. if(right <= dst.right && right >= left + 30 && top <= bottom - 30 && top >= dst.top){
319. ChooseArea.set(left,top,right,bottom);
320. else{
321. if(right > dst.right){
322. right = dst.right;
323. }
324.
325. if(top < dst.top){
326. top = dst.top;
327. }
328.
329. if(right < left + 30){
330. 30;
331. }
332.
333. if(top > bottom - 30){
334. 30;
335. }
336. ChooseArea.set(left,top,right,bottom);
337. }
338. this.setPressRecLoc();
339. }
340.
341.
342. private void pressRB(int x,int y){
343. float left = ChooseArea.left;
344. float right = ChooseArea.right + x;
345. float top = ChooseArea.top;
346. float bottom = ChooseArea.bottom + y;
347.
348. if(right<= dst.right && right >= left + 30 && bottom <= dst.bottom && bottom >= top + 30){
349. ChooseArea.set(left,top,right,bottom);
350. else{
351. if(right > dst.right){
352. right = dst.right;
353. }
354.
355. if(bottom > dst.bottom){
356. bottom = dst.bottom;
357. }
358.
359. if(right < left + 30){
360. 30;
361. }
362.
363. if(bottom < top + 30){
364. 30;
365. }
366. ChooseArea.set(left,top,right,bottom);
367. }
368. this.setPressRecLoc();
369. }
370.
371. //每次改变选择区域矩形的大小或者移动,各角落上的小矩形也要改变它的Location
372. private void setPressRecLoc(){
373. 5,ChooseArea.top-5 , ChooseArea.left+5, ChooseArea.top+5);
374. 5,ChooseArea.bottom-5 , ChooseArea.left+5, ChooseArea.bottom+5);
375. 5,ChooseArea.top-5 , ChooseArea.right+5, ChooseArea.top+5);
376. 5,ChooseArea.bottom-5 , ChooseArea.right+5, ChooseArea.bottom+5);
377. }
378.
379.
380. public boolean judgeLocation(float x,float y){
381. float start_x = this.getChooseArea().left;
382. float start_y = this.getChooseArea().top;
383. float last_x = this.getChooseArea().right;
384. float last_y = this.getChooseArea().bottom;
385. //System.out.println("chubi:" + x + "," + y);
386. //System.out.println(start_y + "," + last_y);
387. if(x > start_x+10 && x < last_x-10 && y > start_y+10 && y < last_y-10){
388. return true;
389. }
390. return false;
391. }
392.
393. public void onDraw(Canvas canvas){
394. super.onDraw(canvas);
395. if(firstFlag){
396. this.imageScale();
397. false;
398. mPaint.setColor(Color.RED);
399. "Width: " + (dst.right - dst.left));
400. "Height: " + (dst.bottom - dst.top));
401. "Width: " + this.getDrawable().getIntrinsicWidth());
402. "Height: " + this.getDrawable().getIntrinsicHeight());
403. else{
404. set_LeftArea_Alpha();
405. }
406. canvas.drawRect(ChooseArea, mPaint);
407. mPaint.setColor(Color.BLUE);
408. canvas.drawRect(recLT, mPaint);
409. canvas.drawRect(recLB, mPaint);
410. canvas.drawRect(recRT, mPaint);
411. canvas.drawRect(recRB, mPaint);
412.
413. canvas.drawRect(leftRectL, leftAreaPaint);
414. canvas.drawRect(leftRectR, leftAreaPaint);
415. canvas.drawRect(leftRectT, leftAreaPaint);
416. canvas.drawRect(leftRectB, leftAreaPaint);
417.
418. }
419.
420. public void set_LeftArea_Alpha(){
421. leftRectL.set(dst.left, dst.top, ChooseArea.left, dst.bottom);
422. leftRectR.set(ChooseArea.right,dst.top,dst.right,dst.bottom);
423. leftRectT.set(ChooseArea.left, dst.top, ChooseArea.right, ChooseArea.top);
424. leftRectB.set(ChooseArea.left,ChooseArea.bottom,ChooseArea.right,dst.bottom);
425. }
426. }
接下来直接看看Activity源码:
1. package com.artifex.mupdf.cut;
2.
3.
4. import java.io.File;
5. import java.io.FileNotFoundException;
6. import java.io.FileOutputStream;
7. import java.io.IOException;
8. import java.util.ArrayList;
9.
10. import android.app.Activity;
11. import android.graphics.Bitmap;
12. import android.os.Bundle;
13. import android.view.View;
14. import android.view.View.OnClickListener;
15. import android.view.Window;
16. import android.widget.Button;
17.
18. import com.andorid.shu.love.R;
19. import com.artifex.mupdf.Crop_Canvas;
20. import com.artifex.mupdf.MuPDFActivity;
21.
22. public class CutActivity extends Activity {
23. private Crop_Canvas canvas = null;
24. private Bitmap backBitmap;
25. private Button cancel;
26. private Button ensure;
27. private Button toPDF;
28.
29. @Override
30. protected void onCreate(Bundle savedInstanceState) {
31. super.onCreate(savedInstanceState);
32. requestWindowFeature(Window.FEATURE_NO_TITLE);
33. setContentView(R.layout.cut_image);
34. backBitmap = MuPDFActivity.backBitmap;
35. init();
36. cancel = (Button) findViewById(R.id.cutCancel);
37. new OnClickListener() {
38.
39. @Override
40. public void onClick(View v) {
41. this.finish();
42. }
43. });
44. ensure = (Button) findViewById(R.id.cutEnsure);
45. new OnClickListener() {
46. @Override
47. public void onClick(View v) {
48. //图片保存的路径,之后将之转换为PDF,并以附件的形似发送邮件
49. new File("/sdcard/lovereader/pic");
50. tmp.mkdirs();
51. new File("/sdcard/lovereader/pic/" + "testpic" + ".png");
52. try {
53. f.createNewFile();
54. catch (IOException e1) {
55. // TODO Auto-generated catch block
56. e1.printStackTrace();
57. }
58. null;
59. try {
60. new FileOutputStream(f);
61. catch (FileNotFoundException e) {
62. e.printStackTrace();
63. }
64. 100, fOut);
65. try {
66. fOut.flush();
67. catch (IOException e) {
68. e.printStackTrace();
69. }
70. try {
71. fOut.close();
72. catch (IOException e) {
73. e.printStackTrace();
74. }
75. }
76. });
77.
78. toPDF = (Button)findViewById(R.id.toPDF);
79. new OnClickListener() {
80.
81. @Override
82. public void onClick(View v) {
83. // TODO Auto-generated method stub
84. new ArrayList<String>();
85. "/sdcard/lovereader/pic/" + "testpic" + ".png");
86. "/sdcard/lovereader/tmp/Foreverlove.pdf";
87. new File("/sdcard/lovereader/tmp");
88. tmp.mkdirs();
89. File file = PdfManager.Pdf(imageUrllist, pdfUrl);
90. try {
91. file.createNewFile();
92. catch (IOException e) {
93. // TODO Auto-generated catch block
94. e.printStackTrace();
95. }
96.
97. }
98. });
99. }
100.
101. private void init() {
102. canvas = (Crop_Canvas) findViewById(R.id.myCanvas);
103. Bitmap bitmap = backBitmap;
104. canvas.setBitmap(bitmap);
105. }
106.
107. }