Home | History | Annotate | Download | only in pdfrendererbasic
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.pdfrendererbasic;
     18 
     19 import android.content.Context;
     20 import android.graphics.Bitmap;
     21 import android.graphics.pdf.PdfRenderer;
     22 import android.os.Bundle;
     23 import android.os.ParcelFileDescriptor;
     24 import android.support.v4.app.Fragment;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.Button;
     29 import android.widget.ImageView;
     30 import android.widget.Toast;
     31 
     32 import java.io.File;
     33 import java.io.FileOutputStream;
     34 import java.io.IOException;
     35 import java.io.InputStream;
     36 
     37 /**
     38  * This fragment has a big {@ImageView} that shows PDF pages, and 2
     39  * {@link android.widget.Button}s to move between pages. We use a
     40  * {@link android.graphics.pdf.PdfRenderer} to render PDF pages as
     41  * {@link android.graphics.Bitmap}s.
     42  */
     43 public class PdfRendererBasicFragment extends Fragment implements View.OnClickListener {
     44 
     45     /**
     46      * Key string for saving the state of current page index.
     47      */
     48     private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index";
     49 
     50     /**
     51      * The filename of the PDF.
     52      */
     53     private static final String FILENAME = "sample.pdf";
     54 
     55     /**
     56      * File descriptor of the PDF.
     57      */
     58     private ParcelFileDescriptor mFileDescriptor;
     59 
     60     /**
     61      * {@link android.graphics.pdf.PdfRenderer} to render the PDF.
     62      */
     63     private PdfRenderer mPdfRenderer;
     64 
     65     /**
     66      * Page that is currently shown on the screen.
     67      */
     68     private PdfRenderer.Page mCurrentPage;
     69 
     70     /**
     71      * {@link android.widget.ImageView} that shows a PDF page as a {@link android.graphics.Bitmap}
     72      */
     73     private ImageView mImageView;
     74 
     75     /**
     76      * {@link android.widget.Button} to move to the previous page.
     77      */
     78     private Button mButtonPrevious;
     79 
     80     /**
     81      * {@link android.widget.Button} to move to the next page.
     82      */
     83     private Button mButtonNext;
     84 
     85     /**
     86      * PDF page index
     87      */
     88     private int mPageIndex;
     89 
     90     public PdfRendererBasicFragment() {
     91     }
     92 
     93     @Override
     94     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     95                              Bundle savedInstanceState) {
     96         return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false);
     97     }
     98 
     99     @Override
    100     public void onViewCreated(View view, Bundle savedInstanceState) {
    101         super.onViewCreated(view, savedInstanceState);
    102         // Retain view references.
    103         mImageView = (ImageView) view.findViewById(R.id.image);
    104         mButtonPrevious = (Button) view.findViewById(R.id.previous);
    105         mButtonNext = (Button) view.findViewById(R.id.next);
    106         // Bind events.
    107         mButtonPrevious.setOnClickListener(this);
    108         mButtonNext.setOnClickListener(this);
    109 
    110         mPageIndex = 0;
    111         // If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
    112         if (null != savedInstanceState) {
    113             mPageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0);
    114         }
    115     }
    116 
    117     @Override
    118     public void onStart() {
    119         super.onStart();
    120         try {
    121             openRenderer(getActivity());
    122             showPage(mPageIndex);
    123         } catch (IOException e) {
    124             e.printStackTrace();
    125             Toast.makeText(getActivity(), "Error! " + e.getMessage(), Toast.LENGTH_SHORT).show();
    126         }
    127     }
    128 
    129     @Override
    130     public void onStop() {
    131         try {
    132             closeRenderer();
    133         } catch (IOException e) {
    134             e.printStackTrace();
    135         }
    136         super.onStop();
    137     }
    138 
    139     @Override
    140     public void onSaveInstanceState(Bundle outState) {
    141         super.onSaveInstanceState(outState);
    142         if (null != mCurrentPage) {
    143             outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex());
    144         }
    145     }
    146 
    147     /**
    148      * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources.
    149      */
    150     private void openRenderer(Context context) throws IOException {
    151         // In this sample, we read a PDF from the assets directory.
    152         File file = new File(context.getCacheDir(), FILENAME);
    153         if (!file.exists()) {
    154             // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
    155             // the cache directory.
    156             InputStream asset = context.getAssets().open(FILENAME);
    157             FileOutputStream output = new FileOutputStream(file);
    158             final byte[] buffer = new byte[1024];
    159             int size;
    160             while ((size = asset.read(buffer)) != -1) {
    161                 output.write(buffer, 0, size);
    162             }
    163             asset.close();
    164             output.close();
    165         }
    166         mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
    167         // This is the PdfRenderer we use to render the PDF.
    168         if (mFileDescriptor != null) {
    169             mPdfRenderer = new PdfRenderer(mFileDescriptor);
    170         }
    171     }
    172 
    173     /**
    174      * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources.
    175      *
    176      * @throws java.io.IOException When the PDF file cannot be closed.
    177      */
    178     private void closeRenderer() throws IOException {
    179         if (null != mCurrentPage) {
    180             mCurrentPage.close();
    181         }
    182         mPdfRenderer.close();
    183         mFileDescriptor.close();
    184     }
    185 
    186     /**
    187      * Shows the specified page of PDF to the screen.
    188      *
    189      * @param index The page index.
    190      */
    191     private void showPage(int index) {
    192         if (mPdfRenderer.getPageCount() <= index) {
    193             return;
    194         }
    195         // Make sure to close the current page before opening another one.
    196         if (null != mCurrentPage) {
    197             mCurrentPage.close();
    198         }
    199         // Use `openPage` to open a specific page in PDF.
    200         mCurrentPage = mPdfRenderer.openPage(index);
    201         // Important: the destination bitmap must be ARGB (not RGB).
    202         Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(),
    203                 Bitmap.Config.ARGB_8888);
    204         // Here, we render the page onto the Bitmap.
    205         // To render a portion of the page, use the second and third parameter. Pass nulls to get
    206         // the default result.
    207         // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
    208         mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
    209         // We are ready to show the Bitmap to user.
    210         mImageView.setImageBitmap(bitmap);
    211         updateUi();
    212     }
    213 
    214     /**
    215      * Updates the state of 2 control buttons in response to the current page index.
    216      */
    217     private void updateUi() {
    218         int index = mCurrentPage.getIndex();
    219         int pageCount = mPdfRenderer.getPageCount();
    220         mButtonPrevious.setEnabled(0 != index);
    221         mButtonNext.setEnabled(index + 1 < pageCount);
    222         getActivity().setTitle(getString(R.string.app_name_with_index, index + 1, pageCount));
    223     }
    224 
    225     /**
    226      * Gets the number of pages in the PDF. This method is marked as public for testing.
    227      *
    228      * @return The number of pages.
    229      */
    230     public int getPageCount() {
    231         return mPdfRenderer.getPageCount();
    232     }
    233 
    234     @Override
    235     public void onClick(View view) {
    236         switch (view.getId()) {
    237             case R.id.previous: {
    238                 // Move to the previous page
    239                 showPage(mCurrentPage.getIndex() - 1);
    240                 break;
    241             }
    242             case R.id.next: {
    243                 // Move to the next page
    244                 showPage(mCurrentPage.getIndex() + 1);
    245                 break;
    246             }
    247         }
    248     }
    249 
    250 }
    251