Özel dokümanları yazdırma

Çizim uygulamaları, sayfa düzeni uygulamaları ve grafik çıktısı gibi, güzel biçimde basılı sayfalar oluşturmak temel bir özelliktir. Bu durumda kullanarak bir resmi veya HTML belgesini yazdırabilirsiniz. Bu tür uygulamaların yazdırma çıktısı almak için yazı tipleri, metin akışı, sayfa sonları ve daha fazlası dahil olmak üzere ve grafik öğeleri dahil edilir.

Uygulamanız için tamamen özelleştirilmiş bir yazdırma çıktısı oluşturmak için daha fazlası gerekir en az 100 dolarlık bir yatırım riski var. Hedeflerinize ulaşmanız için yazdırma çerçevesiyle iletişim kurma, yazıcı ayarlarına ayarlama, sayfa öğelerini çizme ve birden fazla sayfada yazdırmayı yönetebilirsiniz.

Bu derste, yazdırma yöneticisi ile nasıl bağlantı kurduğunuzu, bir yazdırma adaptörünü nasıl oluşturacağınızı ve oluşturmak için kullanabilirsiniz.

Uygulamanız yazdırma işlemini doğrudan yönettiğinde, bir Android yazdırma çerçevesine bağlanarak bir örnek almak için kullanıcınızın yazdırma isteği PrintManager sınıfı. Bu sınıf, bir yazdırma işi başlatmanızı sağlar ve yazdırma yaşam döngüsünü başlatın. Aşağıdaki kod örneğinde, yazdırma yöneticisinin nasıl alınacağı gösterilmektedir ve yazdırma işlemini başlatın.

Kotlin

private fun doPrint() {
    activity?.also { context ->
        // Get a PrintManager instance
        val printManager = context.getSystemService(Context.PRINT_SERVICE) as PrintManager
        // Set job name, which will be displayed in the print queue
        val jobName = "${context.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, MyPrintDocumentAdapter(context), null)
    }
}

Java

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); //
}

Yukarıdaki örnek kod, bir yazdırma işinin nasıl adlandırılacağını ve yazdırma yaşam döngüsünün adımlarını işleyen PrintDocumentAdapter sınıfının bir örneğinin nasıl ayarlanacağını gösterir. İlgili içeriği oluşturmak için kullanılan nasıl uygulanması gerektiğini bir sonraki bölümde ele alacağız.

Not: print() yöntemi bir PrintAttributes nesnesi alır. Bu parametreyi şunlar için kullanabilirsiniz: önceki yazdırma döngüsüne göre yazdırma çerçevesine ipuçları ve önceden ayarlanmış seçenekler sağlar Böylece kullanıcı deneyimini iyileştirebilirsiniz. Bu parametreyi, yönü yatay olarak ayarlamak gibi, yazdırılan içeriğe daha uygun o yönde bir fotoğraf bastırın.

Bir yazdırma adaptörü, Android yazdırma çerçevesiyle etkileşime girer ve yazdırır. Bu işlem, kullanıcıların oluşturmadan önce yazıcıları ve yazdırma seçeneklerini belirlemesini gerektirir yazdıracak bir doküman. Bu seçimler kullanıcı tercihine göre nihai sonucu etkileyebilir farklı çıkış özelliklerine, farklı sayfa boyutlarına veya farklı sayfa yönlerine sahip yazıcılar. Bu seçimler yapılırken, yazdırma çerçevesi bağdaştırıcınızdan bir yerleşim düzeni oluşturmasını ve son çıktıya hazırlanmak için belgeyi yazdırmalıdır. Kullanıcı yazdır düğmesine dokunduğunda, çerçeve Basılı dokümanın son halini alır ve çıktı almak için bunu bir baskı sağlayıcısına iletir. Yazdırma sırasında Kullanıcılar yazdırma işlemini iptal etmeyi seçebilir. Dolayısıyla, yazdırma adaptörünüz de ve iptal isteklerine tepki verebilir.

