【android开发】手写签名系统的设计与实现之实现解析pdf文件(二)

上一篇文章,我们介绍了如何去实现读取手机文件及文件夹,并以列表的形式显示出来,今天我们将说说如何读取pdf文件。先看效果图:

              选择pdf文件                                               显示pdf文件主界面

                        

一、实现原理:

手机端解析pdf的实例并不是很多,android系统本身没有解析的类,就需要第三方开发库,现在常用的两种方式:一种是利用动态链接库libmupdf.so;另一种是利用动态链接库libvudroid.so。两者各有自己的优缺点,前者解析速度快,但是比较耗内存;后者省内存,但是解析比较慢。本项目是利用前者动态库来解析pdf的,这两个在网上都可以下载,也有一个相关的实例。本人感觉,前者比较简单,后者实现的相对复杂,之前有人说前者动态库是在后者的基础上写的,等待求证。下面我们就介绍libmupdf.so动态库:MUPDF是一个轻量级pdf显示阅读器,大家需要把limupdf.so导入到项目中,建立一个包名为com.artifex.mupdf,目录结构如下:


在com.artifex.mupdf包中新建这几个类,我们重点介绍MuPDFActivity、ReaderView、PageView、MuPDFCore。

在MuPDFActivity类中获取要读取的pdf地址,传给MuPDFCore对象:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 功能:根据获取的文件路径,解析pdf,并返回core 
  3.      * @param path 
  4.      * @return core 
  5.      */  
  6.     private MuPDFCore openFile(String path)  
  7.     {  
  8.           
  9.         PATH = path;  
  10.         int lastSlashPos = path.lastIndexOf('/');  
  11.         mFileName = new String(lastSlashPos == -1  
  12.                     ? path  
  13.                     : path.substring(lastSlashPos+1));  
  14.         System.out.println("Trying to open "+path);  
  15.         try  
  16.         {  
  17.             core = new MuPDFCore(path);  
  18.             // New file: drop the old outline data  
  19.         }  
  20.         catch (Exception e)  
  21.         {  
  22.             System.out.println(e);  
  23.             return null;  
  24.         }  
  25.         return core;  
  26.     }  
MuPDFCore开始解析pdf,最后将其实例传给ReaderView:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private ReaderView   mDocView;  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. mDocView = new ReaderView(this) {  
  2.             private boolean showButtonsDisabled;  
  3.   
  4.             public boolean onSingleTapUp(MotionEvent e) {  
  5.                 if (e.getX() < super.getWidth()/TAP_PAGE_MARGIN) {  
  6.                     super.moveToPrevious();  
  7.                 } else if (e.getX() > super.getWidth()*(TAP_PAGE_MARGIN-1)/TAP_PAGE_MARGIN) {  
  8.                     super.moveToNext();  
  9.                 } else if (!showButtonsDisabled) {  
  10.                     int linkPage = -1;  
  11.                     if (mLinkState != LinkState.INHIBIT) {  
  12.                         MuPDFPageView pageView = (MuPDFPageView) mDocView.getDisplayedView();  
  13.                         if (pageView != null) {  
  14. // XXX                          linkPage = pageView.hitLinkPage(e.getX(), e.getY());  
  15.                         }  
  16.                     }  
  17.   
  18.                     if (linkPage != -1) {  
  19.                         mDocView.setDisplayedViewIndex(linkPage);  
  20.                     } else {  
  21.                         if (!mButtonsVisible) {  
  22.                             showButtons();  
  23.                         } else {  
  24.                             hideButtons();  
  25.                         }  
  26.                     }  
  27.                 }  
  28.                 return super.onSingleTapUp(e);  
  29.             }  
  30.   
  31.             public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {  
  32.                 if (!showButtonsDisabled)  
  33.                     hideButtons();  
  34.   
  35.                 return super.onScroll(e1, e2, distanceX, distanceY);  
  36.             }  
  37.   
  38.             public boolean onScaleBegin(ScaleGestureDetector d) {  
  39.                 showButtonsDisabled = true;  
  40.                 return super.onScaleBegin(d);  
  41.             }  
  42.   
  43.             public boolean onTouchEvent(MotionEvent event) {  
  44.                 if (event.getActionMasked() == MotionEvent.ACTION_DOWN){  
  45.                     showButtonsDisabled = false;  
  46.                 }  
  47.                 return super.onTouchEvent(event);  
  48.             }  
  49.   
  50.             protected void onChildSetup(int i, View v) {  
  51.   
  52.                 ((PageView)v).setLinkHighlighting(mLinkState == LinkState.HIGHLIGHT);  
  53.             }  
  54.   
  55.             protected void onMoveToChild(int i) {  
  56.                 if (core == null)  
  57.                     return;  
  58.                 mPageNumberView.setText(String.format("%d/%d", i+1, core.countPages()));  
  59.                 mPageSlider.setMax(core.countPages()-1);  
  60.                 mPageSlider.setProgress(i);  
  61.             }  
  62.   
  63.             protected void onSettle(View v) {  
  64.                 // When the layout has settled ask the page to render  
  65.                 // in HQ  
  66.                 ((PageView)v).addHq();  
  67.             }  
  68.   
  69.             protected void onUnsettle(View v) {  
  70.                 // When something changes making the previous settled view  
  71.                 // no longer appropriate, tell the page to remove HQ  
  72.                 ((PageView)v).removeHq();  
  73.             }  
  74.         };  
  75.           
  76.         mDocView.setAdapter(new MuPDFPageAdapter(this, core));  
