 |
|
 |
Hi Rob,
Thanks for the quick reply.
I am able ot print the pdf documents on the same printer from the PDF file i.e if I print after opening the pdf file and use the print button given on the PDF file.
It means printer is supporting the pdf files.
But if I use the demo.exe and give the pdf file than it produces the plain text resulting in lots of numbers and text.
Please help.
Thanks,
Neeraj
|
|
|
|
 |
|
 |
Hi Neeraj,
I understand your experiment and I will try to explain your observations.
When you open the PDF file with Acrobat Reader this application interprets the PDF code and translates them to GDI calls that are displayed by your video card. When you press the print button, similar GDI calls are sent to the printerdriver that translates them to PostScript or PCL code which is sent to the printer.
To see the difference print to file from Acrobat Reader (checkbox in the driver dialog) and open the resulting file with Wordpad. Assuming you have a PostScript driver the resulting file is Postscript. Also open the original PDF file with Wordpad.
The PDF file starts like: %PDF-1.4
The Postscript starts like: %!PS-Adobe-3.0
The PDF file will look familiar just like the "garbage" printed earlier. Note that 1.4 and 3.0 are version numbers and that they might differ.
So in conclusion when you print from Acrobat Reader to the printer no PDF is sent to the printer but a printer language that depends on the printerdriver chosen.
What you now can do is use the demo application to sent the Postscript file to the printer.
Hopes this explains the difference to you. More detailed information about the printing proces can be found at http://technet.microsoft.com/en-us/library/cc783789.aspx[^]
Regards,
Rob
|
|
|
|
 |
|
 |
Thanks Rob again for the quick reply and excellent explanation.
I use the print to file command and create the PS file from pdf and when I am giving to the printer with Demo exe it is printing the whole contents of ps file in the text format.
Is there is anything missing from my side ?
Given below are the top 30 statements from the PS file:
%-12345X@PJL JOB NAME="FORM.pdf"
@PJL SET STRINGCODESET=UTF8
@PJL SET HOLD=OFF
@PJL SET SEPARATORPAGE=OFF
@PJL SET ECONOMODE=OFF
@PJL SET RESOLUTION=600
@PJL ENTER LANGUAGE=POSTSCRIPT
%!PS-Adobe-3.0
%%Title: FORM.pdf
%%Creator: PScript5.dll Version 5.2.2
%%CreationDate: 4/21/2009 8:44:19
%%BoundingBox: (atend)
%%Pages: (atend)
%%PageOrder: (atend)
%%DocumentNeededResources: (atend)
%%DocumentSuppliedResources: (atend)
%%DocumentData: Clean7Bit
%%TargetDevice: (HP Universal Printing PS) (3010.107) 0
%%LanguageLevel: 2
%%HiResBoundingBox: 12 17.3299 597.9600 775.6302
%%CropBox: 12 17.3299 597.9600 775.6302
%ADO_BeginApplicationHeaderComments
%%Creator: Adobe Acrobat 8.0
%%For: A378737
%%LanguageLevel: 3
%ADO_EndApplicationHeaderComments
%%DocumentProcessColors: (atend)
%%DocumentCustomColors: (atend)
%%EndComments
|
|
|
|
 |
|
 |
Great Rob!!! After removing the first 7 PJL commands I am able to print the pdf from the demo.exe.
I am using the following printer for printing:
HP laserjet 4350dtn
Now the problem is how can we make whole thing automated for printing pdf files through demo.exe.
Currently I am following the steps below to print pdf file through demo.exe:
1) Save the PDF file with print to file option.
2) Remove the first 7 PJL commands
3) Use the file after above changes to print through demo.exe
Thanks,
Neeraj
|
|
|
|
 |
|
 |
OK,
Hypothesis 2: The cause is in the first character [001B].
test 1: Could you remove these and give it a try? Easier to remove two bytes than seven lines
Test 2: Windows has a commandline LPR client. Could you try it with the original printfile (including the PJL comments and the escape character)? type "LPR /?" for explanation of parameters. [reference test]
In case you want to dive into the code: The datafile is read and sent into the network socket around line 420-440. There is a change but the older code is available as comment.
regards,
rob
|
|
|
|
 |
|
 |
Hi Rob,
Thanks again for your quick response.
test1 and test 2 failed and it is printing as text. Now the only option left is to dive into the code.
Reviewed the code also for changes but not able to understand where to make the change. Can you help me with the code change for our scenario ?
Thanks,
Neeraj
|
|
|
|
 |
|
 |
Hi Rob,
Thanks again for your reponse. Just replied to the mail. Please confirm you got the mail or not ?
Neeraj
|
|
|
|
 |
|
 |
Are you aware of any print drivers/processors for windows that could accept a PDF over LPR. The drivers I am using (HP drivers) throw two errors before dropping it from the queue:
Failed to set information to the print job received from client at IP address 10.0.12.214. The specified datatype is invalid.
Failed to set data type 'TEXT' to the print job received from...
So they obviously do not recognize the PDF format. Any ideas?
|
|
|
|
 |
|
 |
Nevermind. It seems to be the way this code is encoding the data. I'll have to look more closely but when I use the command line LPR.exe util in binary mode, it works just fine.
|
|
|
|
 |
|
 |
I love this article because it is very close as I'm looking for.
I'd like to know if is it possible to use as a webservice, where an application will get the response of one webpage, and then, will print a page without user commands ?
Thanks in advance,
Best regards
|
|
|
|
 |
|
 |
Hi Malukinho,
Don't know your requirements in detail but to keep things nicely separated I propose to make one class that generates the file to be printed. When the file is generated it can be offered to the LPR class. Similar to the thread "Printing contents of a textbox to a Network printer using ASP.net" just below.
If you don't have high performance requirements you can store the file as a temporary file and use the LPR class to print it. Note that most of the time the speed of the printer will be the performance bottleneck. This way you can use the LPR client class just as is.
If you need more performance the class should be rewritten so it exposes lower level methods so you can open the printer, fill a buffer, send, ...., and close printer yourself.
Hopes this helps,
regards,
Rob Tillaart
|
|
|
|
 |
|
 |
Hi Rob,
The class was excellent it works great for a windows application. Can you please help me implement it for a web application. The Description for the Project i'm doing is as below:
I have to print a label to a Datamax printer by a ASP.Net web application (C#). The contents to be printed will be given in a Text box.
The Datamax label printer is a Network shared printer whose IP address is known to the web application Developer.
The Web application should use this IP address to communicate to the printer, so that later when the printer is changed we need to change only the IP address in the Web app.
Any one in the network who opens this web application and clicks Print should be able to print a label to that particular printer without any change in printer settings or any installations.
It is a single web application no extra forms can be added.
Kindly Help me in this issue.
Thanks in Advance
|
|
|
|
 |
|
 |
Hi Member4088318,
Excuses for the long delay for the answer. Many threads ask for high priority
The simplest way to solve the problem is to store the text to print in a temporary file and print this file. This could also be part of the printer class. I have made a first implementation which stores the text in a file with a random name to minimize the chance of collisions. Then this temporary file is printed as usual. Because it is a temporary file I give the flag deleteafterprint the value true. Setting this flag to false may help to debug it.
Just include the code snippet below in the printer class. Change the value of temppath to fit your need & system. Temppath should be a property of the printer class ...
public void LPRtext(string text)
{
Random r = new Random();
string temppath = @"C:\";
string fn = temppath + "lpr" + r.Next(999999999).ToString();
StreamWriter sw = new StreamWriter(fn);
sw.Write(text);
sw.Close();
LPR(fn, true);
}
Hopes this solves your need.
regards,
rob
|
|
|
|
 |
|
 |
First off, thank you for the code--it's an excellent LPR implementation.
Any idea how to implement a "real" status request (i.e. query the printer for current state, errors, etc.) Perhaps I missed this in RFC 1179.
Thanks.
Michael Shearer
|
|
|
|
 |
|
 |
Hi Michael,
In RFC 1179 there is no printer state defined, only the queue state by means of the LPQ (short or long) command. The data and its formatting LPQ returns is not specified. This makes it hard to parse output from different printers or devices behaving like printers e.g. print server (windows/linux/..), fax server etc.
My preferred way to interrogate printers about their state is SNMP (Simple Network Management Protocol) and to use the printer Mib RFC 3805 (replaces 1759). With this one can see if the device is idle or running or in error, also the number of papertrays and the amount of paper in them can be requested. But be aware that this only works for printers that support the printer MIB. Note that some printers support the PM partially.
There are several articles about using SNMP in C# e.g. http://www.codeproject.com/useritems/SNMPDLL.asp[^].
Additional to SNMP one can use the PING command to see if the printer is reachable in the first place.
Succes,
Rob Tillaart
|
|
|
|
 |
|
 |
Your code was really great!
but, in my work, i have to print in text mode only (just send txt file to the printer).
can you give me some comment?
ps. sorry if this is the stupid question.
thx in adv
vinai
-:I'm a really Newbie:-
|
|
|
|
 |
|
 |
Hi Vinai,
Look for the follow piece of code in the file lprdemo.cs: (approx line 250)
void Button1Click(object sender, System.EventArgs e)
{
if ((HostName.Text == "") || (QueueName.Text == "") || (UserName.Text == ""))
{
MessageBox.Show("Please fill in host, queue and username");
return;
}
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = DateTime.Now.ToString() + " busy";
Printer printer1 = new Printer(HostName.Text,QueueName.Text,UserName.Text);
printer1.LogFile = @"c:\lpr.log";
string fname = openFileDialog1.FileName;
if (fname.EndsWith(".ps") || fname.EndsWith(".pdf"))
{
printer1.LPR(fname, false);
textBox1.Text = DateTime.Now.ToString();
textBox1.Text += printer1.ErrorMsg;
}
else
{
// error message
textBox1.Text = "File does not end with .ps or .pdf.";
}
}
}
Change the line that tests the extention:
if (fname.EndsWith(".ps") || fname.EndsWith(".pdf"))
in
if (fname.EndsWith(".ps") || fname.EndsWith(".pdf") || fname.EndsWith(".txt"))
and you can select *.txt files too and print them. You can also restrict the LPR client to ".txt" only. Then the line should become:
if (fname.EndsWith(".txt"))
Except for the end of the name you could also restrict files to be printed in other ways. E.g. you could only restrict printing to filenames matching some regular expression, or if the files are at least 2 days old, have a filesize > 0, etc.
You should also edit the errormessage. In theory you can send all filetypes by means of the LPR client (adapt changes of Karl Fleishman for binary files, see forum) but be aware that the receiving device should support the fileformat. There are PostScript printers that does not support .txt. Printers that support PCL will print .txt files as plain text is a subset of PCL.
Succes,
Rob
PS, There exist no stupid questions only stupid answers
|
|
|
|
 |
|
 |
Hi Rob,
Can you also through some light how to write the server side of the code as well.
jayprakashshetty@hotmail.com
CANADA
|
|
|
|
 |
|
 |
Hi Jay,
Sorry it took some time to answer. Currently I am busy writing a prototype of an LPD server and it will be posted as a separate article to CP soon. Do you need special functionality? Let me know and maybe I can include it.
regards,
Rob
|
|
|
|
 |
|
 |
Hi,
I have submitted my LPD article last week but something went wrong I guess as it appeared under another author's name. But nevertheless a prototype LPD daemon can be found here. Or search for "Line Printer Daemon in C#" or "LPD" and you will find it.
http://www.codeproject.com/csharp/_inePrinterDaemon.asp[^]
Regards,
Rob
|
|
|
|
 |
|
 |
I guess I'm missing something. Exactly which scenario I would want to use this code?
Regards,
Shital.
http://www.ShitalShah.com
|
|
|
|
 |
|
 |
Hi Shital,
The LPR class can be used when you want to send a print-ready file to a printer. This file can be a PostScript, PDF, PCL or even a txt file depending on the capabilities of the (network)printer. One might have created this file by means of the 'print to file' option in a printerdriver dialog.
With this class one could build a simple commandline tool that e.g. sends all PDF files in a directory (CD) to a printer.
The class can also be used when you generate the PostScript yourself from within your application. OK, with the current implementation you need to write the PostScript to a file first. A stream interface would be a very nice enhancement.
Major problem for the stream interface is that the size of the data file is unknown and therefor the SubCommand 3 'RECEIVE DATA FILE' cannot give a correct filesize as parameter. In this case one should give 0xFFFFFFFF as filesize, but some printers do not cope with this very well as they allocate memory for the datafile in one chunk => an alloc of 4GB => POOOF!!
A well known way to circumvent this problem is to make a local copy of the PostScript on disk first and only send the file to the printer when the stream is closed. Then the size is known and the memory problem does not occur. OK, when the PostScript file is very large the problem still exists, but these are rare. FYI the largest PostScript file I encountered was approx. 1.2 GB.
Hopes this answers your question,
Regards,
Rob Tillaart
|
|
|
|
 |
|
 |
Hey Rob, Great class, I'm using it quite a bit and it's been working great. However recently we experienced a problem with the byte streaming portion of the class. Here's what we discovered and how we worked around it.
It appears that if the file your trying to print has a byte that can't convert into a character the "while (br.PeekChar() > -1)" line in the LPD.Printer.SendFile() method will throw a "Conversion Buffer Overflow" exception. To work around this you can use the following code which is an alternative way to stream the bytes over the NetworkStream without the conversion error. The commented code is the way it was originally.
// use BinaryReader as print files may contain non ASCII characters.
long totalbytes = 0;
int bytesRead=0;
byte[] buff = new Byte[2048];
FileStream fstream = new FileStream(fname, FileMode.Open);
while ( (readed=fstream.Read(buffer, 0, BUFSIZE)) > 0 )
{
totalbytes += bytesRead;
nws.Write(buffer, 0, bytesRead);
nws.Flush();
}
fstream.Close();
//FileStream fs = new FileStream(fname, FileMode.Open, FileAccess.Read);
//long totalbytes = 0;
//BinaryReader br = new BinaryReader(fs);
//while (br.PeekChar() > -1)
//{
// int n = br.Read(buffer, 0, BUFSIZE);
// totalbytes += n;
// nws.Write(buffer, 0, n);
// nws.Flush();
//}
//br.Close();
//fs.Close();
Here's the web page where we found the solution to this problem.
http://www.codecomments.com/message507645.html[^]
Have a Great Day!
www.karlfleischmann.com
It's better out here.
|
|
|
|
 |
|
 |
Hi Karl,
It is good to hear the project is used. As I used only text files I didn't encounter this problem.
Thanx for the patch, when I find some time I will update it in the source. Think the 'readed' variable in the while loop should be bytesRead otherwise no bytes are written. So it becomes:
long totalbytes = 0;
int bytesRead = 0;
byte[] buff = new Byte[2048];
FileStream fstream = new FileStream(fname, FileMode.Open);
while ( (bytesRead = fstream.Read(buffer, 0, BUFSIZE)) > 0 )
{
totalbytes += bytesRead;
nws.Write(buffer, 0, bytesRead);
nws.Flush();
}
fstream.Close();
Thanx again for the patch,
rob tillaart
|
|
|
|
 |
|
 |
It limits the size of lines with 80.
If I have a file which has some lines exceed 80 characters, it prints left of the line (after 80th chr.) into new line.
Is there any way that I can customize formats of the documents
-- modified at 14:47 Friday 21st April, 2006
|
|
|
|
 |