कस्टम दस्तावेज़ प्रिंट करना

कुछ ऐप्लिकेशन के लिए, जैसे कि ड्रॉइंग ऐप्लिकेशन, पेज लेआउट वाले ऐप्लिकेशन, और अन्य ऐप्लिकेशन जो फ़ोकस करते हैं ग्राफ़िक आउटपुट, सुंदर प्रिंट किए गए पेज बनाना एक मुख्य सुविधा है. इस मामले में, यह काफ़ी नहीं है का इस्तेमाल करें. इस प्रकार के ऐप्लिकेशन के प्रिंट आउटपुट के लिए ज़रूरी है पेज पर जाने वाली सभी चीज़ों का सटीक कंट्रोल, जिसमें फ़ॉन्ट, टेक्स्ट फ़्लो, पेज ब्रेक, हेडर, फ़ुटर, और ग्राफ़िक एलिमेंट.

आपके ऐप्लिकेशन के लिए पूरी तरह से कस्टमाइज़ किए गए प्रिंट आउटपुट बनाने के लिए और आवश्यक है पहले से बताए गए तरीकों से ज़्यादा कमाई कर सकते हैं. आपको ऐसे कॉम्पोनेंट बनाने होंगे जो प्रिंट फ़्रेमवर्क से संपर्क करें, प्रिंटर की सेटिंग में बदलाव करें, पेज के एलिमेंट बनाएं, और कई पेजों पर प्रिंट करने की सुविधा को मैनेज कर सकते हैं.

इस लेसन में, प्रिंट मैनेजर से कनेक्ट करने, प्रिंट अडैप्टर बनाने, और प्रिंट करने के लिए कॉन्टेंट तैयार करते हैं.

जब आपका ऐप्लिकेशन सीधे प्रिंटिंग प्रोसेस को मैनेज करता है, तो आपके उपयोगकर्ता का प्रिंट करने का अनुरोध, Android प्रिंट फ़्रेमवर्क से कनेक्ट करना और किसी इंस्टेंस को पाना है PrintManager क्लास का. इस क्लास की मदद से, प्रिंट जॉब शुरू किया जा सकता है और प्रिंटिंग लाइफ़साइकल शुरू करें. उदाहरण के तौर पर दिया गया यह कोड, प्रिंट मैनेजर पाने का तरीका बताता है और प्रिंट करना शुरू करें.

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

ऊपर दिए गए उदाहरण में, प्रिंट जॉब को नाम देने का तरीका बताया गया है. साथ ही, PrintDocumentAdapter क्लास का इंस्टेंस सेट करने का तरीका भी बताया गया है. यह क्लास, प्रिंटिंग लाइफ़साइकल के चरणों को मैनेज करती है. कॉन्टेंट बनाने अगले सेक्शन में प्रिंट अडैप्टर क्लास को लागू करने के बारे में चर्चा की गई है.

ध्यान दें: print() में आखिरी पैरामीटर तरीका, PrintAttributes ऑब्जेक्ट लेता है. इस पैरामीटर का इस्तेमाल इन कामों के लिए किया जा सकता है पिछले प्रिंटिंग साइकल के आधार पर, प्रिंटिंग फ़्रेमवर्क और पहले से सेट किए गए विकल्पों के लिए संकेत देते हैं, जिससे उपयोगकर्ता अनुभव बेहतर होता है. इस पैरामीटर का इस्तेमाल ऐसे विकल्प सेट करने के लिए भी किया जा सकता है जो प्रिंट किए जाने वाले कॉन्टेंट के हिसाब से सही हो. जैसे, ओरिएंटेशन को लैंडस्केप पर सेट करना उस ओरिएंटेशन में मौजूद फ़ोटो प्रिंट करते समय.

