blob: 89e1cfd05e34264d4f032808fdfdee83c87681e4 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.pdfrendererbasic
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.createBitmap
import android.graphics.pdf.PdfRenderer
import android.os.Bundle
import android.os.ParcelFileDescriptor
import android.support.v4.app.Fragment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
/**
* This fragment has a big [ImageView] that shows PDF pages, and 2 [Button]s to move between pages.
* We use a [PdfRenderer] to render PDF pages as [Bitmap]s.
*/
class PdfRendererBasicFragment : Fragment(), View.OnClickListener {
/**
* The filename of the PDF.
*/
private val FILENAME = "sample.pdf"
/**
* Key string for saving the state of current page index.
*/
private val STATE_CURRENT_PAGE_INDEX = "current_page_index"
/**
* String for logging.
*/
private val TAG = "PdfRendererBasicFragment"
/**
* The initial page index of the PDF.
*/
private val INITIAL_PAGE_INDEX = 0
/**
* File descriptor of the PDF.
*/
private lateinit var fileDescriptor: ParcelFileDescriptor
/**
* [PdfRenderer] to render the PDF.
*/
private lateinit var pdfRenderer: PdfRenderer
/**
* Page that is currently shown on the screen.
*/
private lateinit var currentPage: PdfRenderer.Page
/**
* [ImageView] that shows a PDF page as a [Bitmap].
*/
private lateinit var imageView: ImageView
/**
* [Button] to move to the previous page.
*/
private lateinit var btnPrevious: Button
/**
* [Button] to move to the next page.
*/
private lateinit var btnNext: Button
/**
* PDF page index.
*/
private var pageIndex: Int = INITIAL_PAGE_INDEX
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
imageView = view.findViewById(R.id.image)
btnPrevious = view.findViewById<Button>(R.id.previous).also { it.setOnClickListener(this) }
btnNext = view.findViewById<Button>(R.id.next).also { it.setOnClickListener(this)}
// If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
if (savedInstanceState != null) {
pageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, INITIAL_PAGE_INDEX)
} else {
pageIndex = INITIAL_PAGE_INDEX
}
}
override fun onStart() {
super.onStart()
try {
openRenderer(activity)
showPage(pageIndex)
} catch (e: IOException) {
Log.d(TAG, e.toString())
}
}
override fun onStop() {
try {
closeRenderer()
} catch (e: IOException) {
Log.d(TAG, e.toString())
}
super.onStop()
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(STATE_CURRENT_PAGE_INDEX, currentPage.index)
super.onSaveInstanceState(outState)
}
/**
* Sets up a [PdfRenderer] and related resources.
*/
@Throws(IOException::class)
private fun openRenderer(context: Context?) {
if (context == null) return
// In this sample, we read a PDF from the assets directory.
val file = File(context.cacheDir, FILENAME)
if (!file.exists()) {
// Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
// the cache directory.
val asset = context.assets.open(FILENAME)
val output = FileOutputStream(file)
val buffer = ByteArray(1024)
var size = asset.read(buffer)
while (size != -1) {
output.write(buffer, 0, size)
size = asset.read(buffer)
}
asset.close()
output.close()
}
fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
// This is the PdfRenderer we use to render the PDF.
pdfRenderer = PdfRenderer(fileDescriptor)
currentPage = pdfRenderer.openPage(pageIndex)
}
/**
* Closes the [PdfRenderer] and related resources.
*
* @throws IOException When the PDF file cannot be closed.
*/
@Throws(IOException::class)
private fun closeRenderer() {
currentPage.close()
pdfRenderer.close()
fileDescriptor.close()
}
/**
* Shows the specified page of PDF to the screen.
*
* @param index The page index.
*/
private fun showPage(index: Int) {
if (pdfRenderer.pageCount <= index) return
// Make sure to close the current page before opening another one.
currentPage.close()
// Use `openPage` to open a specific page in PDF.
currentPage = pdfRenderer.openPage(index)
// Important: the destination bitmap must be ARGB (not RGB).
val bitmap = createBitmap(currentPage.width, currentPage.height, Bitmap.Config.ARGB_8888)
// Here, we render the page onto the Bitmap.
// To render a portion of the page, use the second and third parameter. Pass nulls to get
// the default result.
// Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
// We are ready to show the Bitmap to user.
imageView.setImageBitmap(bitmap)
updateUi()
}
/**
* Updates the state of 2 control buttons in response to the current page index.
*/
private fun updateUi() {
val index = currentPage.index
val pageCount = pdfRenderer.pageCount
btnPrevious.isEnabled = (0 != index)
btnNext.isEnabled = (index + 1 < pageCount)
activity?.title = getString(R.string.app_name_with_index, index + 1, pageCount)
}
/**
* Returns the page count of of the PDF.
*/
fun getPageCount() = pdfRenderer.pageCount
override fun onClick(view: View) {
when (view.id) {
R.id.previous -> {
// Move to the previous page/
showPage(currentPage.index - 1)
}
R.id.next -> {
// Move to the next page.
showPage(currentPage.index + 1)
}
}
}
}