===== 들어가며 ===== ==== 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() } 이렇게 하면 상당히 코드가 깔끔해진다. 다음번 부터는 이런 방식으로 소제목 만들기와 표 만들기를 해보자.