ReaderView获取pdf的页面信息后传给PageView,这样pdf文件就显示出来了,其原理就是将每一页转成一个bitmap对象:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. MuPDFPageView pageView = (MuPDFPageView) mDocView.getDisplayedView();  

ReaderView包含了对pdf文件的相关操作,比如页面放大缩小、翻页等相关手势:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发 
  3.      * */  
  4.     public boolean onDown(MotionEvent arg0) {  
  5.         mScroller.forceFinished(true);  
  6.         //Log.e("info", "-->onDown");  
  7.         return true;  
  8.     }  
  9.   
  10.     /* 
  11.      * 用户按下触摸屏、快速移动后松开, 
  12.      * 由1个MotionEvent ACTION_DOWN,  
  13.      * 多个ACTION_MOVE, 1个ACTION_UP触发 
  14.      * */  
  15.     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  16.             float velocityY) {  
  17.         if (mScrollDisabled)  
  18.             return true;  
  19.   
  20.         View v = mChildViews.get(mCurrent);  
  21.         if (v != null) {  
  22.             Rect bounds = getScrollBounds(v);  
  23.             switch(directionOfTravel(velocityX, velocityY)) {  
  24.             case MOVING_LEFT:  
  25.                 if (bounds.left >= 0) {  
  26.                     // Fling off to the left bring next view onto screen  
  27.                     View vl = mChildViews.get(mCurrent+1);  
  28.   
  29.                     if (vl != null) {  
  30.                         slideViewOntoScreen(vl);  
  31.                         return true;  
  32.                     }  
  33.                 }  
  34.                 break;  
  35.             case MOVING_RIGHT:  
  36.                 if (bounds.right <= 0) {  
  37.                     // Fling off to the right bring previous view onto screen  
  38.                     View vr = mChildViews.get(mCurrent-1);  
  39.   
  40.                     if (vr != null) {  
  41.                         slideViewOntoScreen(vr);  
  42.                         return true;  
  43.                     }  
  44.                 }  
  45.                 break;  
  46.             }  
  47.             mScrollerLastX = mScrollerLastY = 0;  
  48.               
  49.             Rect expandedBounds = new Rect(bounds);  
  50.             expandedBounds.inset(-FLING_MARGIN, -FLING_MARGIN);  
  51.   
  52.             if(withinBoundsInDirectionOfTravel(bounds, velocityX, velocityY)  
  53.                     && expandedBounds.contains(00)) {  
  54.                 mScroller.fling(00, (int)velocityX, (int)velocityY, bounds.left, bounds.right, bounds.top, bounds.bottom);  
  55.                 post(this);  
  56.             }  
  57.         }  
  58.   
  59.         return true;  
  60.     }  
  61.     /** 
  62.      * 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发  
  63.      * */  
  64.     public void onLongPress(MotionEvent e) {  
  65.     }  
  66.     /** 
  67.      * 功能:扑捉屏幕手势滑动动作 
  68.      * 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN,  
  69.      * 多个ACTION_MOVE触发。 
  70.      * */  
  71.     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,  
  72.             float distanceY) {  
  73.           
  74.         //Log.e("info", "-->onScroll");  
  75.         //这里控制pdf文件翻页  
  76.         if (!mScrollDisabled) {  
  77.             mXScroll -= distanceX;  
  78.             mYScroll -= distanceY;  
  79.             requestLayout();  
  80.         }         
  81.         return true;  
  82.     }  
  83.       
  84.       
  85.       
  86.     /** 
  87.      * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 
  88.      * 注意和onDown()的区别,强调的是没有松开或者拖动的状态 . 
  89.      * */  
  90.     public void onShowPress(MotionEvent e) {  
  91.         //Log.e("info", "-->onShowPress");  
  92.     }  
  93.     /** 
  94.      * 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发 
  95.      * */  
  96.     public boolean onSingleTapUp(MotionEvent e) {  
  97.         return false;  
  98.     }  
  99.     /** 
  100.      * 处理对屏幕的缩放比例 
  101.      * */  
  102.     public boolean onScale(ScaleGestureDetector detector) {  
  103.         //截屏视图不显示时,手势操作可以进行  
  104.             float previousScale = mScale;  
  105.             mScale = Math.min(Math.max(mScale * detector.getScaleFactor(), MIN_SCALE), MAX_SCALE);  
  106.             scalingFactor = mScale/previousScale;//缩放比例  
  107.             //Log.e("info", "--->scalingFactor="+scalingFactor);  
  108.             View v = mChildViews.get(mCurrent);  
  109.             if (v != null) {  
  110.                 // Work out the focus point relative to the view top left  
  111.                 int viewFocusX = (int)detector.getFocusX() - (v.getLeft() + mXScroll);  
  112.                 int viewFocusY = (int)detector.getFocusY() - (v.getTop() + mYScroll);  
  113.                 // Scroll to maintain the focus point  
  114.                 mXScroll += viewFocusX - viewFocusX * scalingFactor;  
  115.                 mYScroll += viewFocusY - viewFocusY * scalingFactor;  
  116.                 requestLayout();  
  117.         }  
  118.         return true;  
  119.     }  
  120.   
  121.     public boolean onScaleBegin(ScaleGestureDetector detector) {  
  122.         mScaling = true;  
  123.         // Ignore any scroll amounts yet to be accounted for: the  
  124.         // screen is not showing the effect of them, so they can  
  125.         // only confuse the user  
  126.         mXScroll = mYScroll = 0;  
  127.         // Avoid jump at end of scaling by disabling scrolling  
  128.         // until the next start of gesture  
  129.         mScrollDisabled = true;  
  130.         return true;//一定要返回true才会进入onScale()这个函数  
  131.     }  
  132.   
  133.     public void onScaleEnd(ScaleGestureDetector detector) {  
  134.         mScaling = false;  
  135.     }  
  136.       
  137.     /*  
  138.      * 在onTouch()方法中,我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给GestureDetector  
  139.      * 来分析是否有合适的callback函数来处理用户的手势  
  140.      */    
  141.     @Override  
  142.     public boolean onTouch(View v, MotionEvent event) {  
  143.         // TODO Auto-generated method stub  
  144.         return mGestureDetector.onTouchEvent(event);   
  145.     }  
  146.     @Override  
  147.     public boolean onTouchEvent(MotionEvent event) {  
  148.           
  149.         mScaleGestureDetector.onTouchEvent(event);  
  150.         if (!mScaling)  
  151.             mGestureDetector.onTouchEvent(event);  
  152.   
  153.         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {  
  154.             mUserInteracting = true;  
  155.         }  
  156.         if (event.getActionMasked() == MotionEvent.ACTION_UP) {  
  157.             mScrollDisabled = false;  
  158.             mUserInteracting = false;  
  159.               
  160.               
  161.             if(event.getAction() == MotionEvent.ACTION_UP){  
  162.                 View v = mChildViews.get(mCurrent);  
  163.                 if (v != null) {  
  164.                     if (mScroller.isFinished()) {  
  165.                         slideViewOntoScreen(v);  
  166.                     }  
  167.       
  168.                     if (mScroller.isFinished()) {  
  169.                         postSettle(v);  
  170.                         }  
  171.                     }  
  172.             }  
  173.         }  
  174.         requestLayout();  
  175.         return true;  
  176.     }  

