content: /*
   * Copyright (C) 2015 AlexMofer
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.am.printer;
  
  /**
   * ESC-POS Commands
   * Created by Alex on 2017/11/1.
   */
  @SuppressWarnings("WeakerAccess")
  public class PrintCommands {
  
      private static final byte DLE = 16;
      private static final byte ESC = 27;
      private static final byte FS = 28;
      private static final byte GS = 29;
  
      /**
       * Moves the print position to the next tab position.
       * HT
       *
       * @return command
       */
      public static byte[] horizontalTab() {
          return new byte[]{9};
      }
  
      /**
       * Prints the data in the print buffer and feeds one line based on the current line spacing.
       * LF
       *
       * @return command
       */
      public static byte[] printLineFeed() {
          return new byte[]{10};
      }
  
      /**
       * When automatic line feed is enabled, this command functions the same as LF;
       * when automatic line feed is disabled, this command is ignored.
       * CR
       *
       * @return command
       */
      public static byte[] printCarriageReturn() {
          return new byte[]{13};
      }
  
      /**
       * Prints the data in the print buffer and returns to standard mode.
       * FF
       *
       * @return command
       */
      public static byte[] printReturnStandardMode() {
          return new byte[]{12};
      }
  
      /**
       * In page mode, delete all the print data in the current printable area.
       * CAN
       *
       * @return command
       */
      public static byte[] cancelPrintData() {
          return new byte[]{24};
      }
  
      /**
       * Transmits the selected printer status specified by n in real-time,
       * according to the following parameters:
       * n=1 : Transmit printer status
       * n=2 : Transmit off-line status
       * n=3 : Transmit error status
       * n=4 : Transmit paper roll sensor status
       * DLE EOT n
       *
       * @param n 1≤n≤4
       * @return command
       */
      public static byte[] realTimeStatusTransmission(int n) {
          return new byte[]{DLE, 4, (byte) n};
      }
  
      /**
       * Responds to a request from the host computer.
       * n specifies the requests as follows:
       * n=1 : Recover from an error and restart printing from the line where the error occurred
       * n=2 : Recover from an error aft clearing the receive and print buffers
       * DLE ENQ n
       *
       * @param n 1≤n≤2
       * @return command
       */
      public static byte[] realTimeRequestToPrinter(int n) {
          return new byte[]{DLE, 5, (byte) n};
      }
  
      /**
       * Outputs the pulse specified by t to connector pin m as follows:
       * m=0 : Drawer kick-out connector pin 2.
       * m=1 : Drawer kick-out connector pin 5.
       * The pulse ON time is [ t x 100 ms] and the OFF time is [ t x 100 ms].
       * DLE DC4 n m t
       *
       * @param n n=1
       * @param m m=0,1
       * @param t 1≤t≤8
       * @return command
       */
      public static byte[] generatePulseAtRealTime(int n, int m, int t) {
          return new byte[]{DLE, 20, (byte) n, (byte) m, (byte) t};
      }
  
      /**
       * In page mode, prints all buffered data in the printable area collectively.
       * ESC FF
       *
       * @return command
       */
      public static byte[] printData() {
          return new byte[]{ESC, 12};
      }
  
      /**
       * Sets the character spacing for the right side of the character to
       * [n x horizontal or vertical motion units].
       * ESC SP n
       *
       * @param n 0≤n≤255 default 0
       * @return command
       */
      public static byte[] setRightSideCharacterSpacing(int n) {
          return new byte[]{ESC, 32, (byte) n};
      }
  
      /**
       * Selects print mode(s) using n as follows:
       * n=0 : Character font A (12x24)
       * Emphasized mode not selected.
       * Double-height mode not selected.
       * Double-width mode not selected.
       * Underline mode not selected.
       * n=1 : Character font B (9x24)
       * n=8 : Emphasized mode selected.
       * n=16 : Double-height mode selected.
       * n=32 : Double-width mode selected.
       * n=128 : Underline mode selected.
       * ESC ! n
       *
       * @param n 0≤n≤255 default 0
       * @return command
       */
      public static byte[] selectPrintMode(int n) {
          return new byte[]{ESC, 33, (byte) n};
      }
  
      /**
       * Sets the distance from the beginning of the line to the position at which subsequent
       * characters are to be printed.
       * The distance from the beginning of the line to the print position is
       * [(nL + nH x 256) x (vertical or horizontal motion unit)] inches.
       * ESC $ nL nH
       *
       * @param nL 0≤nL≤255
       * @param nH 0≤nH≤255
       * @return command
       */
      public static byte[] setAbsolutePrintPosition(int nL, int nH) {
          return new byte[]{ESC, 36, (byte) nL, (byte) nH};
      }
  
      /**
       * Cancels the user-defined character set.
       * ESC % n
       *
       * @return command
       */
      public static byte[] cancelUserDefinedCharacterSet() {
          return new byte[]{ESC, 37, 0};
      }
  
      /**
       * Selects the user-defined character set.
       * ESC % n
       *
       * @return command
       */
      public static byte[] selectUserDefinedCharacterSet() {
          return new byte[]{ESC, 37, 1};
      }
  
      /**
       * Defines user-defined characters
       * y specifies the number of bytes in the vertical direction, it always 3.
       * c1 specifies the beginning character code for the definition, and c2 specifies the final code.
       * X specifies the number of dots in the horizontal direction.
       * ESC & y c1 c2 [x1 d1…d(y x x1)]..[ xk d1..d(y x xk)]
       *
       * @param c1   32≤c1≤c2≤126
       * @param c2   32≤c1≤c2≤126
       * @param dots 0 ≤ x ≤ 12 Font A (when font A (12 x 24) is selected)
       *             0 ≤ x ≤ 9 Font B (when font B (9 x 17) is selected)
       *             0 ≤ d1 ... d(y x xk) ≤ 255
       * @return command
       */
      public static byte[] defineUserDefinedCharacters(int c1, int c2, byte[] dots) {
          byte[] part = new byte[]{ESC, 38, 3, (byte) c1, (byte) c2};
          byte[] destination = new byte[part.length + dots.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(dots, 0, destination, part.length, dots.length);
          return destination;
      }
  
      /**
       * Selects a bit-image mode using m for the number of dots specified by nL and nH, as follows:
       * m=0
       * Mode:8-dot single-density
       * Vertical NO. of Dots:8
       * Vertical Dot Density: 60 DPI
       * Horizontal Dot Density: 90 DPI
       * Number of (Data(K)):nL + nH x 256
       * m=1
       * Mode:8-dot double-density
       * Vertical NO. of Dots:8
       * Vertical Dot Density: 60 DPI
       * Horizontal Dot Density: 180 DPI
       * Number of (Data(K)):nL + nH x 256
       * m=32
       * Mode:24-dot single-density
       * Vertical NO. of Dots:24
       * Vertical Dot Density: 180 DPI
       * Horizontal Dot Density: 90 DPI
       * Number of (Data(K)):(nL + nH x 256) x 3
       * m=33
       * Mode:24-dot single-density
       * Vertical NO. of Dots:24
       * Vertical Dot Density: 180 DPI
       * Horizontal Dot Density: 180 DPI
       * Number of (Data(K)):(nL + nH x 256) x 3
       * ESC * m nL nH [d1...dk]
       *
       * @param m     m = 0, 1, 32, 33
       * @param nL    0≤nL ≤255
       * @param nH    0≤nH ≤3
       * @param image 0≤d≤255
       * @return command
       */
      public static byte[] selectBitImageMode(int m, int nL, int nH, byte[] image) {
          byte[] part = new byte[]{ESC, 42, (byte) m, (byte) nL, (byte) nH};
          byte[] destination = new byte[part.length + image.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(image, 0, destination, part.length, image.length);
          return destination;
      }
  
      /**
       * Turns underline mode off
       * ESC - n
       *
       * @return command
       */
      public static byte[] turnUnderlineModeOff() {
          return new byte[]{ESC, 45, 0};
      }
  
      /**
       * Turns underline mode on or off, based on the following values of n.
       * n=0, 48 : Turns off underline mode
       * n=1, 49 : Turns on underline mode (1-dot thick)
       * n=2, 50 : Turns on underline mode (2-dots thick)
       * ESC - n
       *
       * @param n 0≤n ≤2, 48≤n ≤50
       * @return command
       */
      public static byte[] turnUnderlineMode(int n) {
          return new byte[]{ESC, 45, 1};
      }
  
      /**
       * Selects approximately 4.23 mm {1/6"} spacing.
       * ESC 2
       *
       * @return command
       */
      public static byte[] selectDefaultLineSpacing() {
          return new byte[]{ESC, 50};
      }
  
      /**
       * Sets the line spacing to [n x (vertical or horizontal motion unit)] inches.
       * ESC 3 n
       *
       * @param n 0≤n≤255
       * @return command
       */
      public static byte[] setLineSpacing(int n) {
          return new byte[]{ESC, 51, (byte) n};
      }
  
      /**
       * Selects device to which host computer sends data, using n as follows:
       * n=0 : Printer disabled
       * n=1 : Printer enabled
       * ESC = n
       *
       * @param n 1≤n≤255 default 1
       * @return command
       */
      public static byte[] setPeripheralDevice(int n) {
          return new byte[]{ESC, 61, (byte) n};
      }
  
      /**
       * Cancels user-defined characters.
       * ESC ? n
       *
       * @param n 32 ≤n ≤126
       * @return command
       */
      public static byte[] cancelUserDefinedCharacters(int n) {
          return new byte[]{ESC, 63, (byte) n};
      }
  
      /**
       * Clears the data in the print buffer and resets the printer mode to the mode
       * that was in effect when the power was turned on.
       * ESC @
       *
       * @return command
       */
      public static byte[] initializePrinter() {
          return new byte[]{ESC, 64};
      }
  
      /**
       * Set is horizontal tab positions.
       * n specifies the column number for setting a horizontal tab position from the beginning of the line.
       * k indicates the total number of horizontal tab positions to be set.
       * ESC D [n1...nk] NUL
       *
       * @param nk 1≤n ≤255
       *           0≤k ≤32
       * @return command
       */
      public static byte[] setHorizontalTabPositions(byte[] nk) {
          byte[] part = new byte[]{ESC, 68};
          byte[] destination = new byte[part.length + nk.length + 1];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(nk, 0, destination, part.length, nk.length);
          destination[part.length + nk.length] = 0;
          return destination;
      }
  
      /**
       * Turns emphasized mode off.
       * ESC E n
       *
       * @return command
       */
      public static byte[] turnOffEmphasizedMode() {
          return new byte[]{ESC, 69, 0};
      }
  
      /**
       * Turns emphasized mode on.
       * ESC E n
       *
       * @return command
       */
      public static byte[] turnOnEmphasizedMode() {
          return new byte[]{ESC, 69, 1};
      }
  
      /**
       * Turns double-strike mode on or off.
       * When the LSB of n is 0, double-strike mode is turned off.
       * When the LSB of n is1, double-strike mode is turned on.
       * ESC G n
       *
       * @param n 0≤n≤255 default 0
       * @return command
       */
      public static byte[] turnDoubleStrikeMode(int n) {
          return new byte[]{ESC, 71, (byte) n};
      }
  
      /**
       * Prints the data in the print buffer and feeds the paper [n x vertical or horizontal motion unit].
       * ESC J n
       *
       * @param n 0≤n ≤255
       * @return command
       */
      public static byte[] printFeedPaper(int n) {
          return new byte[]{ESC, 74, (byte) n};
      }
  
      /**
       * Switches from standard mode to page mode.
       * ESC L
       *
       * @return command
       */
      public static byte[] selectPageMode() {
          return new byte[]{ESC, 76};
      }
  
      /**
       * Selects character fonts
       * n=0, 48 : Character font A (12 X 24 ) Selected
       * n=1, 49 : Character font B (9 X 24 ) Selected
       * ESC M n
       *
       * @param n n= 0, 1 , 48, 49
       * @return command
       */
      public static byte[] selectCharacterFont(int n) {
          return new byte[]{ESC, 77, (byte) n};
      }
  
      /**
       * Selects an international character set n from the following:
       * n=0 : U. S. A
       * n=1 : France
       * n=2 : Germany
       * n=3 : U. K.
       * n=4 : Denmark I
       * n=5 : Sweden
       * n=6 : Italy
       * n=7 : Spain I
       * n=8 : Japan
       * n=9 : Norway
       * n=10 : Denmark II
       * n=11 : Spain II
       * n=12 : Latin America
       *
       * @param n 0≤n≤13 default 0
       * @return command
       */
      public static byte[] selectAnInternationalCharacterSet(int n) {
          return new byte[]{ESC, 82, (byte) n};
      }
  
      /**
       * Switches from page mode to standard mode.
       * ESC S
       *
       * @return command
       */
      public static byte[] selectStandardMode() {
          return new byte[]{ESC, 83};
      }
  
      /**
       * Select the print direction and starting position in page mode.
       * n specifies the print direction and starting position as follows:
       * n=0, 48 : Left to right(Print Direction) Upper left(Starting Position)
       * n=1, 49 : Bottom to top(Print Direction) Lower left(Starting Position)
       * n=2, 50 : Right to left(Print Direction) Lower right(Starting Position)
       * n=3, 51 : Top to bottom(Print Direction) Upper right(Starting Position)
       * ESC T n
       *
       * @param n 0≤n ≤3,
       *          48≤n ≤51
       * @return command
       */
      public static byte[] selectPrintDirectionInPageMode(int n) {
          return new byte[]{ESC, 84, (byte) n};
      }
  
      /**
       * Turns 90˚ clockwise rotation mode on or off.
       * n is used as follows:
       * n=0, 48 : Turns off 90˚ clockwise rotation mode
       * n=1, 49 : Turns on 90˚ clockwise rotation mode
       * ESC V n
       *
       * @param n 0≤n≤1,48≤n≤49 default 0
       * @return command
       */
      public static byte[] turn90ClockwiseRotationMode(int n) {
          return new byte[]{ESC, 86, (byte) n};
      }
  
      /**
       * The horizontal starting position, vertical starting position, printing area
       * width, and printing area height are defined as x0, y0, dx, dy,
       * respectively.
       * Each setting for the printable area is calculated as follow:
       * x0 = [(xL + xH x 256) x (horizontal motion unit)]
       * y0 = [(yL + yH x 256) x (vertical motion unit)]
       * dx = [(dxL + dxH x 256) x (horizontal motion unit)]
       * dy = [(dyL + dyH x 256) x (vertical motion unit)]
       * ESC W xL xH yL yH dxL dxH dyL dyH
       *
       * @param xL  0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param xH  0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param yL  0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param yH  0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param dxL 0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param dxH 0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param dyL 0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       * @param dyH 0≤ xL xH yL yH dxL dxH dyL dyH ≤255 (except dxL=dxH=0 or dyL=dyH=0)
       *            default xL = xH = yL = yH = 0, dxL = 0, dxH = 2, dyL =126, dyH = 6
       * @return command
       */
      public static byte[] setPrintingAreaInPageMode(int xL, int xH, int yL, int yH,
                                                     int dxL, int dxH, int dyL, int dyH) {
          return new byte[]{ESC, 87, (byte) xL, (byte) xH, (byte) yL, (byte) yH,
                  (byte) dxL, (byte) dxH, (byte) dyL, (byte) dyH};
      }
  
      /**
       * Sets the print starting position based on the current position by using the horizontal or vertical motion unit.
       * This command sets the distance from the current position to [(nL+ nH x 256) x (horizontal or vertical unit)].
       * ESC \ nL nH
       *
       * @param nL 0≤nL≤255
       * @param nH 0≤nH≤255
       * @return command
       */
      public static byte[] setRelativePrintPosition(int nL, int nH) {
          return new byte[]{ESC, 92, (byte) nL, (byte) nH};
      }
  
      /**
       * Aligns all the data in one line to the specified position
       * n selects the justification as follows:
       * n=0,48 : Left justification
       * n=1,49 : Centering
       * n=2,50 : Right justification
       * ESC a n
       *
       * @param n 0≤n≤2,48≤n≤50 default 0
       * @return command
       */
      public static byte[] selectJustification(int n) {
          return new byte[]{ESC, 97, (byte) n};
      }
  
      /**
       * Selects the paper sensor(s) to output paper end signals.
       * Each bit of n is used as follows:
       * n=0 : Paper roll near-end sensor disabled / Paper roll end sensor disabled
       * n=1,2 : Paper roll near-end sensor enabled
       * n=4,8 : Paper roll end sensor enabled
       * ESC c 3 n
       *
       * @param n 0≤n≤255 default 15
       * @return command
       */
      public static byte[] selectPaperSensorToOutputPaperEndSignals(int n) {
          return new byte[]{ESC, 99, 51, (byte) n};
      }
  
      /**
       * Selects the paper sensor(s) used to stop printing when a paper-end is detected.
       * using n as follows:
       * n=0 : Paper roll near end sensor disabled
       * n=1,2 : Paper roll near end sensor enabled
       * ESC c 4 n
       *
       * @param n 0≤n≤255 default 0
       * @return command
       */
      public static byte[] selectPaperSensorToStopPrinting(int n) {
          return new byte[]{ESC, 99, 52, (byte) n};
      }
  
      /**
       * Disables the panel buttons.
       * ESC c 5 n
       *
       * @return command
       */
      public static byte[] disablePanelButtons() {
          return new byte[]{ESC, 99, 53, 0};
      }
  
      /**
       * Enables the panel buttons.
       * ESC c 5 n
       *
       * @return command
       */
      public static byte[] enablePanelButtons() {
          return new byte[]{ESC, 99, 53, 1};
      }
  
      /**
       * Prints the data in the print buffer and feeds n lines.
       * ESC d n
       *
       * @param n 0≤n ≤255
       * @return command
       */
      public static byte[] printFeedNLines(int n) {
          return new byte[]{ESC, 100, (byte) n};
      }
  
      /**
       * When this command is received, paper is cut (only when the auto cutter is loaded).
       * ESC i
       *
       * @return command
       */
      public static byte[] executePaperFullCut() {
          return new byte[]{ESC, 105};
      }
  
      /**
       * When this command is received, paper is cut (only when the auto cutter is loaded).
       * ESC m
       *
       * @return command
       */
      public static byte[] executePaperPartialCut() {
          return new byte[]{ESC, 109};
      }
  
      /**
       * Outputs the pulse specified by t1 and t2 to connector pin m as follows:
       * m=0,48 : Drawer kick-out connector pin2.
       * m=1,49 : Drawer kick-out connector pin5.
       * ESC p m t1 t2
       *
       * @param m  m = 0, 1, 48, 49
       * @param t1 0≤t1≤255
       * @param t2 0≤t2≤255
       * @return command
       */
      public static byte[] generatePulse(int m, int t1, int t2) {
          return new byte[]{ESC, 112, (byte) m, (byte) t1, (byte) t2};
      }
  
      /**
       * Selects a page n from the character code table.
       * n=0 : PC437 [U.S.A., Standard Europe]
       * n=1 : Katakana
       * n=2 : PC850 [Multilingual]
       * n=3 : PC860 [Portuguese]
       * n=4 : PC863 [Canadian-French]
       * n=5 : PC865 [Nordic]
       * n=17 : PC866 [Cyrillic #2]
       * n=255 : Space page
       * ESC t n
       *
       * @param n 0≤n≤5, 16≤n≤26, n=255 default 0
       * @return command
       */
      public static byte[] selectCharacterCodeTable(int n) {
          return new byte[]{ESC, 116, (byte) n};
      }
  
      /**
       * Turns upside-down printing mode off.
       * ESC { n
       *
       * @return command
       */
      public static byte[] turnsOffUpsideDownPrintingMode() {
          return new byte[]{ESC, 123, 0};
      }
  
      /**
       * Turns upside-down printing mode on.
       * ESC { n
       *
       * @return command
       */
      public static byte[] turnsOnUpsideDownPrintingMode() {
          return new byte[]{ESC, 123, 1};
      }
  
      /**
       * Prints a NV bit image n using the mode specified by m.
       * m=0,48 : Normal Mode Vertical=180dpi Horizontal=180dpi
       * m=1,49 : Double-width Mode Vertical=180dpi Horizontal=90dpi
       * m=2,50 : Double-height Mode Vertical=90dpi Horizontal=180dpi
       * m=3,51 : Quadruple Mode Vertical=90dpi Horizontal=90dpi
       * FS p n m
       *
       * @param n 1≤n≤255
       * @param m 0≤m≤3, 48≤m≤51
       * @return command
       */
      public static byte[] printNVBitImage(int n, int m) {
          return new byte[]{FS, 112, (byte) n, (byte) m};
      }
  
      /**
       * Define the NV bit image specified by n.
       * FS q n [xL xH yL yH d1...dk] 1...[xL xH yL yH d1...dk]n
       *
       * @param n     1≤n≤255
       * @param image 0≤xL≤255
       *              0≤xH≤3 (when 1≤(xL + xH x 256)≤1023)
       *              0≤yL≤255
       *              0≤yL≤1 (when 1≤(yL + yH x 256)≤288)
       *              0≤d≤255
       *              k = (xL + xH x 256) x (yL + yH x 256) x 8
       *              Total defined data area = 2M bits (256K bytes)
       * @return command
       */
      public static byte[] defineNVBitImage(int n, byte[] image) {
          byte[] part = new byte[]{FS, 113, (byte) n};
          byte[] destination = new byte[part.length + image.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(image, 0, destination, part.length, image.length);
          return destination;
      }
  
      /**
       * Selects the character height using bits 0 to 3 and selects the character width using bits
       * 4 to 7, as follows:
       * 0-3bit:
       * n=0 : height = 1(normal)
       * n=1 : height = 2(double-height)
       * n=2 : height = 3
       * n=3 : height = 4
       * n=4 : height = 5
       * n=5 : height = 6
       * n=6 : height = 7
       * n=7 : height = 8
       * 4-7bit:
       * n=0 : height = 1(normal)
       * n=1 : height = 2(double-width)
       * n=2 : height = 3
       * n=3 : height = 4
       * n=4 : height = 5
       * n=5 : height = 6
       * n=6 : height = 7
       * n=7 : height = 8
       * GS ! n
       *
       * @param n 0≤n≤255(1≤vertical number of times≤8, 1≤horizontal number of times≤8) default 0
       * @return command
       */
      public static byte[] selectCharacterSize(int n) {
          return new byte[]{GS, 33, (byte) n};
      }
  
      /**
       * Sets the absolute vertical print starting position for buffer character data in page mode.
       * This command sets the absolute print position to [ (nL + nH x 256) x (vertical or horizontal
       * motion unit)] inches.
       * If the [ (nL + nH x 256) x (vertical or horizontal motion unit)] exceeds the specified
       * printing area, this command is ignored.
       * The horizontal starting buffer position does not move.
       * The reference starting position is that specified by ESC T.
       * This command operates as follows, depending on the starting position of the printing area
       * specified by ESC T:
       * 1. When the starting position is set to the upper left or lower right, this command sets the
       * absolute position in the vertical direction.
       * 2. When the starting position is set to the upper right or lower left, this command sets the
       * absolute position in the horizontal direction.
       * The horizontal and vertical motion units are specified by GS P.
       * The GS P command can change the horizontal and vertical motion unit.
       * However, the value cannot be less than the minimum horizontal movement amount, and it must be
       * in even units of the minimum horizontal movement amount.
       * GS $ nL nH
       *
       * @param nL 0≤nL≤255
       * @param nH 0≤nH≤255
       * @return command
       */
      public static byte[] setAbsoluteVerticalPrintPositionInPageMade(int nL, int nH) {
          return new byte[]{GS, 36, (byte) nL, (byte) nH};
      }
  
      /**
       * Defines a downloaded bit image with the number of dots specified by x and y.
       * x indicates the number of dots in the horizontal direction.
       * y indicates he number of dots in the vertical direction.
       * GS * x y d1...d (x x y x 8)
       *
       * @param x     1≤n≤255
       * @param y     1≤n≤255
       * @param image x x y≤1536
       *              0≤d≤255
       * @return command
       */
      public static byte[] defineDownloadedBitImage(int x, int y, byte[] image) {
          byte[] part = new byte[]{GS, 42, (byte) x, (byte) y};
          byte[] destination = new byte[part.length + image.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(image, 0, destination, part.length, image.length);
          return destination;
      }
  
      /**
       * Prints a downloaded bit image using the mode specified by m.
       * m selects a mode from the table below:
       * m=0,48 : Normal Mode Vertical=180dpi Horizontal=180dpi
       * m=1,49 : Double-width Mode Vertical=180dpi Horizontal=90dpi
       * m=2,50 : Double-height Mode Vertical=90dpi Horizontal=180dpi
       * m=3,51 : Quadruple Mode Vertical=90dpi Horizontal=90dpi
       * GS / m
       *
       * @param m 0≤m≤3, 48≤m≤51
       * @return command
       */
      public static byte[] printDownloadedBitImage(int m) {
          return new byte[]{GS, 47, (byte) m};
      }
  
      /**
       * Starts or ends macro definition.
       * GS :
       *
       * @return command
       */
      public static byte[] startOrEndMacroDefinition() {
          return new byte[]{GS, 58};
      }
  
      /**
       * Turns off white/black reverse printing mode.
       * GS B n
       *
       * @return command
       */
      public static byte[] turnOffWhiteBlackReversePrintingMode() {
          return new byte[]{GS, 66, 0};
      }
  
      /**
       * Turns on white/black reverse printing mode.
       * GS B n
       *
       * @return command
       */
      public static byte[] turnOnWhiteBlackReversePrintingMode() {
          return new byte[]{GS, 66, 1};
      }
  
      /**
       * Selects the printing position of HRI characters when printing a bar code.
       * n selects the printing position as follows:
       * m=0,48 : Not printed
       * m=1,49 : Above the bar code
       * m=2,50 : Below the bar code
       * m=3,51 : Both above and below the bar code
       * GS H n
       *
       * @param n 0≤m≤3, 48≤m≤51 default 0
       * @return command
       */
      public static byte[] selectPrintingPositionOfHRICharacters(int n) {
          return new byte[]{GS, 72, (byte) n};
      }
  
      /**
       * Sets the left margin using nL and nH.
       * The left margin is set to [(nL + nH x 256) x (horizontal motion unit)] inches.
       * GS L nL nH
       *
       * @param nL 0≤nL≤255 default 0
       * @param nH 0≤nH≤255 default 0
       * @return command
       */
      public static byte[] setLeftMargin(int nL, int nH) {
          return new byte[]{GS, 76, (byte) nL, (byte) nH};
      }
  
      /**
       * Sets the horizontal and vertical motion units to 1/x inch and 1/y inch, respectively.
       * When x and u are set to 0, the default setting of each value is used. (x = 180, y = 360)
       * GS P x y
       *
       * @param x 0≤x≤255 default 180
       * @param y 0≤y≤255 default 360
       * @return command
       */
      public static byte[] setHorizontalAndVerticalMotionUnits(int x, int y) {
          return new byte[]{GS, 80, (byte) x, (byte) y};
      }
  
      /**
       * Selects a mode for cutting paper and executes paper cutting. The value of m selects the mode
       * as follows:
       * m=1,49 : Partial cut(one point center uncut)
       * m=66 : Feeds paper(cutting position + [n x(vertical motion unit)]) ,
       * and cuts the paper partially(one point center uncut)
       * GS V m
       * GS V m n
       *
       * @param m m=1,49,66
       * @param n 0≤n≤255
       * @return command
       */
      public static byte[] selectCutModeAndCutPaper(int m, int n) {
          if (m == 66) {
              return new byte[]{GS, 86, 66, (byte) n};
          } else {
              return new byte[]{GS, 86, (byte) m};
          }
      }
  
      /**
       * Sets the printing area width to the area specified by nL and nH.
       * The printing area width is set to [( nL + nH x 256) x horizontal motion
       * unit]].
       * GS W nL nH
       *
       * @param nL 0≤nL≤255 default 0
       * @param nH 0≤nH≤255 default 2
       * @return command
       */
      public static byte[] setPrintingAreaWidth(int nL, int nH) {
          return new byte[]{GS, 87, (byte) nL, (byte) nH};
      }
  
      /**
       * Sets the relative vertical print starting position from the current position in page mode.
       * This command sets the distance from the current position to [( nL + nH x 256) vertical or
       * horizontal motion unit] inches.
       * GS \ nL nH
       *
       * @param nL 0≤nL≤255
       * @param nH 0≤nH≤255
       * @return command
       */
      public static byte[] setRelativeVerticalPrintPositionInPageMode(int nL, int nH) {
          return new byte[]{GS, 92, (byte) nL, (byte) nH};
      }
  
      /**
       * Executes a macro.
       * r specifies the number of times to execute the macro.
       * t specifies the waiting time for executing the macro.
       * m specifies macro executing mode.
       * When the LSB of m = 0:
       * The macro executes r times continuously at the interval specified by t.
       * When the LSB of m = 1:
       * After waiting for the period specified by t, the PAPER OUT LED indicators blink and the
       * printer waits for the FEED button to be pressed. After the button is pressed, the printer
       * executes the macro once. The printer repeats the operation r times.
       * GS ^ r t m
       *
       * @param r 0≤r≤255
       * @param t 0≤t≤255
       * @param m m=0,1
       * @return command
       */
      public static byte[] executeMacro(int r, int t, int m) {
          return new byte[]{GS, 94, (byte) r, (byte) t, (byte) m};
      }
  
      /**
       * Enables or disables ASB and specifies the status items to include, using n as follows:
       * bit=0,n=0 : Drawer kick-out connector pin 3 status disabled.
       * bit=0,n=1 : Drawer kick-out connector pin 3 status enabled.
       * bit=1,n=0 : On-line/off-line status disabled.
       * bit=1,n=2 : On-line/off-line status enabled,
       * bit=2,n=0 : Error status disabled.
       * bit=2,n=4 : Error status enabled.
       * bit=3,n=0 : Paper roll sensor status disabled.
       * bit=3,n=8 : Paper roll sensor status enabled.
       * GS a n
       *
       * @param n 0≤n≤255 default 0
       * @return command
       */
      public static byte[] setAutomaticStatusBack(int n) {
          return new byte[]{GS, 97, (byte) n};
      }
  
      /**
       * selects a font for the HRI characters used when printing a bar code.
       * n selects the font from the following table:
       * n=0,48 : Font A (12 x 24)
       * n=1,49 : Font B (9 x 24)
       * GS f n
       *
       * @param n n = 0, 1, 48, 49
       * @return command
       */
      public static byte[] selectFontForHumanReadableInterpretationCharacters(int n) {
          return new byte[]{GS, 102, (byte) n};
      }
  
      /**
       * Select the height of the bar code.
       * n specifies the number of dots in the vertical direction.
       * GS h n
       *
       * @param n 1≤n≤255 default 162
       * @return command
       */
      public static byte[] selectBarCodeHeight(int n) {
          return new byte[]{GS, 104, (byte) n};
      }
  
      /**
       * Selects a bar code system and prints the bar code.
       * m selects a bar code system as follows:
       * m=0 : UPC–A 11≤k≤12 48≤d≤57
       * m=1 : UPC–E 11≤k≤12 48≤d≤57
       * m=2 : EAN13 12≤k≤13 48≤d≤57
       * m=3 : EAN8 7≤k≤8 48≤d≤57
       * m=4 : CODE39 1≤k 48≤d≤57,65≤d≤90,32,36,37,43,45,46,47
       * m=5 : ITF 1≤k(even number) 48≤d≤57
       * m=6 : CODABAR 1≤k 48≤d≤57,65≤d≤68,36,43,45,46,47,58
       * m=65 : UPC–A 11≤k≤12 48≤d≤57
       * m=66 : UPC–E 11≤k≤12 48≤d≤57
       * m=67 : EAN13 12≤k≤13 48≤d≤57
       * m=68 : EAN8 7≤k≤8 48≤d≤57
       * m=69 : CODE39 1≤k≤255 48≤d≤57,65≤d≤90,32,36,37,43,45,46,47
       * m=70 : ITF 1≤k≤255(even number) 48≤d≤57
       * m=71 : CODABAR 1≤k≤255 48≤d≤57,65≤d≤68,36,43,45,46,47,58
       * m=72 : CODE93 1≤k≤255 0≤d≤127
       * m=73 : CODE128 2≤k≤255 0≤d≤127
       * GS k m d1…dk NUL
       * GS k m n d1…dn
       *
       * @param m    0≤m≤6
       *             65≤m≤73
       * @param n    n and d depends on the code system used
       * @param data k and d depends on the code system used
       * @return command
       */
      public static byte[] printBarCode(int m, int n, byte[] data) {
          if (m <= 6) {
              byte[] part = new byte[]{GS, 107, (byte) m};
              byte[] destination = new byte[part.length + data.length + 1];
              System.arraycopy(part, 0, destination, 0, part.length);
              System.arraycopy(data, 0, destination, part.length, data.length);
              destination[part.length + data.length] = 0;
              return destination;
          } else {
              byte[] part = new byte[]{GS, 107, (byte) m, (byte) n};
              byte[] destination = new byte[part.length + data.length];
              System.arraycopy(part, 0, destination, 0, part.length);
              System.arraycopy(data, 0, destination, part.length, data.length);
              return destination;
          }
      }
  
      /**
       * Transmits the status specified by n as follows:
       * n=1,49 : Transmits paper sensor status
       * n=2,50 : Transmits drawer kick-out connector status
       * GS r n
       *
       * @param n n=1, 2, 49, 50
       * @return command
       */
      public static byte[] transmitStatus(int n) {
          return new byte[]{GS, 114, (byte) n};
      }
  
      /**
       * Selects Raster bit-image mode.
       * The value of m selects the mode, as follows:
       * m=0,48 : Normal Mode Vertical=180dpi Horizontal=180dpi
       * m=1,49 : Double-width Mode Vertical=180dpi Horizontal=90dpi
       * m=2,50 : Double-height Mode Vertical=90dpi Horizontal=180dpi
       * m=3,51 : Quadruple Mode Vertical=90dpi Horizontal=90dpi
       * xL, xH, select the number of data bytes (xL+xHx256) in the horizontal direction for the bit
       * image.
       * yL, yH, select the number of data bytes (xL+xHx256) in the vertical direction for the bit
       * image.
       * GS v 0 m xL xH yL yH d1....dk
       *
       * @param m     0≤m≤3, 48≤m≤51
       * @param xL    0≤xL≤255
       * @param xH    0≤xH≤255
       * @param yL    0≤yL≤255
       * @param yH    0≤yH≤8
       * @param image 0≤d≤255
       *              k=(xL + xH x 256) x (yL + yH x 256) (k≠0)
       * @return command
       */
      public static byte[] printRasterBitImage(int m, int xL, int xH, int yL, int yH, byte[] image) {
          byte[] part = new byte[]{GS, 118, 48, (byte) m, (byte) xL, (byte) xH, (byte) yL, (byte) yH};
          byte[] destination = new byte[part.length + image.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(image, 0, destination, part.length, image.length);
          return destination;
      }
  
      /**
       * Set the horizontal size of the bar code.
       * n specifies the bar code width as follows:
       * n=2 :
       * 0.282mm (Module width for Mult-level Bar code),
       * 0.282mm (Thin element width),
       * 0.706mm (Thick element width)
       * n=3 :
       * 0.423mm (Module width for Mult-level Bar code),
       * 0.423mm (Thin element width),
       * 1.129mm (Thick element width)
       * n=4 :
       * 0.564mm (Module width for Mult-level Bar code),
       * 0.564mm (Thin element width),
       * 1.411mm (Thick element width)
       * n=5 :
       * 0.706mm (Module width for Mult-level Bar code),
       * 0.706mm (Thin element width),
       * 1.834mm (Thick element width)
       * n=6 :
       * 0.847mm (Module width for Mult-level Bar code),
       * 0.847mm (Thin element width),
       * 2.258mm (Thick element width)
       * Multi-level bar codes are as follows:
       * UPC-A, UPC-E, JAN13 (EAN13), JAN8 (EAN8), CODE93, CODE128
       * Binary-level bar codes are as follows: CODE39, ITF, CODABAR
       * GS w n
       *
       * @param n 2≤n≤6
       * @return command
       */
      public static byte[] setBarCodeWidth(int n) {
          return new byte[]{GS, 119, (byte) n};
      }
  
      /**
       * Selects the model for QR Code.
       * (pL + pH x 256) = 4 (pL=4, pH=0)
       * cn = 49
       * fn = 65
       * n1 Function
       * 49 Selects model 1.
       * 50 Selects model 2.
       * GS ( k pL pH cn fn n1 n2
       *
       * @param n1 n1 = 49,50
       * @param n2 n2 = 0
       * @return command
       */
      public static byte[] selectQRCodeModel(int n1, int n2) {
          return new byte[]{GS, 40, 107, 4, 0, 49, 65, (byte) n1, (byte) n2};
      }
  
      /**
       * Sets the size of the module for QR Code to n dots.
       * GS ( k pL pH cn fn n
       *
       * @param n (pL + pH x 256) = 3 (pL=3, pH=0)
       *          cn = 49
       *          fn = 67
       * @return command
       */
      public static byte[] setQRCodeSizeOfModule(int n) {
          return new byte[]{GS, 40, 107, 3, 0, 49, 67, (byte) n};
      }
  
      /**
       * Selects the error correction level for QR code.
       * n     fuction                             Recovery Capacity %(approx.)
       * 48    Selects Error correction level L    7
       * 49    Selects Error correction level M    15
       * 50    Selects Error correction level Q    25
       * 51    Selects Error correction level H    30
       * (pL + pH x 256) = 3 (pL=3, pH=0)
       * cn = 49
       * fn = 69
       * GS ( k pL pH cn fn n
       *
       * @param n 47<n<52
       * @return command
       */
      public static byte[] selectQRCodeErrorCorrectionLevel(int n) {
          return new byte[]{GS, 40, 107, 3, 0, 49, 69, (byte) n};
      }
  
      /**
       * Store the QR Code symbol data (d1…dk) in the symbol storage area.
       * cn = 49
       * fn = 80
       * m = 48
       * GS ( k pL pH cn fn m d1…dk
       *
       * @param pL   0≤pL<256,
       * @param pH   0≤pH<28
       * @param data 0≤d < 255
       *             k = (pL + pH* 256) - 3
       * @return command
       */
      public static byte[] storeQRCodeDataInTheSymbolStorageArea(int pL, int pH, byte[] data) {
          byte[] part = new byte[]{GS, 40, 107, (byte) pL, (byte) pH, 49, 80, 48};
          byte[] destination = new byte[part.length + data.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(data, 0, destination, part.length, data.length);
          return destination;
      }
  
      /**
       * Encodes and prints the QR Code symbol data in the symbol storage area using the process of
       * <Store the data >.
       * (pL + pH x 256) = 3 (pL=3, pH=0)
       * cn = 49
       * fn = 81
       * m = 48
       * GS ( k pL pH cn fn m
       *
       * @return command
       */
      public static byte[] printQRCodeSymbolDataInTheSymbolStorageArea() {
          return new byte[]{GS, 40, 107, 3, 0, 49, 81, 48};
      }
  
      /**
       * Sets the number of columns of the data area for PDF417.
       * n = 0 specifies automatic processing.
       * (pL + pH x 256) = 3 (pL=3, pH=0)
       * cn = 48
       * fn = 65
       * GS ( k pL pH cn fn n
       *
       * @param n 0≤n≤30
       * @return command
       */
      public static byte[] setNumberOfColumnsOfTheDataAreaForPDF417(int n) {
          return new byte[]{GS, 40, 107, 3, 0, 48, 65, (byte) n};
      }
  
      /**
       * Sets the number of rows of data area for PDF417.
       * n = 0 specifies automatic processing.
       * (pL + pH x 256) = 3 (pL=3, pH=0)
       * cn = 48
       * fn = 66
       * GS ( k pL pH cn fn n
       *
       * @param n n=0, 3≤n≤90
       * @return command
       */
      public static byte[] setNumberOfRowsOfDataAreaForPDF417(int n) {
          return new byte[]{GS, 40, 107, 3, 0, 48, 66, (byte) n};
      }
  
      /**
       * Sets the module width of one PDF417 symbol to n dots.
       * (pL + pH x 256) = 3 (pL=3, pH=0)
       * cn = 48
       * fn = 67
       * GS ( k pL pH cn fn n
       *
       * @param n 2≤n≤8
       * @return command
       */
      public static byte[] setModuleWidthOfOnePDF417SymbolDots(int n) {
          return new byte[]{GS, 40, 107, 3, 0, 48, 67, (byte) n};
      }
  
      /**
       * Sets the module height to [(module width) × n].
       * (pL + pH x 256) = 3 (pL=3, pH=0)
       * cn = 48
       * fn = 68
       * GS ( k pL pH cn fn n
       *
       * @param n 2≤n≤8
       * @return command
       */
      public static byte[] setPDF417ModuleHeight(int n) {
          return new byte[]{GS, 40, 107, 3, 0, 48, 68, (byte) n};
      }
  
      /**
       * Sets the error correction level for PDF417 symbols.
       * (pL + pH x 256) = 4 (pL=4, pH=0)
       * cn = 48
       * fn = 69
       * GS ( k pL pH cn fn m n
       *
       * @param m m = 48,49
       * @param n 48≤n≤56 (when m=48 is specified)
       *          1≤n≤40 (when m=49 is specified)
       * @return command
       */
      public static byte[] setErrorCorrectionLevelForPDF417Symbols(int m, int n) {
          return new byte[]{GS, 40, 107, 4, 0, 48, 69, (byte) m, (byte) n};
      }
  
      /**
       * Stores symbol data (d1...dk) in the PDF417 symbol storage area.
       * Bytes of ((pL + pH × 256) - 3) after m (d1…dk) are processed as symbol data.
       * 4≤(pL + pH x 256) ≤65535 (0≤pL≤255, 0≤pH≤255)
       * cn = 48
       * fn = 80
       * m = 48
       * GS ( k pL pH cn fn m d1…dk
       *
       * @param pL   0≤pL≤255
       * @param pH   0≤pH≤255
       * @param data 0≤d≤255
       *             k = (pL + pH*256) - 3
       * @return command
       */
      public static byte[] storeSymbolDataInThePDF417SymbolStorageArea(int pL, int pH, byte[] data) {
          byte[] part = new byte[]{GS, 40, 107, (byte) pL, (byte) pH, 48, 80, 48};
          byte[] destination = new byte[part.length + data.length];
          System.arraycopy(part, 0, destination, 0, part.length);
          System.arraycopy(data, 0, destination, part.length, data.length);
          return destination;
      }
  
      /**
       * Prints the PDF417 symbol data in the symbol storage area.
       * (pL + pH* 256) = 4 (pL=4, pH=0)
       * cn = 48
       * fn = 81
       * m = 48
       * GS ( k pL pH cn fn m
       *
       * @return command
       */
      public static byte[] printPDF417SymbolDataInTheSymbolStorageArea() {
          return new byte[]{GS, 40, 107, 4, 0, 48, 81, 48};
      }
  }
  