PrintDocumentAdapter soyut sınıfı, dört ana geri çağırma yöntemi vardır. Aşağıdaki yöntemleri uygulamanız gerekir kullanmanı öneririz:

  • onStart() - Şu saatte bir kez arandı: olması gerekir. Uygulamanızda tek seferlik hazırlık görevleri varsa örneğin, yazdırılacak verilerin anlık görüntüsünü almak gibi işlemleri burada yürütebilirsiniz. Uygulama bu yöntemi kullanmanız gerekmez.
  • onLayout() - Her seferinde aranır Kullanıcı, çıkışı etkileyen bir yazdırma ayarını (örneğin, farklı bir sayfa boyutu, veya sayfa yönü gibi özellikler içerir. Bu da uygulamanıza sayfa düzeninin düzenini çok kolay olur. Bu yöntem en azından, beklenen sayfa sayısını döndürmelidir yer alır.
  • onWrite() - Yazdırılmak üzere çağrıldı bir dosyaya ekleyebilirsiniz. Bu yöntem her aramadan sonra bir veya daha fazla onLayout() arama.
  • onFinish() - Sonda bir kez arandı adımlarından biridir. Uygulamanızda gerçekleştirilmesi gereken tek seferlik ayırma görevleri varsa burada yürütmeliyiz. Bağdaştırıcınızda bu yöntemi uygulamanız gerekmez.

Aşağıdaki bölümlerde, düzen ve yazma yöntemlerinin nasıl uygulanacağı açıklanmaktadır. çalışması açısından kritik öneme sahip.

Not: Bu bağdaştırıcı yöntemleri, uygulamanızın ana iş parçacığında çağrılır. Eğer uygulamanızda bu yöntemlerin yürütülmesinin önemli ölçüde harcama yapmasını bunları ayrı bir iş parçacığında yürütülecek şekilde uygulayın. Örneğin, ya da basılı doküman yazmanın işleyiş şekli ayrı AsyncTask nesneleridir.

Yazdırma dokümanı bilgilerini hesapla

PrintDocumentAdapter sınıfının bir uygulamasında, oluşturduğu belgenin türünü belirtebilmeli ve toplam dosya sayısını hesaplayabilmeli yazdırma işi için sayfa sayısı, yazdırılan sayfa boyutu hakkında bilgi. onLayout() yönteminin adaptör bu hesaplamaları yapar ve beklenen çıktısı hakkında bilgi sağlar. PrintDocumentInfo sınıfındaki bir yazdırma işi (ör. sayfa sayısı ve İçerik türü. Aşağıdaki kod örneğinde, PrintDocumentAdapter için onLayout() yönteminin temel bir uygulaması gösterilmektedir:

Kotlin

override fun onLayout(
        oldAttributes: PrintAttributes?,
        newAttributes: PrintAttributes,
        cancellationSignal: CancellationSignal?,
        callback: LayoutResultCallback,
        extras: Bundle?
) {
    // Create a new PdfDocument with the requested page attributes
    pdfDocument = PrintedPdfDocument(activity, newAttributes)

    // Respond to cancellation request
    if (cancellationSignal?.isCanceled == true) {
        callback.onLayoutCancelled()
        return
    }

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

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

Java

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

    // Respond to cancellation request
    if (cancellationSignal.isCanceled() ) {
        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.");
    }
}

onLayout() yöntemi yürütülebilir üç sonucu vardır: bu sonucun hesaplanması, iptal edilmesi veya düzeni tamamlanamıyor. İlgili kişiyi çağırarak bu sonuçlardan birini belirtmeniz gerekir yöntemini PrintDocumentAdapter.LayoutResultCallback nesnesinin içinde tutun.

Not: Boole parametresinden onLayoutFinished() yöntemi, düzen içeriğinin gerçekten değişip değişmediğini gösterir son talepten bu yana. Bu parametreyi doğru şekilde ayarlamak, yazdırma çerçevesinin onWrite() yöntemini gereksiz yere çağırmak, temelde, önceden yazılmış basılı dokümanı önbelleğe almak ve performansı artırmaktır.

onLayout() ana işi yazıcının özelliklerine göre çıktı olarak görülmesi beklenen sayfa sayısını hesaplar. Bu sayıyı nasıl hesaplayacağınız büyük ölçüde uygulamanızın bu sayfalarla ilgili sayfaları nasıl düzenlediğine bağlıdır. yazdırma. Aşağıdaki kod örneğinde, sayfa sayısının baskı yönüne göre belirlenir:

Kotlin

private fun computePageCount(printAttributes: PrintAttributes): Int {
    var itemsPerPage = 4 // default item count for portrait mode

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

    // Determine number of print items
    val printItemCount: Int = getPrintItemCount()

    return Math.ceil((printItemCount / itemsPerPage.toDouble())).toInt()
}

Java

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);
}

Basılı doküman dosyası yazma

Yazdırma çıktısını bir dosyaya yazma zamanı geldiğinde, Android yazdırma çerçevesi uygulamanızın PrintDocumentAdapter sınıfının onWrite() yöntemini çağırır. Yöntemin parametreleri, eklenmesi gereken sayfaları çıktı dosyasıyla birlikte hazırlanır. Daha sonra, bu yöntemi uyguladığınızda her istenen içerik sayfasını çok sayfalı bir PDF belge dosyasına dönüştürmenize olanak tanır. Bu işlem tamamlandığında geri çağırma nesnesinin onWriteFinished() yöntemini çağırın.

Not: Android yazdırma çerçevesi, onWrite() yöntemini her cihaz için bir veya daha fazla kez çağırabilir. onLayout() araması. Bu nedenle, Boole parametresinin ayarlanmasında Yazdırma içeriği düzeni değişmediğinde false olarak onLayoutFinished() yöntemini kullanmak, Böylece basılı dokümanın gereksiz şekilde yeniden yazılmasını önleyebilirsiniz.

