Printing a Bit map image to pos printer via comport in C# [closed]
Asked Answered
D

3

11

I'm directly printing my receipt to the POS printer via serial port in the following way,

        SerialPort port = new SerialPort("com6", 9100, Parity.None, 8, StopBits.One);
        port.Open();
        port.Write("Some Text");
        port.Close();

My question is how I'm going to print a Bitmap image using the above method? Any help would be grateful.

I have not decided to go with Microsoft POS for.net, because it is slow and takes time to initialize the printer, where clients doesn't like to wait.

Thanks.

Disconnect answered 31/12, 2012 at 8:19 Comment(4)
You'll need to read the printer manufacturer's programming manual so you'll know what bytes to send to the printer. It will be slow.Globulin
There is a very similar question here #14530558. As such, I nominate this question for re-opening, because it is demonstrably not too localizedPile
wish I could vote for reopening this question... too localized sounds like a joke :oMediatize
I believe it is a valid question tooCovenant
S
35

This should get you a string from bitmap that you would be able to send to printer:

    public string GetLogo()
    {
        string logo = "";
        if (!File.Exists(@"C:\bitmap.bmp"))
            return null;
         BitmapData data = GetBitmapData(@"C:\bitmap.bmp");
         BitArray dots = data.Dots;
         byte[] width = BitConverter.GetBytes(data.Width);

         int offset = 0;
         MemoryStream stream = new MemoryStream();
         BinaryWriter bw = new BinaryWriter(stream);

         bw.Write((char)0x1B);
         bw.Write('@');

         bw.Write((char)0x1B);
         bw.Write('3');
         bw.Write((byte)24);

         while (offset < data.Height)
         {
             bw.Write((char)0x1B);
             bw.Write('*');         // bit-image mode
             bw.Write((byte)33);    // 24-dot double-density
             bw.Write(width[0]);  // width low byte
             bw.Write(width[1]);  // width high byte

             for (int x = 0; x < data.Width; ++x)
             {
                 for (int k = 0; k < 3; ++k)
                 {
                     byte slice = 0;
                     for (int b = 0; b < 8; ++b)
                     {
                         int y = (((offset / 8) + k) * 8) + b;
                         // Calculate the location of the pixel we want in the bit array.
                         // It'll be at (y * width) + x.
                         int i = (y * data.Width) + x;

                         // If the image is shorter than 24 dots, pad with zero.
                         bool v = false;
                         if (i < dots.Length)
                         {
                             v = dots[i];
                         }
                         slice |= (byte)((v ? 1 : 0) << (7 - b));
                     }

                     bw.Write(slice);
                 }
             }
             offset += 24;
             bw.Write((char)0x0A);
         }
         // Restore the line spacing to the default of 30 dots.
         bw.Write((char)0x1B);
         bw.Write('3');
         bw.Write((byte)30);

         bw.Flush();
         byte[] bytes = stream.ToArray();
         return logo + Encoding.Default.GetString(bytes);
    }

    public BitmapData GetBitmapData(string bmpFileName)
    {
        using (var bitmap = (Bitmap)Bitmap.FromFile(bmpFileName))
        {
            var threshold = 127;
            var index = 0;
            double multiplier = 570; // this depends on your printer model. for Beiyang you should use 1000
            double scale = (double)(multiplier/(double)bitmap.Width);
            int xheight = (int)(bitmap.Height * scale);
            int xwidth = (int)(bitmap.Width * scale);
            var dimensions = xwidth * xheight;
            var dots = new BitArray(dimensions);

            for (var y = 0; y < xheight; y++)
            {
                for (var x = 0; x < xwidth; x++)
                {
                    var _x = (int)(x / scale);
                    var _y = (int)(y / scale);
                    var color = bitmap.GetPixel(_x, _y);
                    var luminance = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
                    dots[index] = (luminance < threshold);
                    index++;
                }
            }

            return new BitmapData()
            {
                Dots = dots,
                Height = (int)(bitmap.Height*scale),
                Width = (int)(bitmap.Width*scale)
            };
        }
    }

    public class BitmapData
    {
        public BitArray Dots
        {
            get;
            set;
        }

        public int Height
        {
            get;
            set;
        }

        public int Width
        {
            get;
            set;
        }
    }
Spillar answered 31/12, 2012 at 9:17 Comment(10)
This one really works...Guillen
does it have to be bitmap, or i can also use this to print jpeg and png?Lauter
this solution is a life savior! thanks!Tonedeaf
someone could tell me what is the requirements of the image: bmp(it's required?), resolution, width, height, density, etc? ThanksAzotemia
You saved my life. Thank you so muchLeiker
This works like a charm. Thank you very much for posting such a nice solution.Lesleylesli
How can i determine which multiplier I need? The word multiplier is not showing up in my printer programming guide.Gentes
@blue, I don't remember what it means or why I called it this way. It's been a long time :) If I understand correctly - this is the width of the printer output in pixels.Spillar
My image prints with horizontal white bars (gaps?) any suggestions?Upstroke
@Spillar Hi, Which code page is this, CP437 or CP850? The printer does not print properly in some areasSuited
G
0

may be not useful at this point, but I think that to print directly to a printer you have to find the programming manual and send command escapes.

this kind of printers have his own set of commands and so on, to format, rotate text, print barcode, upload and print image and so on.

Until you don't know the Language and use it correctly the behavior of the printer may be unpredicatable

Geelong answered 31/12, 2012 at 11:47 Comment(2)
Yes what you said is correct. But as I observed ESC|Pos commands are almost equal for most of the POS Devices VIA com port. I have tested on Epson, Bixolon and E-Pos printers. the commands are same.Disconnect
some commands are the same some are different., there's about 20 different "open drawer" commandsAllow
D
-10

I have Found another way, Guyz Please spread the word!

Step1 :

Download the NV Image Software (nv_image_tool_v3.1.6) and Set the Image to The Printer VIA Comport Do these steps as in the image enter image description here

Step 2 : The code to your favourite button:

 private void button1_Click(object sender, EventArgs e)
{
 SerialPort port = new SerialPort("com6", 9100, Parity.None, 8, StopBits.One);
 port.Open();
 ASCIIEncoding ascii = new ASCIIEncoding();
 port.Write(ascii.GetString(new byte[] { 28, 112, 1, 0})); //Printing the Above uploaded Logo
 port.WriteLine("Your Text");
 port.Close();
}
Disconnect answered 31/12, 2012 at 10:59 Comment(5)
Yes this tool makes up the work easy, as we don't need to write code to register the logo into the printer.Disconnect
..yes but this is QA for programming.. not a tutorial site for 3rd party software..Harmsworth
Thanx for your comment buddy. If you know any better way to do it than this please post it here. Any how this is a standard software that most of the printer manufactures provides to make easier the works. Specially bixolon.Disconnect
This is not a very useful answer what if you are in linux or MacOS, a lot of printer manufacturer do not support other OS that is not windows, what if you are in a Android or iOS device?Abdicate
if u r not using windows, still you can set the image once using a windows pc and then print it from a linux or any other os for everUpsydaisy

© 2022 - 2024 — McMap. All rights reserved.