summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-03-25 12:59:54 +0000
committerPaul Gardiner <paulg.artifex@glidos.net>2013-03-25 12:59:54 +0000
commit199abe0069381d79fc34c86268e408083ad18397 (patch)
tree0dbefb3a08a5d44dae2d5e98635241a7224b231d
parent41f10c71dbae05fb538f51a495ef7aaa1861fd5d (diff)
downloadmupdf-199abe0069381d79fc34c86268e408083ad18397.tar.xz
Android: add support for Ink annotation creation
-rw-r--r--android/jni/mupdf.c94
-rw-r--r--android/res/drawable-ldpi/ic_annot.pngbin0 -> 311 bytes
-rw-r--r--android/res/drawable-ldpi/ic_pen.pngbin0 -> 257 bytes
-rw-r--r--android/res/drawable-mdpi/ic_annot.pngbin0 -> 418 bytes
-rw-r--r--android/res/drawable-mdpi/ic_pen.pngbin0 -> 282 bytes
-rw-r--r--android/res/layout/buttons.xml82
-rw-r--r--android/res/values/strings.xml3
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFActivity.java78
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFCore.java6
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFPageView.java32
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFReaderView.java10
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFReflowView.java12
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFView.java4
-rw-r--r--android/src/com/artifex/mupdfdemo/PageView.java69
14 files changed, 378 insertions, 12 deletions
diff --git a/android/jni/mupdf.c b/android/jni/mupdf.c
index c929e13e..75626133 100644
--- a/android/jni/mupdf.c
+++ b/android/jni/mupdf.c
@@ -35,6 +35,7 @@
#define STRIKE_HEIGHT (0.375f)
#define UNDERLINE_HEIGHT (0.075f)
#define LINE_THICKNESS (0.07f)
+#define INK_THICKNESS (4.0f)
#define SMALL_FLOAT (0.00001)
enum
@@ -1473,6 +1474,99 @@ JNI_FN(MuPDFCore_addMarkupAnnotationInternal)(JNIEnv * env, jobject thiz, jobjec
}
JNIEXPORT void JNICALL
+JNI_FN(MuPDFCore_addInkAnnotationInternal)(JNIEnv * env, jobject thiz, jobjectArray arcs)
+{
+ globals *glo = get_globals(env, thiz);
+ fz_context *ctx = glo->ctx;
+ fz_document *doc = glo->doc;
+ fz_interactive *idoc = fz_interact(doc);
+ page_cache *pc = &glo->pages[glo->current];
+ jclass pt_cls;
+ jfieldID x_fid, y_fid;
+ int i, j, k, n;
+ fz_point *pts = NULL;
+ int *counts = NULL;
+ int total = 0;
+ float color[3];
+
+ if (idoc == NULL)
+ return;
+
+ color[0] = 1.0;
+ color[1] = 0.0;
+ color[2] = 0.0;
+
+ fz_var(pts);
+ fz_var(counts);
+ fz_try(ctx)
+ {
+ fz_annot *annot;
+ fz_matrix ctm;
+
+ float zoom = glo->resolution / 72;
+ zoom = 1.0 / zoom;
+ fz_scale(&ctm, zoom, zoom);
+ pt_cls = (*env)->FindClass(env, "android.graphics.PointF");
+ if (pt_cls == NULL) fz_throw(ctx, "FindClass");
+ x_fid = (*env)->GetFieldID(env, pt_cls, "x", "F");
+ if (x_fid == NULL) fz_throw(ctx, "GetFieldID(x)");
+ y_fid = (*env)->GetFieldID(env, pt_cls, "y", "F");
+ if (y_fid == NULL) fz_throw(ctx, "GetFieldID(y)");
+
+ n = (*env)->GetArrayLength(env, arcs);
+
+ counts = fz_malloc_array(ctx, n, sizeof(int));
+
+ for (i = 0; i < n; i++)
+ {
+ jobjectArray arc = (jobjectArray)(*env)->GetObjectArrayElement(env, arcs, i);
+ int count = (*env)->GetArrayLength(env, arc);
+
+ counts[i] = count;
+ total += count;
+ }
+
+ pts = fz_malloc_array(ctx, total, sizeof(fz_point));
+
+ k = 0;
+ for (i = 0; i < n; i++)
+ {
+ jobjectArray arc = (jobjectArray)(*env)->GetObjectArrayElement(env, arcs, i);
+ int count = counts[i];
+
+ for (j = 0; j < count; j++)
+ {
+ jobject pt = (*env)->GetObjectArrayElement(env, arc, j);
+
+ pts[k].x = pt ? (*env)->GetFloatField(env, pt, x_fid) : 0.0f;
+ pts[k].y = pt ? (*env)->GetFloatField(env, pt, y_fid) : 0.0f;
+ fz_transform_point(&pts[k], &ctm);
+ k++;
+ }
+ }
+
+ annot = fz_create_annot(idoc, pc->page, FZ_ANNOT_INK);
+
+ fz_set_ink_annot_list(idoc, annot, pts, counts, n, color, INK_THICKNESS);
+
+ dump_annotation_display_lists(glo);
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, pts);
+ fz_free(ctx, counts);
+ }
+ fz_catch(ctx)
+ {
+ LOGE("addInkAnnotation: %s failed", ctx->error->message);
+ jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+ if (cls != NULL)
+ (*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_searchPage");
+ (*env)->DeleteLocalRef(env, cls);
+ }
+}
+
+JNIEXPORT void JNICALL
JNI_FN(MuPDFCore_deleteAnnotationInternal)(JNIEnv * env, jobject thiz, int annot_index)
{
globals *glo = get_globals(env, thiz);
diff --git a/android/res/drawable-ldpi/ic_annot.png b/android/res/drawable-ldpi/ic_annot.png
new file mode 100644
index 00000000..c4f1df07
--- /dev/null
+++ b/android/res/drawable-ldpi/ic_annot.png
Binary files differ
diff --git a/android/res/drawable-ldpi/ic_pen.png b/android/res/drawable-ldpi/ic_pen.png
new file mode 100644
index 00000000..7b7de296
--- /dev/null
+++ b/android/res/drawable-ldpi/ic_pen.png
Binary files differ
diff --git a/android/res/drawable-mdpi/ic_annot.png b/android/res/drawable-mdpi/ic_annot.png
new file mode 100644
index 00000000..0b4bfd92
--- /dev/null
+++ b/android/res/drawable-mdpi/ic_annot.png
Binary files differ
diff --git a/android/res/drawable-mdpi/ic_pen.png b/android/res/drawable-mdpi/ic_pen.png
new file mode 100644
index 00000000..db805373
--- /dev/null
+++ b/android/res/drawable-mdpi/ic_pen.png
Binary files differ
diff --git a/android/res/layout/buttons.xml b/android/res/layout/buttons.xml
index 879abf46..e714b022 100644
--- a/android/res/layout/buttons.xml
+++ b/android/res/layout/buttons.xml
@@ -35,20 +35,20 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:layout_toLeftOf="@+id/selectButton"
+ android:layout_toLeftOf="@+id/annotButton"
android:contentDescription="@string/link_control"
android:background="@drawable/button"
android:src="@drawable/ic_link" />
<ImageButton
- android:id="@+id/selectButton"
+ android:id="@+id/annotButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/outlineButton"
- android:contentDescription="@string/select"
+ android:contentDescription="@string/edit_annotations"
android:background="@drawable/button"
- android:src="@drawable/ic_select" />
+ android:src="@drawable/ic_annot" />
<ImageButton
android:id="@+id/outlineButton"
@@ -197,6 +197,16 @@
android:background="@color/toolbar" >
<ImageButton
+ android:id="@+id/cancelDeleteButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:contentDescription="@string/cancel"
+ android:background="@drawable/button"
+ android:src="@drawable/ic_cancel" />
+
+ <ImageButton
android:id="@+id/deleteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -207,7 +217,69 @@
android:src="@drawable/ic_trash" />
</RelativeLayout>
- </ViewAnimator>
+
+ <RelativeLayout
+ android:id="@+id/topBar5"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/toolbar" >
+
+ <ImageButton
+ android:id="@+id/cancelAnnotButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:contentDescription="@string/cancel"
+ android:background="@drawable/button"
+ android:src="@drawable/ic_cancel" />
+
+ <ImageButton
+ android:id="@+id/selectButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@+id/inkButton"
+ android:contentDescription="@string/select"
+ android:background="@drawable/button"
+ android:src="@drawable/ic_select" />
+
+ <ImageButton
+ android:id="@+id/inkButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:contentDescription="@string/ink"
+ android:background="@drawable/button"
+ android:src="@drawable/ic_pen" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/topBar6"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/toolbar" >
+
+ <ImageButton
+ android:id="@+id/cancelInkButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:contentDescription="@string/cancel"
+ android:background="@drawable/button"
+ android:src="@drawable/ic_cancel" />
+
+ <Button
+ android:id="@+id/saveInkButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:text="@string/save" />
+ </RelativeLayout>
+ </ViewAnimator>
<RelativeLayout
android:id="@+id/lowerButtons"
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 9509c9db..c8008591 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -24,4 +24,7 @@
<string name="delete">Delete</string>
<string name="highlight">Highlight</string>
<string name="underline">Underline</string>
+ <string name="edit_annotations">Edit annotations</string>
+ <string name="ink">Ink</string>
+ <string name="save">Save</string>
</resources>
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFActivity.java b/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
index 01783ede..90e55887 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
@@ -28,6 +28,7 @@ import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
@@ -44,7 +45,7 @@ class ThreadPerTaskExecutor implements Executor {
public class MuPDFActivity extends Activity
{
/* The core rendering instance */
- enum TopBarMode {Main, Search, Text, Annotation};
+ enum TopBarMode {Main, Search, Text, AnnotSelect, AnnotCreate, InkCreate};
private MuPDFCore core;
private String mFileName;
@@ -68,6 +69,12 @@ public class MuPDFActivity extends Activity
private ImageButton mCancelButton;
private ImageButton mOutlineButton;
private ImageButton mDeleteButton;
+ private ImageButton mCancelDeleteButton;
+ private ImageButton mAnnotButton;
+ private ImageButton mCancelAnnotButton;
+ private ImageButton mInkButton;
+ private Button mSaveInkButton;
+ private ImageButton mCancelInkButton;
private ViewAnimator mTopBarSwitcher;
private ImageButton mLinkButton;
private TopBarMode mTopBarMode;
@@ -402,12 +409,12 @@ public class MuPDFActivity extends Activity
switch (item) {
case Annotation:
showButtons();
- mTopBarMode = TopBarMode.Annotation;
+ mTopBarMode = TopBarMode.AnnotSelect;
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
break;
case Widget:
case Nothing:
- if (mTopBarMode == TopBarMode.Annotation) {
+ if (mTopBarMode == TopBarMode.AnnotSelect) {
mTopBarMode = TopBarMode.Main;
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
}
@@ -468,6 +475,13 @@ public class MuPDFActivity extends Activity
}
});
+ mAnnotButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mTopBarMode = TopBarMode.AnnotCreate;
+ mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
+ }
+ });
+
// Activate the select button
mSelectButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -483,6 +497,58 @@ public class MuPDFActivity extends Activity
if (pageView != null)
pageView.deselectText();
mDocView.setMode(MuPDFReaderView.Mode.Viewing);
+ mTopBarMode = TopBarMode.AnnotCreate;
+ mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
+ }
+ });
+
+ mInkButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mDocView.setMode(MuPDFReaderView.Mode.Drawing);
+ mTopBarMode = TopBarMode.InkCreate;
+ mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
+ }
+ });
+
+ mCancelInkButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
+ if (pageView != null)
+ pageView.cancelDraw();
+ mDocView.setMode(MuPDFReaderView.Mode.Viewing);
+ mTopBarMode = TopBarMode.AnnotCreate;
+ mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
+ }
+ });
+
+ mSaveInkButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
+ if (pageView != null)
+ pageView.saveDraw();
+ mDocView.setMode(MuPDFReaderView.Mode.Viewing);
+ mTopBarMode = TopBarMode.Main;
+ mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
+ }
+ });
+
+ mCancelDeleteButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
+ if (pageView != null)
+ pageView.deselectAnnotation();
+ mDocView.setMode(MuPDFReaderView.Mode.Viewing);
+ mTopBarMode = TopBarMode.Main;
+ mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
+ }
+ });
+
+ mCancelAnnotButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
+ if (pageView != null)
+ pageView.deselectText();
+ mDocView.setMode(MuPDFReaderView.Mode.Viewing);
mTopBarMode = TopBarMode.Main;
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
}
@@ -897,6 +963,12 @@ public class MuPDFActivity extends Activity
mCancelButton = (ImageButton)mButtonsView.findViewById(R.id.cancel);
mOutlineButton = (ImageButton)mButtonsView.findViewById(R.id.outlineButton);
mDeleteButton = (ImageButton)mButtonsView.findViewById(R.id.deleteButton);
+ mCancelDeleteButton = (ImageButton)mButtonsView.findViewById(R.id.cancelDeleteButton);
+ mAnnotButton = (ImageButton)mButtonsView.findViewById(R.id.annotButton);
+ mCancelAnnotButton = (ImageButton)mButtonsView.findViewById(R.id.cancelAnnotButton);
+ mInkButton = (ImageButton)mButtonsView.findViewById(R.id.inkButton);
+ mSaveInkButton = (Button)mButtonsView.findViewById(R.id.saveInkButton);
+ mCancelInkButton = (ImageButton)mButtonsView.findViewById(R.id.cancelInkButton);
mTopBarSwitcher = (ViewAnimator)mButtonsView.findViewById(R.id.switcher);
mSearchBack = (ImageButton)mButtonsView.findViewById(R.id.searchBack);
mSearchFwd = (ImageButton)mButtonsView.findViewById(R.id.searchForward);
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFCore.java b/android/src/com/artifex/mupdfdemo/MuPDFCore.java
index 424e3536..2443784a 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFCore.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFCore.java
@@ -40,6 +40,7 @@ public class MuPDFCore
private native TextChar[][][][] text();
private native byte[] textAsHtml();
private native void addMarkupAnnotationInternal(PointF[] quadPoints, int type);
+ private native void addInkAnnotationInternal(PointF[][] arcs);
private native void deleteAnnotationInternal(int annot_index);
private native int passClickEventInternal(int page, float x, float y);
private native void setFocusedWidgetChoiceSelectedInternal(String [] selected);
@@ -253,6 +254,11 @@ public class MuPDFCore
addMarkupAnnotationInternal(quadPoints, type.ordinal());
}
+ public synchronized void addInkAnnotation(int page, PointF[][] arcs) {
+ gotoPage(page);
+ addInkAnnotationInternal(arcs);
+ }
+
public synchronized void deleteAnnotation(int page, int annot_index) {
gotoPage(page);
deleteAnnotationInternal(annot_index);
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFPageView.java b/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
index 06c3827a..69f038bb 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
@@ -59,8 +59,6 @@ class PassClickResultChoice extends PassClickResult {
}
public class MuPDFPageView extends PageView implements MuPDFView {
- private static final float LINE_THICKNESS = 0.07f;
- private static final float STRIKE_HEIGHT = 0.375f;
private final MuPDFCore mCore;
private AsyncTask<Void,Void,PassClickResult> mPassClick;
private RectF mWidgetAreas[];
@@ -75,6 +73,7 @@ public class MuPDFPageView extends PageView implements MuPDFView {
private AsyncTask<String,Void,Boolean> mSetWidgetText;
private AsyncTask<String,Void,Void> mSetWidgetChoice;
private AsyncTask<PointF[],Void,Void> mAddStrikeOut;
+ private AsyncTask<PointF[][],Void,Void> mAddInk;
private AsyncTask<Integer,Void,Void> mDeleteAnnotation;
private Runnable changeReporter;
@@ -185,6 +184,7 @@ public class MuPDFPageView extends PageView implements MuPDFView {
case UNDERLINE:
case SQUIGGLY:
case STRIKEOUT:
+ case INK:
mSelectedAnnotationIndex = i;
setItemSelectBox(mAnnotations[i]);
return Hit.Annotation;
@@ -357,6 +357,34 @@ public class MuPDFPageView extends PageView implements MuPDFView {
setItemSelectBox(null);
}
+ public void saveDraw() {
+ PointF[][] path = getDraw();
+
+ if (path != null) {
+ if (mAddInk != null) {
+ mAddInk.cancel(true);
+ mAddInk = null;
+ }
+ mAddInk = new AsyncTask<PointF[][],Void,Void>() {
+ @Override
+ protected Void doInBackground(PointF[][]... params) {
+ mCore.addInkAnnotation(mPageNumber, params[0]);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ loadAnnotations();
+ update();
+ }
+
+ };
+
+ mAddInk.execute(getDraw());
+ cancelDraw();
+ }
+ }
+
@Override
protected Bitmap drawPage(int sizeX, int sizeY,
int patchX, int patchY, int patchWidth, int patchHeight) {
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java b/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java
index 6ddb69da..0aa1909b 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFReaderView.java
@@ -95,15 +95,20 @@ public class MuPDFReaderView extends ReaderView {
}
@Override
- public void onShowPress(MotionEvent e) {
+ public boolean onDown(MotionEvent e) {
switch (mMode) {
case Drawing:
+ MuPDFView pageView = (MuPDFView)getDisplayedView();
+ if (pageView != null)
+ pageView.startDraw(e.getX(), e.getY());
break;
}
+ return super.onDown(e);
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
+ MuPDFView pageView = (MuPDFView)getDisplayedView();
switch (mMode) {
case Viewing:
if (!tapDisabled)
@@ -111,11 +116,12 @@ public class MuPDFReaderView extends ReaderView {
return super.onScroll(e1, e2, distanceX, distanceY);
case Selecting:
- MuPDFView pageView = (MuPDFView)getDisplayedView();
if (pageView != null)
pageView.selectText(e1.getX(), e1.getY(), e2.getX(), e2.getY());
return true;
case Drawing:
+ if (pageView != null)
+ pageView.continueDraw(e2.getX(), e2.getY());
return true;
default:
return true;
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java b/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java
index 1a2f1d91..9200982a 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFReflowView.java
@@ -103,6 +103,18 @@ public class MuPDFReflowView extends WebView implements MuPDFView {
return false;
}
+ public void startDraw(float x, float y) {
+ }
+
+ public void continueDraw(float x, float y) {
+ }
+
+ public void cancelDraw() {
+ }
+
+ public void saveDraw() {
+ }
+
public void setSearchBoxes(RectF[] searchBoxes) {
}
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFView.java b/android/src/com/artifex/mupdfdemo/MuPDFView.java
index 5f7f19e0..5731945d 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFView.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFView.java
@@ -20,6 +20,10 @@ public interface MuPDFView {
public void setSearchBoxes(RectF searchBoxes[]);
public void setLinkHighlighting(boolean f);
public void deselectAnnotation();
+ public void startDraw(float x, float y);
+ public void continueDraw(float x, float y);
+ public void cancelDraw();
+ public void saveDraw();
public void setChangeReporter(Runnable reporter);
public void update();
public void addHq(boolean update);
diff --git a/android/src/com/artifex/mupdfdemo/PageView.java b/android/src/com/artifex/mupdfdemo/PageView.java
index 3eb1e5a3..756ee2f5 100644
--- a/android/src/com/artifex/mupdfdemo/PageView.java
+++ b/android/src/com/artifex/mupdfdemo/PageView.java
@@ -7,6 +7,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -102,6 +103,8 @@ public abstract class PageView extends ViewGroup {
private static final int HIGHLIGHT_COLOR = 0x802572AC;
private static final int LINK_COLOR = 0x80AC7225;
private static final int BOX_COLOR = 0xFF4444FF;
+ private static final int INK_COLOR = 0xFFFF0000;
+ private static final float INK_THICKNESS = 10.0f;
private static final int BACKGROUND_COLOR = 0xFFFFFFFF;
private static final int PROGRESS_DIALOG_DELAY = 200;
protected final Context mContext;
@@ -126,6 +129,7 @@ public abstract class PageView extends ViewGroup {
private RectF mSelectBox;
private TextWord mText[][];
private RectF mItemSelectBox;
+ protected ArrayList<ArrayList<PointF>> mDrawing;
private View mSearchView;
private boolean mIsBlank;
private boolean mHighlightLinks;
@@ -346,6 +350,28 @@ public abstract class PageView extends ViewGroup {
paint.setColor(BOX_COLOR);
canvas.drawRect(mItemSelectBox.left*scale, mItemSelectBox.top*scale, mItemSelectBox.right*scale, mItemSelectBox.bottom*scale, paint);
}
+
+ if (mDrawing != null) {
+ Path path = new Path();
+ PointF p;
+ 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();
+ path.moveTo(p.x*scale, p.y*scale);
+ while (iit.hasNext()) {
+ p = iit.next();
+ path.lineTo(p.x*scale, p.y*scale);
+ }
+ }
+ }
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(INK_THICKNESS*scale);
+ paint.setColor(INK_COLOR);
+ canvas.drawPath(path, paint);
+ }
}
};
@@ -402,6 +428,49 @@ public abstract class PageView extends ViewGroup {
}
}
+ public void startDraw(float x, float y) {
+ float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
+ float docRelX = (x - getLeft())/scale;
+ float docRelY = (y - getTop())/scale;
+ if (mDrawing == null)
+ mDrawing = new ArrayList<ArrayList<PointF>>();
+
+ ArrayList<PointF> arc = new ArrayList<PointF>();
+ arc.add(new PointF(docRelX, docRelY));
+ mDrawing.add(arc);
+ }
+
+ public void continueDraw(float x, float y) {
+ float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
+ float docRelX = (x - getLeft())/scale;
+ float docRelY = (y - getTop())/scale;
+
+ if (mDrawing != null && mDrawing.size() > 0) {
+ ArrayList<PointF> arc = mDrawing.get(mDrawing.size() - 1);
+ arc.add(new PointF(docRelX, docRelY));
+ mSearchView.invalidate();
+ }
+ }
+
+ public void cancelDraw() {
+ mDrawing = null;
+ mSearchView.invalidate();
+ }
+
+ protected PointF[][] getDraw() {
+ if (mDrawing == null)
+ return null;
+
+ PointF[][] path = new PointF[mDrawing.size()][];
+
+ for (int i = 0; i < mDrawing.size(); i++) {
+ ArrayList<PointF> arc = mDrawing.get(i);
+ path[i] = arc.toArray(new PointF[arc.size()]);
+ }
+
+ return path;
+ }
+
protected void processSelectedText(TextProcessor tp) {
(new TextSelector(mText, mSelectBox)).select(tp);
}