Java tutorial
//--------------------------------------------------------------------------------------- // Copyright (c) 2001-2016 by PDFTron Systems Inc. All Rights Reserved. // Consult legal.txt regarding legal and license information. //--------------------------------------------------------------------------------------- package com.pdftron.pdf.utils; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.FloatEvaluator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Matrix; import android.media.ExifInterface; import android.net.Uri; import android.os.Build; import android.os.Parcelable; import android.provider.MediaStore; import android.support.v4.app.Fragment; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.webkit.MimeTypeMap; import com.pdftron.common.PDFNetException; import com.pdftron.pdf.Annot; import com.pdftron.pdf.PDFDoc; import com.pdftron.pdf.PDFViewCtrl; import com.pdftron.pdf.Page; import com.pdftron.pdf.Rect; import com.pdftron.pdf.tools.R; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class ViewerUtils { public class ImageIntent { public Bitmap bitmap; public Uri uri; public String filePath; } public static Uri openImageIntent(Fragment fragment, int requestCode) { // Determine Uri of camera image to save. final String fname = "IMG_" + System.currentTimeMillis() + ".jpg"; File sdImageMainDirectory = new File(fragment.getActivity().getExternalCacheDir(), fname); Uri outputFileUri = Uri.fromFile(sdImageMainDirectory); // Camera. final List<Intent> cameraIntents = new ArrayList<>(); final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); final PackageManager packageManager = fragment.getActivity().getPackageManager(); final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0); for (ResolveInfo res : listCam) { final String packageName = res.activityInfo.packageName; final Intent intent = new Intent(captureIntent); intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); intent.setPackage(packageName); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); cameraIntents.add(intent); } // Filesystem. final Intent galleryIntent = new Intent(Intent.ACTION_PICK); galleryIntent.setType("image/*"); //galleryIntent.setAction(Intent.ACTION_GET_CONTENT); // Chooser of filesystem options. final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source"); // Add the camera options. chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[] {})); fragment.startActivityForResult(chooserIntent, requestCode); return outputFileUri; } public static Map readImageIntent(Intent data, Context context, Uri outputFileUri) throws FileNotFoundException, Exception { final boolean isCamera; if (data == null || data.getData() == null) { isCamera = true; } else { final String action = data.getAction(); if (action == null) { isCamera = false; } else { isCamera = action.equals(MediaStore.ACTION_IMAGE_CAPTURE); } } Uri imageUri; if (isCamera) { imageUri = outputFileUri; AnalyticsHandlerAdapter.getInstance().sendEvent(AnalyticsHandlerAdapter.CATEGORY_FILEBROWSER, "Create new document from camera selected"); } else { imageUri = data.getData(); AnalyticsHandlerAdapter.getInstance().sendEvent(AnalyticsHandlerAdapter.CATEGORY_FILEBROWSER, "Create new document from local image file selected"); } String filePath; if (isCamera) { filePath = imageUri.getPath(); } else { filePath = Utils.getRealPathFromImageURI(context, imageUri); if (Utils.isNullOrEmpty(filePath)) { filePath = imageUri.getPath(); } } // try to get bitmap Bitmap bitmap = Utils.getBitmapFromImageUri(context, imageUri, filePath); // if a file is selected, check if it is an image file if (!isCamera) { // if type is null if (context.getContentResolver().getType(imageUri) == null) { String extension = MimeTypeMap.getFileExtensionFromUrl(imageUri.getPath()); final String[] extensions = { "jpeg", "jpg", "tiff", "tif", "gif", "png", "bmp" }; // if file extension is not an image extension if (!Arrays.asList(extensions).contains(extension) && extension != null && !extension.equals("")) { throw new FileNotFoundException("file extension is not an image extension"); } // if type is not an image } else if (!context.getContentResolver().getType(imageUri).startsWith("image/")) { throw new FileNotFoundException("type is not an image"); } } ////////////////// Determine if image needs to be rotated /////////////////// File imageFile = new File(imageUri.getPath()); ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath()); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); int imageRotation = 0; switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_270: imageRotation = 270; break; case ExifInterface.ORIENTATION_ROTATE_180: imageRotation = 180; break; case ExifInterface.ORIENTATION_ROTATE_90: imageRotation = 90; break; } // in some devices (mainly Samsung), the EXIF is not saved with the image so look at the content // resolver as a second source of the image's rotation if (imageRotation == 0) { String[] orientationColumn = { MediaStore.Images.Media.ORIENTATION }; Cursor cur = context.getContentResolver().query(imageUri, orientationColumn, null, null, null); orientation = -1; if (cur != null && cur.moveToFirst()) { orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0])); } if (orientation > 0) { imageRotation = orientation; } } if (imageRotation != 0) { Matrix matrix = new Matrix(); matrix.postRotate(imageRotation); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } Map<String, Object> output = new HashMap<>(); output.put("bitmap", bitmap); output.put("uri", imageUri); output.put("path", filePath); output.put("camera", isCamera); return output; } public static boolean checkIntent(Map map) { if (map == null || map.get("bitmap") == null || !(map.get("bitmap") instanceof Bitmap) || map.get("path") == null || !(map.get("path") instanceof String) || map.get("uri") == null || !(map.get("uri") instanceof Uri) || map.get("camera") == null || !(map.get("camera") instanceof Boolean)) { return false; } return true; } /** * Helper method that creates a flashing view. * * @param context the context * * @return a new View with the background color already set. */ public static View createFlashingView(Context context) { View flashingView = new View(context); flashingView.setBackgroundColor(context.getResources().getColor(R.color.annotation_flashing_box)); return flashingView; } public static void jumpToAnnotation(PDFViewCtrl pdfViewCtrl, Annot annot, int pageNum) { pdfViewCtrl.setCurrentPage(pageNum); // Now add the flashing view on top of the selected annotation View flashingView = createFlashingView(pdfViewCtrl.getContext()); // Get the annotation bounding box double[] pts1 = new double[] { 0.0f, 0.0f }; double[] pts2 = new double[] { 0.0f, 0.0f }; // Note that the returned Rect from the Annot object is in // page space, so we need to convert the points to screen // space before using them in the view layout. try { Rect annotRect = annot.getRect(); // Lower left corner pts1 = pdfViewCtrl.convPagePtToScreenPt(annotRect.getX1(), annotRect.getY1(), pageNum); // Upper right corner pts2 = pdfViewCtrl.convPagePtToScreenPt(annotRect.getX2(), annotRect.getY2(), pageNum); } catch (PDFNetException e) { com.pdftron.pdf.utils.AnalyticsHandlerAdapter.getInstance().sendException(e); } // [start] adjusting position so that the annotation shows up in the middle of the screen double top = pts2[1]; double bottom = pts1[1]; if (pdfViewCtrl.getPagePresentationMode() == PDFViewCtrl.PAGE_PRESENTATION_SINGLE_CONT || pdfViewCtrl.getPagePresentationMode() == PDFViewCtrl.PAGE_PRESENTATION_FACING_CONT || pdfViewCtrl.getPagePresentationMode() == PDFViewCtrl.PAGE_PRESENTATION_FACING_COVER_CONT) { int screenMidY = pdfViewCtrl.getHeight() / 2; double height = Math.abs(pts1[1] - pts2[1]); double verticalOffset = pts2[1]; if (pdfViewCtrl.getScrollY() > verticalOffset) { top = screenMidY; bottom = screenMidY + height; } double diff = pts2[1] - top; pdfViewCtrl.scrollBy(0, (int) diff); } // [end] // We also need to get the current scrolling position // in case the viewer is currently scrolled float sx = pdfViewCtrl.getScrollX(); float sy = pdfViewCtrl.getScrollY(); // The following deal with rotated pages int flashingRectLeft = (int) (pts1[0] + sx); int flashingRectTop = (int) (top + sy); int flashingRectRight = (int) (pts2[0] + sx); int flashingRectBottom = (int) (bottom + sy); try { Rect flashingRect = new Rect(pts1[0] + sx, top + sy, pts2[0] + sx, bottom + sy); flashingRect.normalize(); flashingRectLeft = (int) flashingRect.getX1(); flashingRectTop = (int) flashingRect.getY1(); flashingRectRight = (int) flashingRect.getX2(); flashingRectBottom = (int) flashingRect.getY2(); } catch (PDFNetException ex) { } // Set the layout of the view (note that top/bottom are // inverted since in page space the lower-left corner // is the origin flashingView.layout(flashingRectLeft, flashingRectTop, flashingRectRight, flashingRectBottom); pdfViewCtrl.addView(flashingView); // And finally animate the flashing view animateView(flashingView, pdfViewCtrl); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static void animateView(final View view, final PDFViewCtrl pdfViewCtrl) { // Example of another animation that could be applied to the view. //ValueAnimator colorAnim = ObjectAnimator.ofInt(view, "backgroundColor", /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF); //colorAnim.setDuration(1500); //colorAnim.setEvaluator(new ArgbEvaluator()); //colorAnim.setRepeatCount(2); //colorAnim.setRepeatMode(ValueAnimator.REVERSE); // Honeycomb introduced new Animation classes that are easier to use // and provide more options. Let's do a runtime check here and use // older classes for pre-Honeycomb devices. if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { AlphaAnimation anim1 = new AlphaAnimation(0.0f, 1.0f); final AlphaAnimation anim2 = new AlphaAnimation(1.0f, 0.0f); anim1.setDuration(500); anim2.setDuration(500); anim1.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { view.startAnimation(anim2); } }); anim2.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (pdfViewCtrl != null) { pdfViewCtrl.removeView(view); } } }); view.startAnimation(anim1); } else { // Since we want the flashing view to be removed once the animation // is finished, we use this listener to remove the view from // PDFViewCtrl when the event is triggered. Animator.AnimatorListener animListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { pdfViewCtrl.removeView(view); } @Override public void onAnimationCancel(Animator animation) { } }; // Get animator for the flashing view. Animator fader = createAlphaAnimator(view, animListener); // If using more than one animator, you can create a set and // play them together, or in some other order... AnimatorSet animation = new AnimatorSet(); animation.playTogether(/*colorAnim, */fader); animation.start(); } } /** * Creates an Animator object that varies the alpha property of the view. The * interpolation used is linear. * * @param view the view to be animated * @param listener the listener to be used by this Animator * * @return a new Animator object that will change the "alpha" property * of the view. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static Animator createAlphaAnimator(View view, Animator.AnimatorListener listener) { if (view == null) { return null; } // We animate only the opacity of the view. ValueAnimator fader = ObjectAnimator.ofFloat(view, "alpha", 0.0f, 1.0f, 0.4f, 1.0f, 0.0f); fader.setDuration(1500); fader.setEvaluator(new FloatEvaluator()); if (listener != null) { fader.addListener(listener); } return fader; } public static Annot getAnnotById(PDFDoc doc, String id, int pageNum) { try { Page page = doc.getPage(pageNum); if (page.isValid()) { int annotationCount = page.getNumAnnots(); for (int a = 0; a < annotationCount; a++) { Annot annotation = page.getAnnot(a); if (annotation != null && annotation.isValid() && annotation.getUniqueID() != null) { String annotId = annotation.getUniqueID().getAsPDFText(); if (id.equals(annotId)) { return annotation; } } } } } catch (Exception e) { AnalyticsHandlerAdapter.getInstance().sendException(e); } return null; } }