===== 들어가며 =====
==== 1. 이 글의 목적 ====
PDF Document API를 이용하여 간단하게 PDF를 만드는 방법에 대하여 알아보자.
==== 2. 용지의 크기 ====
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
===== Starting Page =====
용지 중앙에 글자를 그리는 예시는 다음과 같다.
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()
}
===== PDF Font Change =====
==== 1. Paint API ====
PDFDocument API에서는 글자나 그림이나 모두 android.graphics.Paint API(이하에서는 Paint API로 약칭하겠다)를 사용한다.
제트팩컴퍼즈에서 사용하는 text API는 사용할 수 없으니, Paint API를 사용하여 텍스트를 그려야 한다.
나는 [[https://noonnu.cc/font_page/1132|고령딸기체]]와 [[https://noonnu.cc/font_page/396|떡볶이체]]를 폰트로 사용할 것이다. 따라서 다음과 같이 두개의 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
==== 2. 폰트 불러오기 ====
위의 페인트 오브젝트에서 사용할 폰트는 다음과 같이 불러온다.
// 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)
)
==== 3. 페인트 오브젝트에 폰트리소스 연결하기 ====
페인트 오브젝트에 폰트를 연결하는 함수는 setTypeface이다. 다음과 같이 하면 된다.
title.setTypeface(fontStrawberry) // strawberry font
ttoppokki.setTypeface(fontTtoppoki) // ttoppoki font
==== 4. 컬러, 텍스트 크기, 텍스트 정렬 ====
다음과 같은 방식으로 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을 다음과 같이 정의하였다.
#FFBB86FC
#FF6200EE
#FF3700B3
#FFEFB8C8
#FF03DAC5
#FF018786
#FF000000
#FFFFFFFF
===== 클래스화 하기 =====
==== 1. PDF Util Class ====
지금까를 정리하면 다음과 같이 텍스트를 만드는 기능들을 클래스화 할 수 있을 것이다.
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()
}
}
}
==== 2. 유틸리티 클래스 사용하기 ====
위에서 만들 클래스는 다음과 같이 사용할 수 있다.
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()
}
이렇게 하면 상당히 코드가 깔끔해진다.
다음번 부터는 이런 방식으로 소제목 만들기와 표 만들기를 해보자.