PDF Document API를 이용하여 간단하게 PDF를 만드는 방법에 대하여 알아보자.
PDF 문서를 만들려면 가장 먼저, 용지의 크기를 정해야 한다. 이는 당연할 것이다. 포토샵으로 따지면 캔버스의 크기를 말한다.
통상 우리가 문서를 만들때에는 A4용지를 쓴다. 그런데 A4용지의 크기는 다음과 같다.
가로 210mm = 8.26Inch 세로 297mm = 11.69Inch
그런데 안드로이드에서 제공하는 PDF Document의 단위는 1포인트인데, 이 포인트는 1인치를 기준으로 72포인트라고 한다. 따라서 용지의 크기를 정할 떄에는 인치를 기준으로 포인트를 정하는 것이 좋다. 따라서 위의 인치를 기준으로 한 A4 용지의 크기를 포인트로 환산하면 다음과 같다.
가로 : 8.26Inch = 594.72point ≒ 595point 세로 : 11.69Inch = 841.68point ≒ 842point
A4용지의 크리는 인치를 기준으로 하면 정확하게 포인트가 정수형으로 떨어지지 않는다. 따라서 반올림을 하여 가로 595포인트, 세로 824포인트로 정하면 A4용지의 크기를 정할 수 있다.
/**Dimension For A4 Size Paper (1 inch = 72 points)**/ val PDF_PAGE_WIDTH = 595 //8.26 Inch val PDF_PAGE_HEIGHT = 842 //11.69 Inch
용지 중앙에 글자를 그리는 예시는 다음과 같다.
fun generatePDFStart() { /**Dimension For A4 Size Paper (1 inch = 72 points)**/ val PDF_PAGE_WIDTH = 595 //8.26 Inch val PDF_PAGE_HEIGHT = 842 //11.69 Inch // creating a PDF Document instance val pdfDocument: PdfDocument = PdfDocument() // Page Information : Page's Width, Height, and PageNumber val myPageInfo: PdfDocument.PageInfo? = PdfDocument.PageInfo.Builder(PDF_PAGE_WIDTH, PDF_PAGE_HEIGHT, 1).create() // Page val myPage: PdfDocument.Page = pdfDocument.startPage(myPageInfo) // creating a variable for canvas from our page of PDF. val canvas: Canvas = myPage.canvas // Variable to make a drawing(Text) val title: Paint = Paint() // Draw Text canvas.drawText("Hello, PDF Document!", 209F, 100F, title) pdfDocument.finishPage(myPage) savePdfFileExternalStorage("StartPDF.pdf", pdfDocument) pdfDocument.close() }
PDFDocument API에서는 글자나 그림이나 모두 android.graphics.Paint API(이하에서는 Paint API로 약칭하겠다)를 사용한다.
제트팩컴퍼즈에서 사용하는 text API는 사용할 수 없으니, Paint API를 사용하여 텍스트를 그려야 한다.
나는 고령딸기체와 떡볶이체를 폰트로 사용할 것이다. 따라서 다음과 같이 두개의 Paint object를 만든다.
// Paint object to make a Text val title: Paint = Paint() // Title paint, Goryoengstrawberry font val ttoppokki : Paint = Paint() // text in the center of page, ttoppokki font
위의 페인트 오브젝트에서 사용할 폰트는 다음과 같이 불러온다.
// Loading Strawberry font val fontStrawberry = ResourcesCompat.getFont(context, R.font.goryeongstrawberry) 떡볶이체 폰트 불러오기 val fontTtoppoki = ResourcesCompat.getFont(context, R.font.ttoppokki)
여기서 R.font다음에 있는 폰트리소스는 ui.theme폴더에 있는 fontfamily.kt파일에 설정된 것을 그대로 불러올 수 있다.
이를태면 나는 ui.theme폴더에 다음과 같이 fontfamily.kt를 만들어뒀다.
val fontGoryeong = FontFamily( Font(R.font.goryeongstrawberry, FontWeight.Normal), ) val ttoppokki = FontFamily( Font(R.font.ttoppokki, FontWeight.Normal) )
페인트 오브젝트에 폰트를 연결하는 함수는 setTypeface이다. 다음과 같이 하면 된다.
title.setTypeface(fontStrawberry) // strawberry font ttoppokki.setTypeface(fontTtoppoki) // ttoppoki font
다음과 같은 방식으로 Paint오브젝트의 컬러, 크기, 정렬을 할 수 있다.
// title paint setting title.setTypeface(fontStrawberry) title.color = ContextCompat.getColor(context, R.color.orange_80) title.textSize = 16f // ttoppokki paint setting ttoppokki.setTypeface(fontTtoppoki) ttoppokki.color = ContextCompat.getColor(context, R.color.black) ttoppokki.textSize = 12f ttoppokki.textAlign = Paint.Align.CENTER
여기서 color는 res 폴더 내에 colors.xml로 정의되어 있는 컬러코드를 말한다. ui.theme에 정의되어 있는 Color.kt가 아님에 유의하자.
참고로 나는 colors.xml을 다음과 같이 정의하였다.
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="purple_200">#FFBB86FC</color> <color name="purple_500">#FF6200EE</color> <color name="purple_700">#FF3700B3</color> <color name="orange_80">#FFEFB8C8</color> <color name="teal_200">#FF03DAC5</color> <color name="teal_700">#FF018786</color> <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> </resources>
지금까를 정리하면 다음과 같이 텍스트를 만드는 기능들을 클래스화 할 수 있을 것이다.
class PDFUtil constructor(val context: Context) { /**Dimension For A4 Size Paper (1 inch = 72 points)**/ val PDF_PAGE_WIDTH = 595 //8.26 Inch val PDF_PAGE_HEIGHT = 842 //11.69 Inch /* Font Resource */ val fontStrawberry = ResourcesCompat.getFont(context, R.font.goryeongstrawberry) // Strawberry font // A4 Size Page Info val A4 = a4Paper() // Paint object to make a Text val title: Paint = Paint() // Title paint, Goryoengstrawberry font // A4 Size Paper Initializer private fun a4Paper() : PdfDocument.PageInfo { // Page Information : Page's Width, Height, and PageNumber val myPageInfo: PdfDocument.PageInfo = PdfDocument.PageInfo.Builder(PDF_PAGE_WIDTH, PDF_PAGE_HEIGHT, 1).create() return myPageInfo } // Draw Title fun titleText(text : String, canvas: Canvas) { title.setTypeface(fontStrawberry) title.color = ContextCompat.getColor(context, R.color.orange_80) title.textSize = 16f title.textAlign = Paint.Align.CENTER // Draw Text canvas.drawText(text, (canvas.width / 2).toFloat(), (canvas.height / 2).toFloat(), title) } @Throws(IOException::class) fun savePdfFileExternalStorage(filename: String, document: PdfDocument, context : Context) { try { // First, creating External Storage Directory, and a file name, // Second, write our PDF file to that location. // Third, close file val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val file = File(dir, filename) val fos = FileOutputStream(file) document.writeTo(fos) fos.close() // on below line we are displaying a toast message as PDF file generated.. Toast.makeText(context, "PDF 파일이 다운로드 폴더에 저장되었습니다.", Toast.LENGTH_SHORT).show() } catch (e: Exception) { // below line is used // to handle error e.printStackTrace() // on below line we are displaying a toast message as fail to generate PDF Toast.makeText(context, "PDF파일 작성에 실패했습니다.", Toast.LENGTH_SHORT).show() } } }
위에서 만들 클래스는 다음과 같이 사용할 수 있다.
fun generatePDFStart(context: Context) { // creating a PDF Document instance val pdfDocument: PdfDocument = PdfDocument() // PDFUtil instance val pdfUtil = PDFUtil(context) // Page1 Start val page1: PdfDocument.Page = pdfDocument.startPage(pdfUtil.A4) // creating a variable for canvas from our page of PDF. val canvas: Canvas = page1.canvas pdfUtil.titleText("이건 고령 딸기체 글자입니다.", canvas) // End of Page pdfDocument.finishPage(page1) // Save PDF file pdfUtil.savePdfFileExternalStorage("StartPDF.pdf", pdfDocument, context) // Closing PDF Document pdfDocument.close() }
이렇게 하면 상당히 코드가 깔끔해진다.
다음번 부터는 이런 방식으로 소제목 만들기와 표 만들기를 해보자.