Learn on Kotlin Generate PDF From View Convert Activity XML Layout ScrollView.
In this example, you will see how to convert your any view or layout into the PDF file.
Other than XML or activity view layout, we will also learn how to convert scroll view into the PDF file.
We will do all these things using the Kotlin as the primary language of android studio project.
First of all, see the following output material.
Step 1. Gradle and Manifest Changes
Make a new project in the android studio with kotlin as the source language and empty activity.
Now go to AndroidManifest.xml file and add the below lines in it
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
These are defining READ and WRITE permissions for our app. We also need to implement runtime permissions. We will do this later in the Main Activity file.
Now write the following line in build.gradle(Module:app) file.
implementation 'com.karumi:dexter:5.0.0'
Above line will add the dexter library into our android studio project. This library will help us for runtime permissions.
In this file you need to set minSdkVersion as 19. See the below line
minSdkVersion 19
So, final source code for build.gradle(Module:app) file is as the below
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 28 defaultConfig { applicationId "com.example.pdffromviewkotlin" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.karumi:dexter:5.0.0' }
Step 2. Main Files
In your activity_main.xml file, you should add the following
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical"> <LinearLayout android:id="@+id/llPdf" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fff" android:orientation="vertical"> <Button android:id="@+id/btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Create PDF" /> <ImageView android:id="@+id/iv" android:layout_width="300dp" android:layout_height="200dp" android:layout_marginLeft="30dp" android:layout_marginTop="10dp" android:src="@drawable/pyramid" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="10dp" android:text="Pyramid from Egypt" android:textSize="30sp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnScroll" android:layout_marginTop="20dp" android:layout_marginLeft="20dp" android:text="Make PDF Of ScrollView"/> </LinearLayout> </LinearLayout>
There is one Image view and one text view is present. Image view is previewing the image of pyramid.
Text view has some text which can not be changed from Kotlin file.
There are two buttons in the above file : CREATE PDF and MAKE PDF OF SCROLL VIEW
Now in your MainActivity.kt file, write down the below source snippet
import android.Manifest import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.pdf.PdfDocument import android.os.Build import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.support.annotation.RequiresApi import android.util.DisplayMetrics import android.util.Log import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.LinearLayout import android.widget.Toast import com.karumi.dexter.Dexter import com.karumi.dexter.MultiplePermissionsReport import com.karumi.dexter.PermissionToken import com.karumi.dexter.listener.DexterError import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.PermissionRequestErrorListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener import java.io.File import java.io.FileOutputStream import java.io.IOException class MainActivity : AppCompatActivity() { private var btn: Button? = null private var btnScroll: Button? = null private var llPdf: LinearLayout? = null private var bitmap: Bitmap? = null var targetPdf: String = "/storage/emulated/0//pdffromlayoutview.pdf" @RequiresApi(Build.VERSION_CODES.KITKAT) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestReadPermissions() btn = findViewById(R.id.btn) btnScroll = findViewById(R.id.btnScroll) llPdf = findViewById(R.id.llPdf) btnScroll!!.setOnClickListener { val intent = Intent(this@MainActivity, ScrollActivity::class.java) startActivity(intent) } btn!!.setOnClickListener { Log.d("size", " " + llPdf!!.width + " " + llPdf!!.width) bitmap = loadBitmapFromView(llPdf!!, llPdf!!.width, llPdf!!.height) createPdf() } } private fun createPdf() { val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager // Display display = wm.getDefaultDisplay(); val displaymetrics = DisplayMetrics() this.windowManager.defaultDisplay.getMetrics(displaymetrics) val hight = displaymetrics.heightPixels.toFloat() val width = displaymetrics.widthPixels.toFloat() val convertHighet = hight.toInt() val convertWidth = width.toInt() val document = PdfDocument() val pageInfo = PdfDocument.PageInfo.Builder(convertWidth, convertHighet, 1).create() val page = document.startPage(pageInfo) val canvas = page.canvas val paint = Paint() canvas.drawPaint(paint) bitmap = Bitmap.createScaledBitmap(bitmap!!, convertWidth, convertHighet, true) paint.color = Color.BLUE canvas.drawBitmap(bitmap!!, 0f, 0f, null) document.finishPage(page) // write the document content Log.d("target",targetPdf) val filePath: File filePath = File(targetPdf) try { document.writeTo(FileOutputStream(filePath)) } catch (e: IOException) { e.printStackTrace() Toast.makeText(this, "Something wrong: $e", Toast.LENGTH_LONG).show() } // close the document document.close() Toast.makeText(this, "PDF is created!!!", Toast.LENGTH_SHORT).show() } companion object { fun loadBitmapFromView(v: View, width: Int, height: Int): Bitmap { val b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val c = Canvas(b) v.draw(c) return b } } private fun requestReadPermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ) .withListener(object : MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT) .show() } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied) { // show alert dialog navigating to Settings //openSettingsDialog(); } } override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) { token.continuePermissionRequest() } }).withErrorListener(object : PermissionRequestErrorListener { override fun onError(error: DexterError) { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() } }) .onSameThread() .check() } }
Deep Learn
First of all, see the following
private var btn: Button? = null private var btnScroll: Button? = null private var llPdf: LinearLayout? = null private var bitmap: Bitmap? = null var targetPdf: String = "/storage/emulated/0//pdffromlayoutview.pdf"
Compiler will first make the objects of the button classes. Then there the objects of LinearLayout and Bitmap classes.
After this, it will define one String variable targetPdf . This variable holds the path to the PDF file.
Inside onCreate() method, there is another function called requestReadPermissions()
Below is the source code for requestReadPermissions() method.
private fun requestReadPermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ) .withListener(object : MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT) .show() } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied) { // show alert dialog navigating to Settings //openSettingsDialog(); } } override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) { token.continuePermissionRequest() } }).withErrorListener(object : PermissionRequestErrorListener { override fun onError(error: DexterError) { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() } }) .onSameThread() .check() }
This method is helping us to implement the runtime permissions. In this task, dexter library will help us.
We are asking for READ and WRIGHT permissions in this method.
Now read the following code
btnScroll!!.setOnClickListener { val intent = Intent(this@MainActivity, ScrollActivity::class.java) startActivity(intent) }
Compiler will run the above code when the user clicks “MAKE PDF OF SCROLL VIEW” button.
It will simply open the ScrollActivity. We will create this activity in the next step.
Now compiler will run the following on the click event of CREATE PDF button.
btn!!.setOnClickListener { Log.d("size", " " + llPdf!!.width + " " + llPdf!!.width) bitmap = loadBitmapFromView(llPdf!!, llPdf!!.width, llPdf!!.height) createPdf() }
Here, compiler will get the bitmap of the whole view or layout. For this, it will use loadBitmapFromView() method.
A method named createPdf() will use this bitmap to make the PDF file from this bitmap.
Below are the coding lines for createPdf() function.
private fun createPdf() { val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager // Display display = wm.getDefaultDisplay(); val displaymetrics = DisplayMetrics() this.windowManager.defaultDisplay.getMetrics(displaymetrics) val hight = displaymetrics.heightPixels.toFloat() val width = displaymetrics.widthPixels.toFloat() val convertHighet = hight.toInt() val convertWidth = width.toInt() val document = PdfDocument() val pageInfo = PdfDocument.PageInfo.Builder(convertWidth, convertHighet, 1).create() val page = document.startPage(pageInfo) val canvas = page.canvas val paint = Paint() canvas.drawPaint(paint) bitmap = Bitmap.createScaledBitmap(bitmap!!, convertWidth, convertHighet, true) paint.color = Color.BLUE canvas.drawBitmap(bitmap!!, 0f, 0f, null) document.finishPage(page) // write the document content Log.d("target",targetPdf) val filePath: File filePath = File(targetPdf) try { document.writeTo(FileOutputStream(filePath)) } catch (e: IOException) { e.printStackTrace() Toast.makeText(this, "Something wrong: $e", Toast.LENGTH_LONG).show() } // close the document document.close() Toast.makeText(this, "PDF is created!!!", Toast.LENGTH_SHORT).show() }
This method is using various classes like Canvas, Paint etc. to create the PDF file from XML layout.
Step 3. Making PDF from Scroll View
Make a new activity and give it a name like Scroll Activity. You should add the following in activity_scroll.xml file.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/llScroll" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fff" android:orientation="vertical"> <Button android:id="@+id/btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Create PDF" /> <ImageView android:id="@+id/iv" android:layout_width="300dp" android:layout_height="300dp" android:layout_marginLeft="30dp" android:layout_marginTop="10dp" android:src="@drawable/empire" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="10dp" android:text="Empire state building is located in the New York, US" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="10dp" android:text="Empire state building is located in the New York, US" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="10dp" android:text="Empire state building is located in the New York, US" android:textSize="30sp" /> </LinearLayout> </ScrollView> </LinearLayout>
Above file contains the scroll view as the parent. Inside scroll view, there is one button, one image view and three text views are present.
Now in your ScrollActivity.kt file, you need to write the below source snippet
import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.pdf.PdfDocument import android.icu.util.Calendar import android.media.MediaScannerConnection import android.net.Uri import android.os.Build import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.os.Environment import android.support.annotation.RequiresApi import android.util.DisplayMetrics import android.util.Log import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.LinearLayout import android.widget.Toast import java.io.ByteArrayOutputStream import java.io.File import java.io.FileOutputStream import java.io.IOException class ScrollActivity : AppCompatActivity() { private var btn: Button? = null private var llScroll: LinearLayout? = null private var bitmap: Bitmap? = null @RequiresApi(Build.VERSION_CODES.KITKAT) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_scroll) btn = findViewById(R.id.btn) llScroll = findViewById(R.id.llScroll) btn!!.setOnClickListener { Log.d("size", " " + llScroll!!.width + " " + llScroll!!.width) bitmap = loadBitmapFromView(llScroll!!, llScroll!!.width, llScroll!!.height) createPdf() } } @RequiresApi(Build.VERSION_CODES.KITKAT) private fun createPdf() { val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager // Display display = wm.getDefaultDisplay(); val displaymetrics = DisplayMetrics() this.windowManager.defaultDisplay.getMetrics(displaymetrics) val hight = displaymetrics.heightPixels.toFloat() val width = displaymetrics.widthPixels.toFloat() val convertHighet = hight.toInt() val convertWidth = width.toInt() // Resources mResources = getResources(); // Bitmap bitmap = BitmapFactory.decodeResource(mResources, R.drawable.screenshot); val document = PdfDocument() val pageInfo = PdfDocument.PageInfo.Builder(convertWidth, convertHighet, 1).create() val page = document.startPage(pageInfo) val canvas = page.canvas val paint = Paint() canvas.drawPaint(paint) bitmap = Bitmap.createScaledBitmap(bitmap!!, convertWidth, convertHighet, true) paint.color = Color.BLUE canvas.drawBitmap(bitmap!!, 0f, 0f, null) document.finishPage(page) // write the document content val targetPdf = "/sdcard/pdffromScroll.pdf" val filePath: File filePath = File(targetPdf) try { document.writeTo(FileOutputStream(filePath)) } catch (e: IOException) { e.printStackTrace() Toast.makeText(this, "Something wrong: $e", Toast.LENGTH_LONG).show() } // close the document document.close() Toast.makeText(this, "PDF of Scroll is created!!!", Toast.LENGTH_SHORT).show() } companion object { fun loadBitmapFromView(v: View, width: Int, height: Int): Bitmap { val b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val c = Canvas(b) v.draw(c) return b } } }
Process of creating the PDF file of the scroll view is the same as of we have done in the previous step for Main Activity.
First, compiler will create the bitmap of the scroll view using loadBitmapFromView() method.
Then it will use this bitmap to create the PDF file.
Compiler will run the createPdf() method, when the user clicks the button.
A PDF file from scroll view will have the name like pdffromScroll.pdf
Download For Kotlin Generate PDF From View
https://github.com/demonuts/Kotlin-Generate-PDF-From-View-Convert-Activity-XML-Layout-ScrollView