प्रिंट अडैप्टर, Android प्रिंट फ़्रेमवर्क के साथ इंटरैक्ट करता है और प्रिंट करने की प्रक्रिया शुरू कर देते हैं. इस प्रोसेस के लिए ज़रूरी है कि उपयोगकर्ता, प्रोजेक्ट बनाने से पहले प्रिंटर और प्रिंट के विकल्पों को चुनें प्रिंट करने के लिए एक दस्तावेज़. ये विकल्प आखिरी आउटपुट में उपयोगकर्ता के चुने हुए बदलाव पर असर डाल सकते हैं अलग-अलग आउटपुट क्षमता, अलग-अलग पेज साइज़ या अलग-अलग पेज ओरिएंटेशन वाले प्रिंटर हैं. ये चुनने के बाद, प्रिंट फ़्रेमवर्क आपके अडैप्टर को एक लेआउट बनाने और जनरेट करने के लिए कहता है प्रिंट दस्तावेज़, अंतिम आउटपुट की तैयारी के लिए. जब कोई उपयोगकर्ता प्रिंट बटन पर टैप करता है, तो फ़्रेमवर्क वह अंतिम प्रिंट दस्तावेज़ लेता है और उसे आउटपुट के लिए प्रिंट उपलब्ध कराने वाली कंपनी को भेज देता है. प्रिंट करने के दौरान करते हैं, तो उपयोगकर्ता प्रिंट कार्रवाई को रद्द कर सकते है, इसलिए आपके प्रिंट अडैप्टर को यह भी सुनना चाहिए और सदस्यता रद्द करने के अनुरोधों पर प्रतिक्रिया दें.

PrintDocumentAdapter ऐब्स्ट्रैक्ट क्लास को प्रिंटिंग लाइफ़साइकल, जिसमें कॉलबैक के चार मुख्य तरीके हैं. आपको इन तरीकों को लागू करना होगा ताकि प्रिंट फ़्रेमवर्क के साथ ठीक तरह से इंटरैक्ट किया जा सके:

  • onStart() - इस नंबर पर एक बार कॉल किया हम प्रिंट प्रोसेस की शुरुआत कर रहे हैं. अगर आपके आवेदन की तैयारी के लिए, एक बार किया जाने वाला टास्क है परफ़ॉर्म करें, जैसे कि प्रिंट किए जाने वाले डेटा का स्नैपशॉट पाना, उन्हें यहां एक्ज़ीक्यूट करना. लागू करना अपने अडैप्टर में इस तरीके की ज़रूरत नहीं होती है.
  • onLayout() - हर बार कॉल किया गया जब उपयोगकर्ता कोई प्रिंट सेटिंग बदलता है, तो आउटपुट पर असर पड़ता है. जैसे, पेज का अलग साइज़, या पेज ओरिएंटेशन की सहायता से, आपके ऐप्लिकेशन को पेजों को प्रिंट करना होगा. इस तरीके से, कम से कम यह पता चलना चाहिए कि कितने पेज दिखाए जा सकते हैं प्रिंट करता है.
  • onWrite() - प्रिंट करने के लिए कॉल किया गया पेजों को प्रिंट करने के लिए फ़ाइल में डालना चाहिए. इस तरीके को हर एक के बाद एक या उससे ज़्यादा बार कॉल किया जा सकता है onLayout() कॉल.
  • onFinish() - आख़िर में एक बार कॉल किया आसान हो जाता है. अगर आपके ऐप्लिकेशन में, एक बार किया जाने वाला टियर-डाउन टास्क मौजूद है, तो उन्हें यहां निष्पादित करें. अपने अडैप्टर में इस तरीके को लागू करने की ज़रूरत नहीं है.

नीचे दिए सेक्शन में, लेआउट को लागू करने और लिखने के तरीकों के बारे में बताया गया है. ये तरीके जो प्रिंट अडैप्टर के काम करने के लिए ज़रूरी है.

ध्यान दें: अडैप्टर के इन तरीकों को आपके ऐप्लिकेशन के मुख्य थ्रेड पर कॉल किया जाता है. अगर आपने आपको उम्मीद है कि लागू करने के दौरान इन तरीकों को लागू करने में काफ़ी समय समय है, तो उन्हें एक अलग थ्रेड में एक्ज़ीक्यूट करने के लिए लागू करें. उदाहरण के लिए, आप लेआउट और प्रिंट दस्तावेज़ लिखने के काम को अलग-अलग AsyncTask ऑब्जेक्ट में करते हैं.

प्रिंट दस्तावेज़ की जानकारी कंप्यूट करें

PrintDocumentAdapter क्लास लागू करने के बाद, आपका ऐप्लिकेशन को यह बताया जाना चाहिए कि वह किस तरह का दस्तावेज़ बना रहा है. साथ ही, वह कुल संख्या कैलकुलेट कर सकता है प्रिंट जॉब के लिए पेजों की संख्या, जो प्रिंट किए गए पेज के साइज़ के बारे में जानकारी देता है. इसमें onLayout() तरीके को लागू किया गया है अडैप्टर ये हिसाब करता है और PrintDocumentInfo की क्लास में प्रिंट जॉब करेंगे, जिसमें पेज की संख्या और कॉन्टेंट टाइप. कोड का यह उदाहरण, PrintDocumentAdapter के लिए onLayout() तरीके को बुनियादी तौर पर लागू करने के बारे में बताता है:

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() तरीके को लागू करने पर यह हो सकता है इसके तीन परिणाम होते हैं: पूरा होना, रद्द होना या उस मामले में जहां लेआउट पूरा नहीं हो सका. आपको इनमें से किसी एक परिणाम को उचित कॉल करके PrintDocumentAdapter.LayoutResultCallback ऑब्जेक्ट का तरीका.

ध्यान दें: यह onLayoutFinished() तरीका बताता है कि लेआउट कॉन्टेंट में वाकई बदलाव हुआ है या नहीं आखिरी अनुरोध के बाद से. इस पैरामीटर को ठीक से सेट करने से, प्रिंट फ़्रेमवर्क को onWrite() तरीके को बेवजह कॉल किया जा रहा है, यह ज़रूरी है कि पहले लिखे गए प्रिंट दस्तावेज़ को कैश मेमोरी में सेव किया जा रहा हो और परफ़ॉर्मेंस में सुधार किया जा रहा हो.

onLayout() का मुख्य कॉन्टेंट यह है प्रिंटर की विशेषताओं के आधार पर, आउटपुट के तौर पर उम्मीद किए जाने वाले पेजों की संख्या की गणना करता है. आप इस संख्या की गणना कैसे करते है यह पूरी तरह से इस बात पर निर्भर करता है कि आपका ऐप्लिकेशन प्रिंट करना. नीचे दिया गया उदाहरण कोड, लागू करने का तरीका दिखाता है जिसमें पेजों की संख्या प्रिंट अभिविन् यास द्वारा निर्धारित:

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

दस्तावेज़ को प्रिंट करने के लिए फ़ाइल लिखना

जब किसी फ़ाइल में प्रिंट आउटपुट लिखने का समय आता है, तो Android प्रिंट फ़्रेमवर्क, आपके ऐप्लिकेशन की PrintDocumentAdapter क्लास के लिए onWrite() तरीके को कॉल करता है. तरीके के पैरामीटर से यह तय होता है कि कौनसे पेज लिखी और उपयोग की जाने वाली आउटपुट फ़ाइल होती है. इसके बाद, आपको इस तरीके को लागू करने के बाद, कई पेज वाली PDF दस्तावेज़ फ़ाइल में कॉन्टेंट का अनुरोध किया गया पेज. यह प्रोसेस पूरी होने के बाद, आपको कॉलबैक ऑब्जेक्ट के onWriteFinished() तरीके को कॉल करें.

ध्यान दें: Android प्रिंट फ़्रेमवर्क, onWrite() तरीके को हर onLayout() को कॉल करें. इस वजह से, यह इसका बूलियन पैरामीटर सेट करना ज़रूरी है प्रिंट कॉन्टेंट के लेआउट में बदलाव न होने पर, false के लिए onLayoutFinished() तरीका, ताकि प्रिंट दस्तावेज़ को दोबारा लिखने से बचा जा सके.

ध्यान दें: यह onLayoutFinished() तरीका बताता है कि लेआउट कॉन्टेंट में वाकई बदलाव हुआ है या नहीं आखिरी अनुरोध के बाद से. इस पैरामीटर को ठीक से सेट करने से, प्रिंट फ़्रेमवर्क को onLayout() तरीके को बेवजह कॉल किया जा रहा है, यह ज़रूरी है कि पहले लिखे गए प्रिंट दस्तावेज़ को कैश मेमोरी में सेव किया जा रहा हो और परफ़ॉर्मेंस में सुधार किया जा रहा हो.

