AndroidPDF: Create.Write.Save PDF Files

Harika bv
7 min readMay 16, 2020

--

#Android application to create a resume in pdf format

AndroidPDF : Create. Write. Save PDF files

Generating PDF from android application is essential for most of the developers. So, in this post I will be dealing with the basics implementation of a famous android PDF library called iText.

As shown in the picture above, we will create a simple resume from android application. For the ease-of-understanding, we will be focusing mostly on learning the iText features.

Let’s get started!

Step-1: Adding the library in the app gradle

implementation 'com.itextpdf:itextg:5.5.10'

Step-2: Let’s just keep a simple user design: A single button to open the PDF

Open the activity_main.xml and code 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:padding="@dimen/spacing_medium"
android:orientation="vertical">

<Button
android:id="@+id/openPdf"
android:layout_width="match_parent"
android:layout_height="@dimen/user_picture_jumbo_height"
android:text="Click to open the resume"
android:textColor="#FFF"
android:background="@color/colorAccent">
</Button>

</LinearLayout>
  • And this is how the layout looks!

Step-3: Before starting the java code, lets first add the fonts to the res folder

Download .ttf files of your choice and paste it in “\app\src\main\res\font”.

Step-4:

  • Open the MainActivity.java and follow the steps
  • We Initialize the required variables as follows (Explained inline with code)
//Assets to include for UI 
Button button;
ProgressDialog progressDialog;
//PDF File related variables
private File pdfFile;
private PdfWriter docWriter;
public BaseFont bfBold, bfNormal, bfItalic;

//Profile details
private String name = "H A R I K A B V" ;
private String title = "SOFTWARE DEVELOPER";
private String about = "A tech enthusiast with passion to solve problems and Love to make things. I believe that I am a versatile learner and can get going with any sort of work. Have work experience in various organisations.";

//Contact
private String phone = "91-7729897953";
private String email = "harikabhaskaram31@gmail.com";
private String place = "Nellore, AP";

//Skills
private String skill1 = "Java", skill2="Python", skill3="Tensorflow", skill4="AWS", skill5="SQL", skill6="Adobe Xd";

//Expertise
private String expe1 = "Android App\n Development", expe2="Graphic Design", expe3="UI/ UX Design", expe4="Algorithm Development", expe5="Data Analysis";

//WorkExperience
private String workCom1 = "Alfaleus Technology | Dec 2018 - Present", workCom2="FindMind Analytics | Apr 2020 - Present";
private String workTitle1 = "Software Engineer",workTitle2="UI/ UX Designer";

private String work1_1="* Worked on the design and development of C3 Field Analyzer software which includes algorithm development, AWS Dynamo database and AWS S3 storage (online) and SQLite (offline)";
private String work1_2="* Analyzed data and performed comparison reports";
private String work1_3 = "* Documentation - SDD (Software Design Description), SDP (Software Development Plan), UR&DI (User Requirements and Design Inputs)";

private String work2_1="* Understanding the user requirements and converting into user flows";
private String work2_2="* Designing wire-frames, visual designs and prototypes";

//AdditionalExperience
private String addworkCom1 = "GirlUp Masakali", addworkCom2="Technology and Gaming Club";
private String addworkTitle1 = "Graphic Designer",addworkTitle2="Core Member";

private String addwork1_1="* Designing posters for social media platforms";

private String addwork2_1="* Worked as Design mentor and designed event flyers | Brochures | Badges ";
private String addwork2_2="* Part of organisation team for various university events";
  • Following the initialization, within onCreate activity, we need to assign the UI elements with reference ID and run a loader while the resume gets loaded in background.
button = findViewById(R.id.openPdf);//For loader
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("Resume Loading");
progressDialog.setProgress(10);
progressDialog.setMax(100);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
progressDialog.show();
//Execute a background Task to generate the PDF
//This background task contains the entire process of generating the PDF
new MyTask().execute();
  • Adding on click listener to the button, to open the PDF file once it is generated
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MimeTypeMap map = MimeTypeMap.getSingleton();
String ext = MimeTypeMap.getFileExtensionFromUrl(pdfFile.getName());
String type = map.getMimeTypeFromExtension(ext);

if (type == null)
type = "*/*";

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(pdfFile);

intent.setDataAndType(data, type);
startActivity(intent);
}
});
  • Let’s start with the Background Task (MyTask)
  • For a background task, there will be 3 main sections: a) On pre-execute: As the name suggests, this section code will be executed at first; b) doInBackground: This section performs the functions in the background; c)onPostExecute: This section of code happens after the background work is completed (Here the dialog will be closed)
