Writing a bitmap to Epson TM88IV through ESC/P commands (Write To NVRam)

Anson picture Anson · Dec 5, 2012 · Viewed 8.7k times · Source

Ref links:

  1. https://lh4.googleusercontent.com/-ceLtiOLVtME/UMBL1yf4RpI/AAAAAAAAAD0/itid5KibW_I/s1015/Doc1.png

  2. https://lh6.googleusercontent.com/-nrphBDA6sjk/UMA_Ukh7ZSI/AAAAAAAAADY/LwjkgobOaBg/s846/MappingTable.png

Updated

I have changed the image convertion by using the LockBits now but failed. Does anyone can give me some suggestion?

    /// <summary>
    /// Orginal command Format in Decimal:
    /// 29[GS], 40[(], 76[L], pL, PH, 48(m), 67[fn], 48[a], kc1, kc2, b, xL, xH, yL, yH, c, [d1 -- dk]
    /// pL = Lower bit of sum of parameters (m to dk) = 11(m to c) + last bit of image
    /// pH = Higher bit of sum of parameters (m to dk) = 11(m to c) + last bit of image
    /// kc = Key Code of NVRam, kc1 = first bit of key code, kc2 = second bit of key code. P.S.: The key code will be hardcode H1.
    /// b = number of colors = 1
    /// xL & xH = Lower bit of image width, e.g. Width = 128 = 0x0080 then xL = 0x80, xH = 0x00
    /// </summary>
    /// <param name="pLogo"></param>
    public void LoadImageToPrinter(Bitmap pLogo)
    {
        BitmapData oBmpData = pLogo.LockBits(new Rectangle(0, 0, pLogo.Width, pLogo.Height), ImageLockMode.ReadOnly, pLogo.PixelFormat);

        //The list contains all the commands in Decimal format
        List<int> oCommandList = new List<int>();

        //k = (int((xL + xH × 256) + 7)/8) × (yL + yH × 256)

        string HexValueOfX = pLogo.Width.ToString("X4");
        string HexValueOfY = pLogo.Height.ToString("X4");

        //k
        int oExpectedImageByteCount = Math.Abs(oBmpData.Stride) * pLogo.Height;

        //Total bit used for parameters
        int oTotalParameterBitCount = 11 + oExpectedImageByteCount;

        //The hex value for the oTotalParameterBitCount
        string oTotalParameterBitCountInHex = oTotalParameterBitCount.ToString("X4").PadLeft(4, '0');

        //GS, (, L
        oCommandList.AddRange(new int[] { 29, 40, 76 });

        //pL
        oCommandList.Add(GetLowerHexValue(oTotalParameterBitCountInHex));

        //pH
        oCommandList.Add(GetHigherHexValue(oTotalParameterBitCountInHex));

        //m,  fn, a,  kc1, kc2, b
        oCommandList.AddRange(new int[] { 48, 67, 48, (int)'H', (int)'1', 1 });

        //xL, xH
        oCommandList.AddRange(new int[] { GetLowerHexValue(HexValueOfX), GetHigherHexValue(HexValueOfX) });

        //yL, yH, c
        oCommandList.AddRange(new int[] { GetLowerHexValue(HexValueOfY), GetHigherHexValue(HexValueOfY), 49 });

        //Append the image bit to the List
        byte[] oImageByte = new byte[oExpectedImageByteCount];
        IntPtr oPtr = oBmpData.Scan0;
        Marshal.Copy(oPtr, oImageByte, 0, oExpectedImageByteCount);
        pLogo.UnlockBits(oBmpData);

        //Clear NVRam
        mThermalPrinterLibrary.Write(new int[] { 29, 40, 76, 5, 0, 48, 65, 67, 76, 82 }.IntArrayToCharString());

        //Store graphics data
        mThermalPrinterLibrary.Write(oCommandList.ToArray().IntArrayToCharString());
        mThermalPrinterLibrary.Write(oImageByte);

        //Print the graphics data
        mThermalPrinterLibrary.Write(new int[] { 29, 40, 76, 6, 0, 48, 69, (int)'H', (int)'1', 1, 1 }.IntArrayToCharString());        
}