这里我们说到了手势的相关操作,手势操作是比较流行的,主要是要实现OnGestureListener接口,例如Fling,Scroll等等。这些Gesture会使用户体验大大提升。

这些完成之后,我们就要在FileActivity类中调用MuPDFActivity:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Intent intent = new Intent(getApplicationContext(), MuPDFActivity.class);  
  2. intent.setAction(Intent.ACTION_VIEW);  
  3. intent.setData(uri);  
  4. startActivity(intent);  

最后要在清单文件中注册相应的activity:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <activity android:name="com.artifex.mupdf.MuPDFActivity"  
  2.             android:label="@string/app_name"></activity>  

到此我们就可以显示要读取的pdf文件了,并可以对页面就行放大缩小、翻页操作。这个也是从一个开源项目中学到,根据自己的需求实现了其中一部分功能,MuPDF解析pdf远比这些功能要多,这只是一小部分而已。对于具体实现过程,大家可以下载本博客相应的实例源码,这里就不全部贴出来了,在最后边将把代码下载链接留给大家,需要的朋友可以下载看看。明天我们将会介绍如何实现手写画板。欢迎大家继续关注,对于不足之处敬请指正,大家一起进步,上传资源已经运行,没有问题,如果你不能运行,请在博客留言……
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
android电子签名,屏幕上手写签名 搜集很多资料,项目能够完美运行,拿来即可使用,整理备用 应用场景: 就是在屏幕是用手写字,然后保存成图片,简称就是电子签名,可以用在手机上签合同,等技术。 使用技术: 使用了接口回调,绘制完成之后给用户去操作 自定义Dialog,在dialog上画图,给dialog设置主题,dialog的宽高设置为手机屏幕的宽高充满全屏 注意在计算高度的时候记得减去通知栏的高度 注意把画布的背景设置为白色,不然点击缩略图查看的时候是全黑色 参考如下资料: http://hbxflihua.iteye.com/blog/1512765 http://www.jianshu.com/p/c4f017603413 https://github.com/gcacace/android-signaturepad http://download.csdn.net/download/mmlinux/7687091 1,android 如何让自定义dialog的宽度跟屏幕的宽度一样? 在你dialog.show();后面加上 WindowManager windowManager = getWindowManager(); Display display = windowManager.getDefaultDisplay(); WindowManager.LayoutParams lp = dialog.getWindow().getAttributes(); lp.width = (int)(display.getWidth()); //设置宽度 dialog.getWindow().setAttributes(lp); 2,如何获取通知栏的高度? public int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } 3,如何对图片进行压缩? http://blog.sina.com.cn/s/blog_497f718e0100sl13.html http://www.cnblogs.com/Soprano/articles/2577152.html

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值