PDF阅读器系列之--MuPDF源码分析过程(二)

分析

初看项目工程目录结构,不是很多,直接看类的字面意思均可以得出一些浅显易懂的知识点

1.看清单文件得出来有4个activity

在ChooseActivity中,添加了多个intent-filter意图过滤器,其作用就是规定一些格式文件,一些支持的类型

2.进入src中
tip :项目代码中大量运用枚举

ChoosePDFActivity是程序的主界面,分类型,是文件夹是就进行打开,pdf就跳转等待结果 
ChoosePDFAdapter是加载sd卡文件信息,3中type:上一层,文件夹,文件 
MuPDFReflowView继承WebView 

MuPDFCore 是声明本地方法并加载so的类:功能用c实现

/* The core rendering instance */

enum TopBarMode {Main, Search, Annot, Delete, More, Accept};

enum AcceptMode {Highlight, Underline, StrikeOut, Ink, CopyText};

3.再看xml

布局文件在 buttons.xml下,采用的是ViewAnimator(视图切换)

draw的逻辑分析

draw相关的类

MuPDFActivity MuPDFReaderView ReaderView PageView MuPDFPageView

充分利用 ctrl+shift +F 查找你想要的信息

//墨迹Ink 绘制按钮

public void OnInkButtonClick(View v) {  

mTopBarMode = TopBarMode.Accept;  

mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());  

mAcceptMode = AcceptMode.Ink;  

mDocView.setMode(MuPDFReaderView.Mode.Drawing);  

mAnnotTypeText.setText(R.string.ink);  

showInfo(getString(R.string.draw_annotation));

}

在源PDF文件上绘制图层,找到触发绘制的事件,追踪绘制的逻辑

MuPDFActivity MuPDFReaderView ReaderView PageView MuPDFPageView

Point类: Point holds two integer coordinates

MuPDFPageView继承PageView

在MuPDFReaderView中 
touch事件 
touch_start touch_move 
在方法中都使用MuPDFView,实现MuPDFView接口,中startDraw continueDraw方法

有个问题:当状态为 Drawing时,双手可以进行缩放

Annot 是Annotation的缩写:代表注释状态 
总结如下: 
1.mupdfdemo他核心代码是用本地C写的,java调用在MuPDFCore类中 
2.几个重要的类分别是 
MuPDFActivity控制相关按钮事件 
PageView中绘制相关 
MuPDFView 继承PageView 
reflow 跟重排版文档相关 
print 跟打印相关 
ordinary 回到TopBarMode.main类型

重点分析MuPDFActivity.java

//注释 点击已绘制区域,可删除

//注释 点击已绘制区域,可删除  

public void OnDeleteButtonClick(View v) {  

MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();  

if (pageView != null)  

pageView.deleteSelectedAnnotation();  

LogUtils.d(TAG, "OnDeleteButtonClick: ");  

mTopBarMode = TopBarMode.Annot;  

mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());  

}  

//注释 点击已绘制区域,可返回  

public void OnCancelDeleteButtonClick(View v) {  

MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();  

if (pageView != null)  

pageView.deselectAnnotation();  

LogUtils.d(TAG, "OnCancelDeleteButtonClick: ");  

mTopBarMode = TopBarMode.Annot;  

mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());  

}

思路

触摸PDF view 执行的一些事件 
ReaderView.java 
1。点击屏幕中央:

2.点击屏幕左边或者右边:

2016年2月29日16:05:53 
先实现 绘制页面,添加几个按钮:前进,撤销,颜色选择;

实现结果就是在相应模式下面点击新增按钮实现不同的效果

一、实现绘制回退功能 
需求:点击画笔之后绘制一笔后,点击此按钮,能够撤销操作

1.

二、实现绘制前进功能(待议) 
需求:在撤销操作后,点击此按钮,能够前进操作 
三、实现画笔颜色选择功能 
需求:选择你想要的画笔颜色,能够绘制不同颜色的笔迹

1.popuwindow

难点:目前mupdf的 绘制功能在pageview中 
代码:

//注释  绘制墨迹
if (mDrawing != null) {
   LogUtils.d(TAG,"paint的绘制");
   Path path = new Path();
   PointF p;

   paint.setAntiAlias(true);
   paint.setDither(true);
   paint.setStrokeJoin(Paint.Join.ROUND);
   paint.setStrokeCap(Paint.Cap.ROUND);

   paint.setStyle(Paint.Style.FILL);
   paint.setStrokeWidth(INK_THICKNESS * scale);
   paint.setColor(INK_COLOR);

   Iterator<ArrayList<PointF>> it = mDrawing.iterator();
   while (it.hasNext()) {
      ArrayList<PointF> arc = it.next();
      if (arc.size() >= 2) {
         Iterator<PointF> iit = arc.iterator();
         p = iit.next();
         float mX = p.x * scale;
         float mY = p.y * scale;
         path.moveTo(mX, mY);
         while (iit.hasNext()) {
            p = iit.next();
            float x = p.x * scale;
            float y = p.y * scale;
            path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
         }
         path.lineTo(mX, mY);
      } else {
         p = arc.get(0);
         canvas.drawCircle(p.x * scale, p.y * scale, INK_THICKNESS * scale / 2, paint);
      }
   }

   paint.setStyle(Paint.Style.STROKE);
   canvas.drawPath(path, paint);
}
分析

想拿到当前绘制的paint对象,以及绘制的路径path,存入集合中,

问:对paint熟悉吗,撤销和恢复怎么实现 
如何保证在绘制过程中不丢帧,即在绘制过程中控制笔迹很流畅

源码分析 找不到 接收保存绘制后的红色笔迹,再议 2016年3月1日17:58:50 
头好晕….

2016年3月2日09:28:37 星期三 
再次使用AS进行debug调试,定位在接受按钮点击事件方法中 头 尾 2个断点 
当进行到最后一句代码时 
mDocView.setMode(MuPDFReaderView.Mode.Viewing); 
force step into 强制进入内部 观察代码执行过程 
最后跟踪到View类中的几个方法 
setForegroundTintMode 、getForegroundTintMode、applyForegroundTint


/**
 * Applies a tint to the foreground drawable. Does not modify the current tint
 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
 * <p>
 * Subsequent calls to {@link #setForeground(Drawable)} will automatically
 * mutate the drawable and apply the specified tint and tint mode using
 * {@link Drawable#setTintList(ColorStateList)}.
 *
 * @param tint the tint to apply, may be {@code null} to clear tint
 *
 * @attr ref android.R.styleable#View_foregroundTint
 * @see #getForegroundTintList()
 * @see Drawable#setTintList(ColorStateList)
 */
public void setForegroundTintList(@Nullable ColorStateList tint) {
    if (mForegroundInfo == null) {
        mForegroundInfo = new ForegroundInfo();
    }
    if (mForegroundInfo.mTintInfo == null) {
        mForegroundInfo.mTintInfo = new TintInfo();
    }
    mForegroundInfo.mTintInfo.mTintList = tint;
    mForegroundInfo.mTintInfo.mHasTintList = true;

    applyForegroundTint();
}

/**
 * Return the tint applied to the foreground drawable, if specified.
 *
 * @return the tint applied to the foreground drawable
 * @attr ref android.R.styleable#View_foregroundTint
 * @see #setForegroundTintList(ColorStateList)
 */
@Nullable
public ColorStateList getForegroundTintList() {
    return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
            ? mForegroundInfo.mTintInfo.mTintList : null;
}

/**
 * Specifies the blending mode used to apply the tint specified by
 * {@link #setForegroundTintList(ColorStateList)}} to the background
 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
 *
 * @param tintMode the blending mode used to apply the tint, may be
 *                 {@code null} to clear tint
 * @attr ref android.R.styleable#View_foregroundTintMode
 * @see #getForegroundTintMode()
 * @see Drawable#setTintMode(PorterDuff.Mode)
 */
public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
    if (mForegroundInfo == null) {
        mForegroundInfo = new ForegroundInfo();
    }
    if (mForegroundInfo.mTintInfo == null) {
        mForegroundInfo.mTintInfo = new TintInfo();
    }
    mForegroundInfo.mTintInfo.mTintMode = tintMode;
    mForegroundInfo.mTintInfo.mHasTintMode = true;

    applyForegroundTint();
}

/**
 * Return the blending mode used to apply the tint to the foreground
 * drawable, if specified.
 *
 * @return the blending mode used to apply the tint to the foreground
 *         drawable
 * @attr ref android.R.styleable#View_foregroundTintMode
 * @see #setForegroundTintMode(PorterDuff.Mode)
 */
@Nullable
public PorterDuff.Mode getForegroundTintMode() {
    return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
            ? mForegroundInfo.mTintInfo.mTintMode : null;
}

private void applyForegroundTint() {
    if (mForegroundInfo != null && mForegroundInfo.mDrawable != null
            && mForegroundInfo.mTintInfo != null) {
        final TintInfo tintInfo = mForegroundInfo.mTintInfo;
        if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
            mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate();

            if (tintInfo.mHasTintList) {
                mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList);
            }

            if (tintInfo.mHasTintMode) {
                mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode);
            }

            // The drawable (or one of its children) may not have been
            // stateful before applying the tint, so let's try again.
            if (mForegroundInfo.mDrawable.isStateful()) {
                mForegroundInfo.mDrawable.setState(getDrawableState());
            }
        }
    }
}
发现这几个方法都有传入ColorStateList引用,点进去一看,找到了



原来默认的颜色是红色;


再次回到 OnAcceptButtonClick点击方法中来
/*################### 添加注释 #################*/
//注释 这个方法是当用户完成相应操作后,点击保存时的事件
//    Edited by Oayiel on ${DATE}.
public void OnAcceptButtonClick(View v) {
   LogUtils.d(TAG, "OnAcceptButtonClick: ");
   MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
   boolean success = false;
   switch (mAcceptMode) {
   case CopyText: //复制文本
      if (pageView != null)
         success = pageView.copySelection();
      mTopBarMode = TopBarMode.More;
      showInfo(success?getString(R.string.copied_to_clipboard):getString(R.string.no_text_selected));
      break;

   case Highlight: //高亮
      if (pageView != null)
         success = pageView.markupSelection(Annotation.Type.HIGHLIGHT);
      mTopBarMode = TopBarMode.Annot;
      if (!success)
         showInfo(getString(R.string.no_text_selected));
      break;

   case Underline: //下划线
      if (pageView != null)
         success = pageView.markupSelection(Annotation.Type.UNDERLINE);
      mTopBarMode = TopBarMode.Annot;
      if (!success)
         showInfo(getString(R.string.no_text_selected));
      break;

   case StrikeOut: //删除线
      if (pageView != null)
         success = pageView.markupSelection(Annotation.Type.STRIKEOUT);
      mTopBarMode = TopBarMode.Annot;
      if (!success)
         showInfo(getString(R.string.no_text_selected));
      break;

   case Ink: //墨迹
      //注释 添加va  TODO 动画效果
      mViewAnimator.setVisibility(View.INVISIBLE);
      if (pageView != null)
         LogUtils.d(TAG,"保存已经绘制好的墨迹");
         success = pageView.saveDraw();
      mTopBarMode = TopBarMode.Annot;
      if (!success)
         showInfo(getString(R.string.nothing_to_save));
      break;
   }
   mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
   mDocView.setMode(MuPDFReaderView.Mode.Viewing); //绘制  回到观察模式
   //注释 绘制后的笔迹是走的View--getForegroundTintList--ColorStateList默认的红色
}

经过测试
   发现Underline:是蓝色,StrikeOut和Ink默认走的系统红色

不知道从哪改这种颜色 TODO:
修改后保存的文件也能被打开? 
@Override 
public void onBackPressed() { 
//注释 发生绘制事件时,提示用户是否保存 
if (core != null && core.hasChanges()) { 
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 
public void onClick(DialogInterface dialog, int which) { 
if (which == AlertDialog.BUTTON_POSITIVE) 
core.save();

finish();
     }
  };
  AlertDialog alert = mAlertBuilder.create();
  alert.setTitle("MuPDF");
  alert.setMessage(getString(R.string.document_has_changes_save_them_));
  alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.yes), listener);
  alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.no), listener);
  alert.show();
} else { 
super.onBackPressed(); 
} 
}

绘制的 撤销,恢复,画笔颜色,画笔粗细 
自定义一个PaintView 实现撤销恢复操作2016年3月2日18:11:22

