Android实现PDF预览打印功能
最近在做一个项目,需要用到android手机连接打印机进行打印的功能,目前在网上找到的教程介绍的都是蓝牙连接热敏打印机(pos机大小的打印机)和蓝牙打印机,如果连接日常所见到的网络打印机,进行打印,很显然这些教程是做不到的。
由于android没有提供任何标准,都是自家封的API,参考了WPS的APP的打印功能,决定按照WPS的方案来写,需要安装打印服务插件,比如PrinterShare以及三星、HP提供的自家打印服务插件。
一、连接打印管理者
当程序需要直接管理打印进程时,在收到用户的打印请求之后,第一步就是连接Android的打印框架,以及操作PrintManager类的实例。这个类允许你实例化一个打印工作并开始打印的生命过程。下面的代码展示了如何获得一个打印管理者和启动打印进程。
private void onPrintPdf() { PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE); PrintAttributes.Builder builder = new PrintAttributes.Builder(); builder.setColorMode(PrintAttributes.COLOR_MODE_COLOR); printManager.print("test pdf print", new MyPrintAdapter(this,filePath), builder.build()); }
二、创建打印适配器
打印适配器会与Android的打印框架相连接,并会处理打印过程的每一个步骤。这个过程要求用户在创建文档打印之前选择打印机及相关的打印选项。这些过程会影响最终的输出结果,就像用户选择了不同打印能力,不同的页面尺寸,不同的页面方向一样。随着这些选项的设置,打印框架会要求适配器展示并生成一个打印文稿,为最终的打印做准备。一旦用户按下了打印按钮,打印框架会拿到最终的打印文档然后交付给打印提供者以便打印。
package com.android.guocheng.printdemo; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.pdf.PdfDocument; import android.graphics.pdf.PdfDocument.PageInfo; import android.graphics.pdf.PdfRenderer; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintDocumentAdapter; import android.print.PrintDocumentInfo; import android.print.pdf.PrintedPdfDocument; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Created by guocheng on 2017/6/13. */ public class MyPrintAdapter extends PrintDocumentAdapter { private Context context; private int pageHeight; private int pageWidth; private PdfDocument mPdfDocument; private int totalpages = 1; private String pdfPath; private List<Bitmap> mlist; public MyPrintAdapter(Context context,String pdfPath) { this.context = context; this.pdfPath = pdfPath; } @Override public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle metadata) { mPdfDocument = new PrintedPdfDocument(context, newAttributes); //创建可打印PDF文档对象 pageHeight = newAttributes.getMediaSize().ISO_A4.getHeightMils() * 72 / 1000; //设置尺寸 pageWidth = newAttributes.getMediaSize().ISO_A4.getWidthMils() * 72 / 1000; if (cancellationSignal.isCanceled()) { callback.onLayoutCancelled(); return; } ParcelFileDescriptor mFileDescriptor = null; PdfRenderer pdfRender = null; PdfRenderer.Page page = null; try { mFileDescriptor = ParcelFileDescriptor.open(new File(pdfPath), ParcelFileDescriptor.MODE_READ_ONLY); if (mFileDescriptor != null) pdfRender = new PdfRenderer(mFileDescriptor); mlist = new ArrayList<>(); if (pdfRender.getPageCount() > 0) { totalpages = pdfRender.getPageCount(); for (int i = 0; i < pdfRender.getPageCount(); i++) { if(null != page) page.close(); page = pdfRender.openPage(i); Bitmap bmp = Bitmap.createBitmap(page.getWidth()*2,page.getHeight()*2, Bitmap.Config.ARGB_8888); page.render(bmp, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); mlist.add(bmp); } } if(null != page) page.close(); if(null != mFileDescriptor) mFileDescriptor.close(); if (null != pdfRender) pdfRender.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (totalpages > 0) { PrintDocumentInfo.Builder builder = new PrintDocumentInfo .Builder("快速入门.pdf") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(totalpages); //构建文档配置信息 PrintDocumentInfo info = builder.build(); callback.onLayoutFinished(info, true); } else { callback.onLayoutFailed("Page count is zero."); } } @Override public void onWrite(final PageRange[] pageRanges, final ParcelFileDescriptor destination, final CancellationSignal cancellationSignal, final WriteResultCallback callback) { for (int i = 0; i < totalpages; i++) { if (pageInRange(pageRanges, i)) //保证页码正确 { PageInfo newPage = new PageInfo.Builder(pageWidth, pageHeight, i).create(); PdfDocument.Page page = mPdfDocument.startPage(newPage); //创建新页面 if (cancellationSignal.isCanceled()) { //取消信号 callback.onWriteCancelled(); mPdfDocument.close(); mPdfDocument = null; return; } drawPage(page, i); //将内容绘制到页面Canvas上 mPdfDocument.finishPage(page); } } try { mPdfDocument.writeTo(new FileOutputStream( destination.getFileDescriptor())); } catch (IOException e) { callback.onWriteFailed(e.toString()); return; } finally { mPdfDocument.close(); mPdfDocument = null; } callback.onWriteFinished(pageRanges); } private boolean pageInRange(PageRange[] pageRanges, int page) { for (int i = 0; i < pageRanges.length; i++) { if ((page >= pageRanges[i].getStart()) && (page <= pageRanges[i].getEnd())) return true; } return false; } //页面绘制(渲染) private void drawPage(PdfDocument.Page page,int pagenumber) { Canvas canvas = page.getCanvas(); if(mlist != null){ Paint paint = new Paint(); Bitmap bitmap = mlist.get(pagenumber); int bitmapWidth = bitmap.getWidth(); int bitmapHeight = bitmap.getHeight(); // 计算缩放比例 float scale = (float)pageWidth/(float)bitmapWidth; // 取得想要缩放的matrix参数 Matrix matrix = new Matrix(); matrix.postScale(scale, scale); canvas.drawBitmap(bitmap,matrix,paint); } } }
最后看一下效果图
通过打印服务插件添加打印机就可以进行打印了。