Android實(shí)現(xiàn)PDF預(yù)覽打印功能
最近在做一個(gè)項(xiàng)目,需要用到android手機(jī)連接打印機(jī)進(jìn)行打印的功能,目前在網(wǎng)上找到的教程介紹的都是藍(lán)牙連接熱敏打印機(jī)(pos機(jī)大小的打印機(jī))和藍(lán)牙打印機(jī),如果連接日常所見到的網(wǎng)絡(luò)打印機(jī),進(jìn)行打印,很顯然這些教程是做不到的。
由于android沒有提供任何標(biāo)準(zhǔn),都是自家封的API,參考了WPS的APP的打印功能,決定按照WPS的方案來寫,需要安裝打印服務(wù)插件,比如PrinterShare以及三星、HP提供的自家打印服務(wù)插件。
一、連接打印管理者
當(dāng)程序需要直接管理打印進(jìn)程時(shí),在收到用戶的打印請(qǐng)求之后,第一步就是連接Android的打印框架,以及操作PrintManager類的實(shí)例。這個(gè)類允許你實(shí)例化一個(gè)打印工作并開始打印的生命過程。下面的代碼展示了如何獲得一個(gè)打印管理者和啟動(dòng)打印進(jìn)程。
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()); }
二、創(chuàng)建打印適配器
打印適配器會(huì)與Android的打印框架相連接,并會(huì)處理打印過程的每一個(gè)步驟。這個(gè)過程要求用戶在創(chuàng)建文檔打印之前選擇打印機(jī)及相關(guān)的打印選項(xiàng)。這些過程會(huì)影響最終的輸出結(jié)果,就像用戶選擇了不同打印能力,不同的頁面尺寸,不同的頁面方向一樣。隨著這些選項(xiàng)的設(shè)置,打印框架會(huì)要求適配器展示并生成一個(gè)打印文稿,為最終的打印做準(zhǔn)備。一旦用戶按下了打印按鈕,打印框架會(huì)拿到最終的打印文檔然后交付給打印提供者以便打印。
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); //創(chuàng)建可打印PDF文檔對(duì)象 pageHeight = newAttributes.getMediaSize().ISO_A4.getHeightMils() * 72 / 1000; //設(shè)置尺寸 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); //構(gòu)建文檔配置信息 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); //創(chuàng)建新頁面 if (cancellationSignal.isCanceled()) { //取消信號(hào) callback.onWriteCancelled(); mPdfDocument.close(); mPdfDocument = null; return; } drawPage(page, i); //將內(nè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(); // 計(jì)算縮放比例 float scale = (float)pageWidth/(float)bitmapWidth; // 取得想要縮放的matrix參數(shù) Matrix matrix = new Matrix(); matrix.postScale(scale, scale); canvas.drawBitmap(bitmap,matrix,paint); } } }
最后看一下效果圖
通過打印服務(wù)插件添加打印機(jī)就可以進(jìn)行打印了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android gradle插件打印時(shí)間戳的方法詳解
- Android編程實(shí)現(xiàn)計(jì)算兩個(gè)日期之間天數(shù)并打印所有日期的方法
- Android中如何安全地打印日志詳解
- Mac 下 Android Studio 不打印日志的解決辦法
- Android jni調(diào)試打印char陣列的實(shí)例詳解
- Android下的POS打印機(jī)調(diào)用的簡(jiǎn)單實(shí)現(xiàn)
- Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(ESC/POS指令篇)
- Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(藍(lán)牙連接篇)
- Android打印機(jī)--小票打印格式及模板設(shè)置實(shí)例代碼
- Android進(jìn)階——安卓調(diào)用ESC/POS打印機(jī)打印實(shí)例
- Android手機(jī)通過藍(lán)牙連接佳博打印機(jī)的實(shí)例代碼
- Android實(shí)現(xiàn)系統(tǒng)打印功能
相關(guān)文章
Android藍(lán)牙的開啟和搜索設(shè)備功能開發(fā)實(shí)例
這篇文章主要介紹了Android藍(lán)牙服務(wù)啟動(dòng)搜索流程,了解內(nèi)部原理是為了幫助我們做擴(kuò)展,同時(shí)也是驗(yàn)證了一個(gè)人的學(xué)習(xí)能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會(huì)的2023-04-04Android中在GridView網(wǎng)格視圖上實(shí)現(xiàn)item拖拽交換的方法
這篇文章主要介紹了Android中在GridView上實(shí)現(xiàn)item拖拽交換效果的方法,比起ListView的列表?xiàng)l目交換稍顯復(fù)雜,文中先介紹了關(guān)于創(chuàng)建GridView的一些基礎(chǔ)知識(shí),需要的朋友可以參考下2016-04-04揭秘雙十一手機(jī)淘寶圖標(biāo)如何被動(dòng)態(tài)更換
這篇文章主要介紹了每到雙十一十二的時(shí)候Android手機(jī)動(dòng)態(tài)更換手機(jī)圖標(biāo)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08