绘制的功能全是在MuPDFView接口中定义好了 
在PageView中与接口中方法同名,如撤销&恢复&保存等,利用子类继承父类并且实现该接口的方式,在activity中click事件中先拿到当前的view对象,强制转换为MuPDFView接口类型 
MuPDFView : 
public void cancelDraw(int i); //撤销 
public class MuPDFPageView extends PageView implements MuPDFView { 
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView(); 
if (v == mInkBack) { 
pageView.cancelDraw(0);

PageView: 
MuPDFView: 
MuPDFActivity: 
Buttons.xml:

txt功能以另一种引擎方式进行打开


之前的想法:方向对了,但是无法与开源项目联系起来
    public static ArrayList<View> mViews = new ArrayList<View>();
    public static DrawViewListener mDrawViewListener;
    public static void setDrawViewListener(DrawViewListener drawViewListener) {
        mDrawViewListener = drawViewListener;
    }
    public interface DrawViewListener {
        void onDrawView(View view, ArrayList<ArrayList<PointF>> drawing);
    }
    //注释 添加事件
    /**
     * 撤销的核心思想就是将画布清空,
     * 将保存下来的Path路径最后一个移除掉,
     * 重新将路径画在画布上面。
     */
    public void undo() {
        LogUtils.d(TAG, "PageView's -- undo");
        if (savePath != null && savePath.size() > 0) {
            //调用初始化画布函数以清空画布
            //          initCanvas();
            //将路径保存列表中的最后一个元素删除 ,并将其保存在路径删除列表中
            DrawPath drawPath = savePath.get(savePath.size() - 1);
            deletePath.add(drawPath);
            savePath.remove(savePath.size() - 1);
            //将路径保存列表中的路径重绘在画布上
            Iterator<DrawPath> iter = savePath.iterator();      //重复保存
            while (iter.hasNext()) {
                DrawPath dp = iter.next();
                mCanvas.drawPath(dp.path, dp.paint);
            }
            invalidate();// 刷新
        }
    }
    /**
     * 恢复的核心思想就是将撤销的路径保存到另外一个列表里面(栈),
     * 然后从redo的列表里面取出最顶端对象,
     * 画在画布上面即可
     */
    public void redo() {
        LogUtils.d(TAG, "PageView's -- redo");
        if (deletePath.size() > 0) {
            //将删除的路径列表中的最后一个,也就是最顶端路径取出(栈),并加入路径保存列表中
            DrawPath dp = deletePath.get(deletePath.size() - 1);
            savePath.add(dp);
            //将取出的路径重绘在画布上
            mCanvas.drawPath(dp.path, dp.paint);
            //将该路径从删除的路径列表中去除
            deletePath.remove(deletePath.size() - 1);
            invalidate();
        }
    }
    private Canvas mCanvas;
    private ArrayList<DrawPath> savePath   = new ArrayList<>();
    private ArrayList<DrawPath> deletePath = new ArrayList<>();
    //路径对象
    class DrawPath {
        Path  path;
        Paint paint;
    }
试了一下,还是git提交到github保存吧


橡皮擦功能:触摸笔迹消失
选择绘笔粗细 setStrokeWidth
选择绘笔颜色 setColor
复制文本到粘贴板

跳转页面:结合 seekbar(可自定义)

txt文件:给个跳转到另一个解码库
       String path = mFiles[position].getAbsolutePath();
      if(path.endsWith("txt")){
         Toast.makeText(ChoosePDFActivity.this, "PickTXT", Toast.LENGTH_SHORT).show();
         //如果点击了txt格式文件,跳转至txt解码器  TODO txt解码
//       startActivity(new Intent(this,TXTActivity.class));
      }else {
可以新建txt文件,操作

Rss:网络阅读器json

settings:TODO

浏览最近的文件:Vudroid
UI:ChoosePDFItem:Type(PARENT,DIR,DOC),显示对应icon

搜索功能  TODO


TXT文件解码相关
//打开txt文本格式的逻辑
private void open(Bookmark bookmark) {
  Intent intent = new Intent(BookmarkListActivity.this, ReadActivity.class);
  intent.setData(Uri.parse("file://" + bookmark.getPath()));
  startActivity(intent);
}
  ReadActivity  ReadView  BookmarkManager


复制到系统粘贴板
ClipboardManager cbm = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
cbm.setPrimaryClip(ClipData.newPlainText(null, content.toString()));


Typeface typeface = Typeface.createFromAsset(context.getAssets(),"fonts/FZBYSK.TTF");
1
1
https://github.com/lfkdsk/JustWeTools#readview%E5%B0%8F%E8%AF%B4%E9%98%85%E8%AF%BB 不是打广告啊,是这个博主写的真的好

<activity
            android:name="com.cinread.ebook.TXTActivity"
            android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="file"/>
                <data android:mimeType="*/*"/>
                <data android:pathPattern=".*\\.txt"/>
                <data android:host="*"/>
            </intent-filter>
        </activity>
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TXTActivity extends Activity {
    private ReadView readView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        File dir = null;
        Uri fileUri = getIntent().getData();
        if (fileUri != null) {
            dir = new File(fileUri.getPath());
        }
        readView = null;
        if (dir != null) {
            readView = new ReadView(this,dir.getPath());
        }
        else
            finish();
        setContentView(readView);
    }
}
String path = mFiles[position].getAbsolutePath();
        if(path.endsWith("txt")){
            //如果点击了txt格式文件,跳转至txt解码器  TODO txt解码
            Intent intent = new Intent(this, TXTActivity.class);
            intent.setAction(Intent.ACTION_VIEW);
            intent.setData(Uri.parse("file://"+path));
            startActivity(intent);
拓展

可以拓展其它功能:笔记/修改,新建笔记;
    功能:选择字体大小
         选择背景



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值