【问题标题】:How to get notification from printer when physical page/job is complete物理页面/作业完成时如何从打印机获取通知
【发布时间】:2012-04-10 11:06:43
【问题描述】:

我希望能够在网络打印机物理完成打印页面(和/或整个作业)时收到通知。这将用于我正在编写的用于通过网络进行打印管理的应用程序中,并且由于用户按页面收费,并且在页面实际完成之前费用不应该下降。

我不确定这是否需要编写驱动程序、某种插件或客户端应用程序是否可以。我的平台很灵活,因为我的客户端还没有编写,所以我想听听 Windows 或 Linux 中任何编程语言/级别的任何合适的解决方案。

我知道后台处理程序和打印机之间存在差异。我正在尝试检查当页面或作业物理完成时,打印机可能会在哪个级别通过 IPP 通知机器。

我目前正在研究 Java,使用 jspicups4j 包在 IPP 属性 job-impressions-completed 更改时获取通知,或者轮询它。我正在使用连接本地打印机的 CUPS IPP 接口。运行一个简单的测试器(HelloPrint.java 附在下面;或包含在 cups4j 中的CupsTest.java),我没有收到任何job-impressions-completed 属性更改,也没有在我轮询时列出作业的属性。

以下是问题:

  • 这样做对吗?如果没有,那我该怎么办?
  • 由于这是本地打印机的 CUPS 接口,可能是 job-impressions-completed 属性未更新,特别是因为它充当真实打印机的假脱机程序。假设真正的打印机通知或列出此属性,这是特定于打印机的还是必须任何支持 IPP 的打印机都有此属性可用和更新?

系统信息:Ubuntu 11.10,CUPS 1.5.0,打印机是 Brother HL-2240D (PPD available here)

注意:HL-2240D 不是我将用于最终项目的打印机(具体来说,它不支持 IPP);我打算使用 HP HL4250DN 或三星 3741ND 或类似设备。

这是一个使用 javax.print 包和 jspi 的示例应用:

HelloPrint.java

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;

import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import javax.print.event.*;

import de.lohndirekt.print.IppPrintService;

public class HelloPrint {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // create request attributes
        PrintRequestAttributeSet requestAttributeSet = new HashPrintRequestAttributeSet();
        requestAttributeSet.add(MediaSizeName.ISO_A4);
        requestAttributeSet.add(new Copies(1));
        requestAttributeSet.add(Sides.DUPLEX);

        // find an appropriate service
        // using jspi (http://code.google.com/p/jspi/)
        URI printerURI;
        try {
            printerURI = new URI("ipp://localhost:631/printers/HL2240D-local");
        } catch (URISyntaxException e2) {
            e2.printStackTrace();
            return;
        }
        IppPrintService service = new IppPrintService(printerURI);

        // by enumerating       
        //      PrintService[] services = PrintServiceLookup.lookupPrintServices(
        //              DocFlavor.INPUT_STREAM.PDF, requestAttributeSet);
        //      for (PrintService service1 : services) {
        //          System.out.println(service1);
        //      }
        //      PrintService service = services[0];

        // add listeners to service
        service.addPrintServiceAttributeListener(new PrintServiceAttributeListener() {
            @Override
            public void attributeUpdate(PrintServiceAttributeEvent event) {
                PrintServiceAttributeSet serviceAttributeSet = event
                        .getAttributes();
                StringBuilder s = new StringBuilder();
                s.append("=== PrintServiceAttributeEvent: (" + serviceAttributeSet.size() + " attributes)\n");
                for (Attribute attribute : serviceAttributeSet.toArray()) {
                    PrintServiceAttribute printServiceAttribute = (PrintServiceAttribute) attribute;

                    s.append(printServiceAttribute.getCategory().getName()
                            + "/" + printServiceAttribute.getName() + " = "
                            + printServiceAttribute.toString() + "\n");

                }
                System.out.println(s.toString());
            }
        });

        // add file (blank.pdf is a blank page exported as PDF from LibreOffice
        // Writer)
        FileInputStream inputStream;
        try {
            inputStream = new FileInputStream("blank.pdf");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return;
        }

        // create a new doc and job
        DocAttributeSet docAttributeSet = new HashDocAttributeSet();
        docAttributeSet.add(MediaSizeName.ISO_A4);
        docAttributeSet.add(Sides.DUPLEX);

