Как получить уведомление от принтера о завершении физической страницы / задания

Я хотел бы иметь возможность получать уведомление от сетевого принтера, когда он физически заканчивает печать страницы (и / или всей работы). Это будет использоваться в приложении, которое я пишу, для управления печатью через Интернет, и так как пользователи получают плату за страницу, и плата не должна снижаться до того, как страница фактически завершится.

Я не уверен, что для этого нужно написать драйвер, какой-нибудь плагин или подойдет клиентское приложение. Я гибок с моей платформой, так как мой клиент еще не написан, поэтому я хотел бы услышать о любом подходящем решении в Windows или Linux, на любом языке программирования / уровне.

Я знаю, что между диспетчером очереди и принтером есть разница. Я пытаюсь выяснить, на каком уровне принтер может уведомить аппарат через IPP, когда страница или задание будут физически завершены.

В настоящее время я изучаю Java, используя пакет jspi или cups4j, чтобы получить уведомление, когда свойство IPP job-impressions-completed изменения или, альтернативно, опрос для этого. Я использую интерфейс CUPS IPP для локального принтера. Запуск простого тестера (HelloPrint.java прилагается ниже; или CupsTest.java включены в cups4j), я не получил ни одного job-impressions-completed атрибут не изменился, и при этом он не перечислял атрибут для работы, когда я проводил опрос.

Итак, вот вопросы:

  • Я делаю это правильно? Если нет, то как мне это сделать?
  • Поскольку это интерфейс CUPS к локальному принтеру, возможно, job-impressions-completed атрибут не обновляется, особенно потому, что он действует как спулер для реального принтера. Предполагая, что настоящий принтер будет уведомлять об этом атрибуте или перечислять его, будет ли это специфичным для принтера, или у любого принтера, поддерживающего IPP, этот атрибут будет доступен и обновлен?

Информация о системе: Ubuntu 11.10, CUPS 1.5.0, принтер Brother HL-2240D ( PPD доступен здесь)

Примечание: HL-2240D не тот принтер, который я буду использовать для возможного проекта (в частности, он не поддерживает IPP); Я собираюсь использовать HP HL4250DN, Samsung 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()));
            }
        }
    }

}

1 ответ

В конце концов все зависит от прошивки принтеров. IPP указывает атрибут "задание-показ-выполнено" как необязательный. Это означает, что если принтер не может определить, какая страница была напечатана, вы не сможете ее прочитать - независимо от того, правильное ли у вас программирование или нет.

Производители обычно утверждают, что поддерживают IPP, но не очень хорошо документируют дополнительные детали, которые они могли реализовать (или нет).

Прежде чем приступить к программированию, я предлагаю прочитать все доступные задания с помощью ipptool доступны от CUPS:

#!/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 является обязательным атрибутом и через некоторое время должен достичь конечного состояния: completed, aborted или же canceled, Это может быть достаточно, если вы можете получить количество рабочих страниц где-то еще:-)

Другие вопросы по тегам