नीचे दिया गया सैंपल, PDF फ़ाइल बनाने के लिए PrintedPdfDocument क्लास का इस्तेमाल करके, इस प्रोसेस की बुनियादी तकनीकों को दिखाता है:

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

    ...
}

यह सैंपल, PDF पेज के कॉन्टेंट को drawPage() को रेंडर करने का ऐक्सेस देता है दिया गया है, जिसकी चर्चा अगले सेक्शन में की गई है.

लेआउट की तरह ही, onWrite() को लागू किया जाता है इसके तीन नतीजे हो सकते हैं: प्रोसेस पूरी होना, रद्द करना या फिर उस स्थिति में जिसमें कॉन्टेंट को लिखा नहीं जा सकता. आप PrintDocumentAdapter.WriteResultCallback ऑब्जेक्ट का सही तरीका है.

ध्यान दें: किसी दस्तावेज़ को प्रिंट करने के लिए रेंडर करने में बहुत ज़्यादा संसाधनों का इस्तेमाल हो सकता है. तय सीमा में अपने ऐप्लिकेशन के मुख्य यूज़र इंटरफ़ेस थ्रेड को ब्लॉक करने से बचने के लिए, आपको किसी अलग थ्रेड पर पेज रेंडर करने और लिखने से जुड़े काम करना, उदाहरण के लिए AsyncTask में. एसिंक्रोनस टास्क जैसे एक्ज़ीक्यूशन थ्रेड के साथ काम करने के बारे में ज़्यादा जानकारी के लिए, प्रोसेस और Threads पर टैप करें.

ड्रॉइंग वाले PDF पेज का कॉन्टेंट

जब आपका ऐप्लिकेशन प्रिंट करता है, तो आपके ऐप्लिकेशन को एक PDF दस्तावेज़ जनरेट करना होगा और उसे Android प्रिंट फ़्रेमवर्क का इस्तेमाल करें. इसके लिए, किसी भी PDF जनरेशन लाइब्रेरी का इस्तेमाल किया जा सकता है उद्देश्य है. इस लेसन में, PrintedPdfDocument क्लास को इस्तेमाल करने का तरीका बताया गया है का इस्तेमाल करें.

PrintedPdfDocument क्लास, Canvas का इस्तेमाल करती है ऑब्जेक्ट को PDF पेज पर टैग करें. यह किसी गतिविधि लेआउट पर ड्रॉइंग करने की तरह ही है. आपके पास ड्रॉ करने का विकल्प है एलिमेंट, जो प्रिंट किए गए पेज पर मौजूद हैं. इसके लिए, वे Canvas ड्रॉ करने के तरीकों का इस्तेमाल करते हैं. नीचे दिए गए उदाहरण के तौर पर दिया गया कोड, PDF दस्तावेज़ के पेज पर आसान एलिमेंट बनाने का तरीका बताता है. तरीका:

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 पेज पर ड्रॉ करने के लिए Canvas का इस्तेमाल करते समय, एलिमेंट को इनमें बताया जाता है पॉइंट, जो एक इंच का 1/72 है. पक्का करें कि साइज़ की जानकारी देने के लिए, माप की इस इकाई का इस्तेमाल किया जाता हो कई एलिमेंट शामिल होते हैं. बनाए गए एलिमेंट की पोज़िशन तय करने के लिए, निर्देशांक सिस्टम 0,0 से शुरू होता है आज़माएं.

सलाह: हालांकि, Canvas ऑब्जेक्ट आपको प्रिंट करने की सुविधा देता है कुछ चीज़ें PDF दस्तावेज़ के किनारे पर मौजूद होती हैं, तो कई प्रिंटर दस्तावेज़ के किनारे से प्रिंट नहीं कर सकते कागज़ का एक टुकड़ा. पक्का करें कि आपने पेज के उन किनारों को ध्यान में रखा हो जो प्रिंट नहीं किए जा सकते. ऐसा करते समय, तो आपको इस क्लास का प्रिंट दस्तावेज़ बनाना होगा.