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

}

最后看一下效果图

通过打印服务插件添加打印机就可以进行打印了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android下的POS打印机调用的简单实现

    本文基于GP58系列,它可以兼容ESC/POS指令集,对EPSON的打印机通用. Android下的设备调试,如果设备提供了驱动,按照厂家的驱动调试即可:设备未提供驱动,只能按照通用的方法进行调试.这里采用的是调用USB接口来控制打印机输出. 1.首先获取USB管理器 public UsbAdmin(Context context) { mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); mPermi

  • Android实现系统打印功能

    本文实例为大家分享了Android实现系统打印的具体代码,供大家参考,具体内容如下 一.打印图片 使用PrintHelper类,如: private void doPhotoPrint() { PrintHelper photoPrinter = new PrintHelper(getActivity()); photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT); Bitmap bitmap = BitmapFactory.decodeRes

  • Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

    上一篇 主要介绍了如何通过蓝牙连接到打印机.这一篇,我们就介绍如何向打印机发送打印指令,来打印字符和图片. 1. 构造输出流 首先要明确一点,就是蓝牙连接打印机这种场景下,手机是 Client 端,打印机是 Server 端. 在上一篇的最后,我们从 BluetoothSocket 得到了一个OutputStream.这里我们做一层包装,得到一个OutputStreamWriter 对象: OutputStreamWriter writer = new OutputStreamWriter(ou

  • Android中如何安全地打印日志详解

    前言 在Android开发过程中,不管是写Demo还是实战项目中,都会打印一些日志用于记录数据,调试来着,Android中的日志工具类是Log,这个类提供了一些方法来打印日志.五个级别,v.d.i.w.e,各有不同的重载. 当谈到如何打印日志?很多人会想这不是很简单,直接使用android.util.Log这个类不就行了?然而,日志属于非常敏感的信息:逆向工程师在逆向你的程序的时候,本来需要捕捉你程序的各种输出,然后进行推测,顺藤摸瓜然后得到需要的信息:一旦你的日志泄漏,无异于门户洞开,破解你的

  • Android jni调试打印char阵列的实例详解

    Android jni调试打印char阵列的实例详解 前言: 在android开发中,用jni有时候需要打印某一个字符串的二进制格式输出,比较友好的输出格式是一个四列,八列,十六列的矩阵格式.类似在错误删除野指针时出现如下错误: pid: 2721, tid: 3005, name: pool-5-thread-5 >>> onxmaps.hunt <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr dea

  • Android编程实现计算两个日期之间天数并打印所有日期的方法

    本文实例讲述了Android编程实现计算两个日期之间天数并打印所有日期的方法.分享给大家供大家参考,具体如下: 以下代码是计算两个日期之间的天数,并打印所有日期 注:开始时,增加天数时,一天的毫秒数直接用24*60*60*1000来逐步增加天数,再测试时发现,当两个日期之间的天数超过24天时,打印的日期反而在开始日期之前了,(如打印2016/12/18-2017/1/23,打印的日期反而有2016/12/1),后来发现原因在于24*60*60*1000是一个int值,int值的取值范围在2的31

  • Android 蓝牙连接 ESC/POS 热敏打印机打印实例(蓝牙连接篇)

    公司的一个手机端的 CRM 项目最近要增加小票打印的功能,就是我们点外卖的时候经常会见到的那种小票.这里主要涉及到两大块的知识: 蓝牙连接及数据传输 ESC/POS 打印指令 蓝牙连接不用说了,太常见了,这篇主要介绍这部分的内容.但ESC/POS 打印指令是个什么鬼?简单说,我们常见的热敏小票打印机都支持这样一种指令,只要按照指令的格式向打印机发送指令,哪怕是不同型号品牌的打印机也会执行相同的动作.比如打印一行文本,换行,加粗等都有对应的指令,这部分内容放在下一篇介绍. 本篇主要基于官方文档,相

  • Android gradle插件打印时间戳的方法详解

    Android中时间戳的详细解释: (1).定义: 时间戳就是根据当前系统时间生成的一组随机数字. (2).作用: 作为对数据唯一性的一种判断依据.避免了重复修改数据所带来的错误! (3).应用: (1).在银行account表中建立时间戳字段timestamp,设定为文本类型varchar. (2).当银行A读取account表中的存款字段时,同时也读取时间戳字段,比如123456. (3).当银行A修改完存款数值后,进行存盘操作时,将先前读取的时间戳123456与当时表中的时间戳进行一次对比

  • Android打印机--小票打印格式及模板设置实例代码

    小票打印就是向打印设备发送控制打印格式的指令集,而这些打印格式需要去查询对应打印机的API文档,这里我把常用的api给封装了一下 文字对齐方式 打印字体大小 字体是否加粗 打印二维码 打印条形码 切纸 打开钱箱 字符串转字节数组 字符拼接 PrintFormatUtils.Java /** * 打印格式 * Created by john on 17-3-23. */ public class PrintFormatUtils { // 对齐方式 public static final int

  • Android进阶——安卓调用ESC/POS打印机打印实例

    前言 前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用socket连接,来实现打印功能.写了个Demo,分享一下. 工具:一台打印机(芯烨XP-80XX),一台安卓测试机 开发环境:Android Studio 1.5 需求:点击按钮,实现打印小票功能,小票上除必要文字外,还要有二维码. 封装了一个Pos打印工具类: package com.example.haoguibao.myapplication; import java.io.

  • Mac 下 Android Studio 不打印日志的解决办法

    Mac 下 Android Studio 不打印日志的解决办法 前言: 在 Mac 下使用 Android Studio 时常会遇到 Android Monitor 突然不打印日志的情况,目前我知道的有三个方法: 1.重启 Android Studio 这个不需要多说,点击 Android Studio 的 File => Invalidate caches / Restart ,选择 Just Restart 2.重启 adb 命令行下输入:adb kill-server 关闭 adb,adb

  • Android手机通过蓝牙连接佳博打印机的实例代码

    所使用的打印机为佳博打印机,支持蓝牙.wifi.usb我所使用的是通过蓝牙来连接. 在网上找到一个佳博官方针对安卓开发的App源码,但是各种的跳转,没有看太懂,所以又去问度娘,找到了一个不错的文章 Android对于蓝牙开发从2.0版本的sdk才开始支持,而且模拟器不支持,测试至少需要两部手机,所以制约了很多技术人员的开发. 1. 首先,要操作蓝牙,先要在AndroidManifest.xml里加入权限 // 管理蓝牙设备的权限 <uses-permissionandroid:name="

随机推荐