简体   繁体   English

在android中打印现有的pdf文件

[英]Print existing pdf file in android

Hey everyone so I am trying to build a small sample printing app on android and can't seem to print an existing pdf.大家好,我正在尝试在 android 上构建一个小型示例打印应用程序,但似乎无法打印现有的 pdf。 There is plenty of documentation on creating a custom document with the canvas but I already have the document.有很多关于使用画布创建自定义文档的文档,但我已经有了该文档。 Basically I just want to be a able to read in a pdf document and send it as a file output stream directly to the printer to be printed.基本上,我只想能够读取 pdf 文档并将其作为文件输出流直接发送到要打印的打印机。 Any help is appreciated.任何帮助表示赞赏。

We can simply achieve this by creating a custom PrintDocumentAdapter我们可以通过创建自定义PrintDocumentAdapter来简单地实现这一点

PdfDocumentAdapter.java文档适配器.java

public class PdfDocumentAdapter extends PrintDocumentAdapter {

Context context = null;
String pathName = "";
public PdfDocumentAdapter(Context ctxt, String pathName) {
    context = ctxt;
    this.pathName = pathName;
}
@Override
public void onLayout(PrintAttributes printAttributes, PrintAttributes printAttributes1, CancellationSignal cancellationSignal, LayoutResultCallback layoutResultCallback, Bundle bundle) {
    if (cancellationSignal.isCanceled()) {
        layoutResultCallback.onLayoutCancelled();
    }
    else {
        PrintDocumentInfo.Builder builder=
                new PrintDocumentInfo.Builder(" file name");
        builder.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
                .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
                .build();
        layoutResultCallback.onLayoutFinished(builder.build(),
                !printAttributes1.equals(printAttributes));
    }
}

@Override
public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor parcelFileDescriptor, CancellationSignal cancellationSignal, WriteResultCallback writeResultCallback) {
    InputStream in=null;
    OutputStream out=null;
    try {
        File file = new File(pathName);
        in = new FileInputStream(file);
        out=new FileOutputStream(parcelFileDescriptor.getFileDescriptor());

        byte[] buf=new byte[16384];
        int size;

        while ((size=in.read(buf)) >= 0
                && !cancellationSignal.isCanceled()) {
            out.write(buf, 0, size);
        }

        if (cancellationSignal.isCanceled()) {
            writeResultCallback.onWriteCancelled();
        }
        else {
            writeResultCallback.onWriteFinished(new PageRange[] { PageRange.ALL_PAGES });
        }
    }
    catch (Exception e) {
        writeResultCallback.onWriteFailed(e.getMessage());
        Logger.logError( e);
    }
    finally {
        try {
            in.close();
            out.close();
        }
        catch (IOException e) {
            Logger.logError( e);
        }
    }
}}

Now call print by using PrintManager现在使用PrintManager调用打印

        PrintManager printManager=(PrintManager) getActivityContext().getSystemService(Context.PRINT_SERVICE);
    try
    {
        PrintDocumentAdapter printAdapter = new PdfDocumentAdapter(Settings.sharedPref.context,filePath );
        }
        printManager.print("Document", printAdapter,new PrintAttributes.Builder().build());
    }
    catch (Exception e)
    {
        Logger.logError(e);
    }

Basically I just want to be a able to read in a pdf document and send it as a file output stream directly to the printer to be printed.基本上,我只想能够读取 pdf 文档并将其作为文件输出流直接发送到要打印的打印机。

That's not strictly possible, unless you find some particular printer that offers such an API for Android.这不是绝对可能的,除非您找到某些特定的打印机为 Android 提供此类 API。

If you wish to use the Android printing framework, you will need to create a PrintDocumentAdapter that can handle your existing PDF file.如果您希望使用 Android 打印框架,则需要创建一个可以处理现有 PDF 文件的PrintDocumentAdapter This sample project demonstrates one such PrintDocumentAdapter , though it is not general-purpose. 这个示例项目演示了一个这样的PrintDocumentAdapter ,尽管它不是通用的。

For those interested in the kotlin version of the Karthik Bollisetti answer here is it.对于那些对Karthik Bollisetti的 kotlin 版本感兴趣的人,答案就在这里。

The PdfDocumentAdapter is re-written as this PdfDocumentAdapter重写为这样

class PdfDocumentAdapter(private val pathName: String) : PrintDocumentAdapter() {

override fun onLayout(
    oldAttributes: PrintAttributes?,
    newAttributes: PrintAttributes,
    cancellationSignal: CancellationSignal?,
    callback: LayoutResultCallback,
    bundle: Bundle
) {
    if (cancellationSignal?.isCanceled == true) {
        callback.onLayoutCancelled()
        return
    } else {
        val builder = PrintDocumentInfo.Builder(" file name")
        builder.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
            .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
            .build()

        callback.onLayoutFinished(builder.build(), newAttributes == oldAttributes)
    }
}

override fun onWrite(
    pageRanges: Array<out PageRange>,
    destination: ParcelFileDescriptor,
    cancellationSignal: CancellationSignal?,
    callback: WriteResultCallback
) {
    try {
        // copy file from the input stream to the output stream
        FileInputStream(File(pathName)).use { inStream ->
            FileOutputStream(destination.fileDescriptor).use { outStream ->
                inStream.copyTo(outStream)
            }
        }

        if (cancellationSignal?.isCanceled == true) {
            callback.onWriteCancelled()
        } else {
            callback.onWriteFinished(arrayOf(PageRange.ALL_PAGES))
        }

    } catch (e: Exception) {
        callback.onWriteFailed(e.message)
    }
}
}

then call the PrintManager in your code like this然后像这样在您的代码中调用 PrintManager

val printManager : PrintManager = requireContext().getSystemService(Context.PRINT_SERVICE) as PrintManager
try {
    val printAdapter = PdfDocumentAdapter(file.absolutePath)
    printManager.print("Document", printAdapter, PrintAttributes.Builder().build())
} catch (e : Exception) {
    Timber.e(e)
}

For use cases with printers supporting ipp and pdf you can send pdfs straight to printers using my library https://github.com/gmuth/ipp-client-kotlin :对于支持 ipp 和 pdf 的打印机用例,您可以使用我的库https://github.com/gmuth/ipp-client-kotlin将 pdf 直接发送到打印机:

Kotlin:
val printer = IppPrinter(URI.create("ipp://myprinter/ipp"))
val job = printer.printJob(File("mydocument.pdf"))
job.waitForTermination()

No print dialog is involved.不涉及打印对话框。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM