I am printing using the Windows Compact Framework to a Zebra belt printer using the OpenNetCF serial port class and CPCL. The printed label is pretty much as it should be, but the barcode value is not printing beneath the barcode as it should.
I create an ArrayList of commands to be sent the printer and then pass them one at a time to the serial port. If the controls that supply the values are empty, I use some dummy data, like so:
private void btnPrint_Click(object sender, System.EventArgs e)
{
string listPrice = txtList.Text;
if (listPrice.Trim() == string.Empty)
{
listPrice = "3.14";
}
string description = txtDesc.Text;
if (description.Trim() == string.Empty)
{
description = "The Life of Pi";
}
string barcode = txtUPC.Text;
if (barcode.Trim() == string.Empty)
{
barcode = "01701013992";
}
ArrayList arrList = new ArrayList();
arrList.Add("! 0 200 200 120 1\r\n"); // replace 120 with label height if different than 1.25"/120 pixels (at 96 pixels per inch)
arrList.Add("RIGHT\r\n");
arrList.Add(string.Format("TEXT 0 5 0 0 {0}\r\n", listPrice));
arrList.Add("LEFT\r\n");
arrList.Add(string.Format("TEXT 0 0 0 52 {0}\r\n", description));
arrList.Add("CENTER\r\n");
arrList.Add("BARCODE-TEXT 0 0 5\r\n");
arrList.Add(string.Format("BARCODE 128 1 1 50 0 77 {0}\r\n", barcode));
arrList.Add("FORM\r\n");
arrList.Add("PRINT\r\n");
PrintUtils pu = new PrintUtils();
pu.PrintLabel(arrList);
}
public void PrintLabel(ArrayList linesToSend)
{
using (SerialPort serialPort = new SerialPort())
{
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.DataBits = 8;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.PortName = "COM1:";
serialPort.Open();
Thread.Sleep(500); //this may not even be necessary and, if so, a different value may be better
foreach (string line in linesToSend)
{
serialPort.Write(line);
}
serialPort.Close();
}
}
...the problem is that the label (when I allow the dummy data to print) should be:
3.14
The Life of Pi
<barcode here>
01701013992
...and here's what is really printing:
3.14
The Life of Pi
<barcode here>
[blank]
So the problem is that the barcode as text ("01701013992") is not printing beneath the barcode.
Does anybody know why this is occurring even though I've got a BARCODE-TEXT command in there, and how to rectify it?
UPDATE
A key piece of info came my way, namely that the label height (in my case) should be 254, not 120 (for my 1.25" in height label, I was calculating based on 96 pixels == 1 inch, but in actuality this particular printer is 203 dpi, so 1.25 X == 254 (more precisely 253.75, but 254 is close enough).
So the code has changed to this:
// Command args (first line, prepended with a "!": horizontal (X) pos, resolution, resolution, label height, copies
// TEXT args are: fontNumber, fontSizeIdentifier, horizontal (X) pos, vertical (Y) pos
// BARCODE args are: barcodeType, unitWidthOfTheNarrowBar, ratioOfTheWideBarToTheNarrowBar, unitHeightOfTheBarCode,
// horizontal (X) pos, vertical (Y) pos, barcodeValue
// BARCODE-TEXT args are: fontNumber, fontSizeIdentifier, space between barcode and -text
// 1 inch = 203 dots (Zebra QL220 is a 203 dpi printer); font 4,3 == 90 pixels; font 2,0 == 12 pixels
arrList.Add("! 0 200 200 254 1\r\n"); // 203 dpi X 1.25 = 254
arrList.Add("RIGHT\r\n");
arrList.Add(string.Format("TEXT 4 3 0 0 {0}\r\n", listPrice));
arrList.Add("LEFT\r\n");
arrList.Add(string.Format("TEXT 2 0 0 100 {0}\r\n", description));
arrList.Add("BARCODE-TEXT 2 0 5\r\n");
arrList.Add("CENTER\r\n");
arrList.Add(string.Format("BARCODE 128 1 1 50 0 120 {0}\r\n", barcode));
arrList.Add("FORM\r\n");
arrList.Add("PRINT\r\n");
...but I'm STILL not seeing the description label - except for a lonely "P" below the "3" and the "." in the price.
Are my calculations wrong, or what?
Here's what I'm thinking I have:
Label is 254 dots/1.25" high.
First line starts at YPos 0 and prints "3.14" in a 90 pixel font, right-aligned. That prints fine.
Second line starts at YPos 100 (10 dots below the 90-dot first line), left-aligned. All I see is the aforementioned "P" in what seems to be the right size.
Third line is the barcode, at YPos (120), centered; prints fine
Fourth/final line is the barcode as text beneath the barcode proper, centered; prints fine.
NOTE: I can't put a bounty on this yet, but anybody who solves it I will award 100 points as soon as I'm able (in two days, I reckon).
It turns out that the problem was that I was using font # 2 in order to get a font size of 12 (it is the only font that provides that size). The problem with font # 2 is that it is "OCR-A" and as such only prints certain characters. In the string I was passing as a test ("The Life of Pi", to go along with the list price of 3.14), the only character it recognizes in that string is P. So that's why it's the only one I saw.
I had to increase my font size to the next available, namely 24, using font #5 (Manhattan) or 7 (Warwick).
"mk" from zebra provided me with this information ("The OCR font is a special font that doesn’t include all characters that you are trying to print.").
If you look at Appendix D in the CPCL programming manual, it does show font #2 as being "OCR-A," but it didn't dawn on me that that meant it's character set precluded most alpha characters. Even if that's obvious to some, it seems to me that should be emphasized in the manual: When printing text, don't use font #2!
Note: Font #6 (MICR) is also to be avoided for text.
Related
My Photo Booth application uses code similar to the code below to automatically print.
It works great, however recently when I changed my Dye Sub printer to use 5 x 7 media instead of the usual 4 x 6, as soon as the print code starts, the ribbon error on the printer lights.
I am setting the paper size as shown below but to get the error to go away, I found that I need to set the paper size in the Printer settings:
PrintingSettings->Paper/Quality -> Advanced Options->Paper Output/paperSize
I am setting the paper size in the print document
Is there another setting I can set in code to set the printer page size?
I am setting the paper size as follows:
public static PrintDocument pd = new PrintDocument();
PrintController printController = new StandardPrintController();
pd.PrintController = printController;
//page sizes in hundredths of an inch
if (selectedLayout.LayoutPrintWidthPixels >0) PrintWidth = selectedLayout.LayoutPrintWidthPixels/300 * 100;
if (selectedLayout.LayoutPrintHeightPixels > 0) PrintHeight = selectedLayout.LayoutPrintHeightPixels/300 *100;
pd.PrinterSettings.DefaultPageSettings.PaperSize = new PaperSize("Custom", PrintWidth, PrintHeight);
I am also having trouble understanding page sizes
For example, for 5 x 7 prints, I calculate the sizes as follows:
5 x 7 = 1500 x 2100 px based on 300 dpi
700 x 500 in Milli Inches (pixel size / 300) X 100
But if I look at the page size in the printer properties while debugging,
the paper size shows 713 x 516 or 1548 x 2139 in pixels
Is that the actual page size or are they allowing some extra for margins or bleed?
When printing 4 x 6, I normally design my template based on 1844 x 1240 pixels (instead of 1800 x 1200)
// milliinches=(pixels / 300) X 100
// pixels = (milli inches /100)*300
transform pdf points to pixels, worked correctly:
point-to-pixel = 1/72*300(DPI)
getting each text chunk positions (X,Y) in PDF the Y is calculated from
bottom-to-top, not as in standard html or java Script.
to get the Y value from top-to-down , cause not accurate Y position as in
html style , or win Form style.
how to get the correct Y top-to-down using any Page height, or rect mediaBox
or cropBox or rect textMarging finder ?
the code I used is your example of :
public class LocationTextExtractionStrategyClass : LocationTextExtractionStrategy
{
//Hold each coordinate
public List<RectAndText> myPoints = new List<RectAndText>();
/*
//The string that we're searching for
public String TextToSearchFor { get; set; }
//How to compare strings
public System.Globalization.CompareOptions CompareOptions { get; set; }
public MyLocationTextExtractionStrategy(String textToSearchFor, System.Globalization.CompareOptions compareOptions = System.Globalization.CompareOptions.None)
{
this.TextToSearchFor = textToSearchFor;
this.CompareOptions = compareOptions;
}
*/
//Automatically called for each chunk of text in the PDF
public override void RenderText(TextRenderInfo renderInfo)
{
base.RenderText(renderInfo);
//See if the current chunk contains the text
var startPosition = 0;// System.Globalization.CultureInfo.CurrentCulture.CompareInfo.IndexOf(renderInfo.GetText(), this.TextToSearchFor, this.CompareOptions);
//If not found bail
if (startPosition < 0)
{
return;
}
//Grab the individual characters
var chars = renderInfo.GetCharacterRenderInfos().ToList();//.Skip(startPosition).Take(this.TextToSearchFor.Length)
var charsText = renderInfo.GetText();
//Grab the first and last character
var firstChar = chars.First();
var lastChar = chars.Last();
//Get the bounding box for the chunk of text
var bottomLeft = firstChar.GetDescentLine().GetStartPoint();
var topRight = lastChar.GetAscentLine().GetEndPoint();
//Create a rectangle from it
var rect = new iTextSharp.text.Rectangle(
bottomLeft[Vector.I1],
bottomLeft[Vector.I2],
topRight[Vector.I1],
topRight[Vector.I2]
);
BaseColor curColor = new BaseColor(0f, 0f, 0f);
if (renderInfo.GetFillColor() != null)
curColor = renderInfo.GetFillColor();
//Add this to our main collection
myPoints.Add(new RectAndText(rect, charsText, curColor));//this.TextToSearchFor));
}
}//end-of-txtLocation-class//
You are asking many different questions in one post.
First let's start with the coordinate system in the PDF standard. Observe that I am talking about a standard, more specifically about ISO 32000. The coordinate system on a PDF page is explained in my answer to the Stack Overflow question How should I interpret the coordinates of a rectangle in PDF?
As you can see, a rectangle drawn in a PDF using a coordinate (llx, lly) for the lower-left corner and a coordinate (urx, ury) for the upper-right corner, assumes that the X-axis points to the right, and the Y-axis points upwards.
As for the width and the height of a page, that's explained in my answer to the Stack Overflow question How to Get PDF page width and Height?
For instance: you could have a /MediaBox that is defined as [0 0 595 842], and therefore measures 595 x 842 points (an A4 page), but that has a /CropBox that is defined as [5 5 590 837], which means that the visible area is only 585 x 832 points.
You also shouldn't assume that the lower-left corner of a page coincides with the (0, 0) coordinate. See Where is the Origin (x,y) of a PDF page?
When you create a document from scratch, a default margin of half an inch is used if you don't define a margin yourself. If you want to change the default, see Fit content on pdf size with iTextSharp?
Now for the height of a Chunk or, if you're using iText 7 (which you should, but —for some reason unknown to me— don't) the height of a Text object, this depends on the font size. The font size is an average size of the different glyphs in a font. If you look at the letter g, and you compare it with the letter h, you see that g takes more space under the baseline of the text than h, whereas h takes more space above the baseline than g.
If you want to calculate the exact space that is taken, read my answer to the question How to calculate the height of an element?
If the text snippet is used in the context of lines in a paragraph, you also have to take the leading into account: Changing text line spacing (Maybe that's not relevant in the context of your question, but it's good to know.)
If you have Chunk objects in iText 5, and you want to do specific things with these Chunks, you might benefit from using page events. See How to draw a line every 25 words?
If you want to add a colored background to a Chunk, it's even easier: How to set the paragraph of itext pdf file as rectangle with background color in Java
Update 1: All of the above may be irrelevant if you are looking to convert HTML to PDF. In that case, it's easy: use iText 7 + pdfHTML as described in Converting HTML to PDF using iText and all the Math is done by the pdfHTML add-on.
Update 2: There seems to be some confusion regarding the measurement units. The differences between user units, points and pixels is explained in the FAQ page How do the measurement systems in HTML relate to the measurement system in PDF?
Summarized:
1 in. = 25.4 mm = 72 user units by default (but it can be changed).
1 in. = 25.4 mm = 72 pt.
1 in. = 25.4 mm = 96 px.
Platform: Windows Mobile 6.5 Handheld
Language: C#
My problem: I'm being asked to capture a signature from the user and then send that signature to a printer to print on a receipt. I've successfully captured the image of the signature and have the byte array of the signature in memory but cannot seem to print it properly.
To get me started, I followed the blog here to get the Hex representation of the bitmap. However, this just printed out a very long receipt with the hex
representation of the signature. Code here instead of following the link:
private static string DrawBitmap(Bitmap bmp, int xPosition, int yPosition)
{
if (bmp == null)
throw new ArgumentNullException("bmp");
StringBuilder DataString = new StringBuilder();
//Make sure the width is divisible by 8
int loopWidth = 8 - (bmp.Width % 8);
if (loopWidth == 8)
loopWidth = bmp.Width;
else
loopWidth += bmp.Width;
//DataString.Append(string.Format("EG {0} {1} {2} {3} ", xPosition, yPosition));
DataString.Append(string.Format("EG 64 128 {0} {1} ", xPosition, yPosition));
for (int y = 0; y < bmp.Height; y++)
{
int bit = 128;
int currentValue = 0;
for (int x = 0; x < loopWidth; x++)
{
int intensity;
if (x < bmp.Width)
{
Color color = bmp.GetPixel(x, y);
intensity = 255 - ((color.R + color.G + color.B) / 3);
}
else
intensity = 0;
if (intensity >= 128)
currentValue |= bit;
bit = bit >> 1;
if (bit == 0)
{
DataString.Append(currentValue.ToString("X2"));
bit = 128;
currentValue = 0;
}
}//x
}//y
DataString.Append("\r\n");
return DataString.ToString();
}
After that failed, I found the CPCL programming guide for Zebra printers and followed the example on page 95 to print the little tile image. However, this did the same thing as the signature. Once that failed, I found that I needed to run the command: ! U1 setvar "device.languages" "zpl" before doing any EG commands; so I went ahead and did this but things took a bad turn here which end up forcing me to fully reset the printer and/or cleanboot the handheld because it causes a COM exception that crashes COM6 and the printer.
I have exhausted most if not all of the resources that I can think of and none of them have worked.
Does anyone have any other ideas or examples that could help me get this working?
Thanks
I found another CPCL programmers guide and it has this simple (test) example:
! 0 200 200 210 1
EG 2 16 90 45 F0F0F0F0F0F0F0F00F0F0F0F0F0F0F0F
F0F0F0F0F0F0F0F00F0F0F0F0F0F0F0F
FORM
PRINT
This should print a small checker board pattern.
The next example prints a PCX graphic:
PCX Commands
The PCX command gives a user the ability to send “.PCX” graphics formatted images to the printer. The
.PCX image MUST be encoded as a black and white image.
Format:
{command} {x} {y}
{data}
where:
{command}: PCX
{x}: X-coordinate of the top-left corner.
{y}: Y-coordinate of the top-left corner.
{data}: PCX image data.
Example:
! 0 200 200 500 1
PCX 0 30
<binary black and white pcx data stream>
FORM
PRINT
Example using a file (loaded previously the printers file system)
! 0 200 200 500 1
PCX 0 30 !<IMAGE.PCX
FORM
PRINT
If the printer has been switched to line printer mode, the command
! U1 PCX {x coordinate} {y coordinate} !< {filename.pcx}
for example
! U1 PCX 0 30 !< IMAGE.PCX
can be used to print monochrome PCX from file system.
Remeber that .NET is UTF-8 and so all commands and data has to be converted to ASCII before sending over a COM port. So do something like this:
Encoding ansi = Encoding.GetEncoding(1252);
byte[] buf = ansi.GetBytes(DataString);
System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM1:");
sp.Write(buf, 0, buf.Length);
for the PCX data just use the byte stream for the byte[] buffer.
I write program in C# but hope that C++ and C# in background exactly same.
What i want - take grayscaled image and separate colors over 127 and under 17 to separate images. If i simply get "white" colors and programmatically stretch them from range (127-255) to (0-255) like
// pseudocode
int min = 127, max = 255;
for(int x; x< width; x++)
pixels[x] = pixels[x]/(max-min) * max;
Then here will be not smooth interval.. I mean, that 127 converts to 0 but 128 converts to 2 and colors 1,3,5,... are not exist.
That is original image with alpha:image original
That is image with "extracted white":image original
That is image with "extracted black": snorgg.ru/patchwork/tst_black.png.
I don't clearly understand how it can be realized so exampe code will like:
{
im.MagickImage image = new im.MagickImage("c:/55/11.png");
im.MagickImage imageWhite = ExtractWhite(image);
im.MagickImage imageBlack = ExtractBlack(image);
}
....
public static im.MagickImage ExtractWhite(im.MagickImage img){
im.MagickImage result = new im.MagickImage(img);
?????
?????
return result;
}
thankы in advance ))
I think your calculation is wrong. You are confusing the input range with the output range. The input ranges from min to max and the output ranges from 0 to 255. It is a coincidence that your input max is equal to your output max (255).
If you want to stretch a value in the range of min ... max (= input range) to 0 ... 255 (= output range) then calculate this
int brightness = pixel[x];
if (brightness <= min) {
pixel[x] = 0;
} else if (brightness >= max) {
pixel[x] = 255;
} else {
pixel[x] = 255 * (brightness - min) / (max - min);
}
Where min >= 0 and max <= 255 and min < max.
First you have to make sure the brightness is within the range min ... max, otherwise your result will exceed the range 0 ... 255. You could also limit the range of the output afterwards, but in any case you have to make a range check.
Then subtract min from the brightness. Now you have a value between 0 and (max - min). By dividing by (max - min) you get a value between 0 and 1. Multiply the result by 255 and you get a value in the desired range 0 ... 255.
Also you must be aware of the fact that you are performing integer arithmetic. Therefore multiply by 255 first and then divide. If you start by dividing you get either 0 or 1 as intermediate result (because integer arithmetic does not yield decimals and the final result will either be 0 or 255 and all the gray tones get lost.
The effect you are seeing is called banding or posterisation. It is caused by making contrast stretches to data that is not sampled with sufficient bit-depth. As you only have 8-bit data, you only have 255 grey levels. If you stretch the 50 levels between 100-150 over a range of 255 levels, there will be gaps in your histogram around 5 levels wide. The solution is either to obtain 16-bit data, or make less drastic changes in the contrast.
Alternatively, if like me, you are a photographer, and more interested in the aesthetics of the image than its scientific accuracy, you can add a small amount of random noise to disguise and "smear over" the banding...
There is a nice description here.
I can also show you an example with ImageMagick, first we create two greyscale ramps (gradients), one 8-bit and one 16-bit, both ranging from brightness level 100 to 150 like this:
convert -depth 8 -size 100x500 gradient:"rgb(100,100,100)-rgb(150,150,150)" -rotate 90 gradient8.png
convert -depth 16 -size 100x500 gradient:"rgb(100,100,100)-rgb(150,150,150)" -rotate 90 gradient16.png
They look like this:
If I now stretch them both to the full range of 0-255 you will immediately see the banding effect in the 8-bit version, and the smoothness of the 16-bit version - which, incidentally, is the reason for using RAW format (12-14 bit) on your camera rather than shooting 8-bit JPEGs:
convert gradient8.png -auto-level out8.png
convert gradient16.png -auto-level out16.png
I alluded to using noise to redue the visibility of the banding effect, and you can do that using a technique like this:
convert out8.png -attenuate 0.3 +noise gaussian out.png
which gives you a less marked effect, somewhat similar to film grain:
I am not certain exactly what you are trying to do, but if you just want to spread the brightness levels from 127-255 over the full range of 0-255, you can do that simply at the command-line like this:
convert orig.png -level 50%,100% whites.png
Likewise, if you want the brightness levels from 0-17 spread over the range 0-255, you can do
convert orig.png -level 0,6.66667% blacks.png
I created a tool that generates PDF417 2D barcodes. The output png file is 290x78 pixels.
The reason behind this width and height is a formula used to create this symbol so that it is correctly read by bar code scanners.
My symbol is 13 columns and 39 rows.
This formula is:
Width = ((17 * # of columns) + 69) X + 2 (size of quiet zone)
Height = (# of rows) (row height) + 2 (size of quiet zone)
So:
17 * 13 + 69 = 290px
39 * 2 = 78px
My question is the software I use to create these bar codes allows you to save the file to this size but prints it at a different size.
These print parameters turn out to be as follow but I cannot figure out how to calculate them:
X Dimension (in) :0.0067
Y Dimension (in) :0.0133
Height x Width (in) :0.52 x 1.93
Height x Width (mm) :13.21 x 49.11
Rows x Columns : 39 x 13
Error Correction Level :5
Bytes Encoded :257
SLD Codeword :1
Data Codewords :157
Pad Codewords :285
MPDF Codewords :0
EC Codewords :64
Total Codewords :507
Here's a snapshot of the program I currently use:
This appears to be an issue of DPI and print size.
pixels/dpi=inches
or if you're going the other way
inches x dpi = pixels
You can set the DPI dropdown in your software to the necessary value.
See this calculator to play with the values: http://auctionrepair.com/pixels.html