Answer

Joe picture Joe · Dec 5, 2012

I've done this before many years ago, in C. I don't have the code to hand, but it's more than just a snippet. To do this you will need to do the following.

  • Understand the BMP file format - assuming you're reading your Bitmap from a file.

  • Look at WINGDI.H (Microsoft Windows SDK) which has C-style definitions of the file headers etc: BITMAPFILEHEADER, BITMAPCOREHEADER, BITMAPINFOHEADER.

  • Process the headers to determine if the bitmap meets your requirement (for example, to simplify your processing, you might want to insist that the bitmap is exactly 128 x 98 (BITMAPINFOHEADER.biWidth, BITMAPINFOHEADER.biHeight), has one plane (BITMAPINFOHEADER.biPlanes = 1), is monochrome (BITMAPINFOHEADER.biBitCount =1 ), is not compressed (BITMAPINFOHEADER.biCompression = 0). These restrictions aren't absolutely necessary, but will simplify your processing.

  • Process the pixel array, and convert it to the format required for the ESCPOS escape sequence.

Alternatively, you might want to abandon using ESCPOS, and instead use OPOS / UPOS / POS for .NET, which provides a higher-level API for accessing POS peripherals: the POSPrinter device exposes a method to print a bitmap, and avoids you needing to do the format conversion yourself. You'll need to download the Epson OPOS ADK to do this. Good luck!

UPDATE

And the document from EPSON just like hell, doesn't understand what it needs.

What's your difficulty with the document from Epson? Maybe you could try asking specific questions about the bits you don't understand.

UPDATE 2

Here are some pointers:

  • GS ( L pL pH m fn [params] : pL and pH are the low- and high-order bytes of a 16-bit integer value that specifies the length in bytes of the following data (i.e. m fn [params]).

  • For fn = 67 (Define NV data raster format), the format is GS ( L pL pH m fn a kc1 kc2 b xL xH yL yH [c d1...dk]1...[c d1...dk]b where m = 48, fn = 67, a = 48.

  • kc1 and kc2 are key codes used to identify the downloaded data when you print it

  • b specifies the number of colors for the downloaded data, 1 for monochrome, 2 for two-color.

  • xL and xH are low- and high-order bytes of a 16-bit integer value that defines the width in dots (pixels) of the image.

  • yL and yH are low- and high-order bytes of a 16-bit integer value that defines the height in dots (pixels) of the image.

  • For a monochrome bitmap there will be one block c d1 ... dk that specifies the color c and the pixel data. For color bitmaps, there is one block c d1 ... dk per color.

  • The pixel data d1 ... dk has k bytes where k = (width x (height+7))/8. A bit set to 1 means print that dot (pixel).

I don't know if the above is any clearer to you than the notes in the Epson documentation; if not say which bits you don't understand.

UPDATE 3

Here's an example based on a 128 width x 98 height bitmap as indicated in your question, monochrome for simplicity.

  • You'll need k = (int(width + 7)/8) × (height) = (int(128+7)/8) x 98 = 16 x 98 = 1568 bytes of pixel data (bit = 1 means dot printed): d1 to d1568

  • Assume color c = Color 1 = 49 decimal = 0x31 hex (could also be 0x32 or 0x33)

  • Width = 128 = 0x0080, so xH = 0x00, xL = 0x80

  • Height = 98 = 0x0062, so yH = 0x00, yL = 0x62

  • b = number of colors = 1

  • Assume your key is "H1", i.e. kc1 = 'H' = 0x48 and kc2 = '1' = 0x31

  • param length = length of m fn a kc1 kc2 b xL xH yL yH c d1 ... d1568 = 11 + 1568 = 1579 = 0x062B hex, so pL = 0x2B, pH = 0x06.

So the data you send will be:

GS ( L pL pH m fn a kc1 kc2 b xL xH yL yH c d1...d1568

In Hex:

1D 28 4C 2B 06 30 43 30 48 31 01 80 00 62 00 31 d1 ... d1568