사용자 도구

사이트 도구


android:pdfdocument:sectioning
sectioning

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판이전 판
다음 판
이전 판
android:pdfdocument:sectioning [2024/12/16 11:46] 이거니맨android:pdfdocument:sectioning [2024/12/24 20:00] (현재) 이거니맨
줄 17: 줄 17:
 ===== 구역화하기 ===== ===== 구역화하기 =====
  
-==== 1. 각 구역의 절대 좌표 기억하기 ====+==== 1. 절대 좌표 및 구역의 너비와 높이를 저장는 클래스 만들기 ====
  
-일단 각 구역을 기준으로 상대좌표로 인쇄하기로 하였으면, 일단은 각 구역이 페이지 내에서 어느 지점에 위치하는를 정해야 할 것이다. 따라서 다음과 같은 코드가 필요하다. +다음과 같이 각 구역의 속성을 기하는 클래스를 만들었다. 
  
 <code kotlin> <code kotlin>
 +// Rect 좌표와 너비 높이
 +data class PNL(private val rect : Rect = Rect(0, 0, 100, 100), private  val width : Int = 0, private val height : Int = 0)
 +{
 +    var rectP = rect
 +    var Width = width
 +    var Height = height
 +}
 +</code>
 +
 +==== 2. 각 구역의 절대 좌표 기억하기 ====
 +
 +A4종이에서 본문을 중심으로 한 각 마진을 구한 후, 이를 기초로 하여 본문 지역의 위치 속성을 다음과 같이 지정했다. 
 +
 +<code kotlin>
 +    // creating a PDF Document instance
 +    val pdfDocument: PdfDocument = PdfDocument()
 +    // 여백
 +    val marginTop = 42
 +    val marginBottom = 50
 +    val marginLeft = 47
 +    val marginRight = 48
 +
     // 각 구역 좌표     // 각 구역 좌표
-    val headerSection Rect(0, 0, PDF_PAGE_WIDTH, marginTop)  // 머리말 부분 위치 +    var body PNL(Rect(marginLeft, marginTop, PDF_PAGE_WIDTH - marginLeft, PDF_PAGE_HEIGHT - marginBottom), 
-    val footerSection = Rect(0, PDF_PAGE_HEIGHT - marginBottom, PDF_PAGE_WIDTH, PDF_PAGE_HEIGHT)  // 꼬리말 부분 위치 +        PDF_PAGE_WIDTH - (marginLeft + marginRight), 
-    val bodySection = Rect(marginLeft, marginTop, PDF_PAGE_WIDTH - marginLeft, PDF_PAGE_HEIGHT - marginBottom)  // 본문 +        PDF_PAGE_HEIGHT - (marginTop marginBottom) )
-    val leftSection = Rect(0, marginTop, marginLeft, PDF_PAGE_HEIGHT - marginBottom) // 왼쪽 여백 +
-    val rightSection = Rect(PDF_PAGE_WIDTH - marginRight, marginTop, PDF_PAGE_WIDTH, PDF_PAGE_HEIGHT - marginBottom) // 오른쪽 여백+
 </code> </code>
  
 +===== 구역화를 할 때 고려해야 할 문제점 ===== 
  
-==== 2. 비트맵으로 저장하고 그리기 ==== +안드이드의 기본 PDF API(android.graphics.pdf)를 이용여 pdf문서를 만들자 할 때의 가장 큰 문제점은,
  
