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.

Nasif
  • 447
  • 1
  • 5
  • 9
  • 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. – Hans Passant Dec 31 '12 at 09:06
  • 5
    There is a very similar question here http://stackoverflow.com/questions/14530058/how-can-i-print-an-image-on-a-bluetooth-printer-in-android. As such, I nominate this question for re-opening, because it is demonstrably not too localized – Andrew Alcock May 23 '13 at 08:26
  • 2
    wish I could vote for reopening this question... too localized sounds like a joke :o – Dominique Nov 12 '14 at 20:05
  • 1
    I believe it is a valid question too – AaA Mar 13 '18 at 02:33

3 Answers3

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;
        }
    }
avivklas
  • 565
  • 7
  • 13
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

Luca Morelli
  • 2,530
  • 3
  • 28
  • 45
  • 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. – Nasif Dec 31 '12 at 13:27
  • some commands are the same some are different., there's about 20 different "open drawer" commands – Jasen Jan 28 '15 at 03:37
-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();
}
Nasif
  • 447
  • 1
  • 5
  • 9
  • Yes this tool makes up the work easy, as we don't need to write code to register the logo into the printer. – Nasif Dec 31 '12 at 11:20
  • 1
    ..yes but this is QA for programming.. not a tutorial site for 3rd party software.. – Simon Whitehead Dec 31 '12 at 11:22
  • 1
    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. – Nasif Dec 31 '12 at 11:25
  • 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? – Necronet Nov 11 '13 at 23:22
  • 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 ever – kuma DK Aug 15 '21 at 00:58