Not: Boole parametresinden onLayoutFinished() yöntemi, düzen içeriğinin gerçekten değişip değişmediğini gösterir son talepten bu yana. Bu parametreyi doğru şekilde ayarlamak, yazdırma çerçevesinin onLayout() yöntemini gereksiz yere çağırmak, temelde, önceden yazılmış basılı dokümanı önbelleğe almak ve performansı artırmaktır.

Aşağıdaki örnekte, PDF dosyası oluşturmak için PrintedPdfDocument sınıfının kullanıldığı bu işlemin temel mekanizması gösterilmektedir:

Kotlin

override fun onWrite(
        pageRanges: Array<out PageRange>,
        destination: ParcelFileDescriptor,
        cancellationSignal: CancellationSignal?,
        callback: WriteResultCallback
) {
    // Iterate over each page of the document,
    // check if it's in the output range.
    for (i in 0 until totalPages) {
        // 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?.startPage(i)?.also { page ->

                // check for cancellation
                if (cancellationSignal?.isCanceled == true) {
                    callback.onWriteCancelled()
                    pdfDocument?.close()
                    pdfDocument = null
                    return
                }

                // Draw page content for printing
                drawPage(page)

                // Rendering is complete, so page can be finalized.
                pdfDocument?.finishPage(page)
            }
        }
    }

    // Write PDF document to file
    try {
        pdfDocument?.writeTo(FileOutputStream(destination.fileDescriptor))
    } catch (e: IOException) {
        callback.onWriteFailed(e.toString())
        return
    } finally {
        pdfDocument?.close()
        pdfDocument = null
    }
    val writtenPages = computeWrittenPages()
    // Signal the print framework the document is complete
    callback.onWriteFinished(writtenPages)

    ...
}

Java

@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 = pdfDocument.startPage(i);

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

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

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

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

    ...
}

Bu örnekte, PDF sayfası içeriği oluşturma yetkisi drawPage() adlı iş ortağına verilir yöntemidir.

Düzende olduğu gibi onWrite() yürütmesi yönteminin üç sonucu olabilir: standartların tamamlanması, iptal veya başarısız olması. içerik yazılamıyor. Bu sonuçlardan birini, PrintDocumentAdapter.WriteResultCallback nesnesinin uygun yöntemini çağırın.

Not: Yazdırmak için doküman oluşturmak yoğun kaynak kullanan bir işlem olabilir. İçinde uygulamanızın ana kullanıcı arayüzü iş parçacığının engellenmesini önlemek için sayfa oluşturma ve yazma işlemlerini ayrı bir iş parçacığında yapmak, örneğin AsyncTask içinde Eşzamansız görevler gibi yürütme ileti dizileriyle çalışma hakkında daha fazla bilgi için bkz. Süreçler ve İleti dizileri'dir.

Çizim PDF sayfası içeriği

Uygulamanız yazdırıldığında, uygulamanızın bir PDF belgesi oluşturması ve bunu şuraya iletmesi gerekir: Android yazdırma çerçevesidir. Bunun için herhangi bir PDF oluşturma kitaplığını kullanabilirsiniz amaçlanıyor. Bu derste, PrintedPdfDocument sınıfının nasıl kullanılacağı gösterilmektedir içeriğinizden PDF sayfaları oluşturun.

PrintedPdfDocument sınıfı Canvas kullanıyor nesne çizen bir nesnedir. Bu nesne, etkinlik düzeni üzerinde çizim yapmaya benzer. Çizim yapabilirsiniz öğeleri yazdırılan sayfadaki Canvas çizim yöntemlerini kullanarak yapar. Aşağıdakiler örnek kod, bu öğeler kullanılarak PDF dokümanı sayfasına bazı basit öğelerin nasıl çizileceğini gösterir yöntemleri:

Kotlin

private fun drawPage(page: PdfDocument.Page) {
    page.canvas.apply {

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

        val paint = Paint()
        paint.color = Color.BLACK
        paint.textSize = 36f
        drawText("Test Title", leftMargin, titleBaseLine, paint)

        paint.textSize = 11f
        drawText("Test paragraph", leftMargin, titleBaseLine + 25, paint)

        paint.color = Color.BLUE
        drawRect(100f, 100f, 172f, 172f, paint)
    }
}

Java

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);
}

PDF sayfasında çizim yapmak için Canvas kullanılırken öğeler şurada belirtilir: punto gibi, yani bir inçin 1/72'si. Boyutu belirtmek için bu ölçü birimini kullandığınızdan emin olun görebilirsiniz. Çizilen elemanların konumlandırılması için koordinat sistemi 0,0 noktasından başlar tıklayın.

İpucu: Canvas nesnesi yazdırmanıza olanak tanır bir PDF dokümanının kenarına yerleştirirseniz, birçok yazıcı bir dokümanın kenarının kenarına yazdıramaz. bir kağıt parçasına dikkat edin. Sayfanın yazdırılamayan kenarlarını da hesaba kattığınızdan emin olun. bu dersle basılı bir doküman oluşturacaksınız.