@SuppressLint("StaticFieldLeak")
public class MyTask extends AsyncTask<Void, Void, Void> {
public void onPreExecute() {
}
public Void doInBackground(Void... unused) {

try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
createPdfWrapper();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
progressDialog.cancel();
super.onPostExecute(aVoid);
}
}
  • As we will be storing the generated PDF file in File manager, we require the Internal Storage permission. So let’s add the snippet to dynamically ask for permission
private void createPdfWrapper() throws FileNotFoundException, DocumentException {

int hasWriteStoragePermission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteStoragePermission != PackageManager.PERMISSION_GRANTED) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!shouldShowRequestPermissionRationale(android.Manifest.permission.WRITE_CONTACTS)) {

}
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
111);
}
return;
} else {
createResume();
}
}
  • Before going to the function createResume(), lets Initialize the fonts
private void initializeFonts(){

Font font = FontFactory.getFont("res/font/google_sans_medium.ttf",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 0.8f, Font.NORMAL, BaseColor.BLACK);
bfNormal = font.getBaseFont();
Font font1 = FontFactory.getFont("res/font/google_sans_bold.ttf",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 0.8f, Font.NORMAL, BaseColor.BLACK);
bfBold = font1.getBaseFont();

Font font2 = FontFactory.getFont("res/font/google_sans_italic.ttf",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 0.8f, Font.NORMAL, BaseColor.BLACK);
bfItalic = font2.getBaseFont();
}
  • Here, in this tutorial I will be using Google Sans Font (Don’t forget to add the .ttf files in the fonts folder)

Let’s create a function to easily write headings and short lenght texts in the document

private void createHeadings(PdfContentByte cb, float x, float y, String text, int size, String fontStyle, BaseColor color ){
cb.beginText();
if(fontStyle.equals("normal"))
cb.setFontAndSize(bfNormal, size);
else if(fontStyle.equals("bold"))
cb.setFontAndSize(bfBold, size);
else if(fontStyle.equals("italic"))
cb.setFontAndSize(bfItalic, size);


cb.setColorFill(color);
cb.setTextMatrix(x,y);
cb.showText(text);
cb.endText();
}

Let’s start the main function “createResume” ,

a) Create the folder “BuildTheResume” in the Internal Storage

b) Name the pdf file ( I named it as name’s Resume.pdf)

c) Create and open the document | call the function to Initialize the fonts

