문서를 수동 설정하여 프린터로 인쇄하기

Android 2014. 2. 13. 13:10

 PrintManager객체를 얻어서, 인쇄하기 위해서 아래와 같이 한다.

private void doPrint() {
   
// Get a PrintManager instance
   
PrintManager printManager = (PrintManager) getActivity()
           
.getSystemService(Context.PRINT_SERVICE);

   
// Set job name, which will be displayed in the print queue
   
String jobName = getActivity().getString(R.string.app_name) + " Document";

   
// Start a print job, passing in a PrintDocumentAdapter implementation
   
// to handle the generation of a print document
    printManager
.print(jobName, new MyPrintDocumentAdapter(getActivity()),
           
null); //
}

- 인쇄할 내용에 대한 정의는 PrintDocumentAdapter에서 하게 되며, 인쇄할 때의 다양한 옵션(가로/세로 모드 등)은 print()의 마지막 인자값(위 코드의 null)인  PrintAttributes을 통해서 설정할 수 있다.

PrintDocumentAdapter는 인쇄 Lifecycle에 해당하는 아래 4개의 콜백 메소드를 가지고 있다. 이 메소드들은 Main Thread에서 돌아가므로, 오래 걸리는 작업은 AsyncTask등을 이용해서 별도 Thread로 돌려야 한다.

onStart() : 인쇄 시작할때 불린다. (필수 아님)

onLayout() : 인쇄 결과물에 영향을 주는 옵션(페이지 크기, 인쇄 방향 등)을 사용자가 변경할 때 불린다. 변경된 옵션(페이지 크기 등)에 맞는 내용을 계산해서 Framework에 관련 내용(PrintDocumentInfo, 페이지수 등의 정보를 담고 있음)을 설정한다.

onWrite() : 인쇄할 페이지 내용에 대한 랜더링이 필요할때 불린다. onLayout()이 불린 후, 1번 이상 불린다.

onFinish() : 인쇄가 끝났을때 불린다. (필수 아님)

- onLayout()은 LayoutResultCallback을 통해 3종류(설정 완료, 취소, 실패)의 결과를 반환할 수 있다. 아래와 같이 구현한다.

@Override
public void onLayout(PrintAttributes oldAttributes,
                     
PrintAttributes newAttributes,
                     
CancellationSignal cancellationSignal,
                     
LayoutResultCallback callback,
                     
Bundle metadata) {
   
// Create a new PdfDocument with the requested page attributes
    mPdfDocument
= new PrintedPdfDocument(getActivity(), newAttributes);

   
// Respond to cancellation request
   
if (cancellationSignal.isCancelled() ) {
        callback
.onLayoutCancelled();
       
return;
   
}

   
// Compute the expected number of printed pages
   
int pages = computePageCount(newAttributes);

   
if (pages > 0) {
       
// Return print information to print framework
       
PrintDocumentInfo info = new PrintDocumentInfo
               
.Builder("print_output.pdf")
               
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
               
.setPageCount(pages);
               
.build();
       
// Content layout reflow is complete
        callback
.onLayoutFinished(info, true);
   
} else {
       
// Otherwise report an error to the print framework
        callback
.onLayoutFailed("Page count calculation failed.");
   
}
}

onLayoutFinished()의 두번째 인자값(true)은 기존의 설정에서 변경된 것이 있는지를 나타내며, 필요없는 onWrite() 호출을 막을 수 있다. 성능 향상을 위해서는 기존 설정값을 저장/비교하여 이 인자값을 잘 보내주도록 한다.

- 위 코드의 computePageCount()는 아래와 같이 구현한다.

private int computePageCount(PrintAttributes printAttributes) {
   
int itemsPerPage = 4; // default item count for portrait mode

   
MediaSize pageSize = printAttributes.getMediaSize();
   
if (!pageSize.isPortrait()) {
       
// Six items per page in landscape orientation
        itemsPerPage
= 6;
   
}

   
// Determine number of print items
   
int printItemCount = getPrintItemCount();

   
return (int) Math.ceil(printItemCount / itemsPerPage);
}

- onWrite()는 WriteResultCallback을 통해 3종류(설정 완료, 취소, 실패)의 결과를 반환할 수 있다. 아래는 PrintedPdfDocument을 사용하여 PDF 파일을 출력하는 예제이다.

@Override
public void onWrite(final PageRange[] pageRanges,
                   
final ParcelFileDescriptor destination,
                   
final CancellationSignal cancellationSignal,
                   
final WriteResultCallback callback) {
   
// Iterate over each page of the document,
   
// check if it's in the output range.
   
for (int i = 0; i < totalPages; i++) {
       
// Check to see if this page is in the output range.
       
if (containsPage(pageRanges, i)) {
           
// If so, add it to writtenPagesArray. writtenPagesArray.size()
           
// is used to compute the next output page index.
            writtenPagesArray
.append(writtenPagesArray.size(), i);
           
PdfDocument.Page page = mPdfDocument.startPage(i);

           
// check for cancellation
           
if (cancellationSignal.isCancelled()) {
                callback
.onWriteCancelled();
                mPdfDocument
.close();
                mPdfDocument
= null;
               
return;
           
}

           
// Draw page content for printing
            drawPage
(page);

           
// Rendering is complete, so page can be finalized.
            mPdfDocument
.finishPage(page);
       
}
   
}

   
// Write PDF document to file
   
try {
        mPdfDocument
.writeTo(new FileOutputStream(
                destination
.getFileDescriptor()));
   
} catch (IOException e) {
        callback
.onWriteFailed(e.toString());
       
return;
   
} finally {
        mPdfDocument
.close();
        mPdfDocument
= null;
   
}
   
PageRange[] writtenPages = computeWrittenPages();
   
// Signal the print framework the document is complete
    callback
.onWriteFinished(writtenPages);

   
...
}

- 위 코드의 drawPage()는 추가적으로 출력하고 싶은 내용을 그리는 메소드이며, 아래와 같이 구현한 수 있다. Page의 Canvas에 그릴때 종이 가장자리에 찍히지 않는 영역이 있다는 것을 고려해야 한다.

private void drawPage(PdfDocument.Page page) {
   
Canvas canvas = page.getCanvas();

   
// units are in points (1/72 of an inch)
   
int titleBaseLine = 72;
   
int leftMargin = 54;

   
Paint paint = new Paint();
    paint
.setColor(Color.BLACK);
    paint
.setTextSize(36);
    canvas
.drawText("Test Title", leftMargin, titleBaseLine, paint);

    paint
.setTextSize(11);
    canvas
.drawText("Test paragraph", leftMargin, titleBaseLine + 25, paint);

    paint
.setColor(Color.BLUE);
    canvas
.drawRect(100, 100, 172, 172, paint);
}


출처 : http://developer.android.com/

설정

트랙백

댓글