Select paper source in php printing solution

1.4k views Asked by At

Hi I've got a PHP printing solutions using sockets. Using this function/class.

public function printJob($queue){

        //Private static function prints waiting jobs on the queue.
        $this->printWaiting($queue);

        //Open a new connection to send the control file and data.
        $stream = stream_socket_client("tcp://".$this->host.":".$this->port, $this->errNo, $this->errStr, $this->timeout);
        if(!$stream){
            return $this->errNo." (".$this->errStr.")";
        } else {

            $job = self::getJobId();//Get a new id for this job

            //Set printer to receive file
            fwrite($stream, chr(2).$queue."\n");
            $this->debug .= "Confirmation of receive cmd:".ord(fread($stream, 1))."\n";

            //Send Control file.
            (isset($_SERVER['SERVER_NAME'])) ? $server = $_SERVER['SERVER_NAME'] : $server = "me";//Might be CLI and not have _SERVER
            $ctrl = "H".$server."\nPphp\nfdfA".$job.$server."\n";
            fwrite($stream, chr(2).strlen($ctrl)." cfA".$job.$server."\n");
            $this->debug .= "Confirmation of sending of control file cmd:".ord(fread($stream, 1))."\n";

            fwrite($stream, $ctrl.chr(0)); //Write null to indicate end of stream
            $this->debug .= "Confirmation of sending of control file itself:".ord(fread($stream, 1))."\n";






            if (is_readable($this->data)){

                //It's a filename, rather than just some ascii text that needs printing.  Open and stream.
                if (strstr(strtolower($_ENV["OS"]), "windows")){
                    $this->debug .= "Operating system is Windows\n";
                    $data = fopen($this->data, "rb");//Force binary in Windows.
                } else {
                    $this->debug .= "Operating system is not Windows\n";
                    $data = fopen($this->data, "r");
                }

                fwrite($stream, chr(3).filesize($this->data)." dfA".$job.$server."\n");
                $this->debug .= "Confirmation of sending receive data cmd:".ord(fread($stream, 1))."\n";

                while(!feof($data)){
                    fwrite($stream, fread($data, 8192));                     
                }
                fwrite($stream, chr(0));//Write null to indicate end of stream
                $this->debug .= "Confirmation of sending data:".ord(fread($stream, 1))."\n"; 

                fclose($data);

            } else {                      

                //Send data string
                fwrite($stream, chr(3).strlen($this->data)." dfA".$job.$server."\n");           
                $this->debug .= "Confirmation of sending receive data cmd:".ord(fread($stream, 1))."\n";

                fwrite($stream, $this->data.chr(0)); //Write null to indicate end of stream
                $this->debug .= "Confirmation of sending data:".ord(fread($stream, 1))."\n"; 

            }
        }

    }

All is well with it but I can't seem to control the paper source/tray that the printer then selects. Does anyone know how to do this?

Or perhaps a different solution that I an use, I like this one because I can send the ip address (no need for install), postscript file and it prints out. So if there is another solution that requires the same things then I can use that.

I'm using PHP, iis, windows. Richard

2

There are 2 answers

9
KenS On BEST ANSWER

I think this is more a question about the printing system on the OS you are using (you don't seem to say what that is). I also can't see where the print job is taking place, is this C# code ?

All printer have properties, included in which are things like the tray setup. When printing you need to configure the device, the steps for doing that are going to be different per OS. For example, on Windows 8+ you would need to set up a job ticket. I don't recall exactly how its done on earlier versions of Windows, some complicated structure as I recall. On Linux it would depend if you are using CUPS, if you are you would probably need to set up a CUPS pipeline for the specific tray you wanted to use.

I see there is some code testing to see whether the OS is Windows or something else. I guess you will need to figure out wht to do in there.

[added later]

OK so now I understand better what you are doing. Since you are using Ghostscript to create PostScript from your PDF file the question does make more sense.

The link you noted above and the PSDocOptions and PSPageOptions is what you need, combined with luser_droog's points about tray selection.

So first you need to find out what your printer expects in the way of PostScript in order to change trays. Your PPD file contains ths:

*InputSlot Internal/Cassette 1 (Internal): "<</ManualFeed false>> setpagedevice statusdict begin 0 setpapertray end"
*InputSlot PF60A/Cassette 2: "<</ManualFeed false>> setpagedevice statusdict begin 1 setpapertray end"
*InputSlot PF60B/Cassette 3: "<</ManualFeed false>> setpagedevice statusdict begin 4 setpapertray end"
*InputSlot PF60C/Cassette 4: "<</ManualFeed false>> setpagedevice statusdict begin 5 setpapertray end"
*InputSlot EF1/Envelope Feeder: "<</ManualFeed false>> setpagedevice statusdict begin 2 setpapertray end"

So to select 'cassette' 1 the required PostScript is:

<</ManualFeed false>> setpagedevice statusdict begin 0 setpapertray end

Now assuming you are using a recent version of Ghostscript (ie at least version 9.16) you can then add, as part of your PDF to PostScript command line;

-dPSDocOptions="<</ManualFeed false>> setpagedevice statusdict begin 0 setpapertray end"

Which will set the current tray to tray 1 before starting the job. Note that your PostScript file is no longer device-independent, it will now only work reliably on that class of printer.

If you wanted (for example) page 1 to be printed on cassette 1 and page 2 on cassette 2 you would need to use PSPageOptions, eg:

    -dPSpageOptions=["<</ManualFeed false>> setpagedevice statusdict begin 0 setpapertray end"
 "<</ManualFeed false>> setpagedevice statusdict begin 1 setpapertray end"]

I'm assuming that you are deploying this in a particular organisation, rather than open to the world. However it might be good to stick a note somewhere that Ghostscript is AGPL licenced, and if this was ever made available as a general service, the entire source code would probably have to be made available (the AGPL covers software as a service).

2
luser droog On

This is going to require printer-specific postscript code. You should search for .PPD files (postscript printer definition) for the specific printers you need to use.

The .ppd files are ascii text in a special format, but easily human-readable. Any special capabilities of the printer that cannot be done in standard postscript (but still achievable with postscript) are documented this way.

I've done a similar style of printing in the past, by using the unix telnet command specifying the ip-address and port, and redirecting the input to be my ps file. The same should be possible with the windows shell using a command-line telnet program.