最近由于工作需要,要写一套打印相关的接口。

Linux上一般自带一套管理打印机的通用工具,叫cups。

它提供了打印机的连接,配置,打印等等功能,因此我这次选择用cups的api来实现打印相关的内容。

cups本身提供了一系列命令行工具方便用户使用,我们接下来会使用一些命令行来测试。

文章目录

  • @[toc]
  • 配置环境
  • 连接打印机
  • 获取当前打印机列表
  • 设置打印参数
  • 打印

配置环境

sudo apt install libcups2-dev

连接打印机

当我们将打印机开机并正确连接到电脑上之后,进入设置->打印机页面会看到当前连接的打印机。

arm架构linux装打印机_ide

比如我现在连接的是惠普的501dn打印机。

Ubuntu预装了cups相关的内容,打印机连接不需要手动配置,系统会自动进行配置。

当只连接一台打印机的时候,Ubuntu会将当前打印机自动设置为默认打印机。

#查看当前的默认打印机
lpstat -t

我们这个时候还需要打印一次文件,来测试一下打印机的连接无误,以及打印机本身可以正常使用。

#打印文件,我这里打印的是之前准备好的pdf
lp fork.pdf

如果打印成功,那就可以进行接下来的步骤啦!

如果打印的有问题,请根据打印机的提示解决问题后再进行下一步操作。

获取当前打印机列表

为了要先获取当前打印机列表呢?这是因为打印的api的入参需要打印机名,因此需要获取打印机列表,来获取打印机名。

打印机名是可以修改的,但是一般系统都会自动配置,因此我们下需要获取一下才能知道就具体的打印机名是什么。

int get_printer_list()
{
    printf("[%s] Start\n", __FUNCTION__);
    cups_dest_t *dests = NULL;
    int num_dests = 0;
    int i = 0;

    num_dests = cupsGetDests(&dests);
    if (num_dests == 0 &&
        (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
         cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
    {
#ifdef PRT_DEBUG
        _cupsLangPrintf(stderr, "Printer: Error - add '/version=1.1' to server name.");
#endif
        return NULL;
    }
    for (i = 0; i < num_dests; i++)
    {
        printf("[%s] printer name is %s \n", __FUNCTION__, dests[i].name);
    }
    cupsFreeDests(num_dests, dests);

    return num_dests;
}

输出
printer name is HP-LaserJet-Pro-M501dn

解析:

上面用到了一个结构体cups_dest_t,这个结构体用于表示cups的目的地(destinations)。

typedef struct cups_dest_s		/**** Destination ****/
{
  char		*name,			/* 打印机名*/
			*instance;		/* Local instance name or NULL */
  int		is_default;		/* 是默认打印机? */
  int		num_options;		/* 打印机设置的数量 */
  cups_option_t	*options;		/* 打印机设置 */
} cups_dest_t;

其中的name就是我们需要的打印机名。

在打印机已经配置好了的情况下,可以直接通过cupsGetDests来获取cups_dest_t。

// @brief	获取当前的destinations列表

// @return 	destinations的数量即当前打印机的数量

int cupsGetDests(cups_dest_t ** dests);

cupsGetDests返回当前的打印机数量,因此只要返回值不大于0,我们就可以遍历当前的cups_dest_t变量,获取对应的打印机名。

设置打印参数

我们在打印的时候有时会选择单面打印,有时会选择双面打印,这些都需要额外设置,因此我们需要先设置才能进行打印。

不设置也可以打印,此时使用默认的打印参数,一般是单页单面打印。

//这里先设置两个全局变量
cups_option_t *cups_options; // cups设置
int num_options; 

//入参是想要设置的打印参数值,如2, "A4", "lrtb", "two-sided-short-edge"等
//可以设置的参数不止这些,我只是挑了一些常用的做示范            
void set_printer_options(int number_up,
                         char *media,
                         char *number_up_layout, char *sides)
{
    cups_options = NULL;
    num_options = 0;

    char NumberUp[2] = {0};

    snprintf(NumberUp, 2, "%d", number_up);
    /* 设置打印参数 */
    num_options = cupsAddOption("number-up", NumberUp, num_options, &cups_options);

    num_options = cupsAddOption("media", media, num_options, &cups_options);

    num_options = cupsAddOption("number-up-layout", number_up_layout, num_options, &cups_options);

    num_options = cupsAddOption("sides", sides, num_options, &cups_options);
}

这里用到了cups_option_s这个结构体,它也是cups_dest_s的成员,结构体的内容如下:

typedef struct cups_option_s		/**** Printer Options ****/
{
  char		*name;			/* Name of option */
  char		*value;			/* Value of option */
} cups_option_t;

执行cupsAddOption会将对应的参数加入参数数组(cups_option_t)。

cupsAddOption会返回当前的参数个数,因此如果在每次执行之后都将num_options打印出来会发现num_options的数值是1,2,3,4,这样就是设置成功了。

打印

知道了打印机名并获取了参数之后,就可以进行正式打印啦!

int printer_print_file(char *printername, char *filepath)
{
    printf("[%s] Start\n", __FUNCTION__);
    printf("[%s] printer_name: %s, file_path: %s\n", __FUNCTION__,
           printername,
           filepath);
	//"Print report"是打印的标题,这个可以随意换
	// num_options和cups_options都用设置参数那一节的全局变量,不然之前设置的打印参数不生效
    int jobid = cupsPrintFile(printername, filepath, "Print report", num_options, cups_options);

    return jobid;
}