        Doc doc = new SimpleDoc(inputStream, DocFlavor.INPUT_STREAM.PDF,
                docAttributeSet);

        DocPrintJob job = service.createPrintJob();

        // listen to print job attribute change events
        // attribute set is null, means this means to listen on all dynamic
        // attributes that the job supports.
        job.addPrintJobAttributeListener(new PrintJobAttributeListener() {
            @Override
            public void attributeUpdate(PrintJobAttributeEvent event) {
                PrintJobAttributeSet jobAttributeSet = event.getAttributes();
                StringBuilder s = new StringBuilder();
                s.append("=== PrintJobAttributeEvent: (" + jobAttributeSet.size() + " attributes)\n");
                for (Attribute attribute : jobAttributeSet.toArray()) {
                    PrintJobAttribute jobAttribute = (PrintJobAttribute) attribute;

                    s.append(jobAttribute.getCategory().getName() + "/"
                            + jobAttribute.getName() + " = "
                            + jobAttribute.toString() + "\n");

                }
                System.out.println(s.toString());

            }
        }, null);

        // listen to print job events
        job.addPrintJobListener(new PrintJobListener() {

            @Override
            public void printJobRequiresAttention(PrintJobEvent pje) {
                System.out.println("=== PrintJobEvent: printJobRequiresAttention");
            }

            @Override
            public void printJobNoMoreEvents(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobNoMoreEvents");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printJobFailed(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobFailed");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printJobCompleted(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobCompleted");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printJobCanceled(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobCanceled");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printDataTransferCompleted(PrintJobEvent pje) {
                System.out.println("=== PrintJobEvent: printDataTransferCompleted");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }
        });

        // print
        try {
            job.print(doc, requestAttributeSet);
        } catch (PrintException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return;
        }
        
        // try polling
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return;
            }
            
            System.out.println("=== Polling: I'm alive and it's " + new Date());
            System.out.println("Job attributes");
            for (Attribute attribute : job.getAttributes().toArray()) {
                System.out.println((attribute.getCategory().getName() + "/"
                        + attribute.getName() + " = " + attribute.toString()));
            }
            System.out.println("Service attributes");
            for (Attribute attribute : service.getAttributes().toArray()) {
                System.out.println((attribute.getCategory().getName() + "/"
                        + attribute.getName() + " = " + attribute.toString()));
            }
        }
    }

}

【问题讨论】:

  • 嗯,我认为“我如何监控物理打印作业进度”是一个合适的问题。我考虑了你的 cmets,希望这个版本的问题更清楚(甚至可能得到回答!)
  • 您修改后的问题非常合适。感谢您的(大量)编辑;现在好多了。 :)
  • 嗨 Yuval,您能找到问题的答案吗?我有完全相同的要求,但还没有找到解决方案。
  • 我现在真的回到了这个项目。我刚拿到一张带打印卡的京瓷 KM-3530(我希望我的型号是对的),我会检查如何使用它。这是一个志愿者项目,我需要一个月左右的时间才能有时间解决它,但我会保持联系并更新问题。

标签: printing driver monitoring


【解决方案1】:

最终,这一切都取决于打印机固件。 IPP 将属性 job-impressions-completed 指定为可选。这意味着如果打印机无法判断打印了哪一页,您将无法读取它 - 无论您的编程是否正确。

制造商通常声称支持 IPP,但没有很好地记录他们可能已实施(或未实施)的可选部分。

在进行任何编程之前,我建议使用 CUPS 提供的 ipptool 阅读所有可用的工作属性:

#!/usr/bin/env ipptool -tv -d job=482 ipp://192.168.2.113/ipp
{
OPERATION Get-Job-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR language attributes-natural-language en
ATTR uri printer-uri $uri
ATTR integer job-id $job
}

job-state 是强制属性,应在一段时间后达到最终状态:completedabortedcanceled。如果您可以在其他地方获得作业页面的数量,这可能就足够了。

实现提示:IppJob 提供方法waitForTermination()

【讨论】:

  • 谢谢。您是否有参考说明job-impressions-completed 是可选的?
  • RFC 2911, Section 4.3职位描述属性:“如果它[该属性]未指示为必需,则它是可选的”
猜你喜欢
  • 1970-01-01
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 2020-10-25
相关资源
最近更新 更多