private void createResume() throws DocumentException {

File docsFolder = new File(Environment.getExternalStorageDirectory(),"BuildTheResume");
if (!docsFolder.exists()) {
docsFolder.mkdir();
docsFolder.setExecutable(true);
}

pdfFile = new File(docsFolder, name+"'s Resume"+".pdf");

OutputStream output = null;
try {
output = new FileOutputStream(pdfFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Document document = new Document();
try {
docWriter = PdfWriter.getInstance(document, output);
} catch (DocumentException e) {
e.printStackTrace();
}
document.open();
initializeFonts();
PdfContentByte cb = docWriter.getDirectContent();
  • Create a rectangle and add the text (Name and Title) in the box
Rectangle rectangle1 = new Rectangle(0, 1000, 800, 600);
BaseColor myColor = new BaseColor(42, 42, 42);
rectangle1.setBackgroundColor(myColor);
cb.rectangle(rectangle1);

BaseColor black = new BaseColor(0, 0, 0);
BaseColor white = new BaseColor(255, 255, 255);
Font font = FontFactory.getFont("res/font/google_sans_medium.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 10, Font.NORMAL, BaseColor.BLACK);

createHeadings(cb,170,730,name,40,"bold",white);
createHeadings(cb,190,680,title,20,"normal", white);
  • Add contact details and a section breaker with a line
createHeadings(cb, 30, 570,"CONTACT",12, "bold", black);

createHeadings(cb, 40, 550,phone,10, "normal", black);
createHeadings(cb, 40, 530,email,10, "normal", black);
createHeadings(cb, 40, 510,place,10, "normal", black);

Rectangle line1 = new Rectangle(30, 490, 180, 491);
line1.setBackgroundColor(myColor);
cb.rectangle(line1);
  • Add skills and a section breaker with a line
createHeadings(cb, 30, 470,"SKILLS",12, "bold", black);

createHeadings(cb, 40, 450,skill1,10, "normal", black);
createHeadings(cb, 40, 430,skill2,10, "normal", black);
createHeadings(cb, 40, 410,skill3,10, "normal", black);
createHeadings(cb, 40, 390,skill4,10, "normal", black);
createHeadings(cb, 40, 370,skill5,10, "normal", black);
createHeadings(cb, 40, 350,skill6,10, "normal", black);

Rectangle line2 = new Rectangle(30, 330, 180, 331);
line2.setBackgroundColor(myColor);
cb.rectangle(line2);
  • Add Expertise fields
createHeadings(cb, 30, 310,"EXPERTISE",12, "bold", black);

createHeadings(cb, 40, 290,expe1,10, "normal", black);
createHeadings(cb, 40, 270,expe2,10, "normal", black);
createHeadings(cb, 40, 250,expe3,10, "normal", black);
createHeadings(cb, 40, 230,expe4,10, "normal", black);
createHeadings(cb, 40, 210,expe5,10, "normal", black);
  • Add profile (about us), as it is a multi-lined text, we would require ColumnText to add this
createHeadings(cb, 200, 570,"PROFILE",12, "bold", black);

Rectangle rect = new Rectangle(210, 570, 580, 460);
ColumnText ct = new ColumnText(docWriter.getDirectContent());

ct.setSimpleColumn(rect);

ct.addElement(new Paragraph(about, font));
try {
ct.go();
} catch (DocumentException e) {
e.printStackTrace();
}
  • Similarly, add work experience
createHeadings(cb, 200, 490,"PROFESSIONAL EXPERIENCE",12, "bold", black);
createHeadings(cb, 210, 470, workTitle1, 11, "bold", black);
createHeadings(cb, 210, 450, workCom1, 10, "italic", black);

Rectangle rect1 = new Rectangle(210, 450, 580, 380);
ColumnText ct1 = new ColumnText(docWriter.getDirectContent());

ct1.setSimpleColumn(rect1);
ct1.addElement(new Paragraph(work1_1, font));
ct1.go();


Rectangle rect2 = new Rectangle(210, 400, 580, 380);
ColumnText ct2 = new ColumnText(docWriter.getDirectContent());
ct2.setSimpleColumn(rect2);
ct2.addElement(new Paragraph(work1_2, font));
ct2.go();

Rectangle rect3 = new Rectangle(210, 380, 580, 360);
ColumnText ct3 = new ColumnText(docWriter.getDirectContent());
ct3.setSimpleColumn(rect3);
ct3.addElement(new Paragraph(work1_3, font));
ct3.go();


createHeadings(cb, 210, 340, workTitle2, 11, "bold", black);
createHeadings(cb, 210, 320, workCom2, 10, "italic", black);

Rectangle rect4 = new Rectangle(210, 320, 580, 300);
ColumnText ct4 = new ColumnText(docWriter.getDirectContent());
ct4.setSimpleColumn(rect4);
ct4.addElement(new Paragraph(work2_1, font));
ct4.go();

Rectangle rect5 = new Rectangle(210, 300, 580, 280);
ColumnText ct5 = new ColumnText(docWriter.getDirectContent());
ct5.setSimpleColumn(rect5);
ct5.addElement(new Paragraph(work2_2, font));
ct5.go();
  • Add additional experience fields
createHeadings(cb, 200, 250,"ADDITIONAL EXPERIENCE",12, "bold", black);

createHeadings(cb, 210, 230, addworkTitle1, 11, "bold", black);
createHeadings(cb, 210, 210, addworkCom1, 10, "italic", black);

Rectangle rect6 = new Rectangle(210, 210, 580, 190);
ColumnText ct6 = new ColumnText(docWriter.getDirectContent());
ct6.setSimpleColumn(rect6);
ct6.addElement(new Paragraph(addwork1_1, font));
ct6.go();

createHeadings(cb, 210, 170, addworkTitle2, 11, "bold", black);
createHeadings(cb, 210, 150, addworkCom2, 10, "italic", black);

Rectangle rect7 = new Rectangle(210, 150, 580, 130);
ColumnText ct7 = new ColumnText(docWriter.getDirectContent());
ct7.setSimpleColumn(rect7);
ct7.addElement(new Paragraph(addwork2_1, font));
ct7.go();


Rectangle rect8 = new Rectangle(210, 130, 580, 110);
ColumnText ct8 = new ColumnText(docWriter.getDirectContent());
ct8.setSimpleColumn(rect8);
ct8.addElement(new Paragraph(addwork2_2, font));
ct8.go();
  • Finally, close the document
try {
document.close();
output.flush();
output.close();
docWriter.close();
} catch (IOException e) {
e.printStackTrace();
}

Step-5: Add the storage permission in the manifest file

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
PDF created from the application

Yeah! We are done building the application. Run the application in the android mobile phone and check out the PDF created.

--

--

Harika bv

Tech Enthusiast | Passion to solve problems | Love to make things Proven skills in Android application development, Graphic and UI Design