-^  비트맵으로 그린 본문 ^^+pdf의 페이지 작성 및 캔버스 그리기는 모두 일방향이라는 것이었다.  
 + 
 +즉, 페이지를 먼저 만들면, 그 페이지 안에 canvas가 이미 지정되어 있고, 그 캔버스 안에 그림을 그리는 방식이다.  
 + 
 +예를 들면 다음과 같다((https://developer.android.com/reference/android/graphics/pdf/PdfDocument)). 
 + 
 +<code kotlin> 
 +// creating a PDF Document instance 
 +val pdfDocument: PdfDocument = PdfDocument() 
 + 
 +// create a page description 
 +val myPageInfo: PdfDocument.PageInfo = 
 +            PdfDocument.PageInfo.Builder(PDF_PAGE_WIDTH, PDF_PAGE_HEIGHT, num).create() 
 + 
 +// start a page 
 +val newPage: PdfDocument.Page = pdfDocument.startPage(a4Paper(pageNum + 1)) 
 + 
 +// start canvas 
 +val canvas = newPage.canvas 
 + 
 +// draw something on the page 
 +canvas.draw(....) 
 + 
 + // finish the page 
 +pdfDocument.finishPage(page); 
 + . . . 
 + 
 +// add more pages 
 + . . . 
 +// write the document content 
 +pdfDocument.writeTo(getOutputStream()); 
 + 
 +// close the document 
 +pdfDocument.close(); 
 +</code> 
 + 
 + 
 +위와 같이  canvas는  page에서  get하는 것만 가능하고, set은 안된다.  
 + 
 +따라서 어떤 식으로 하든, 이미 만들어진 canvas를 pdf page에 복사할 수가 없다.  
 + 
 + 
 +그래서 고민끝에 생각해낸 해결책은 다음의 세가지이다. 
 + 
 +첫째, 안드로이드에서 제공하는 pdf graphics api가 아닌,  제3의 라이브러리를 이용하는 것이다. [[https://itextpdf.com/|iText]]라는 라이브러리가 있는데, 찾아보니 이 라이브러리로는 헤더와 푸터를 만들어주었다. 그런데 내가 구현하려고 하는 궁극적인 목적인 '꼬리말에 전체 페이지수와 현재페이지수를 보여주기'는 이 라이브러리로 가능한지가 모르겠다. 무엇보다도, 여기까지 왔는데 외부 라이브러리를 쓴다는건  허탈하기도 할 뿐더러, 무척 자존심이 상하는 일이기도 하다.  
 + 
 +둘째, canvas는 비단 pdf page로만 만들 필요가 없다.  canvas만 따로 선언이 가능하다. 그리고 이 경우에는 캔버스가 비트맵을 그려주었다. 이러한 비트맵그림 파일을 pdf의 본문 영역에 그림으로 그려주는 것도 가능하다. 이하에서는 이에 대하여 알아 보도록 하겠다. 다만 후술하겠지만 이 경우에는 문제가 생긴다.  
 + 
 + 
 +셋째, 본문 영역에 대한 pdf를 만든 후에, 이 작업을 모두 기억했다가 다시 헤더와 푸터가 포함되어 있는 [[android:pdfdocument:commandmirroring|pdf전체를 만들 때에 기억한 작업을 그대로 반복하는 경우]]가 있을 수가 있다. 이렇게 해야만 pdf 파일이 벡터로 저장되어 확대했을 때 글자가 깨지지 않는다.  
 + 
 + 
 + 
 +===== 비트맵으로 저장하고 그리기 ===== 
 + 
 +==== 1. 비트맵 파일 배열 만들기 ==== 
 + 
 +다음과 같이 비트맵 그림으로 저장할 배열을 만들 수 있다.  
 + 
 +<code kotlin> 
 +    // 비트맵 및 캔버스 리스트 만들기 
 +    val bitmapList : ArrayList<Bitmap> = arrayListOf() 
 +    val canvasList : ArrayList<Canvas> = arrayListOf<Canvas>() 
 +</code> 
 + 
 + 
 +==== 2. 페이지가 바뀔 때마다 비트맵을 새로 만들고 배열에 추가하기 ====  
 + 
 +이런 식으로 페이지가 바뀔 때마다 비트맵을 배열에 추가하는 것이다. 
 + 
 +<code kotlin> 
 +//  캔버스 시작하기 
 +fun beginCanvas() { 
 +    bitmapList.add(Bitmap.createBitmap(body.Width, body.Height, Bitmap.Config.ARGB_8888)) 
 +    canvasList.add(Canvas(bitmapList[0])) 
 + 
 +    pageNum = 0; 
 +    totalPOS = POS(0, 0) 
 +    currentPOS = POS(0, 0) 
 +
 + 
 +// Next Page 
 +fun nextPage() { 
 + 
 +    val newNum = totalPOS.Y / body.Height 
 + 
 +    if (newNum > pageNum) { 
 +        pageNum = newNum 
 +        currentPOS.Y = 20 
 + 
 +        bitmapList.add(Bitmap.createBitmap(body.Width, body.Height, Bitmap.Config.ARGB_8888)) 
 +        canvasList.add(Canvas(bitmapList[pageNum])) 
 + 
 + 
 +    } 
 +
 +</code> 
 + 
 +==== 3. 그리기 함수들 ==== 
 + 
 +각 그리기 함수에는 캔버스의 배열 번호를 지정해주면 될 것이다.  
 + 
 +예를들면 다음과 같다.  
 + 
 +<code kotlin> 
 +// Draw Title Text 
 +fun titleText(text : String) { 
 + 
 +    nextPage() 
 +    linefeedBig() 
 +    canvasList[pageNum].drawText(text, (canvasList[pageNum].width / 2).toFloat(), currentPOS.Y.toFloat(), title) 
 +    linefeedBig() 
 +
 +</code> 
 + 
 +=== 4. PDF 페이지 만들기 ====  
 + 
 +이렇게 만든 그림들을 canvas의 drawbitmap을 이용하여 본문 부분을 비트맵으로 그리면 된다. 
 + 
 +<code kotlin> 
 +// PDF 페이지 만들기 
 +fun makePDFDocument() { 
 + 
 +    for (i in 0 until canvasList.size) { 
 +        val newPage: PdfDocument.Page = pdfDocument.startPage(a4Paper(pageNum + 1)) 
 + 
 +        val canvas = newPage.canvas 
 + 
 +        drawPageHeader(canvas) 
 +        canvas.drawBitmap(bitmapList[i], body.rectP.left.toFloat(), body.rectP.top.toFloat(), null) 
 +        drawPageFooter(canvas, i + 1) 
 +        pdfDocument.finishPage(newPage) 
 + 
 +    } 
 +
 +</code> 
 + 
 + 
 +==== 5. 헤더와 푸터 ==== 
 + 
 +참고로, 머리말과 꼬리말은 다음과 같이 만들었다. 
 + 
 +<code kotlin> 
 +private fun drawPageHeader(canvas: Canvas) { 
 +    canvas.drawText("간이 고소장(모욕)", (PDF_PAGE_WIDTH - 20).toFloat(), (marginTop - 7).toFloat(), textRight) 
 +    canvas.drawLine(20f, marginTop - 3f, PDF_PAGE_WIDTH - 20f, marginTop - 3f, linePaint) 
 +
 + 
 +private fun drawPageFooter(canvas: Canvas, i : Int) { 
 +    canvas.drawLine(20f, PDF_PAGE_HEIGHT - marginBottom + 10f, PDF_PAGE_WIDTH - 20f, PDF_PAGE_HEIGHT - marginBottom + 10f, linePaint) 
 +    canvas.drawText( i.toString() + " / " + canvasList.size , (PDF_PAGE_WIDTH - 30).toFloat(), (PDF_PAGE_HEIGHT - marginBottom + 30f), textRight) 
 +    canvas.drawText("고소인 : $plaintiffName", marginLeft.toFloat(), (PDF_PAGE_HEIGHT - marginBottom + 30f), cellBodyLeft) 
 +
 +</code> 
 + 
 + 
 +=== 6. 결론 ==== 
 + 
 +이렇게 하면 머릿말과 꼬릿말은 pdf로 그린 것이지만, 본문 부문은 비트맵으로 만든 그림을 그래도 출력한 것이다.  
 + 
 +그래서 머릿말과 꼬릿말은 확대를 해도 글자가 깨지지 않지만 본문 부분은 확대를 하면 깨지는 것을 볼 수 있다.  
 + 
 + 
 +^  비트맵으로 그린 본문  ^^
 |  {{:android:pdfdocument:bitmap1.jpg?400|bitmap1}}  |  {{:android:pdfdocument:bitmap2.jpg?400|bitmap2}}  | |  {{:android:pdfdocument:bitmap1.jpg?400|bitmap1}}  |  {{:android:pdfdocument:bitmap2.jpg?400|bitmap2}}  |
 +
 +
 +
 +따라서 이러한 방식이 그다지 좋은 것은 아님을 알 수 있다.  
 +
 +이에 지금까지 했던 일을 기억 한 후에 다시 벡터로 그리는 방식을 채택하기로 했다.
 +
 +이에 대해서는 [[android:pdfdocument:commandmirroring|다음 포스팅]]을 참고하라. 
android/pdfdocument/sectioning.1734317161.txt.gz · 마지막으로 수정됨: 2024/12/16 11:46 저자 이거니맨