]> rtime.felk.cvut.cz Git - hornmich/skoda-qr-demo.git/blob - QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java
Clean and coment the code.
[hornmich/skoda-qr-demo.git] / QRScanner / mobile / src / main / java / cz / cvut / fel / dce / qrscanner / pdfviewer / PdfPageView.java
1 package cz.cvut.fel.dce.qrscanner.pdfviewer;
2
3 import android.content.Context;
4 import android.graphics.Bitmap;
5 import android.graphics.Canvas;
6 import android.graphics.Paint;
7 import android.util.Log;
8 import android.view.View;
9
10 import java.io.File;
11
12 import cz.cvut.fel.dce.qrscanner.mupdf.MuPDFCore;
13
14 /**
15  * View for viewing PDF page.
16  *
17  * This view is designed to be used in two ways.
18  * 1) To view the PDF page itself on the device, which is supported by an interface for scrolling, zooming, switching pages and loading pages.
19  * 2) To load the PDF page to a bitmap, which can be accessed in the program by calling getPageBitmap() method.
20  */
21 public class PdfPageView extends View {
22         /**
23          * Value with some allowed minimum and maximum.
24          * @author Michal Horn
25          *
26          * @param <T> some comparable numeric data type
27          */
28         class IntervalValue<T extends Number & Comparable<? super T>> {
29                 /**
30                  * Stored value
31                  */
32                 private T mValue;
33                 /**
34                  * The lowest allowed value. All values stored in the object are
35                  * higher or equal this minimum.
36                  */
37                 private T mMinimum;
38                 /**
39                  * The highest allowed value. All values stored in the object are
40                  * lower or equal this maximum.
41                  */
42                 private T mMaximum;
43
44                 /**
45                  * Class constructor.
46                  * Creates object that represents a value in range <minimum; maximum>.
47                  *
48                  * @param defValue      Value to be stored in the object. Must be in the allowed range specified by other two parameters.
49                  * @param minimum       The lowes allowed value to be stored in the object.
50                  * @param maximum       The highest allowed value to be stored in the object.
51                  * @throws Exception Throwed when minimal, maximal or inserted value were rejected.
52                  */
53                 public IntervalValue(T defValue, T minimum, T maximum) throws Exception {
54                         setMinimum(minimum);
55                         setMaximum(maximum);
56                         if (!setValue(defValue)) {
57                                 throw new Exception("Provided value is not in the range.");
58                         }
59                 }
60
61                 /**
62                  * Store value in the object. The value must lie between the minimum and maximum
63                  * defined for the object.
64                  * @param value value to be stored in the object
65                  * @return true - vale was stored successfully,<br>false - value could not be inserted because it was out of range.
66                  */
67                 public boolean setValue(T value) {
68                         if (value.compareTo(mMinimum) >= 0 && value.compareTo(mMaximum) <= 0) {
69                                 mValue = value;
70                                 return true;
71                         }
72                         else {
73                                 return false;
74                         }
75                 }
76
77                 /**
78                  * Set minimum for values in the object.
79                  * Last inserted value is not changed even if it is lower then the new minimum.
80                  * @param min new allowed minimum for the values stored to the object.
81                  * @throws Exception throwed when new minimum is higher than old maximum.
82                  */
83                 public void setMinimum(T min) throws Exception {
84                         if (mMaximum != null && mMinimum != null &&  mMinimum.compareTo(mMaximum) > 0) {
85                                 throw new Exception("Minimum is higher then maximum.");
86                         }
87                         mMinimum = min;
88                 }
89
90                 /**
91                  * Set maximum for values in the object.
92                  * Last inserted value is not changed even if it is higher then the new maximum.
93                  * @param max new allowed maximum for the values stored to the object.
94                  * @throws Exception throwed when new maximum is lower than old minimum.
95                  */
96                 public void setMaximum(T max) throws Exception {
97                         if (mMinimum != null && mMaximum != null &&  mMaximum.compareTo(mMinimum) < 0) {
98                                 throw new Exception("Maximum is lower then minimum.");
99                         }
100                         mMaximum = max;
101                 }
102
103                 /**
104                  * Get value stored in the object
105                  * @return value stored in the object.
106                  */
107                 public T getValue() {
108                         return mValue;
109                 }
110
111                 /**
112                  * Get the lowest allowed value that can be stored in the object.
113                  * @return minimal value
114                  */
115                 public T getMinimum() {
116                         return mMinimum;
117                 }
118
119                 /**
120                  * Get the highest allowed value that can be stored in the object.
121                  * @return maximal value
122                  */
123                 public T getMaximum() {
124                         return mMaximum;
125                 }
126         }
127
128         /**
129          * Interface for events generated by the view
130          * @author Michal Horn
131          *
132          */
133         public interface SceneChange {
134                 /**
135                  * Invoked every time when the scene should be redrawed.
136                  * @param source
137                  */
138                 public void onViewChanged(PdfPageView source);
139
140                 /**
141                  * Invoked once the PDF page is loaded and prepared as a bitmap to be shown
142                  * @param source
143                  */
144                 public void onPageLoaded(PdfPageView source);
145         }
146
147         public static final String TAG = "PdfPageView";
148         protected Paint mPaint;
149         protected IntervalValue<Float> mZoom;
150         protected IntervalValue<Float> mXPosition;
151         protected IntervalValue<Float> mYPosition;
152         protected SceneChange mListener;
153         protected float mSceneHeight;
154         protected float mSceneWidth;
155         protected Bitmap mPdfBitmap;
156         protected File mPdfFile;
157         protected Boolean mPageLoaded;
158         private MuPDFCore mPdfCore;
159         private IntervalValue<Integer> mPage;
160         private MuPDFCore.Cookie mPdfCookie;
161
162         public PdfPageView(Context context, String filePath) throws Exception {
163                 super(context);
164                 mPageLoaded = false;
165                 mPdfFile = new File(filePath);
166                 if (!mPdfFile.exists()) {
167                         throw new PdfViewerException("File " + filePath + " does not exist.");
168                 }
169                 mPaint = new Paint();
170                 mPdfCore = new MuPDFCore(context, mPdfFile.getAbsolutePath());
171                 mPdfCookie = mPdfCore.new Cookie();
172                 if (mPdfCore == null) {
173                         throw new PdfViewerException("The PDF file could not be loaded.");
174                 }
175                 mPage = new IntervalValue<>(0, 0, mPdfCore.countPages()-1);
176                 Log.i(TAG, "Pages: " + mPage.toString());
177         }
178
179         /**
180          * Get actual page. The actual page can be selected by setPage() method.
181          * @return actual page.
182          */
183         public int getActualPage() {
184                 return mPage.getValue();
185         }
186
187         /**
188          * Get total number of pages in the document
189          * @return total number of pages
190          */
191         public int getLastPage() {
192                 return mPage.getMaximum();
193         }
194
195         public boolean setPage(int page) {
196                 return mPage.setValue(page);
197         }
198
199         /**
200          * Load PDF and convert selected page to a bitmap.
201          *
202          * The page of the PDF document can be selected by setPage() method.
203          * This method can take significant time to finish. Consider calling it in separated thread.
204          */
205         public void loadPage() {
206                 long startTime = System.currentTimeMillis();
207                 try {
208                         Log.i(TAG, "Loading PDF page " + getActualPage());
209                         mSceneWidth = mPdfCore.getPageSize(getActualPage()).x;
210                         mSceneHeight = mPdfCore.getPageSize(getActualPage()).y;
211                         Log.i(TAG, "Page size: " + mSceneWidth + "x" + mSceneHeight);
212                         Bitmap.Config mPdfBitmapConf = Bitmap.Config.ARGB_8888;
213                         mPdfBitmap = Bitmap.createBitmap((int)mSceneWidth, (int)mSceneHeight, mPdfBitmapConf);
214                         mPdfCore.drawPage(mPdfBitmap, 0, (int) mSceneWidth, (int) mSceneHeight, 0, 0, (int) mSceneWidth, (int) mSceneHeight, mPdfCookie);
215
216                         mXPosition = new IntervalValue<>(640.0f/2, -mSceneWidth+640.0f/2, mSceneWidth+640.0f/2);
217                         mYPosition = new IntervalValue<>(360.0f/2, -mSceneHeight+360.0f/2, mSceneHeight+360.0f/2);
218                         mZoom = new IntervalValue<>(1.0f, 0.2f, 2.0f);
219                 } catch (Exception e) {
220                         Log.e(TAG, "Error in setting page dimensions: " + e.getMessage());
221                         e.printStackTrace();
222                 }
223                 long endTime = System.currentTimeMillis();
224                 mPageLoaded = true;
225                 Log.i(TAG, "PDF page loaded in " + Long.toString(endTime - startTime) + "ms.");
226                 if (mListener != null) {
227                         mListener.onPageLoaded(this);
228                 }
229         }
230
231         /**
232          * Get PDF page bitmap
233          * @return Bitmap of the PDF page or null, if it has not been yet loaded.
234          */
235         public Bitmap getPageBitmap() {
236                 return mPdfBitmap;
237         }
238
239         /**
240          * Set a listener of the events
241          * @param listener listener of the events
242          */
243         public void setListener(SceneChange listener) {
244                 mListener = listener;
245         }
246
247         /**
248          * Clear listener.
249          */
250         public void clearListener() {
251                 mListener = null;
252         }
253
254         /**
255          * Zoom scene function. The scene can be zoomed in or out only in limits
256          * defined in constructor.
257          * @param deltaRatio when > 0 - zoom in,<br> when < 0 - zoom out
258          */
259         public  void zoom(float deltaRatio) {
260                 if (!mPageLoaded) return;
261                 float ratio = mZoom.getValue();
262                 ratio += deltaRatio;
263                 if (mZoom.setValue(ratio) && mListener != null) {
264                         mListener.onViewChanged(this);
265                 }
266         }
267
268         /**
269          * Move scene function. The scene can be moved only in the rectangle specified
270          * by limits defined in constructor.
271          * @param x change of the x coordinate relatively to the actual position
272          * @param y change of the y coordinate relatively to the actual position
273          */
274         public void move(float x, float y) {
275                 if (!mPageLoaded) return;
276                 boolean xWasSet = mXPosition.setValue(mXPosition.getValue() + x/mZoom.getValue()*2.2f);
277                 boolean yWasSet = mYPosition.setValue(mYPosition.getValue() + y/mZoom.getValue()*2.2f);
278
279                 if ((xWasSet || yWasSet) && mListener != null) {
280                         mListener.onViewChanged(this);
281                 }
282         }
283         /**
284          * @return actual scene zoom ratio
285          */
286         public float getZoomRatio() {
287                 return mZoom.getValue();
288         }
289
290         /**
291          * @return actual scene position on X axis
292          */
293         public float getXPosition() {
294                 return mXPosition.getValue();
295         }
296
297         /**
298          * @return actual scene positoin on Y axis
299          */
300         public float getYPosition() {
301                 return mYPosition.getValue();
302         }
303
304         /**
305          * @return how tall the scene is
306          */
307         public float getSceneHeight() {
308                 return mSceneHeight;
309         }
310
311         /**
312          * @return how wide the scene is
313          */
314         public float getSceneWidth() {
315                 return mSceneWidth;
316         }
317
318         @Override
319         protected void onDraw(Canvas c) {
320                 if (!mPageLoaded) return;
321                 draw(c);
322                 super.onDraw(c);
323         }
324
325         @Override
326         public void draw(Canvas c) {
327                 if (!mPageLoaded) return;
328                 c.translate(c.getWidth() / 2, c.getHeight() / 2);
329                 c.scale(mZoom.getValue(), mZoom.getValue());
330                 c.translate(-mXPosition.getValue(), -mYPosition.getValue());
331                 c.drawBitmap(mPdfBitmap, 0, 0, mPaint);
332         }
333 }