PrinterPort.java
     1: //========================================================================================
     2: //  Printer.java
     3: //    en:Printer Port -- (under construction)
     4: //    ja:プリンタポート -- (工事中)
     5: //  Copyright (C) 2003-2017 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  http://stdkmd.com/xeij/
    11: //========================================================================================
    12: 
    13: package xeij;
    14: 
    15: import java.awt.*;  //BasicStroke,BorderLayout,BoxLayout,Color,Component,Container,Cursor,Desktop,Dimension,Font,FlowLayout,Frame,Graphics,Graphics2D,GraphicsDevice,GraphicsEnvironment,GridLayout,Image,Insets,Paint,Point,Rectangle,RenderingHints,Robot,Shape,Stroke,TexturePaint,Toolkit
    16: import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    17: import java.awt.image.*;  //BufferedImage,DataBuffer,DataBufferByte,DataBufferInt,IndexColorModel
    18: import java.io.*;  //BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter,ByteArrayOutputStream,File,FileInputStream,FileNotFoundException,FileReader,InputStream,InputStreamReader,IOException,OutputStreamWriter,RandomAccessFile,UnsupportedEncodingException
    19: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    20: import javax.imageio.*;  //IIOImage,ImageIO,ImageTypeSpecifier,ImageWriter
    21: import javax.imageio.metadata.*;  //IIOMetadata,IIOMetadataNode
    22: import javax.imageio.stream.*;  //ImageOutputStream
    23: import javax.swing.*;  //AbstractButton,AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JComponent,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    24: import javax.swing.event.*;  //CaretEvent,CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener
    25: import java.util.*;  //ArrayList,Arrays,Calendar,Collections,GregorianCalendar,HashMap,Iterator,Map,Map.Entry,TimeZone,Timer,TimerTask,TreeMap
    26: import java.util.regex.*;  //Matcher,Pattern
    27: 
    28: 
    29: //----------------------------------------------------------------------------------------
    30: //!!! 工事中
    31: //----------------------------------------------------------------------------------------
    32: //
    33: //  プリンタポート
    34: //    0x00e8c001  bit7-0  write  DATA    プリンタデータ
    35: //    0x00e8c003  bit0    write  STROBE  0→1=プリンタデータ受け取り指示
    36: //    0x00e9c001  bit0    write  INTEN   0=プリンタ割り込み禁止,1=プリンタ割り込み許可。INTENが1でREADYが0→1のとき割り込みがかかる
    37: //                bit5    read   READY   0=プリンタビジー,1=プリンタレディ。逆に書かれている資料があるので注意
    38: //                                       STROBEの0→1から0.5μs以内にREADYが1→0になる
    39: //                                       プリンタが次のデータを受け取る準備ができるとREADYが0→1になる
    40: //    0x00e9c003  bit7-2  write  VECTOR  割り込みベクタ番号
    41: //
    42: //  プリンタ出力手順
    43: //    準備
    44: //      (1)0x00e9c003(VECTOR)に割り込みベクタ番号0x63&0xfc=0x60を設定する
    45: //      (2)0x00e9c001のbit0(INTEN)を1にする
    46: //    ループ
    47: //      (3)プリンタ割り込みを待つか、0x00e9c001のbit5(READY)が1になるまで待つ
    48: //      (4)0x00e8c001(DATA)にデータをセットする
    49: //      (5)0x00e8c003のbit0(STROBE)を0にする
    50: //      (6)0x00e8c003のbit0(STROBE)を1にする
    51: //      (7)0x00e9c001のbit5(READY)が0になる
    52: //      (8)プリンタがデータを受け取る
    53: //      (9)プリンタが次のデータを受け取る準備ができる
    54: //      (10)0x00e9c001のbit5(READY)が1になる
    55: //      (11)0x00e9c001のbit0(INTEN)が1のときプリンタ割り込みがかかる
    56: //
    57: //----------------------------------------------------------------------------------------
    58: //
    59: //  CZ-8PC4
    60: //    48ドット熱転写カラー漢字プリンタ
    61: //    実機はないがマニュアルがあるのでこれを参考にする
    62: //
    63: //  CZ-8PC5
    64: //    CZ-8PC4の後継機
    65: //    明朝体とゴシック体の切り替えができるらしい
    66: //    Oh!X 1991年3月号に紹介記事
    67: //    詳しい資料がないので保留
    68: //
    69: //  電源スイッチ
    70: //
    71: //  操作パネルのランプ
    72: //    電源ランプ
    73: //      緑点灯  電源ON
    74: //      消灯    電源OFF
    75: //    リボン切れランプ
    76: //      赤点灯  リボン片面終了
    77: //    用紙切れランプ
    78: //      赤点灯  用紙切れ
    79: //    ハガキランプ
    80: //      橙点灯  はがきモードON
    81: //      消灯    はがきモードOFF
    82: //    特殊リボンランプ
    83: //      橙点灯  特殊リボンモード
    84: //    高速ランプ
    85: //      橙点灯  高速印字
    86: //      消灯    標準速度
    87: //    微小送りランプ
    88: //      橙点灯  微小送りモード
    89: //    セレクトランプ
    90: //      緑点灯  セレクト状態
    91: //      消灯    ディセレクト状態
    92: //
    93: //  操作パネルのスイッチ
    94: //    ハガキスイッチ
    95: //      はがきモードのON/OFF
    96: //    特殊リボンスイッチ
    97: //      特殊リボンモードのON/OFF
    98: //    高速スイッチ
    99: //      高速印字と標準速度の切り替え
   100: //    微小送りスイッチ
   101: //      微小送りモードのON/OFF
   102: //    改頁スイッチ
   103: //      微小送りモードのとき
   104: //        順方向に1/180[in]微小送りする
   105: //      さもなくば(微小送りモードでないとき)
   106: //        改頁する
   107: //    改行スイッチ
   108: //      微小送りモードのとき
   109: //        逆方向に1/180[in]微小送りする
   110: //      さもなくば(微小送りモードでないとき)
   111: //        改行する
   112: //    セレクトスイッチ
   113: //      セレクト状態とディセレクト状態の切り替え
   114: //
   115: //  ディップスイッチ
   116: //    電源投入時、INIT信号入力時、ESC c 1実行時の初期値を選択する
   117: //      SW1  ゼロ書体      ON   スラッシュなし
   118: //                         OFF  スラッシュあり(工場出荷時)
   119: //                              パイカ、エリート、縮小、半角に有効
   120: //      SW2  印字速度      ON   高速印字
   121: //                         OFF  標準速度(工場出荷時)
   122: //      SW3  はがきモード  ON   ON
   123: //                         OFF  OFF(工場出荷時)
   124: //      SW4  頁長          ON   12[in]
   125: //                         OFF  11[in](工場出荷時)
   126: //      SW5                OFF  (固定)
   127: //      SW6  給紙位置      ON   8.5mm
   128: //                         OFF  22mm(工場出荷時)
   129: //      SW7                OFF  (固定)
   130: //      SW8                OFF  (固定)
   131: //
   132: //  分解能
   133: //    360[dot/in]
   134: //
   135: //  用紙ガイド
   136: //    用紙ガイドで水平方向の印字開始位置を調節する
   137: //    8[in]の印字領域は動かせないので、幅の異なる用紙(の中央)に印字するために、用紙ガイドを動かして用紙の左端から印字領域までの幅を調節する
   138: //
   139: //  給紙位置と微小送り
   140: //    給紙位置と微小送りで垂直方向の印字開始位置を調節する
   141: //    給紙すると用紙の上端から22[mm]の位置まで送られる。SW6で8.5[mm]に変更できる
   142: //    微小送りモードで用紙を微小送りして印字開始位置を調節する
   143: //    調節後の位置は記憶され、次の用紙を給紙すると調節後の位置まで送られる
   144: //
   145: //  はがきモード
   146: //    はがきモードにすると左マージンと右マージンが自動的に設定される
   147: //    左マージン
   148: //      1.9[in]=684[dot]=48.26[mm]
   149: //    右マージン
   150: //      7.4[in]=2664[dot]=187.96[mm]
   151: //    幅
   152: //      7.4[in]-1.9[in]=5.5[in]=1980[dot]=139.7[mm]
   153: //
   154: //  文字種
   155: //    パイカ
   156: //      10文字/in
   157: //      36dot/文字
   158: //      floor(2880dot/行/36dot/文字)=80文字/行
   159: //      A4縦
   160: //        (210-14-9)/(25.4/10)=73文字/行
   161: //      B5縦
   162: //        (182-13-9)/(25.4/10)=63文字/行
   163: //    エリート
   164: //      12文字/in
   165: //      30dot/文字
   166: //      floor(2880dot/行/30dot/文字)=96文字/行
   167: //      A4縦
   168: //        (210-14-9)/(25.4/12))=88文字/行
   169: //      B5縦
   170: //        (182-13-9)/(25.4/12)=75文字/行
   171: //    縮小
   172: //      17文字/in
   173: //      21dot/文字
   174: //      floor(2880dot/行/21dot/文字)=137文字/行
   175: //      A4縦
   176: //        126文字/行
   177: //      B5縦
   178: //        108文字/行
   179: //    漢字
   180: //      2+48+6=56dot/文字
   181: //      floor(2880dot/行/56dot/文字)=51文字/行
   182: //    半角
   183: //      0+24+4=28dot/文字
   184: //      floor(2880dot/行/28dot/文字)=102文字/行
   185: //      A4縦
   186: //        94文字/行
   187: //      B5縦
   188: //        81文字/行
   189: //    スーパースクリプト、サブスクリプト
   190: //      15文字/in
   191: //      24dot/文字
   192: //      floor(2880dot/行/24dot/文字)=120文字/行
   193: //
   194: //  漢字モード
   195: //    漢字モードOFFのとき
   196: //      1バイトで1文字
   197: //      ANKとみなしてパイカ、エリート、縮小のいずれかで印字する
   198: //    漢字モードONのとき
   199: //      2バイトで1文字
   200: //      1バイト目が0x00のとき
   201: //        2バイト目をANKとみなして半角で印字する
   202: //      さもなくば(1バイト目が0x00でないとき)
   203: //        1バイト目が区(0x21~0x7e)、2バイト目が点(0x21~0x7e)のJISコードとみなして全角で印字する
   204: //
   205: //  黒リボン
   206: //    黒インクが塗布されたインクリボン
   207: //
   208: //  単色カラーリボン
   209: //    赤、青、緑、金、銀などのインクが塗布された単色のインクリボン
   210: //
   211: //  カラーリボン
   212: //    イエロー、マゼンタ、シアンの3色のインクが繰り返し塗布されたインクリボン
   213: //
   214: //  カラーモード
   215: //    カラーリボンをセットしてESC EMでカラーモードにするとCRを出力する度にリボンが送られてイエロー、マゼンタ、シアンの順に色が切り替わる
   216: //    1行分のデータをイエロー、マゼンタ、シアンの順に最大3回繰り返し出力して重ね合わせることで減法混色で7色印字できる
   217: //    色コードを直接指定するコマンドはない
   218: //
   219: //----------------------------------------------------------------------------------------
   220: 
   221: public class PrinterPort {
   222: 
   223: 
   224:   //デバッグ
   225:   public static final boolean PRN_DEBUG_TRACE = false;
   226: 
   227: 
   228:   //接続
   229:   public static final boolean PRN_PRINTER_CONNECTED = true;  //true=プリンタが繋がっている
   230: 
   231: 
   232:   //プリンタポート
   233:   //  プリンタが繋がっていなくてもプリンタポートは存在する
   234:   //  プリンタが繋がっていないときは常にプリンタビシー
   235:   public static final int PRN_DATA   = 0x00e8c001;
   236:   public static final int PRN_STROBE = 0x00e8c003;
   237:   public static int prnData;  //PRN_DATAにwriteされたプリンタデータ
   238:   public static int prnStrobe;  //PRN_STROBEにwriteされたストローブ。0→1のときprnDataがプリンタまたはプリンタアダプタに出力される
   239: 
   240: 
   241:   //プリンタアダプタ
   242:   //  フォントの作成や展開に時間がかかるのでプリンタのスレッドを分ける
   243:   //  プリンタポートとプリンタの間にプリンタアダプタを挟む
   244:   //  データをプリンタに出力する代わりにプリンタアダプタに出力する
   245:   //  プリンタアダプタはプリンタアダプタバッファが一杯になるか一定時間出力がないとき、
   246:   //  プリンタアダプタスレッドでプリンタアダプタタスクを実行する
   247:   //  プリンタアダプタタスクがプリンタにデータを出力する
   248:   //
   249:   //  プリンタアダプタ出力
   250:   //    出力するデータをプリンタアダプタバッファに追加する
   251:   //    プリンタアダプタバッファが一杯にならなかったとき
   252:   //      プリンタアダプタティッカーをキューに入れ(直し)て10ms後に呼び出す
   253:   //    プリンタアダプタバッファが一杯になったとき
   254:   //      プリンタアダプタティッカーがキューにあれば取り除く
   255:   //      プリンタアダプタタスクランチャを呼び出す
   256:   //      プリンタアダプタバッファをクリアする
   257:   //
   258:   //  プリンタアダプタティッカー
   259:   //    プリンタアダプタタスクランチャを呼び出す
   260:   //
   261:   //  プリンタアダプタタスクランチャ
   262:   //    プリンタアダプタバッファのコピーを持ったプリンタアダプタタスクをプリンタアダプタスレッドで実行する
   263:   //
   264:   //  プリンタアダプタタスク
   265:   //    プリンタアダプタバッファのコピーの内容をプリンタに出力する
   266:   //
   267:   public static final boolean PRN_USE_ADAPTER = true;  //プリンタアダプタを使う
   268:   public static final int PRN_ADAPTER_CAPACITY = 1024;  //プリンタアダプタバッファの容量
   269:   public static final long PRN_ADAPTER_DELAY = XEiJ.TMR_FREQ * 10000 / 1000000;  //10ms。プリンタアダプタディレイタイム。プリンタアダプタバッファが一杯にならなくても最後のプリンタアダプタ出力からこの時間が経過したらプリンタアダプタタスクを実行する
   270:   public static byte[] prnAdapterBuffer;  //プリンタアダプタバッファ
   271:   public static int prnAdapterPointer;  //プリンタアダプタバッファの書き込み位置
   272:   public static TickerQueue.Ticker prnAdapterTicker;  //プリンタアダプタティッカー
   273:   public static java.util.Timer prnAdapterTimer;  //プリンタアダプタスレッド。Timerだけだとjavax.swing.Timerと紛らわしい
   274: 
   275:   //prnAdapterInit ()
   276:   //  プリンタアダプタ初期化
   277:   public static void prnAdapterInit () {
   278:     if (PRN_DEBUG_TRACE) {
   279:       System.out.printf ("%08x prnAdapterInit()\n", XEiJ.regPC0);
   280:     }
   281:     prnAdapterBuffer = new byte[PRN_ADAPTER_CAPACITY];  //プリンタアダプタバッファ
   282:     prnAdapterPointer = 0;  //プリンタアダプタバッファの書き込み位置
   283:     prnAdapterTicker = new PrinterAdapterTicker ();  //プリンタアダプタティッカー
   284:     prnAdapterTimer = new java.util.Timer ();  //プリンタアダプタスレッド。Timerだけだとjavax.swing.Timerと紛らわしい
   285:   }  //prnAdapterInit()
   286: 
   287:   //prnAdapterOutput (data)
   288:   //  プリンタアダプタ出力
   289:   public static void prnAdapterOutput (int data) {
   290:     if (PRN_DEBUG_TRACE) {
   291:       System.out.printf ("%08x prnAdapterOutput(0x%02x)\n", XEiJ.regPC0, data & 255);
   292:     }
   293:     //出力するデータをプリンタアダプタバッファに追加する
   294:     prnAdapterBuffer[prnAdapterPointer++] = (byte) data;
   295:     if (prnAdapterPointer < PRN_ADAPTER_CAPACITY) {  //プリンタアダプタバッファが一杯にならなかったとき
   296:       //プリンタアダプタティッカーをキューに入れ(直し)て10ms後に呼び出す
   297:       TickerQueue.tkqAdd (prnAdapterTicker, XEiJ.mpuClockTime + PRN_ADAPTER_DELAY);
   298:     } else {  //プリンタアダプタバッファが一杯になったとき
   299:       //プリンタアダプタティッカーがキューにあれば取り除く
   300:       TickerQueue.tkqRemove (prnAdapterTicker);
   301:       //プリンタアダプタタスクランチャを呼び出す
   302:       prnAdapterTaskLauncher ();
   303:     }
   304:   }  //prnAdapterOutput(int)
   305: 
   306:   //class PrinterAdapterTicker
   307:   //  プリンタアダプタティッカー
   308:   public static class PrinterAdapterTicker extends TickerQueue.Ticker {
   309:     @Override protected void tick () {
   310:       if (PRN_DEBUG_TRACE) {
   311:         System.out.printf ("%08x PrinterAdapterTicker.tick()\n", XEiJ.regPC0);
   312:       }
   313:       //プリンタアダプタタスクランチャを呼び出す
   314:       prnAdapterTaskLauncher ();
   315:     }  //tick()
   316:   };
   317: 
   318:   //prnAdapterTaskLauncher ()
   319:   //  プリンタアダプタタスクランチャ
   320:   public static void prnAdapterTaskLauncher () {
   321:     if (PRN_DEBUG_TRACE) {
   322:       System.out.printf ("%08x prnAdapterTaskLauncher()\n", XEiJ.regPC0);
   323:     }
   324:     //プリンタアダプタバッファをコピーする
   325:     byte[] copiedBuffer = Arrays.copyOf (prnAdapterBuffer, prnAdapterPointer);
   326:     //プリンタアダプタバッファをクリアする
   327:     prnAdapterPointer = 0;
   328:     //プリンタアダプタバッファのコピーを持ったプリンタアダプタタスクをプリンタアダプタスレッドで実行する
   329:     prnAdapterTimer.schedule (new PrinterAdapterTask (copiedBuffer), 100L);  //0Lだとログが重なってしまい読み難い
   330:   }  //prnAdapterTaskLauncher()
   331: 
   332:   //class PrinterAdapterTask
   333:   //  プリンタアダプタタスク
   334:   public static class PrinterAdapterTask extends TimerTask {
   335:     private byte[] buffer;
   336:     public PrinterAdapterTask (byte[] copiedBuffer) {
   337:       if (PRN_DEBUG_TRACE) {
   338:         System.out.printf ("%08x PrinterAdapterTask({", XEiJ.regPC0);
   339:         for (int i = 0; i < copiedBuffer.length; i++) {
   340:           if (0 < i) {
   341:             System.out.print (',');
   342:           }
   343:           System.out.printf ("0x%02x", copiedBuffer[i] & 255);
   344:         }
   345:         System.out.println ("})");
   346:       }
   347:       buffer = copiedBuffer;
   348:     }  //PrinterAdapterTask(byte[])
   349:     @Override public void run () {
   350:       if (PRN_DEBUG_TRACE) {
   351:         System.out.printf ("%08x PrinterAdapterTask.run()\n", XEiJ.regPC0);
   352:       }
   353:       //プリンタアダプタバッファのコピーの内容をプリンタに出力する
   354:       for (int i = 0; i < buffer.length; i++) {
   355:         prnOutput (buffer[i]);
   356:       }
   357:     }  //run()
   358:   }  //class PrinterAdapterTask
   359: 
   360: 
   361:   //プリンタ
   362: 
   363:   //カラーモデル
   364:   //  1dotを1byteで表現する。下位3bitだけ使う
   365:   //    0  0xff000000  ブラック
   366:   //    1  0xff0000ff  ブルー
   367:   //    2  0xff00ff00  ライム
   368:   //    3  0xff00ffff  シアン
   369:   //    4  0xffff0000  レッド
   370:   //    5  0xffff00ff  マゼンタ
   371:   //    6  0xffffff00  イエロー
   372:   //    7  0xffffffff  ホワイト
   373:   //  最初に用紙の全体を7(ホワイト)で塗り潰す
   374:   //  黒リボンのときは0(ブラック)、カラーリボンのときは6(イエロー)、5(マゼンタ)、3(シアン)の順にANDで描画する
   375:   public static IndexColorModel prnImageColorModel;  //カラーモデル
   376: 
   377: 
   378:   //用紙
   379: 
   380:   //  定数
   381:   public static final int PRN_MAX_WIDTH_DOT = 360 * 48;  //印字範囲の最大幅[dot]。B0縦の幅1030[mm]=40.6[in]が収まるサイズ。CZ-8PC4の8[in]の6倍
   382:   public static final int PRN_MAX_HEIGHT_DOT = 360 * 66;  //印字範囲の最大高さ[dot]。B0縦の高さ1456[mm]=57.3[in]が収まるサイズ。CZ-8PC4の11[in]の6倍
   383:   public static final int PRN_MAX_WIDTH_MM = (int) Math.floor ((double) PRN_MAX_WIDTH_DOT * 25.4 / 360.0);  //印字範囲の最大幅[mm]
   384:   public static final int PRN_MAX_HEIGHT_MM = (int) Math.floor ((double) PRN_MAX_HEIGHT_DOT * 25.4 / 360.0);  //印字範囲の最大高さ[mm]
   385: 
   386:   //  列
   387:   public static final int PRN_A_SERIES = 0;  //A列
   388:   public static final int PRN_B_SERIES = 1;  //B列
   389:   public static final int PRN_POSTCARD = 2;  //はがき
   390: 
   391:   //  向き
   392:   public static final int PRN_PORTRAIT  = 0;  //縦
   393:   public static final int PRN_LANDSCAPE = 1;  //横
   394: 
   395:   //class Paper
   396:   //  用紙クラス
   397:   //  参考
   398:   //    https://ja.wikipedia.org/wiki/%E7%B4%99%E3%81%AE%E5%AF%B8%E6%B3%95
   399:   public static class Paper {
   400: 
   401:     //用紙
   402:     public int paperWidthMm;  //用紙の幅[mm]
   403:     public int paperHeightMm;  //用紙の高さ[mm]
   404:     public int paperWidth;  //用紙の幅[dot]
   405:     public int paperHeight;  //用紙の高さ[dot]
   406: 
   407:     //印字不可領域
   408:     //  用紙の端の印字できない部分。ヘッドが移動できない場所
   409:     public int deadLeftMm;  //用紙の左端の印字できない部分の幅[mm]
   410:     public int deadTopMm;  //用紙の上端の印字できない部分の高さ[mm]
   411:     public int deadRightMm;  //用紙の右端の印字できない部分の幅[mm]
   412:     public int deadBottomMm;  //用紙の下端の印字できない部分の高さ[mm]
   413: 
   414:     //印字可能範囲
   415:     //  用紙から印字不可領域を除いた部分。ヘッドが移動できる場所
   416:     //  ヘッドの位置が印字可能範囲の下端からはみ出したら排紙する
   417:     //  印字可能範囲はメニューで直接変更できるので給紙したときコピーしたものを使う
   418:     public int aliveLeftX;  //印字可能範囲の左端の用紙座標[dot]
   419:     public int aliveTopY;  //印字可能範囲の上端の用紙座標[dot]
   420:     public int aliveRightX;  //印字可能範囲の右端の用紙座標[dot]
   421:     public int aliveBottomY;  //印字可能範囲の下端の用紙座標[dot]
   422: 
   423:     //マージン
   424:     public int marginLeftX;  //左マージンの印字可能範囲座標[dot]。初期値は0
   425:     public int marginRightX;  //右マージンの印字可能範囲座標[dot]。初期値は印字可能範囲の幅
   426:     public int marginTopHeight;  //上マージンの高さ[dot]。初期値は0
   427:     public int marginBottomHeight;  //下マージンの高さ[dot]。初期値は0
   428: 
   429:     public String nameEn;  //英語名
   430:     public String nameJa;  //日本語名
   431: 
   432:     public BufferedImage image;  //イメージ
   433:     public byte[] bitmap;  //ビットマップ
   434: 
   435:     //new Paper (series, n, orientation)
   436:     //  コンストラクタ
   437:     //  series       列
   438:     //               PRN_A_SERIES  A列
   439:     //               PRN_B_SERIES  B列
   440:     //               PRN_POSTCARD  はがき
   441:     //  n            サイズ
   442:     //               4  A4またはB4
   443:     //               5  A5またはB5
   444:     //               など
   445:     //  orientation  向き
   446:     //               PRN_PORTRAIT   縦長
   447:     //               PRN_LANDSCAPE  横長
   448:     public Paper (int series, int n, int orientation) {
   449:       if (PRN_DEBUG_TRACE) {
   450:         System.out.printf ("%08x new Paper(%d,%d,%d)\n", XEiJ.regPC0, series, n, orientation);
   451:       }
   452: 
   453:       int narrowMm;  //短辺[mm]
   454:       int longMm;  //長辺[mm]
   455:       String seriesEn;  //列の英語表記
   456:       String seriesJa;  //列の日本語表記
   457:       String orientationEn;  //向きの英語表記
   458:       String orientationJa;  //向きの日本語表記
   459: 
   460:       if (series == PRN_A_SERIES) {  //A列
   461:         narrowMm = (int) Math.floor (1000.0 / Math.pow (2.0, (double) (2 * n + 1) * 0.25) + 0.2);
   462:         longMm = (int) Math.floor (1000.0 / Math.pow (2.0, (double) (2 * n - 1) * 0.25) + 0.2);
   463:         deadLeftMm = 14;
   464:         deadTopMm = 11;  //A4縦210x297に名刺横91x55がちょうど10枚収まる
   465:         deadRightMm = 14;
   466:         deadBottomMm = 11;
   467:         seriesEn = n < 0 ? (1 << -n) + "A0" : "A" + n;
   468:         seriesJa = seriesEn;
   469:       } else if (series == PRN_B_SERIES) {  //B列
   470:         narrowMm = (int) Math.floor (1000.0 * Math.sqrt (3.0) / Math.pow (2.0, (double) (2 * n + 3) * 0.25) + 0.2);
   471:         longMm = (int) Math.floor (1000.0 * Math.sqrt (3.0) / Math.pow (2.0, (double) (2 * n + 1) * 0.25) + 0.2);
   472:         deadLeftMm = 24;
   473:         deadTopMm = 11;
   474:         deadRightMm = 24;
   475:         deadBottomMm = 11;
   476:         seriesEn = n < 0 ? (1 << -n) + "B0" : "B" + n;
   477:         seriesJa = seriesEn;
   478:       } else {  //はがき
   479:         narrowMm = 100;
   480:         longMm = 148;
   481:         deadLeftMm = 3;
   482:         deadTopMm = 10;
   483:         deadRightMm = 3;
   484:         deadBottomMm = 10;
   485:         seriesEn = "Japanese standard postcard";
   486:         seriesJa = "はがき";
   487:       }
   488:       if (orientation == PRN_PORTRAIT) {  //縦長
   489:         paperWidthMm = narrowMm;
   490:         paperHeightMm = longMm;
   491:         orientationEn = "portrait";
   492:         orientationJa = "縦";
   493:       } else {  //横長
   494:         paperWidthMm = longMm;
   495:         paperHeightMm = narrowMm;
   496:         orientationEn = "landscape";
   497:         orientationJa = "横";
   498:       }
   499:       paperWidth = (int) Math.floor ((double) paperWidthMm * (360.0 / 25.4) + 0.5);
   500:       paperHeight = (int) Math.floor ((double) paperHeightMm * (360.0 / 25.4) + 0.5);
   501: 
   502:       aliveLeftX = (int) Math.floor ((double) deadLeftMm * (360.0 / 25.4) + 0.5);
   503:       aliveTopY = (int) Math.floor ((double) deadTopMm * (360.0 / 25.4) + 0.5);
   504:       aliveRightX = (int) Math.floor ((double) (paperWidthMm - deadRightMm) * (360.0 / 25.4) + 0.5);
   505:       aliveBottomY = (int) Math.floor ((double) (paperHeightMm - deadBottomMm) * (360.0 / 25.4) + 0.5);
   506: 
   507:       marginLeftX = 0;
   508:       marginRightX = aliveRightX - aliveLeftX;
   509:       marginTopHeight = 0;
   510:       marginBottomHeight = 0;
   511: 
   512:       nameEn = seriesEn + " " + orientationEn + " " + paperWidthMm + "x" + paperHeightMm;
   513:       nameJa = seriesJa + " " + orientationJa + " " + paperWidthMm + "x" + paperHeightMm;
   514: 
   515:       image = null;
   516:       bitmap = null;
   517: 
   518:     }  //Paper(int,int,boolean)
   519: 
   520:     //paper.getImage ()
   521:     //  イメージを返す
   522:     //  なければ作る
   523:     public BufferedImage getImage () {
   524:       if (PRN_DEBUG_TRACE) {
   525:         System.out.printf ("%08x paper.getImage()\n", XEiJ.regPC0);
   526:       }
   527:       if (image == null) {
   528:         image = new BufferedImage (paperWidth, paperHeight, BufferedImage.TYPE_BYTE_INDEXED, prnImageColorModel);
   529:       }
   530:       return image;
   531:     }  //getImage()
   532: 
   533:     //paper.getBitmap ()
   534:     //  ビットマップを返す
   535:     //  なければ作る
   536:     public byte[] getBitmap () {
   537:       if (PRN_DEBUG_TRACE) {
   538:         System.out.printf ("%08x paper.getBitmap()\n", XEiJ.regPC0);
   539:       }
   540:       if (bitmap == null) {
   541:         bitmap = ((DataBufferByte) getImage ().getRaster ().getDataBuffer ()).getData ();
   542:       }
   543:       return bitmap;
   544:     }  //getBitmap()
   545: 
   546:     //paper.clear ()
   547:     //  白紙にする
   548:     public void clear () {
   549:       if (PRN_DEBUG_TRACE) {
   550:         System.out.printf ("%08x paper.clear()\n", XEiJ.regPC0);
   551:       }
   552:       Arrays.fill (getBitmap (), 0, paperWidth * paperHeight, (byte) 7);  //白で塗り潰す
   553:     }  //clear()
   554: 
   555:     //success = paper.save ()
   556:     //  保存
   557:     public boolean save () {
   558:       if (!XEiJ.prgIsLocal) {  //ローカルでないとき
   559:         return false;  //何もしない
   560:       }
   561:       if (PRN_DEBUG_TRACE) {
   562:         System.out.printf ("%08x paper.save()\n", XEiJ.regPC0);
   563:       }
   564:       //ImageWriterを探す
   565:       //  参考
   566:       //    http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
   567:       //    http://docs.oracle.com/javase/8/docs/api/javax/imageio/metadata/doc-files/standard_metadata.html
   568:       int index = prnSaveName.lastIndexOf ('.');
   569:       if (index < 0) {  //拡張子がないとき
   570:         prnSaveName += ".png";  //pngにする
   571:         index = prnSaveName.lastIndexOf ('.');
   572:       }
   573:       String full = prnSavePath + File.separator + prnSaveName;  //フルパスのファイル名
   574:       File imageFile = new File (full);
   575:       if (imageFile.isFile ()) {  //既に存在するとき
   576:         //ファイルが既に存在するとき読み取り専用属性が付いていないことを確認する
   577:         //  Windows10のエクスプローラの読み取り専用属性は保護機能ではないので無視して上書きできる
   578:         //  canWrite()は読み取り専用属性が付いているとfalseを返す
   579:         //  ファイルが存在するときcanWrite()がtrueでなければ上書きしてはならない
   580:         //  canWrite()は「存在して書き込める」なので!canWrite()は「存在しないか書き込めない」であることに注意
   581:         if (!imageFile.canWrite ()) {  //既に存在するが書き込めないとき
   582:           JOptionPane.showMessageDialog (
   583:             null,
   584:             full + (Multilingual.mlnJapanese ?
   585:                     "\nは既に存在します。上書きできません。" :
   586:                     "\nalreay exists. You cannot overwrite it."));
   587:           return false;
   588:         }
   589:         //上書きしてよいか確認する
   590:         if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog (
   591:           null,
   592:           full + (Multilingual.mlnJapanese ?
   593:                   "\nは既に存在します。上書きしますか?" :
   594:                   "\nalreay exists. Do you want to overwrite it?"),
   595:           Multilingual.mlnJapanese ? "ファイルの上書きの確認" : "Confirmation of overwriting file",
   596:           JOptionPane.YES_NO_OPTION,
   597:           JOptionPane.PLAIN_MESSAGE)) {
   598:           return false;
   599:         }
   600:       }
   601:       BufferedImage image = getImage ();  //保存するイメージ
   602:       for (Iterator<ImageWriter> iterator = ImageIO.getImageWritersBySuffix (prnSaveName.substring (index + 1));
   603:            //拡張子に対応するImageWriterがないときは空のIteratorを返すのでiteratorはnullにならない
   604:            iterator.hasNext (); ) {
   605:         ImageWriter imageWriter = iterator.next ();
   606:         ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam ();
   607:         if (false) {
   608:           if (imageWriteParam.canWriteCompressed ()) {
   609:             imageWriteParam.setCompressionMode (ImageWriteParam.MODE_EXPLICIT);
   610:             imageWriteParam.setCompressionQuality (0.75F);
   611:           }
   612:         }
   613:         IIOMetadata imageMetadata = imageWriter.getDefaultImageMetadata (
   614:           ImageTypeSpecifier.createFromBufferedImageType (image.getType ()),
   615:           imageWriteParam);
   616:         if (imageMetadata.isStandardMetadataFormatSupported ()) {
   617:           //解像度を設定する
   618:           //  PNGファイルの仕様では解像度の単位は[dot/m]だが
   619:           //  javax_imageio_1.0のHorizontalPixelSizeとVerticalPixelSizeの単位は[dot/mm]なので
   620:           //    360[dot/in] → 360/25.4[dot/mm]
   621:           //  とする
   622:           //  これを[dot/m]にしてしまうとペイントのプロパティで360000 DPIなどと表示されておかしなことになる
   623:           IIOMetadataNode rootNode = new IIOMetadataNode ("javax_imageio_1.0");
   624:           IIOMetadataNode dimensionNode = new IIOMetadataNode ("Dimension");
   625:           IIOMetadataNode horizontalPixelSizeNode = new IIOMetadataNode("HorizontalPixelSize");
   626:           IIOMetadataNode verticalPixelSizeNode = new IIOMetadataNode ("VerticalPixelSize");
   627:           horizontalPixelSizeNode.setAttribute ("value", String.valueOf (360.0 / 25.4));
   628:           verticalPixelSizeNode.setAttribute ("value", String.valueOf (360.0 / 25.4));
   629:           dimensionNode.appendChild (horizontalPixelSizeNode);
   630:           dimensionNode.appendChild (verticalPixelSizeNode);
   631:           rootNode.appendChild (dimensionNode);
   632:           try {
   633:             imageMetadata.mergeTree ("javax_imageio_1.0", rootNode);
   634:           } catch (IIOInvalidTreeException iioite) {
   635:             continue;
   636:           }
   637:           imageFile.delete ();
   638:           try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream (imageFile)) {
   639:             imageWriter.setOutput (imageOutputStream);
   640:             imageWriter.write (imageMetadata, new IIOImage (image, null, imageMetadata), imageWriteParam);
   641:           } catch (IOException ioe) {
   642:             continue;
   643:           }
   644:           return true;
   645:         }
   646:       }  //for iterator
   647:       JOptionPane.showMessageDialog (
   648:         null,
   649:         full + (Multilingual.mlnJapanese ?
   650:                 "\nを更新できませんでした。" :
   651:                 "\nwas not updated")
   652:         );
   653:       return false;
   654:     }  //paper.save()
   655: 
   656:   }  //class Paper
   657: 
   658:   public static Paper[] prnPaperArray;  //用紙の配列
   659:   public static Paper prnNextPaper;  //次に給紙する用紙。nullではない
   660:   public static Paper prnCurrentPaper;  //現在の用紙。null=未給紙
   661:   public static boolean prnPrinted;  //false=印字なし,true=印字あり。印字ありのとき排紙するとイメージが保存される
   662: 
   663: 
   664:   //印字可能範囲のコピー
   665:   //  prnNextPaperの印字可能範囲はメニューで変更できる
   666:   //  印字中に印字可能範囲が変わると困るので給紙したときにprnCurrentPaperの印字可能範囲をコピーして使う
   667:   public static int prnAliveLeftX;  //印字可能範囲の左端の用紙座標のコピー[dot]
   668:   public static int prnAliveTopY;  //印字可能範囲の上端の用紙座標のコピー[dot]
   669:   public static int prnAliveRightX;  //印字可能範囲の右端の用紙座標のコピー[dot]
   670:   public static int prnAliveBottomY;  //印字可能範囲の下端の用紙座標のコピー[dot]
   671: 
   672: 
   673:   //設定
   674: 
   675:   //  改行ピッチ
   676:   public static int prnDefaultLineHeight;  //デフォルトの改行ピッチ[dot]。ESC 6で1/6[in]=60[dot]、ESC 8で1/8[in]=45[dot]になる。ESC % 9 0で1/6[in]または1/8[in]に戻すときに使う
   677:   public static int prnLineHeight;  //改行ピッチ[dot]
   678: 
   679:   //  文字種
   680:   public static final int PRN_PICA  = 0;  //パイカ 1/10[in]=36[dot]
   681:   public static final int PRN_ELITE = 1;  //エリート 1/12[in]=30[dot]
   682:   public static final int PRN_SMALL = 2;  //縮小 1/20[in]=18[dot]。隙間が3[dot]あって1/17[in]=21[dot]になる
   683:   public static int prnCharacterType;  //文字種
   684: 
   685:   //  ひらがなモード
   686:   public static boolean prnHiraganaMode;  //false=ひらがなOFF,true=ひらがなON
   687: 
   688:   //  スクリプトモード
   689:   public static final int PRN_NO_SCRIPT    = 0;  //スクリプト解除
   690:   public static final int PRN_SUPER_SCRIPT = 1;  //スーパースクリプト
   691:   public static final int PRN_SUB_SCRIPT   = 2;  //サブスクリプト
   692:   public static int prnScriptMode;  //スクリプトモード
   693: 
   694:   //  強調モード
   695:   public static boolean prnStrongMode;  //false=強調OFF,true=強調ON
   696: 
   697:   //  アンダーラインモード
   698:   public static boolean prnUnderlineMode;  //false=アンダーラインOFF,true=アンダーラインON
   699: 
   700:   //  文字スタイル
   701:   public static final int PRN_NORMAL_STYLE      = 0;  //標準文字
   702:   public static final int PRN_OPEN_STYLE        = 1;  //袋文字
   703:   public static final int PRN_SHADOW_STYLE      = 2;  //影文字
   704:   public static final int PRN_OPEN_SHADOW_STYLE = 3;  //袋影文字
   705:   public static int prnCharacterStyle;  //文字スタイル
   706: 
   707:   //  漢字モード
   708:   public static boolean prnKanjiMode;  //false=漢字モードOFF,true=漢字モードON
   709: 
   710:   //  外字データ
   711:   //    外字定義エリアは0x7621..0x767eと0x7721..0x7726の100文字
   712:   //    ESC c 1でクリアされる
   713:   public static byte[] prnGaijiData = null;
   714: 
   715:   //  縦書きモード
   716:   public static boolean prnVerticalWritingMode;  //false=縦書きOFF,true=縦書きON
   717: 
   718:   //  左右スペース
   719:   public static int prnFullWidthLeftSpace;  //全角左スペース[dot]
   720:   public static int prnFullWidthRightSpace;  //全角右スペース[dot]
   721:   public static int prnHalfWidthLeftSpace;  //半角左スペース[dot]
   722:   public static int prnHalfWidthRightSpace;  //半角右スペース[dot]
   723: 
   724:   //  横2倍モード
   725:   public static boolean prnHorizontalDoubleSizeMode;  //false=横2倍OFF,true=横2倍ON。漢字モードの全角と半角もビットイメージも拡大する
   726:   public static boolean prnVerticalDoubleSizeMode;  //false=縦2倍OFF,true=縦2倍ON。漢字モードの全角と半角もビットイメージも拡大する
   727:   public static boolean prnKanjiHorizontalDoubleSizeMode;  //false=漢字横2倍OFF,true=漢字横2倍ON。漢字モードの全角と半角だけ拡大する
   728: 
   729:   //  水平タブ
   730:   public static final int PRN_HORIZONTAL_ANCHOR_LIMIT = 16;
   731:   public static final int[] prnHorizontalTabAnchor = new int[PRN_HORIZONTAL_ANCHOR_LIMIT];  //水平タブアンカー[dot]
   732: 
   733:   //  垂直タブ
   734:   public static final int PRN_VERTICAL_ANCHOR_LIMIT = 128;
   735:   public static final int[] prnVerticalTabAnchor = new int[PRN_VERTICAL_ANCHOR_LIMIT];  //垂直タブアンカー
   736: 
   737:   //  カラーモード
   738:   public static boolean prnColorMode;  //false=単色,true=カラー
   739:   public static int prnSingleColor;  //単色の色。0=ブラック,1=ブルー,2=ライム,3=シアン,4=レッド,5=マゼンタ,6=イエロー,7=ホワイト
   740:   public static int prnCurrentColor;  //現在の色。0=ブラック,1=ブルー,2=ライム,3=シアン,4=レッド,5=マゼンタ,6=イエロー,7=ホワイト。単色のときprnSingleColorと同じで0~7。カラーのときESC EMで6になりCRで6→5→3→6の順に切り替わる
   741: 
   742:   //ページ範囲
   743:   //  X方向は印字可能範囲の左端から右端まで
   744:   //  Y方向はページ開始位置からページ開始位置+ページ長まで
   745:   //  ページ範囲の下端
   746:   //    ページ開始位置+ページ長
   747:   //    下マージンの基準の位置
   748:   //    改ページの移動先
   749:   //    ページ範囲の下端が印字可能範囲の内側にあるとき
   750:   //      改ページを行うとヘッドがページ範囲の下端に移動してそこが新たなページ開始位置になる
   751:   //    ページ範囲の下端が印字可能範囲の外側にあるとき
   752:   //      改ページを行うとヘッドが印字可能範囲の下端からはみ出して排紙される
   753:   //      次に給紙された用紙の印刷可能範囲の先頭が新たなページ開始位置になる
   754:   //  ページ長
   755:   //    A4縦は上下の印字不可領域が17[mm]までのとき12[in]、18[mm]以上のとき11[in]
   756:   public static int prnPageStart;  //ページ開始位置の印字可能範囲座標[dot]。給紙したとき0
   757:   public static int prnPageLength;  //ページ長[dot]。給紙したとき印字可能範囲の高さを1[in]=360[dot]の倍数に切り上げた値
   758: 
   759:   //コンテント範囲
   760:   //  ページ範囲からマージンを除いた部分
   761:   //  ヘッドの位置がコンテント範囲の下端を超えると改ページされてページ範囲の下端に移動する
   762:   //  ページ範囲の下端が印字可能範囲の下端を超えていれば排紙される
   763:   public static int prnContentTopY;  //コンテント範囲の上端の印字可能範囲座標[dot]。給紙したときページ開始位置+上マージン
   764:   public static int prnContentBottomY;  //コンテント範囲の下端の印字可能範囲座標[dot]。給紙したときページ開始位置+ページ長-下マージン
   765: 
   766:   //ヘッドの位置
   767:   public static int prnHeadX;  //ヘッドX座標[dot]。-1=未給紙。改行したとき左マージン
   768:   public static int prnHeadY;  //ヘッドY座標[dot]。-1=未給紙。改ページしたとき新しいページのコンテント範囲の上端
   769:   public static int prnHeadLine;  //ヘッド行番号。-1=未給紙。改ページしたとき0、改行でインクリメント。垂直タブで使う
   770: 
   771: 
   772:   //コマンドバッファ
   773:   //  先頭の数バイトで長さが確定するコマンド
   774:   //    対応しているコマンドはすべてバッファに収まる
   775:   //  終了コードが出てくるまで長さが分からないコマンド
   776:   //    コマンドがコマンドバッファに収まらないとき
   777:   //      書き込み位置をコマンドバッファの末尾で止めて末尾の1バイト以外のはみ出した部分のデータを無視する
   778:   public static final byte[] prnCommandBuffer = new byte[4 + 6 * PRN_MAX_WIDTH_DOT];  //ESC M n1 n2 d1 d2 … dkの最大幅2880ドット
   779:   public static int prnCommandLength;  //コマンドの長さ。次にコマンドを判別する位置。この位置まではバッファに書き込むだけ。prnCommandBuffer.length以上になることはない
   780:   public static int prnCommandPointer;  //コマンド書き込み位置。prnCommandBufferのサイズを超える場合があるので注意
   781: 
   782: 
   783:   //ウインドウ
   784:   public static ScrollCanvas prnCanvas;  //キャンバス
   785:   public static JFrame prnFrame;  //ウインドウ
   786:   public static int prnScaleShift;  //拡大縮小
   787: 
   788:   //メニュー
   789:   public static int prnSpinnerLocked;
   790:   public static SpinnerNumberModel prnDeadLeftModel;  //用紙の左端の印字できない部分の幅[mm]
   791:   public static SpinnerNumberModel prnDeadTopModel;  //用紙の上端の印字できない部分の高さ[mm]
   792:   public static SpinnerNumberModel prnDeadRightModel;  //用紙の右端の印字できない部分の幅[mm]
   793:   public static SpinnerNumberModel prnDeadBottomModel;  //用紙の下端の印字できない部分の高さ[mm]
   794:   public static NumberSpinner prnDeadLeftSpinner;  //用紙の左端の印字できない部分の幅[mm]
   795:   public static NumberSpinner prnDeadTopSpinner;  //用紙の上端の印字できない部分の高さ[mm]
   796:   public static NumberSpinner prnDeadRightSpinner;  //用紙の右端の印字できない部分の幅[mm]
   797:   public static NumberSpinner prnDeadBottomSpinner;  //用紙の下端の印字できない部分の高さ[mm]
   798:   public static JRadioButtonMenuItem[] prnScaleMenuItem;
   799: 
   800:   //プリンタ出力
   801:   public static boolean prnAutosaveOn;  //true=プリンタ出力を自動保存する
   802:   public static String prnSavePath;  //プリンタ出力を保存するディレクトリのabsoluteパス
   803:   public static String prnSaveName;  //主ファイル名。フルパスのファイル名はprnSavePath+File.separator+prnSaveName
   804:   public static JDialog prnSaveDialog;  //ダイアログ
   805:   public static JFileChooser2 prnSaveFileChooser;  //ファイルチューザー
   806:   public static String[] prnWriterSuffixes;  //出力できるイメージファイルの拡張子の配列
   807:   public static javax.swing.filechooser.FileFilter prnSaveFileFilter;  //プリンタ出力イメージファイルフィルタ
   808:   public static JCheckBox prnAutosaveCheckBox;  //自動保存チェックボックス
   809:   public static JCheckBoxMenuItem prnAutosaveMenuItem;  //自動保存メニューアイテム
   810: 
   811:   //prnInit ()
   812:   //  初期化
   813:   public static void prnInit () {
   814:     if (PRN_DEBUG_TRACE) {
   815:       System.out.printf ("%08x prnInit()\n", XEiJ.regPC0);
   816:     }
   817:     //プリンタポート
   818:     prnReset ();
   819:     if (PRN_PRINTER_CONNECTED) {
   820:       if (PRN_USE_ADAPTER) {
   821:         //プリンタアダプタ
   822:         prnAdapterInit ();
   823:       }
   824:       //カラーモデル
   825:       prnImageColorModel = new IndexColorModel (
   826:         8, 8,
   827:         new byte[] {  0,  0,  0,  0, -1, -1, -1, -1 },  //red
   828:         new byte[] {  0,  0, -1, -1,  0,  0, -1, -1 },  //green
   829:         new byte[] {  0, -1,  0, -1,  0, -1,  0, -1 }  //blue
   830:         );
   831:       //用紙
   832:       prnPaperArray = new Paper[] {
   833:         //縦長
   834:         new Paper (PRN_A_SERIES, 3, PRN_PORTRAIT),  //A3縦
   835:         new Paper (PRN_A_SERIES, 4, PRN_PORTRAIT),  //A4縦
   836:         new Paper (PRN_A_SERIES, 5, PRN_PORTRAIT),  //A5縦
   837:         new Paper (PRN_A_SERIES, 6, PRN_PORTRAIT),  //A6縦
   838:         new Paper (PRN_B_SERIES, 3, PRN_PORTRAIT),  //B3縦
   839:         new Paper (PRN_B_SERIES, 4, PRN_PORTRAIT),  //B4縦
   840:         new Paper (PRN_B_SERIES, 5, PRN_PORTRAIT),  //B5縦
   841:         new Paper (PRN_B_SERIES, 6, PRN_PORTRAIT),  //B6縦
   842:         new Paper (PRN_POSTCARD, 0, PRN_PORTRAIT),  //はがき縦
   843:         //横長
   844:         new Paper (PRN_A_SERIES, 3, PRN_LANDSCAPE),  //A3横
   845:         new Paper (PRN_A_SERIES, 4, PRN_LANDSCAPE),  //A4横
   846:         new Paper (PRN_A_SERIES, 5, PRN_LANDSCAPE),  //A5横
   847:         new Paper (PRN_A_SERIES, 6, PRN_LANDSCAPE),  //A6横
   848:         new Paper (PRN_B_SERIES, 3, PRN_LANDSCAPE),  //B3横
   849:         new Paper (PRN_B_SERIES, 4, PRN_LANDSCAPE),  //B4横
   850:         new Paper (PRN_B_SERIES, 5, PRN_LANDSCAPE),  //B5横
   851:         new Paper (PRN_B_SERIES, 6, PRN_LANDSCAPE),  //B6横
   852:         new Paper (PRN_POSTCARD, 0, PRN_LANDSCAPE),  //はがき横
   853:       };
   854:       prnNextPaper = prnPaperArray[1];  //次に給紙する用紙。A4縦
   855:       prnCurrentPaper = null;  //未給紙
   856:       prnPrinted = false;  //印字なし
   857:       //設定
   858:       prnResetSettings ();
   859:       //出力
   860:       //prnAutosaveOn = false;
   861:       //prnSavePath = ".";
   862:       prnSaveName = "1.png";
   863:     }
   864:   }  //prnInit()
   865: 
   866:   //gaijiData = prnGetGaijiData ()
   867:   //  外字データ
   868:   public static byte[] prnGetGaijiData () {
   869:     if (prnGaijiData == null) {
   870:       prnGaijiData = new byte[6 * 48 * 100];
   871:     }
   872:     return prnGaijiData;
   873:   }  //prnGetGaijiData()
   874: 
   875:   //prnStart ()
   876:   public static void prnStart () {
   877:     if (RestorableFrame.rfmGetOpened (Settings.SGS_PRN_FRAME_KEY)) {
   878:       prnOpen ();
   879:     }
   880:   }  //prnStart()
   881: 
   882:   //prnOpen ()
   883:   //  ウインドウを開く
   884:   public static void prnOpen () {
   885:     if (prnFrame == null) {
   886:       prnMakeFrame ();
   887:     }
   888:     prnFrame.setVisible (true);
   889:   }  //prnOpen()
   890: 
   891:   //prnMakeFrame ()
   892:   //  ウインドウを作る
   893:   //  ここでは開かない
   894:   public static void prnMakeFrame () {
   895: 
   896:     //キャンバス
   897:     prnScaleShift = 0;
   898:     prnCanvas = new ScrollCanvas (prnCurrentPaper == null ? null : prnCurrentPaper.getImage ());
   899:     prnCanvas.setMatColor (new Color (LnF.LNF_RGB[10]));
   900: 
   901:     //アクションリスナー
   902:     ActionListener listener = new ActionListener () {
   903:       @Override public void actionPerformed (ActionEvent ae) {
   904:         Object source = ae.getSource ();
   905:         String command = ae.getActionCommand ();
   906:         switch (command) {
   907:         case "Eject":  //排紙
   908:           if (PRN_USE_ADAPTER) {
   909:             //!!! 印刷中に操作すると制御コードの途中に改ページコードが混ざることになる
   910:             prnAdapterTimer.schedule (new PrinterAdapterTask (new byte[] { 0x1a, 0x0c }), 0L);
   911:           }
   912:           break;
   913:         case "Destroy":  //破棄
   914:           if (PRN_USE_ADAPTER) {
   915:             //!!! 印刷中に操作すると制御コードの途中に改行コードが混ざることになる
   916:             prnAdapterTimer.schedule (new PrinterAdapterTask (new byte[] { 0x1a, 0x1a, 0x1a, 0x0c }), 0L);
   917:           }
   918:           break;
   919:         case "Reset":  //リセット
   920:           if (PRN_USE_ADAPTER) {
   921:             //!!! 印刷中に操作すると制御コードの途中に改行コードが混ざることになる
   922:             prnAdapterTimer.schedule (new PrinterAdapterTask (new byte[] { 0x1a, 0x1a, 0x1b, 'c', '1' }), 0L);
   923:           }
   924:           break;
   925:         case "Autosave":  //自動保存
   926:           prnSetAutosaveOn (((JCheckBoxMenuItem) source).isSelected ());
   927:           break;
   928:         case "Close":  //閉じる
   929:           prnFrame.setVisible (false);
   930:           break;
   931:         case "Black ink ribbon":  //黒色インクリボン
   932:           prnSetSingleColor (0);
   933:           break;
   934:         case "Blue ink ribbon":  //青色インクリボン
   935:           prnSetSingleColor (1);
   936:           break;
   937:         case "Lime ink ribbon":  //緑色インクリボン
   938:           prnSetSingleColor (2);
   939:           break;
   940:         case "Cyan ink ribbon":  //水色インクリボン
   941:           prnSetSingleColor (3);
   942:           break;
   943:         case "Red ink ribbon":  //赤色インクリボン
   944:           prnSetSingleColor (4);
   945:           break;
   946:         case "Magenta ink ribbon":  //紫色インクリボン
   947:           prnSetSingleColor (5);
   948:           break;
   949:         case "Yellow ink ribbon":  //黄色インクリボン
   950:           prnSetSingleColor (6);
   951:           break;
   952:         case "White ink ribbon":  //白色インクリボン
   953:           prnSetSingleColor (7);
   954:           break;
   955:         case "6.25%":
   956:           prnCanvas.setScaleShift (-4);
   957:           break;
   958:         case "12.5%":
   959:           prnCanvas.setScaleShift (-3);
   960:           break;
   961:         case "25%":
   962:           prnCanvas.setScaleShift (-2);
   963:           break;
   964:         case "50%":
   965:           prnCanvas.setScaleShift (-1);
   966:           break;
   967:         case "100%":
   968:           prnCanvas.setScaleShift (0);
   969:           break;
   970:         case "200%":
   971:           prnCanvas.setScaleShift (1);
   972:           break;
   973:         case "400%":
   974:           prnCanvas.setScaleShift (2);
   975:           break;
   976:         case "800%":
   977:           prnCanvas.setScaleShift (3);
   978:           break;
   979:         case "1600%":
   980:           prnCanvas.setScaleShift (4);
   981:           break;
   982:         default:
   983:           for (Paper paper : prnPaperArray) {
   984:             if (paper.nameEn.equals (command)) {
   985:               prnNextPaper = paper;
   986:               prnSpinnerLocked++;
   987:               prnDeadLeftModel.setMaximum (new Integer (paper.paperWidthMm - 1 - paper.deadRightMm));
   988:               prnDeadTopModel.setMaximum (new Integer (paper.paperHeightMm - 1 - paper.deadBottomMm));
   989:               prnDeadRightModel.setMaximum (new Integer (paper.paperWidthMm - 1 - paper.deadLeftMm));
   990:               prnDeadBottomModel.setMaximum (new Integer (paper.paperHeightMm - 1 - paper.deadTopMm));
   991:               prnDeadLeftModel.setValue (new Integer (paper.deadLeftMm));
   992:               prnDeadTopModel.setValue (new Integer (paper.deadTopMm));
   993:               prnDeadRightModel.setValue (new Integer (paper.deadRightMm));
   994:               prnDeadBottomModel.setValue (new Integer (paper.deadBottomMm));
   995:               prnSpinnerLocked--;
   996:               break;
   997:             }
   998:           }
   999:         }
  1000:       }
  1001:     };
  1002: 
  1003:     //用紙メニュー
  1004:     ButtonGroup paperGroup = new ButtonGroup ();
  1005:     JMenu portraitMenu = Multilingual.mlnText (ComponentFactory.createMenu ("Portrait", 'P'), "ja", "縦長");
  1006:     JMenu landscapeMenu = Multilingual.mlnText (ComponentFactory.createMenu ("Landscape", 'L'), "ja", "横長");
  1007:     for (int i = 0; i < prnPaperArray.length; i++) {
  1008:       Paper paper = prnPaperArray[i];
  1009:       (i < prnPaperArray.length >> 1 ? portraitMenu : landscapeMenu).add (
  1010:         Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (
  1011:           paperGroup, paper == prnNextPaper, paper.nameEn, listener), "ja", paper.nameJa));
  1012:     }
  1013:     //  印字不可領域
  1014:     prnSpinnerLocked = 0;
  1015:     prnDeadLeftModel = new SpinnerNumberModel (
  1016:       prnNextPaper.deadLeftMm, 0, prnNextPaper.paperWidthMm - 1 - prnNextPaper.deadRightMm, 1);
  1017:     prnDeadTopModel = new SpinnerNumberModel (
  1018:       prnNextPaper.deadTopMm, 0, prnNextPaper.paperHeightMm - 1 - prnNextPaper.deadBottomMm, 1);
  1019:     prnDeadRightModel = new SpinnerNumberModel (
  1020:       prnNextPaper.deadRightMm, 0, prnNextPaper.paperWidthMm - 1 - prnNextPaper.deadLeftMm, 1);
  1021:     prnDeadBottomModel = new SpinnerNumberModel (
  1022:       prnNextPaper.deadBottomMm, 0, prnNextPaper.paperHeightMm - 1 - prnNextPaper.deadTopMm, 1);
  1023:     prnDeadLeftSpinner = ComponentFactory.createNumberSpinner (prnDeadLeftModel, 4, new ChangeListener () {
  1024:       @Override public void stateChanged (ChangeEvent ce) {
  1025:         if (prnSpinnerLocked == 0) {
  1026:           prnNextPaper.deadLeftMm = prnDeadLeftModel.getNumber ().intValue ();
  1027:           prnDeadRightModel.setMaximum (new Integer (prnNextPaper.paperWidthMm - 1 - prnNextPaper.deadLeftMm));
  1028:         }
  1029:       }  //stateChanged(ChangeEvent)
  1030:     });
  1031:     prnDeadTopSpinner = ComponentFactory.createNumberSpinner (prnDeadTopModel, 4, new ChangeListener () {
  1032:       @Override public void stateChanged (ChangeEvent ce) {
  1033:         if (prnSpinnerLocked == 0) {
  1034:           prnNextPaper.deadTopMm = prnDeadTopModel.getNumber ().intValue ();
  1035:           prnDeadBottomModel.setMaximum (new Integer (prnNextPaper.paperHeightMm - 1 - prnNextPaper.deadTopMm));
  1036:         }
  1037:       }  //stateChanged(ChangeEvent)
  1038:     });
  1039:     prnDeadRightSpinner = ComponentFactory.createNumberSpinner (prnDeadRightModel, 4, new ChangeListener () {
  1040:       @Override public void stateChanged (ChangeEvent ce) {
  1041:         if (prnSpinnerLocked == 0) {
  1042:           prnNextPaper.deadRightMm = prnDeadRightModel.getNumber ().intValue ();
  1043:           prnDeadLeftModel.setMaximum (new Integer (prnNextPaper.paperWidthMm - 1 - prnNextPaper.deadRightMm));
  1044:         }
  1045:       }  //stateChanged(ChangeEvent)
  1046:     });
  1047:     prnDeadBottomSpinner = ComponentFactory.createNumberSpinner (prnDeadBottomModel, 4, new ChangeListener () {
  1048:       @Override public void stateChanged (ChangeEvent ce) {
  1049:         if (prnSpinnerLocked == 0) {
  1050:           prnNextPaper.deadBottomMm = prnDeadBottomModel.getNumber ().intValue ();
  1051:           prnDeadTopModel.setMaximum (new Integer (prnNextPaper.paperHeightMm - 1 - prnNextPaper.deadBottomMm));
  1052:         }
  1053:       }  //stateChanged(ChangeEvent)
  1054:     });
  1055: 
  1056:     //インクリボンメニュー
  1057:     ButtonGroup ribbonGroup = new ButtonGroup ();
  1058: 
  1059:     //拡大縮小メニュー
  1060:     ButtonGroup zoomGroup = new ButtonGroup ();
  1061:     prnScaleMenuItem = new JRadioButtonMenuItem[9];
  1062: 
  1063:     //メニューバー
  1064:     JMenuBar menuBar = ComponentFactory.createMenuBar (
  1065: 
  1066:       //ファイルメニュー
  1067:       Multilingual.mlnText (
  1068:         ComponentFactory.createMenu (
  1069:           "File", 'F',
  1070:           !PRN_USE_ADAPTER ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("Eject", 'E', listener), "ja", "排紙"),
  1071:           !PRN_USE_ADAPTER ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("Destroy", 'D', listener), "ja", "破棄"),
  1072:           !PRN_USE_ADAPTER ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("Reset", 'R', listener), "ja", "リセット"),
  1073:           ComponentFactory.createHorizontalSeparator (),
  1074:           prnAutosaveMenuItem = Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (prnAutosaveOn, "Autosave", listener), "ja", "自動保存"),
  1075:           ComponentFactory.createHorizontalSeparator (),
  1076:           Multilingual.mlnText (ComponentFactory.createMenuItem ("Close", 'C', listener), "ja", "閉じる")
  1077:           ),
  1078:         "ja", "ファイル"),
  1079: 
  1080:       //用紙メニュー
  1081:       Multilingual.mlnText (
  1082:         ComponentFactory.createMenu (
  1083:           "Paper", 'P',
  1084:           portraitMenu,
  1085:           landscapeMenu,
  1086:           ComponentFactory.createHorizontalSeparator (),
  1087:           Multilingual.mlnText (
  1088:             ComponentFactory.createMenu (
  1089:               "Margin", 'M',
  1090:               ComponentFactory.createHorizontalBox (
  1091:                 Box.createHorizontalGlue (),
  1092:                 Multilingual.mlnText (ComponentFactory.createLabel ("Top "), "ja", "上 "),
  1093:                 prnDeadTopSpinner,
  1094:                 ComponentFactory.createLabel (" mm"),
  1095:                 Box.createHorizontalGlue ()
  1096:                 ),
  1097:               ComponentFactory.createHorizontalBox (
  1098:                 Box.createHorizontalGlue (),
  1099:                 Multilingual.mlnText (ComponentFactory.createLabel ("Left "), "ja", "左 "),
  1100:                 prnDeadLeftSpinner,
  1101:                 ComponentFactory.createLabel (" mm"),
  1102:                 Box.createHorizontalStrut (20),
  1103:                 Multilingual.mlnText (ComponentFactory.createLabel ("Right "), "ja", "右 "),
  1104:                 prnDeadRightSpinner,
  1105:                 ComponentFactory.createLabel (" mm"),
  1106:                 Box.createHorizontalGlue ()
  1107:                 ),
  1108:               ComponentFactory.createHorizontalBox (
  1109:                 Box.createHorizontalGlue (),
  1110:                 Multilingual.mlnText (ComponentFactory.createLabel ("Bottom "), "ja", "下 "),
  1111:                 prnDeadBottomSpinner,
  1112:                 ComponentFactory.createLabel (" mm"),
  1113:                 Box.createHorizontalGlue ()
  1114:                 )
  1115:               ),
  1116:             "ja", "余白")
  1117:           ),
  1118:         "ja", "用紙"),
  1119: 
  1120:       //インクリボンメニュー
  1121:       Multilingual.mlnText (
  1122:         ComponentFactory.createMenu (
  1123:           "Ink ribbon", 'R',
  1124:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 0,
  1125:                                                                 "Black ink ribbon", '0', listener),
  1126:                                 "ja", "黒色インクリボン"),
  1127:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 1,
  1128:                                                                 "Blue ink ribbon", '1', listener),
  1129:                                 "ja", "青色インクリボン"),
  1130:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 2,
  1131:                                                                 "Lime ink ribbon", '2', listener),
  1132:                                 "ja", "緑色インクリボン"),
  1133:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 3,
  1134:                                                                 "Cyan ink ribbon", '3', listener),
  1135:                                 "ja", "水色インクリボン"),
  1136:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 4,
  1137:                                                                 "Red ink ribbon", '4', listener),
  1138:                                 "ja", "赤色インクリボン"),
  1139:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 5,
  1140:                                                                 "Magenta ink ribbon", '5', listener),
  1141:                                 "ja", "紫色インクリボン"),
  1142:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 6,
  1143:                                                                 "Yellow ink ribbon", '6', listener),
  1144:                                 "ja", "黄色インクリボン"),
  1145:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 7,
  1146:                                                                 "White ink ribbon", '7', listener),
  1147:                                 "ja", "白色インクリボン")
  1148:           ),
  1149:         "ja", "インクリボン"),
  1150: 
  1151:       //表示メニュー
  1152:       Multilingual.mlnText (
  1153:         ComponentFactory.createMenu (
  1154:           "Display", 'D',
  1155:           prnScaleMenuItem[0] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -4, "6.25%", '1', listener),
  1156:           prnScaleMenuItem[1] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -3, "12.5%", '2', listener),
  1157:           prnScaleMenuItem[2] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -2, "25%", '3', listener),
  1158:           prnScaleMenuItem[3] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -1, "50%", '4', listener),
  1159:           prnScaleMenuItem[4] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  0, "100%", '5', listener),
  1160:           prnScaleMenuItem[5] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  1, "200%", '6', listener),
  1161:           prnScaleMenuItem[6] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  2, "400%", '7', listener),
  1162:           prnScaleMenuItem[7] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  3, "800%", '8', listener),
  1163:           prnScaleMenuItem[8] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  4, "1600%", '9', listener)
  1164:           ),
  1165:         "ja", "表示")
  1166: 
  1167:       );
  1168: 
  1169:     //スケールシフトリスナー
  1170:     prnCanvas.addScaleShiftListener (new ScrollCanvas.ScaleShiftListener () {
  1171:       @Override public void scaleShiftChanged (int scaleShift) {
  1172:         if (-4 <= scaleShift && scaleShift <= 4) {
  1173:           prnScaleMenuItem[4 + scaleShift].setSelected (true);
  1174:         }
  1175:       }
  1176:     });
  1177: 
  1178:     //ウインドウ
  1179:     prnFrame = Multilingual.mlnTitle (
  1180:       ComponentFactory.createRestorableSubFrame (
  1181:         Settings.SGS_PRN_FRAME_KEY,
  1182:         "Printer",
  1183:         menuBar,
  1184:         ComponentFactory.createBorderPanel (
  1185:           ComponentFactory.setPreferredSize (prnCanvas, 600, 400),
  1186:           null,
  1187:           null,
  1188:           null
  1189:           )
  1190:         ),
  1191:       "ja", "プリンタ");
  1192: 
  1193:   }  //prnMakeFrame()
  1194: 
  1195:   //prnMakeSaveDialog ()
  1196:   //  プリンタ出力イメージ保存ダイアログを作る
  1197:   public static void prnMakeSaveDialog () {
  1198:     if (PRN_DEBUG_TRACE) {
  1199:       System.out.printf ("%08x prnMakeSaveDialog()\n", XEiJ.regPC0);
  1200:     }
  1201:     //出力できるイメージファイルの拡張子の配列を作る
  1202:     prnWriterSuffixes = ImageIO.getWriterFileSuffixes ();  //出力できるイメージファイルの拡張子の配列
  1203:     if (XEiJ.prgCaseIgnored) {  //ファイル名の大文字と小文字が区別されない
  1204:       for (int i = 0; i < prnWriterSuffixes.length; i++) {
  1205:         prnWriterSuffixes[i] = prnWriterSuffixes[i].toLowerCase ();  //小文字化しておく
  1206:       }
  1207:     }
  1208:     //プリンタ出力イメージファイルフィルタ
  1209:     prnSaveFileFilter = new javax.swing.filechooser.FileFilter () {  //java.io.FileFilterと紛らわしい
  1210:       @Override public boolean accept (File file) {
  1211:         if (file.isDirectory ()) {
  1212:           return true;
  1213:         }
  1214:         String name = file.getName ();
  1215:         if (XEiJ.prgCaseIgnored) {
  1216:           name = name.toLowerCase ();
  1217:         }
  1218:         for (String suffix : prnWriterSuffixes) {
  1219:           if (name.endsWith ("." + suffix)) {
  1220:             return true;
  1221:           }
  1222:         }
  1223:         return false;
  1224:       }
  1225:       @Override public String getDescription () {
  1226:         return Multilingual.mlnJapanese ? "プリンタ出力イメージ" : "Printer Output Image";
  1227:       }
  1228:     };
  1229:     //アクションリスナー
  1230:     ActionListener listener = new ActionListener () {
  1231:       @Override public void actionPerformed (ActionEvent ae) {
  1232:         switch (ae.getActionCommand ()) {
  1233:         case JFileChooser.APPROVE_SELECTION:
  1234:         case "Save":  //保存
  1235:           {
  1236:             File file = prnSaveFileChooser.getSelectedFile2 ().getAbsoluteFile ();
  1237:             prnSavePath = file.getParentFile ().getAbsolutePath ();
  1238:             prnSaveName = file.getName ();
  1239:           }
  1240:           if (prnCurrentPaper.save ()) {
  1241:             //  ダイアログを閉じた瞬間に排紙処理が再開されてイメージが廃棄される(可能性がある)ので、
  1242:             //  イメージの保存が終わってからダイアログを閉じる
  1243:             prnSaveDialog.setVisible (false);
  1244:           }
  1245:           break;
  1246:         case JFileChooser.CANCEL_SELECTION:
  1247:         case "Discard":  //破棄
  1248:           prnSaveDialog.setVisible (false);
  1249:           break;
  1250:         case "Autosave from next time":  //次回から自動保存
  1251:           prnSetAutosaveOn (prnAutosaveCheckBox.isSelected ());
  1252:           break;
  1253:         }
  1254:       }
  1255:     };
  1256:     //ファイルチューザー
  1257:     prnSaveFileChooser = new JFileChooser2 (new File (prnSavePath + File.separator + prnSaveName).getAbsoluteFile ());
  1258:     prnSaveFileChooser.setFileFilter (prnSaveFileFilter);
  1259:     prnSaveFileChooser.setMultiSelectionEnabled (false);
  1260:     prnSaveFileChooser.setControlButtonsAreShown (false);
  1261:     prnSaveFileChooser.addActionListener (listener);
  1262:     //ダイアログ
  1263:     prnSaveDialog = Multilingual.mlnTitle (
  1264:       ComponentFactory.createModalDialog (
  1265:         XEiJ.frmFrame,
  1266:         "Save printer output image",
  1267:         ComponentFactory.createBorderPanel (
  1268:           0, 0,
  1269:           ComponentFactory.createVerticalBox (
  1270:             prnSaveFileChooser,
  1271:             ComponentFactory.createHorizontalBox (
  1272:               Box.createHorizontalStrut (12),
  1273:               Box.createHorizontalGlue (),
  1274:               prnAutosaveCheckBox =
  1275:               Multilingual.mlnText (ComponentFactory.createCheckBox (prnAutosaveOn, "Autosave from next time", listener), "ja", "次回から自動保存"),
  1276:               Box.createHorizontalGlue (),
  1277:               Box.createHorizontalStrut (12),
  1278:               Multilingual.mlnText (ComponentFactory.createButton ("Save", KeyEvent.VK_S, listener), "ja", "保存"),
  1279:               Box.createHorizontalStrut (12),
  1280:               Multilingual.mlnText (ComponentFactory.createButton ("Discard", KeyEvent.VK_D, listener), "ja", "破棄"),
  1281:               Box.createHorizontalStrut (12)
  1282:               ),
  1283:             Box.createVerticalStrut (12)
  1284:             )
  1285:           )
  1286:         ),
  1287:       "ja", "プリンタ出力イメージの保存");
  1288:   }  //prnMakeSaveDialog()
  1289: 
  1290:   //prnSetAutosaveOn (on)
  1291:   //  自動保存を設定する
  1292:   public static void prnSetAutosaveOn (boolean on) {
  1293:     prnAutosaveOn = on;
  1294:     if (prnAutosaveCheckBox != null &&
  1295:         prnAutosaveCheckBox.isSelected () != prnAutosaveOn) {
  1296:       prnAutosaveCheckBox.setSelected (prnAutosaveOn);
  1297:     }
  1298:     if (prnAutosaveMenuItem != null &&
  1299:         prnAutosaveMenuItem.isSelected () != prnAutosaveOn) {
  1300:       prnAutosaveMenuItem.setSelected (prnAutosaveOn);
  1301:     }
  1302:   }  //prnSetAutosaveOn(boolean)
  1303: 
  1304: 
  1305:   //プリンタポート
  1306: 
  1307:   //prnReset ()
  1308:   //  リセット
  1309:   //  プリンタポートをリセットする
  1310:   public static void prnReset () {
  1311:     if (PRN_DEBUG_TRACE) {
  1312:       System.out.printf ("%08x prnReset()\n", XEiJ.regPC0);
  1313:     }
  1314:     prnData = 0;
  1315:     prnStrobe = 1;
  1316:   }  //prnReset()
  1317: 
  1318:   //prnReadData ()
  1319:   public static int prnReadData () {
  1320:     if (PRN_DEBUG_TRACE) {
  1321:       System.out.printf ("%08x prnReadData()=%02x\n", XEiJ.regPC0, prnData);
  1322:     }
  1323:     return prnData;
  1324:   }  //prnReadData(int)
  1325: 
  1326:   //prnReadStrobe ()
  1327:   public static int prnReadStrobe () {
  1328:     if (PRN_DEBUG_TRACE) {
  1329:       System.out.printf ("%08x prnReadStrobe()=%02x\n", XEiJ.regPC0, prnStrobe);
  1330:     }
  1331:     return prnStrobe;
  1332:   }  //prnReadStrobe(int)
  1333: 
  1334:   //prnWriteData (int d)
  1335:   public static void prnWriteData (int d) {
  1336:     if (PRN_DEBUG_TRACE) {
  1337:       System.out.printf ("%08x prnWriteData(0x%02x)\n", XEiJ.regPC0, d & 255);
  1338:     }
  1339:     prnData = d & 255;
  1340:   }  //prnWriteData(int,int)
  1341: 
  1342:   //prnWriteStrobe (int d)
  1343:   public static void prnWriteStrobe (int d) {
  1344:     if (PRN_DEBUG_TRACE) {
  1345:       System.out.printf ("%08x prnWriteStrobe(0x%02x)\n", XEiJ.regPC0, d & 255);
  1346:     }
  1347:     d &= 1;
  1348:     if (prnStrobe != d) {
  1349:       prnStrobe = d;
  1350:       if (PRN_PRINTER_CONNECTED) {
  1351:         if (d != 0) {  //0→1
  1352:           //プリンタビジー
  1353:           IOInterrupt.ioiPrnFall ();
  1354:           //出力
  1355:           if (PRN_USE_ADAPTER) {
  1356:             prnAdapterOutput (prnData);
  1357:           } else {
  1358:             prnOutput (prnData);
  1359:           }
  1360:           //プリンタレディ
  1361:           IOInterrupt.ioiPrnRise ();
  1362:         }
  1363:       }
  1364:     }
  1365:   }  //prnWriteStrobe(int,int)
  1366: 
  1367: 
  1368:   //プリンタ
  1369: 
  1370:   //prnOutput (x)
  1371:   //  プリンタ出力
  1372:   //  PRN_PRINTER_CONNECTEDであること
  1373:   public static void prnOutput (int x) {
  1374:     if (PRN_DEBUG_TRACE) {
  1375:       System.out.printf ("%08x prnOutput(0x%02x)\n", XEiJ.regPC0, x & 255);
  1376:     }
  1377:     prnCommandBuffer[prnCommandPointer++] = (byte) x;
  1378:     if (prnCommandPointer < prnCommandLength) {
  1379:       return;  //コマンド継続
  1380:     }
  1381:   command:
  1382:     {
  1383:       int c = prnCommandBuffer[0] & 255;  //1バイト目
  1384:       int d, e, f, g, h, i, j, z, n;
  1385:       switch (c) {
  1386:       case 0x08:  //BS
  1387:         prnPrintBackSpace ();  //バックスペース
  1388:         break command;  //コマンド終了
  1389:       case 0x09:  //HT
  1390:         prnPrintHorizontalTab ();  //水平タブ
  1391:         break command;  //コマンド終了
  1392:       case 0x0a:  //LF
  1393:         prnPrintLineFeed (1);  //1行改行
  1394:         break command;  //コマンド終了
  1395:       case 0x0b:  //VT
  1396:         if (prnCommandLength < 2) {
  1397:           prnCommandLength = 2;
  1398:           return;  //コマンド継続
  1399:         }
  1400:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1401:         prnPrintVerticalTab (d & 15);  //垂直タブ
  1402:         break command;  //コマンド終了
  1403:       case 0x0c:  //FF
  1404:         prnPrintFormFeed ();  //改ページ
  1405:         break command;  //コマンド終了
  1406:       case 0x0d:  //CR
  1407:         prnPrintCarriageReturn ();  //復帰
  1408:         break command;  //コマンド終了
  1409:       case 0x0e:  //SO
  1410:         prnSetHorizontalDoubleSizeMode (true);  //横2倍ON
  1411:         break command;  //コマンド終了
  1412:       case 0x0f:  //SI
  1413:         prnSetHorizontalDoubleSizeMode (false);  //横2倍OFF
  1414:         break command;  //コマンド終了
  1415:       case 0x10:  //POS n1 n2 n3
  1416:         if (prnCommandLength < 4) {
  1417:           prnCommandLength = 4;
  1418:           return;  //コマンド継続
  1419:         }
  1420:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1421:         e = prnCommandBuffer[2] & 255;  //3バイト目
  1422:         f = prnCommandBuffer[3] & 255;  //4バイト目
  1423:         prnSetStartColumn ((d & 15) * 100 + (e & 15) * 10 + (f & 15));  //開始桁位置設定
  1424:         break command;  //コマンド終了
  1425:       case 0x11:  //DC1
  1426:         prnSelect (true);  //セレクト
  1427:         break command;  //コマンド終了
  1428:       case 0x13:  //DC3
  1429:         prnSelect (false);  //ディセレクト
  1430:         break command;  //コマンド終了
  1431:       case 0x14:  //DC4 … ?
  1432:         z = prnCommandBuffer[prnCommandLength - 1] & 255;  //末尾
  1433:         if (z != 0x3f) {
  1434:           if (prnCommandLength + 1 < prnCommandBuffer.length) {
  1435:             prnCommandLength++;
  1436:           }
  1437:           return;  //コマンド継続
  1438:         }
  1439:         prnSetVerticalTabAnchor (prnCommandBuffer, 1, prnCommandLength - 1);  //垂直タブアンカー設置
  1440:         break command;  //コマンド終了
  1441:       case 0x18:  //CAN
  1442:         prnCancel ();  //キャンセル
  1443:         break command;  //コマンド終了
  1444:       case 0x1a:  //SUB
  1445:         if (prnCommandLength < 2) {
  1446:           prnCommandLength = 2;
  1447:           return;  //コマンド継続
  1448:         }
  1449:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1450:         switch (d) {
  1451:         case 0x0c:  //SUB FF (拡張)
  1452:           prnEjectPaper ();  //排紙
  1453:           break command;  //コマンド終了
  1454:         case 0x1a:  //SUB SUB (拡張)
  1455:           prnErasePaper ();  //消去
  1456:           break command;  //コマンド終了
  1457:         case 0x56:  //SUB V
  1458:           prnSetVerticalDoubleSizeMode (true);  //縦2倍ON
  1459:           break command;  //コマンド終了
  1460:         case 0x57:  //SUB W
  1461:           prnSetVerticalDoubleSizeMode (false);  //縦2倍OFF
  1462:           break command;  //コマンド終了
  1463:         }
  1464:         break;  //コマンド不明
  1465:       case 0x1b:  //ESC
  1466:         if (prnCommandLength < 2) {
  1467:           prnCommandLength = 2;
  1468:           return;  //コマンド継続
  1469:         }
  1470:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1471:         switch (d) {
  1472:         case 0x00:  //ESC n
  1473:         case 0x01:  //ESC n
  1474:         case 0x02:  //ESC n
  1475:         case 0x03:  //ESC n
  1476:         case 0x04:  //ESC n
  1477:         case 0x05:  //ESC n
  1478:         case 0x06:  //ESC n
  1479:           prnHorizontalMove (d);  //水平移動。バイナリ指定
  1480:           break command;  //コマンド終了
  1481:         case 0x0b:  //ESC VT n1 n2
  1482:           if (prnCommandLength < 4) {
  1483:             prnCommandLength = 4;
  1484:             return;  //コマンド継続
  1485:           }
  1486:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1487:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1488:           prnPrintLineFeed ((e & 15) * 10 + (f & 15));  //n行改行
  1489:           break command;  //コマンド終了
  1490:         case 0x10:  //ESC POS n1 n2 n3 n4
  1491:           if (prnCommandLength < 6) {
  1492:             prnCommandLength = 6;
  1493:             return;  //コマンド継続
  1494:           }
  1495:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1496:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1497:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1498:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1499:           prnSetHorizontalStartPosition ((e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15));  //水平開始位置設定
  1500:           break command;  //コマンド終了
  1501:         case 0x19:  //ESC EM
  1502:           prnSetColorMode ();  //カラーモード
  1503:           break command;  //コマンド終了
  1504:         case 0x21:  //ESC !
  1505:           prnSetStrongMode (true);  //強調文字設定
  1506:           break command;  //コマンド終了
  1507:         case 0x22:  //ESC "
  1508:           prnSetStrongMode (false);  //強調文字解除
  1509:           break command;  //コマンド終了
  1510:         case 0x24:  //ESC $
  1511:           prnSetHiraganaMode (false);  //カタカナモード
  1512:           break command;  //コマンド終了
  1513:         case 0x25:  //ESC %
  1514:           if (prnCommandLength < 3) {
  1515:             prnCommandLength = 3;
  1516:             return;  //コマンド継続
  1517:           }
  1518:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1519:           switch (e) {
  1520:           case 0x32:  //ESC % 2 n1 n2 d1 d2 … dk
  1521:             if (prnCommandLength < 5) {
  1522:               prnCommandLength = 5;
  1523:               return;  //コマンド継続
  1524:             }
  1525:             f = prnCommandBuffer[3] & 255;  //4バイト目
  1526:             g = prnCommandBuffer[4] & 255;  //5バイト目
  1527:             n = f << 8 | g;  //バイナリ指定
  1528:             if (prnCommandLength < 5 + n) {
  1529:               prnCommandLength = 5 + n;
  1530:               return;  //コマンド継続
  1531:             }
  1532:             prn8DotBitImage (prnCommandBuffer, 5, n);  //8ドットビットイメージ
  1533:             break command;  //コマンド終了
  1534:           case 0x39:  //ESC % 9 n
  1535:             if (prnCommandLength < 4) {
  1536:               prnCommandLength = 4;
  1537:               return;  //コマンド継続
  1538:             }
  1539:             f = prnCommandBuffer[3] & 255;  //4バイト目
  1540:             prnSetLineHeight (f);  //1/120[in]紙送り量設定
  1541:             break command;  //コマンド終了
  1542:           }
  1543:           break;  //コマンド不明
  1544:         case 0x26:  //ESC &
  1545:           prnSetHiraganaMode (true);  //ひらがなモード
  1546:           break command;  //コマンド終了
  1547:         case 0x28:  //ESC ( … .
  1548:           z = prnCommandBuffer[prnCommandLength - 1] & 255;  //末尾
  1549:           if (z != 0x2e) {
  1550:             if (prnCommandLength + 1 < prnCommandBuffer.length) {
  1551:               prnCommandLength++;
  1552:             }
  1553:             return;  //コマンド継続
  1554:           }
  1555:           prnSetHorizontalTabAnchor (prnCommandBuffer, 2, prnCommandLength - 2);  //水平タブアンカー設置
  1556:           break command;  //コマンド終了
  1557:         case 0x29:  //ESC ) … .
  1558:           z = prnCommandBuffer[prnCommandLength - 1] & 255;  //末尾
  1559:           if (z != 0x2e) {
  1560:             if (prnCommandLength + 1 < prnCommandBuffer.length) {
  1561:               prnCommandLength++;
  1562:             }
  1563:             return;  //コマンド継続
  1564:           }
  1565:           prnClearHorizontalTabAnchor (prnCommandBuffer, 2, prnCommandLength - 2);  //水平タブアンカー除去
  1566:           break command;  //コマンド終了
  1567:         case 0x2a:  //ESC * n1 n2 d1 d2 … d32
  1568:           if (prnCommandLength < 36) {
  1569:             prnCommandLength = 36;
  1570:             return;  //コマンド継続
  1571:           }
  1572:           prn16DotExtendedCharacterDefinition (prnCommandBuffer, 2, prnCommandLength - 2);  //16ドット外字定義
  1573:           break command;  //コマンド終了
  1574:         case 0x2b:  //ESC + n1 n2 d1 d2 … d72
  1575:           if (prnCommandLength < 76) {
  1576:             prnCommandLength = 76;
  1577:             return;  //コマンド継続
  1578:           }
  1579:           prn24DotExtendedCharacterDefinition (prnCommandBuffer, 2, prnCommandLength - 2);  //24ドット外字定義
  1580:           break command;  //コマンド終了
  1581:         case 0x2f:  //ESC / n1 n2 n3
  1582:           if (prnCommandLength < 5) {
  1583:             prnCommandLength = 5;
  1584:             return;  //コマンド継続
  1585:           }
  1586:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1587:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1588:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1589:           prnSetRightMargin ((e & 15) * 100 + (f & 15) * 10 + (g & 15));  //右マージン設定
  1590:           break command;  //コマンド終了
  1591:         case 0x32:  //ESC 2
  1592:           prnClearAllHorizontalTabAnchor ();  //全水平タブアンカー除去
  1593:           break command;  //コマンド終了
  1594:         case 0x35:  //ESC 5
  1595:           prnSetPageStartPosition ();  //ページ先頭設定
  1596:           break command;  //コマンド終了
  1597:         case 0x36:  //ESC 6
  1598:           prnSetOneSixth ();  //1/6[in]改行設定
  1599:           break command;  //コマンド終了
  1600:         case 0x38:  //ESC 8
  1601:           prnSetOneEighth ();  //1/8[in]改行設定
  1602:           break command;  //コマンド終了
  1603:         case 0x43:  //ESC C n1 n2
  1604:           if (prnCommandLength < 4) {
  1605:             prnCommandLength = 4;
  1606:             return;  //コマンド継続
  1607:           }
  1608:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1609:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1610:           prnSetBottomMargin ((e & 15) * 10 + (f & 15));  //下マージン設定
  1611:           break command;  //コマンド終了
  1612:         case 0x45:  //ESC E
  1613:           prnSetEliteCharacterMode ();  //エリート文字設定
  1614:           break command;  //コマンド終了
  1615:         case 0x46:  //ESC F n1 n2
  1616:           if (prnCommandLength < 4) {
  1617:             prnCommandLength = 4;
  1618:             return;  //コマンド継続
  1619:           }
  1620:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1621:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1622:           prnSetPageHeight ((e & 15) * 10 + (f & 15));  //ページ高さ設定
  1623:           break command;  //コマンド終了
  1624:         case 0x48:  //ESC H
  1625:           prnSetKanjiMode (false);  //漢字モードOFF
  1626:           break command;  //コマンド終了
  1627:         case 0x49:  //ESC I n1 n2 n3 n4 d1 d2 … dk
  1628:           if (prnCommandLength < 6) {
  1629:             prnCommandLength = 6;
  1630:             return;  //コマンド継続
  1631:           }
  1632:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1633:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1634:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1635:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1636:           n = (e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15);
  1637:           if (prnCommandLength < 6 + 2 * n) {
  1638:             prnCommandLength = 6 + 2 * n;
  1639:             return;  //コマンド継続
  1640:           }
  1641:           prn16DotBitImage (prnCommandBuffer, 6, n);  //16ドットビットイメージ
  1642:           break command;  //コマンド終了
  1643:         case 0x4a:  //ESC J n1 n2 d1 d2 … dk
  1644:           if (prnCommandLength < 4) {
  1645:             prnCommandLength = 4;
  1646:             return;  //コマンド継続
  1647:           }
  1648:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1649:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1650:           n = e << 8 | f;  //バイナリ指定
  1651:           if (prnCommandLength < 4 + 3 * n) {
  1652:             prnCommandLength = 4 + 3 * n;
  1653:             return;  //コマンド継続
  1654:           }
  1655:           prn24DotBitImage (prnCommandBuffer, 4, n);  //24ドットビットイメージ
  1656:           break command;  //コマンド終了
  1657:         case 0x4b:  //ESC K
  1658:           prnSetKanjiMode (true);  //漢字モードON
  1659:           break command;  //コマンド終了
  1660:         case 0x4c:  //ESC L n1 n2 n3
  1661:           if (prnCommandLength < 5) {
  1662:             prnCommandLength = 5;
  1663:             return;  //コマンド継続
  1664:           }
  1665:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1666:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1667:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1668:           prnSetLeftMargin ((e & 15) * 100 + (f & 15) * 10 + (g & 15));  //左マージン設定
  1669:           break command;  //コマンド終了
  1670:         case 0x4d:  //ESC M n1 n2 d1 d2 … dk
  1671:           if (prnCommandLength < 4) {
  1672:             prnCommandLength = 4;
  1673:             return;  //コマンド継続
  1674:           }
  1675:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1676:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1677:           n = e << 8 | f;  //バイナリ指定
  1678:           if (prnCommandLength < 4 + 6 * n) {
  1679:             prnCommandLength = 4 + 6 * n;
  1680:             return;  //コマンド継続
  1681:           }
  1682:           prn48DotBitImage (prnCommandBuffer, 4, n);  //48ドットビットイメージ
  1683:           break command;  //コマンド終了
  1684:         case 0x4e:  //ESC N n1 n2 n3 d
  1685:           if (prnCommandLength < 6) {
  1686:             prnCommandLength = 6;
  1687:             return;  //コマンド継続
  1688:           }
  1689:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1690:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1691:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1692:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1693:           prnRepeatCharacter ((e & 15) * 100 + (f & 15) * 10 + (g & 15), h);  //連続文字
  1694:           break command;  //コマンド終了
  1695:         case 0x50:  //ESC P
  1696:           prnSetKanjiMode (false);  //漢字モードOFF
  1697:           break command;  //コマンド終了
  1698:         case 0x51:  //ESC Q
  1699:           prnSetSmallCharacterMode ();  //縮小文字設定
  1700:           break command;  //コマンド終了
  1701:         case 0x52:  //ESC R
  1702:           prnSetPicaCharacterMode ();  //パイカ文字設定
  1703:           break command;  //コマンド終了
  1704:         case 0x55:  //ESC U
  1705:           prnSetHorizontalDoubleSizeMode (true);  //横2倍ON
  1706:           break command;  //コマンド終了
  1707:         case 0x56:  //ESC V n1 n2 n3 n4 d
  1708:           if (prnCommandLength < 7) {
  1709:             prnCommandLength = 7;
  1710:             return;  //コマンド継続
  1711:           }
  1712:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1713:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1714:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1715:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1716:           i = prnCommandBuffer[6] & 255;  //7バイト目
  1717:           prnRepeat8DotBitImage ((e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15), i);  //連続8ドットビットメージ
  1718:           break command;  //コマンド終了
  1719:         case 0x57:  //ESC W n1 n2 n3 n4 d1 d2
  1720:           if (prnCommandLength < 8) {
  1721:             prnCommandLength = 8;
  1722:             return;  //コマンド継続
  1723:           }
  1724:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1725:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1726:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1727:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1728:           i = prnCommandBuffer[6] & 255;  //7バイト目
  1729:           j = prnCommandBuffer[7] & 255;  //8バイト目
  1730:           prnRepeat16DotBitImage ((e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15), i << 8 | j);  //連続16ドットビットメージ
  1731:           break command;  //コマンド終了
  1732:         case 0x58:  //ESC X
  1733:           prnSetUnderlineMode (true);  //アンダーラインあり
  1734:           break command;  //コマンド終了
  1735:         case 0x59:  //ESC Y
  1736:           prnSetUnderlineMode (false);  //アンダーラインなし
  1737:           break command;  //コマンド終了
  1738:         case 0x5c:  //ESC \\ n1 n2
  1739:           if (prnCommandLength < 4) {
  1740:             prnCommandLength = 4;
  1741:             return;  //コマンド継続
  1742:           }
  1743:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1744:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1745:           prnHorizontalMove ((short) (f << 8 | e));  //水平移動。バイナリ指定。下位、上位。符号あり
  1746:           break command;  //コマンド終了
  1747:         case 0x63:  //ESC c
  1748:           if (prnCommandLength < 3) {
  1749:             prnCommandLength = 3;
  1750:             return;  //コマンド継続
  1751:           }
  1752:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1753:           switch (e) {
  1754:           case 0x31:  //ESC c 1
  1755:             prnResetSettings ();  //設定リセット
  1756:             break command;  //コマンド終了
  1757:           }
  1758:           break;  //コマンド不明
  1759:         case 0x70:  //ESC p
  1760:           if (prnCommandLength < 3) {
  1761:             prnCommandLength = 3;
  1762:             return;  //コマンド継続
  1763:           }
  1764:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1765:           switch (e) {
  1766:           case 0x30:  //ESC p 0
  1767:             prnSenseOutOfPaper (false);  //用紙切れ検出無効
  1768:             break command;  //コマンド終了
  1769:           case 0x31:  //ESC p 1
  1770:             prnSenseOutOfPaper (true);  //用紙切れ検出有効
  1771:             break command;  //コマンド終了
  1772:           }
  1773:           break;  //コマンド不明
  1774:         case 0x71:  //ESC q n
  1775:           if (prnCommandLength < 3) {
  1776:             prnCommandLength = 3;
  1777:             return;  //コマンド継続
  1778:           }
  1779:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1780:           prnSetCharacterStyle (e);  //文字スタイル設定。バイナリ指定
  1781:           break command;  //コマンド終了
  1782:         case 0x73:  //ESC s
  1783:           if (prnCommandLength < 3) {
  1784:             prnCommandLength = 3;
  1785:             return;  //コマンド継続
  1786:           }
  1787:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1788:           switch (e) {
  1789:           case 0x30:  //ESC s 0
  1790:             prnSetScriptMode (0);  //スクリプト解除
  1791:             break command;  //コマンド終了
  1792:           case 0x31:  //ESC s 1
  1793:             prnSetScriptMode (1);  //スーパースクリプト設定
  1794:             break command;  //コマンド終了
  1795:           case 0x32:  //ESC s 2
  1796:             prnSetScriptMode (2);  //サブスクリプト設定
  1797:             break command;  //コマンド終了
  1798:           }
  1799:           break;  //コマンド不明
  1800:         }
  1801:         break;  //コマンド不明
  1802:       case 0x1c:  //FS
  1803:         if (prnCommandLength < 2) {
  1804:           prnCommandLength = 2;
  1805:           return;  //コマンド継続
  1806:         }
  1807:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1808:         switch (d) {
  1809:         case 0x4a:  //FS J
  1810:           prnSetVerticalWritingMode (true);  //縦書き
  1811:           break command;  //コマンド終了
  1812:         case 0x4b:  //FS K
  1813:           prnSetVerticalWritingMode (false);  //横書き
  1814:           break command;  //コマンド終了
  1815:         case 0x53:  //FS S n1 n2
  1816:           if (prnCommandLength < 4) {
  1817:             prnCommandLength = 4;
  1818:             return;  //コマンド継続
  1819:           }
  1820:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1821:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1822:           prnSetFullWidthLeftRightSpace (e, f);  //全角左右スペース。バイナリ指定
  1823:           break command;  //コマンド終了
  1824:         case 0x54:  //FS T n1 n2
  1825:           if (prnCommandLength < 4) {
  1826:             prnCommandLength = 4;
  1827:             return;  //コマンド継続
  1828:           }
  1829:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1830:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1831:           prnSetHalfWidthLeftRightSpace (e, f);  //半角左右スペース。バイナリ指定
  1832:           break command;  //コマンド終了
  1833:         case 0x70:  //FS p
  1834:           prnSetKanjiHorizontalDoubleSizeMode (true);  //漢字横2倍ON
  1835:           break command;  //コマンド終了
  1836:         case 0x71:  //FS q
  1837:           prnSetKanjiHorizontalDoubleSizeMode (false);  //漢字横2倍OFF
  1838:           break command;  //コマンド終了
  1839:         }  //switch d
  1840:         break;  //コマンド不明
  1841:       default:
  1842:         if (prnKanjiMode) {  //漢字モードONのとき
  1843:           if (prnCommandLength < 2) {
  1844:             prnCommandLength = 2;
  1845:             return;  //コマンド継続
  1846:           }
  1847:           d = prnCommandBuffer[1] & 255;  //2バイト目
  1848:           c = c << 8 | d;
  1849:         }
  1850:         if (c != 0) {  //0のときは何もしない
  1851:           prnPrintCharacter (c);  //1文字印字
  1852:         }
  1853:         break command;  //コマンド終了
  1854:       }  //switch c
  1855:       //コマンド不明
  1856:       for (int k = 0; k < prnCommandLength; k++) {
  1857:         prnPrintCharacter (prnCommandBuffer[k] & 255);  //1文字印字
  1858:       }
  1859:     }  //command
  1860:     //コマンド終了
  1861:     prnCommandLength = 1;
  1862:     prnCommandPointer = 0;
  1863:   }  //prnOutput(int)
  1864: 
  1865:   public static void prnDebugTracePrintBuffer (String s, byte[] a, int o, int n) {
  1866:     if (PRN_DEBUG_TRACE) {
  1867:       System.out.printf ("%08x %s({", XEiJ.regPC0, s);
  1868:       for (int i = 0; i < n; i++) {
  1869:         if (0 < i) {
  1870:           System.out.print (',');
  1871:         }
  1872:         System.out.printf ("0x%02x", a[o + i] & 255);
  1873:       }
  1874:       System.out.println ("})");
  1875:     }
  1876:   }  //prnDebugTracePrintBuffer(String,byte[],int,int)
  1877: 
  1878:   //prnFeedPaper ()
  1879:   //  給紙
  1880:   public static void prnFeedPaper () {
  1881:     if (prnCurrentPaper != null) {  //既に給紙されているとき
  1882:       return;  //何もしない
  1883:     }
  1884:     if (PRN_DEBUG_TRACE) {
  1885:       System.out.printf ("%08x prnFeedPaper()\n", XEiJ.regPC0);
  1886:     }
  1887:     prnCurrentPaper = prnNextPaper;  //給紙する
  1888:     //印字可能範囲
  1889:     //  prnNextPaperの印字可能範囲はメニューで変更できる
  1890:     //  印字中に印字可能範囲が変わると困るので給紙したときにprnCurrentPaperの印字可能範囲をコピーして使う
  1891:     prnAliveLeftX = prnCurrentPaper.aliveLeftX;  //印字可能範囲の左端の用紙座標[dot]
  1892:     prnAliveTopY = prnCurrentPaper.aliveTopY;  //印字可能範囲の上端の用紙座標[dot]
  1893:     prnAliveRightX = prnCurrentPaper.aliveRightX;  //印字可能範囲の右端の用紙座標[dot]
  1894:     prnAliveBottomY = prnCurrentPaper.aliveBottomY;  //印字可能範囲の下端の用紙座標[dot]
  1895:     prnErasePaper ();  //消去
  1896:   }  //prnFeedPaper()
  1897: 
  1898:   //prnErasePaper ()
  1899:   //  消去
  1900:   //  印刷済みの用紙を保存せずに破棄する
  1901:   public static void prnErasePaper () {
  1902:     if (prnCurrentPaper == null) {  //給紙されていないとき
  1903:       prnFeedPaper ();  //給紙する
  1904:     } else {  //給紙されているとき
  1905:       prnCurrentPaper.clear ();  //白紙にする
  1906:       prnPrinted = false;  //印字なし
  1907:       //ページ範囲
  1908:       prnPageStart = 0;
  1909:       prnPageLength = ((prnAliveBottomY - prnAliveTopY + (360 - 1)) / 360) * 360;
  1910:       //コンテント範囲
  1911:       prnContentTopY = prnPageStart + prnCurrentPaper.marginTopHeight;
  1912:       prnContentBottomY = prnPageStart + prnPageLength - prnCurrentPaper.marginBottomHeight;
  1913:       //ヘッドの位置
  1914:       prnHeadX = prnCurrentPaper.marginLeftX;
  1915:       prnHeadY = prnContentTopY;
  1916:       prnHeadLine = 0;
  1917:       if (prnCanvas != null) {
  1918:         prnCanvas.setImage (prnCurrentPaper.getImage ());
  1919:       }
  1920:     }
  1921:   }  //prnErasePaper()
  1922: 
  1923:   //prnEjectPaper ()
  1924:   //  排紙
  1925:   public static void prnEjectPaper () {
  1926:     if (prnCurrentPaper == null) {  //既に排紙されているとき
  1927:       return;  //何もしない
  1928:     }
  1929:     if (PRN_DEBUG_TRACE) {
  1930:       System.out.printf ("%08x prnEjectPaper()\n", XEiJ.regPC0);
  1931:     }
  1932:     if (prnPrinted) {  //印字されているとき
  1933:       prnSavePaper ();  //保存する
  1934:     }
  1935:     prnCurrentPaper = null;  //未給紙にする
  1936:     prnHeadX = -1;  //ヘッドX座標[dot]
  1937:     prnHeadY = -1;  //ヘッドY座標[dot]
  1938:     prnHeadLine = -1;  //ヘッド行番号
  1939:     if (prnCanvas != null) {
  1940:       prnCanvas.setImage (null);
  1941:     }
  1942:   }  //prnEjectPaper()
  1943: 
  1944:   //prnSavePaper ()
  1945:   //  保存する
  1946:   //  ファイル名はprnSavePath+File.separator+prnSaveName
  1947:   //  ファイルが既にあるとき
  1948:   //    主ファイル名の末尾に数字があるとき
  1949:   //      主ファイル名の末尾の数字をインクリメントする
  1950:   //    主ファイル名の末尾に数字がないとき
  1951:   //      主ファイル名の末尾に"2"を追加する
  1952:   public static void prnSavePaper () {
  1953:     if (!XEiJ.prgIsLocal) {  //ローカルでないとき
  1954:       return;  //何もしない
  1955:     }
  1956:     if (PRN_DEBUG_TRACE) {
  1957:       System.out.printf ("%08x prnSavePaper()\n", XEiJ.regPC0);
  1958:     }
  1959:     //存在しないファイル名に書き換える
  1960:     while (new File (prnSavePath + File.separator + prnSaveName).isFile ()) {  //ファイルが既にある
  1961:       int j = prnSaveName.lastIndexOf ('.');  //主ファイル名の末尾
  1962:       if (j < 0) {
  1963:         j = prnSaveName.length ();
  1964:       }
  1965:       int i = j;
  1966:       int n = 2;
  1967:       if (0 < j && Character.isDigit (prnSaveName.charAt (j - 1))) {  //主ファイル名の末尾に数字がある
  1968:         //主ファイル名の末尾の数字を最大8桁取り出してインクリメントする
  1969:         i--;
  1970:         while (j - 8 < i &&
  1971:                0 < i && Character.isDigit (prnSaveName.charAt (i - 1))) {
  1972:           i--;
  1973:         }
  1974:         n = Integer.parseInt (prnSaveName.substring (i, j));
  1975:         n = (n + 1) % 100000000;  //1億個すべて使い切ると無限ループに陥る
  1976:       }
  1977:       prnSaveName = prnSaveName.substring (0, i) + n + prnSaveName.substring (j);
  1978:     }
  1979:     //親ディレクトリを掘る
  1980:     File file = new File (prnSavePath + File.separator + prnSaveName).getAbsoluteFile ();
  1981:     File parent = file.getParentFile ();
  1982:     prnSavePath = parent.getAbsolutePath ();  //区切り直す
  1983:     prnSaveName = file.getName ();
  1984:     parent.mkdirs ();
  1985:     //保存する
  1986:     if (prnAutosaveOn) {  //自動保存のとき
  1987:       if (!prnCurrentPaper.save ()) {  //保存できなかったとき
  1988:         prnSetAutosaveOn (false);  //手動保存に切り替える
  1989:       }
  1990:     }
  1991:     if (!prnAutosaveOn) {  //手動保存のとき
  1992:       if (prnSaveDialog == null) {
  1993:         prnMakeSaveDialog ();  //ダイアログを作る
  1994:       }
  1995:       prnSaveFileChooser.setCurrentDirectory (parent);  //親ディレクトリを設定する
  1996:       prnSaveFileChooser.rescanCurrentDirectory ();  //親ディレクトリのファイルのリストを更新する。これをやらないと前回保存したファイルが表示されない
  1997:       prnSaveFileChooser.setSelectedFile (file);  //主ファイル名を設定する
  1998:       //ダイアログを表示する
  1999:       //  モーダルダイアログなのでダイアログを閉じるまでここでブロックされる
  2000:       prnSaveDialog.setVisible (true);
  2001:     }
  2002:   }  //prnSavePaper()
  2003: 
  2004:   private static final byte[] PRN_DOUBLE_4BIT = {
  2005:     0b00_00_00_00,
  2006:     0b00_00_00_11,
  2007:     0b00_00_11_00,
  2008:     0b00_00_11_11,
  2009:     0b00_11_00_00,
  2010:     0b00_11_00_11,
  2011:     0b00_11_11_00,
  2012:     0b00_11_11_11,
  2013:     (byte) 0b11_00_00_00,
  2014:     (byte) 0b11_00_00_11,
  2015:     (byte) 0b11_00_11_00,
  2016:     (byte) 0b11_00_11_11,
  2017:     (byte) 0b11_11_00_00,
  2018:     (byte) 0b11_11_00_11,
  2019:     (byte) 0b11_11_11_00,
  2020:     (byte) 0b11_11_11_11,
  2021:   };
  2022: 
  2023:   //prnSetSingleColor (color)
  2024:   //  単色インクリボンの色を設定する
  2025:   public static void prnSetSingleColor (int color) {
  2026:     prnSingleColor = color;
  2027:     if (!prnColorMode) {  //単色モードのとき
  2028:       prnCurrentColor = color;
  2029:     }
  2030:   }  //prnSetSingleColor(int)
  2031: 
  2032:   //prnGetCharacterWidth ()
  2033:   //  現在の文字の幅[dot]を返す
  2034:   public static int prnGetCharacterWidth () {
  2035:     return (prnKanjiMode ?
  2036:             (prnHalfWidthLeftSpace + 24 + prnHalfWidthRightSpace) *
  2037:             (prnHorizontalDoubleSizeMode || prnKanjiHorizontalDoubleSizeMode ? 2 : 1) :
  2038:             (prnCharacterType == PRN_PICA ? 36 :
  2039:              prnCharacterType == PRN_ELITE ? 30 :
  2040:              prnCharacterType == PRN_SMALL ? 21 : 0) *
  2041:             (prnHorizontalDoubleSizeMode ? 2 : 1));
  2042:   }  //prnGetCharacterWidth()
  2043: 
  2044:   //prnPrintCharacter (c)
  2045:   //  1文字印字
  2046:   //  コントロールコードは処理しない
  2047:   public static void prnPrintCharacter (int c) {
  2048:     c = (char) c;
  2049:     if (PRN_DEBUG_TRACE) {
  2050:       System.out.printf ("%08x prnPrintCharacter(0x%04x)\n", XEiJ.regPC0, c);
  2051:     }
  2052:     if (prnCurrentPaper == null) {  //未給紙のとき
  2053:       prnFeedPaper ();  //給紙する
  2054:     }
  2055:     //フォントを選ぶ
  2056:     FontPage page = null;
  2057:     int y0 = 0;  //開始ラスタ。サブスクリプトのとき14、それ以外は0
  2058:     int col = 0;
  2059:     int row = 0;
  2060:     int w, h, o, oh;
  2061:     byte[] b;
  2062:   gaiji:
  2063:     {
  2064:       if (c <= 0x00ff) {  //ANK
  2065:         if (prnKanjiMode) {  //半角
  2066:           page = FontEditor.fntPageHAN24X48;
  2067:         } else if (prnScriptMode != 0) {  //スクリプト
  2068:           page = FontEditor.fntPageSCR28X32;
  2069:           if (prnScriptMode == 2) {  //サブスクリプト
  2070:             y0 = 14;
  2071:           }
  2072:         } else {
  2073:           page = (prnCharacterType == PRN_PICA ? FontEditor.fntPagePIC36X46 :  //パイカ
  2074:                   prnCharacterType == PRN_ELITE ? FontEditor.fntPageELI30X46 :  //エリート
  2075:                   FontEditor.fntPageSMA18X46);  //縮小
  2076:         }
  2077:         col = c & 15;
  2078:         row = c >> 4;
  2079:         if (prnHiraganaMode) {  //ひらがな
  2080:           row += 16;
  2081:         }
  2082:       } else {  //漢字
  2083:         page = FontEditor.fntPageKNJ48X48;
  2084:         row = c >> 8;
  2085:         col = c & 255;
  2086:         if ((row == 0x76 && (0x21 <= col && col <= 0x7e)) ||
  2087:             (row == 0x77 && (0x21 <= col && col <= 0x26))) {  //外字定義エリア
  2088:           w = 48;  //フォントの幅
  2089:           h = 48;  //フォントの高さ
  2090:           o = 6;  //フォントの1ラスタのバイト数
  2091:           oh = o * h;  //フォントのバイト数
  2092:           b = new byte[oh];
  2093:           System.arraycopy (prnGetGaijiData (), oh * ((col - 0x21) + 94 * (row - 0x76)), b, 0, oh);
  2094:           break gaiji;
  2095:         }
  2096:         if (0x21 <= col && col <= 0x7e) {
  2097:           col -= 0x21;
  2098:           if (0x21 <= row && row <= 0x28) {
  2099:             row -= 0x21;
  2100:           } else if (0x30 <= row && row <= 0x74) {
  2101:             row -= 0x30 - 8;
  2102:           } else {
  2103:             row = 0;
  2104:             col = 0;
  2105:           }
  2106:         } else {
  2107:           row = 0;
  2108:           col = 0;
  2109:         }
  2110:       }
  2111:       if (!page.fnpReady) {  //フォントの準備ができていない
  2112:         page.fnpGenerate (FontEditor.fntGetMinchoFamily ());  //フォントを作る
  2113:       }
  2114:       w = page.fnpFontWidth;  //フォントの幅
  2115:       h = page.fnpFontHeight;  //フォントの高さ
  2116:       o = page.fnpDataOffset;  //フォントの1ラスタのバイト数
  2117:       oh = o * h;  //フォントのバイト数
  2118:       b = new byte[o * y0 + oh];
  2119:       System.arraycopy (page.fnpDataMemory, page.fnpDataAddress + oh * (col + page.fnpCols * row), b, o * y0, oh);
  2120:     }  //gaiji
  2121:     h += y0;
  2122:     oh = o * h;
  2123:     //縦書き
  2124:     //  漢字モードで全角のとき48x48のパターンを左に90度回転させる
  2125:     //  横2倍は回転してから横に拡大するので文字は縦長になる
  2126:     //  回転させない文字
  2127:     //    2126-2128 215d 2162-2166 222a-222d 2821-2840
  2128:     //  縦書き用のパターンが存在する文字
  2129:     //    2122-2123 2131-2132 213c-213e 2141-2145 214a-215b 2161 2421 2423 2425 2427 2429 2443 2463 2465 2467 246e 2521 2523 2525 2527 2529 2543 2563 2565 2567 256e 2575 2576
  2130:     //    括弧の多くは回転させないだけでよさそうに思われるが縦書き用のパターンが存在する
  2131:     //  参考
  2132:     //    http://www.unicode.org/reports/tr50/
  2133:     if (prnVerticalWritingMode &&  //縦書き
  2134:         (page != null && page.fnpId == FontEditor.FNT_ID_KNJ48X48) &&  //全角48x48
  2135:         !((row == 0x21 - 0x21 && ((0x26 - 0x21 <= col && col <= 0x28 - 0x21) ||
  2136:                                   (col == 0x5d - 0x21) ||
  2137:                                   (0x62 - 0x21 <= col && col <= 0x66 - 0x21))) ||
  2138:           (row == 0x22 - 0x21 && (0x2a - 0x21 <= col && col <= 0x2d - 0x21)) ||
  2139:           (row == 0x28 - 0x21 && (0x21 - 0x21 <= col && col <= 0x40 - 0x21)))) {  //回転させる
  2140:       if ((row == 0x21 - 0x21 && ((0x22 - 0x21 <= col && col <= 0x23 - 0x21) ||
  2141:                                   (0x31 - 0x21 <= col && col <= 0x32 - 0x21) ||
  2142:                                   (0x3c - 0x21 <= col && col <= 0x3e - 0x21) ||
  2143:                                   (0x41 - 0x21 <= col && col <= 0x45 - 0x21) ||
  2144:                                   (0x4a - 0x21 <= col && col <= 0x5b - 0x21) ||
  2145:                                   (col == 0x61 - 0x21))) ||
  2146:           (row == 0x24 - 0x21 && (col == 0x21 - 0x21 ||
  2147:                                   col == 0x23 - 0x21 ||
  2148:                                   col == 0x25 - 0x21 ||
  2149:                                   col == 0x27 - 0x21 ||
  2150:                                   col == 0x29 - 0x21 ||
  2151:                                   col == 0x43 - 0x21 ||
  2152:                                   col == 0x63 - 0x21 ||
  2153:                                   col == 0x65 - 0x21 ||
  2154:                                   col == 0x67 - 0x21 ||
  2155:                                   col == 0x6e - 0x21)) ||
  2156:           (row == 0x25 - 0x21 && (col == 0x21 - 0x21 ||
  2157:                                   col == 0x23 - 0x21 ||
  2158:                                   col == 0x25 - 0x21 ||
  2159:                                   col == 0x27 - 0x21 ||
  2160:                                   col == 0x29 - 0x21 ||
  2161:                                   col == 0x43 - 0x21 ||
  2162:                                   col == 0x63 - 0x21 ||
  2163:                                   col == 0x65 - 0x21 ||
  2164:                                   col == 0x67 - 0x21 ||
  2165:                                   col == 0x6e - 0x21 ||
  2166:                                   col == 0x75 - 0x21 ||
  2167:                                   col == 0x76 - 0x21))) {  //縦書き用のパターンが存在する
  2168:         //!!! 縦書き用のパターンがない
  2169:       }
  2170:       //左に90度回転させる
  2171:       //  デスティネーションを左上から右へ走査する
  2172:       //  ソースを右上から下へ走査する
  2173:       byte[] bb = new byte[6 * 48];
  2174:       //Arrays.fill (bb, (byte) 0);
  2175:       for (int yy = 0; yy < 48; yy++) {
  2176:         int x = 48 - 1 - yy;
  2177:         for (int xx = 0; xx < 48; xx++) {
  2178:           int y = xx;
  2179:           //!!! 遅そう
  2180:           bb[6 * yy + (xx >> 3)] |= (byte) ((b[6 * y + (x >> 3)] >> (~x & 7) & 1) << (~xx & 7));
  2181:         }
  2182:       }
  2183:       b = bb;
  2184:     }  //if 縦書き
  2185:     if (false) {
  2186:       //高さを最低48[dot]にする
  2187:       //  パイカは46[dot]なので48[dot]にしておくと袋文字、影文字、袋影文字の下端が切れなくなる
  2188:       //  マニュアルのサンプルを見ると下端が切れているのでCZ-8PC4は46[dot]のままなのだと思われる
  2189:       if (h < 48) {
  2190:         int hh = 48;
  2191:         int ohh = o * hh;
  2192:         byte[] bb = new byte[ohh];
  2193:         System.arraycopy (b, 0, bb, 0, oh);
  2194:         //Arrays.fill (bb, oh, ohh - oh, (byte) 0);
  2195:         h = hh;
  2196:         oh = ohh;
  2197:         b = bb;
  2198:       }
  2199:     }
  2200:     //強調
  2201:     if (prnStrongMode) {
  2202:       for (int a = 0; a < oh; a += o) {
  2203:         for (int i = o - 1; i > 0; i--) {  //右にずらして重ねるので右から処理する
  2204:           b[a + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2205:         }
  2206:         b[a] |= (byte) ((b[a] & 255) >> 1);
  2207:       }
  2208:     }  //if 強調
  2209:     //アンダーライン
  2210:     if (prnUnderlineMode) {
  2211:       int a = o * (h - 1);
  2212:       for (int i = 0; i < o - 1; i++) {
  2213:         b[a + i] = -1;
  2214:       }
  2215:       b[a + o - 1] |= (byte) (-256 >> (w - 1 & 7) + 1);
  2216:     }  //if アンダーライン
  2217:     //横2倍
  2218:     if (prnHorizontalDoubleSizeMode ||
  2219:         (prnKanjiMode && prnKanjiHorizontalDoubleSizeMode)) {  //横2倍
  2220:       int ww = w * 2;
  2221:       int oo = ww + 7 >> 3;  //o*2またはo*2-1
  2222:       int ooh = oo * h;
  2223:       byte[] bb = new byte[ooh];
  2224:       for (int a = 0, aa = 0; a < oh; a += o, aa += oo) {  //ラスタの先頭
  2225:         for (int i = 0, ii = 0; i < o; i++, ii += 2) {  //ラスタ内インデックス
  2226:           int d = b[a + i] & 255;
  2227:           bb[aa + ii] = PRN_DOUBLE_4BIT[d >> 4];
  2228:           if (ii + 1 < oo) {
  2229:             bb[aa + ii + 1] = PRN_DOUBLE_4BIT[d & 15];
  2230:           }
  2231:         }
  2232:       }
  2233:       w = ww;
  2234:       o = oo;
  2235:       oh = ooh;
  2236:       b = bb;
  2237:     }  //if 横2倍
  2238:     //縦2倍
  2239:     if (prnVerticalDoubleSizeMode) {  //縦2倍
  2240:       int hh = h * 2;
  2241:       int ohh = o * hh;
  2242:       byte[] bb = new byte[ohh];
  2243:       for (int a = 0, aa = 0; a < oh; a += o, aa += o * 2) {
  2244:         for (int i = 0; i < o; i++) {
  2245:           bb[aa + o + i] = bb[aa + i] = b[a + i];
  2246:         }
  2247:       }
  2248:       h = hh;
  2249:       oh = ohh;
  2250:       b = bb;
  2251:     }  //if 縦2倍
  2252:     //文字スタイル
  2253:     if (prnCharacterStyle != 0) {  //袋文字または影文字または袋影文字
  2254:       //  1  袋文字    左上 上 右上 左 右 左下 下 右下           ずらしたパターンを重ねてから元のパターンをくり抜く
  2255:       //  2  影文字                               右下 右右下下  ずらしたパターンを重ねてから元のパターンをくり抜く
  2256:       //  3  袋影文字  左上 上 右上 左 右 左下 下 右下 右右下下  ずらしたパターンを重ねてから元のパターンをくり抜く
  2257:       byte[] bb = new byte[oh];
  2258:       //右下にずらしてコピーする
  2259:       for (int i = 0; i < o; i++) {
  2260:         bb[i] = 0;
  2261:       }
  2262:       for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2263:         bb[aa] = (byte) ((b[a] & 255) >> 1);
  2264:         for (int i = 1; i < o; i++) {
  2265:           bb[aa + i] = (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2266:         }
  2267:       }
  2268:       if (prnCharacterStyle == 2 || prnCharacterStyle == 3) {  //影文字または袋影文字
  2269:         //右右下下にずらして重ねる
  2270:         for (int a = 0, aa = o * 2; aa < oh; a += o, aa += o) {
  2271:           bb[aa] |= (byte) ((b[a] & 255) >> 2);
  2272:           for (int i = 1; i < o; i++) {
  2273:             bb[aa + i] |= (byte) (b[a + i - 1] << 6 | (b[a + i] & 255) >> 2);
  2274:           }
  2275:         }
  2276:       }
  2277:       if (prnCharacterStyle == 1 || prnCharacterStyle == 3) {  //袋文字または袋影文字
  2278:         //左上にずらして重ねる
  2279:         for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2280:           for (int i = 0; i < o - 1; i++) {
  2281:             bb[aa + i] |= (byte) (b[a + i] << 1 | (b[a + i + 1] & 255) >> 7);
  2282:           }
  2283:           bb[aa + o - 1] |= (byte) (b[a + o - 1] << 1);
  2284:         }
  2285:         //上にずらして重ねる
  2286:         for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2287:           for (int i = 0; i < o; i++) {
  2288:             bb[aa + i] |= b[a + i];
  2289:           }
  2290:         }
  2291:         //右上にずらして重ねる
  2292:         for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2293:           bb[aa] |= (byte) ((b[a] & 255) >> 1);
  2294:           for (int i = 1; i < o; i++) {
  2295:             bb[aa + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2296:           }
  2297:         }
  2298:         //左にずらして重ねる
  2299:         for (int a = 0; a < oh; a += o) {
  2300:           for (int i = 0; i < o - 1; i++) {
  2301:             bb[a + i] |= (byte) (b[a + i] << 1 | (b[a + i + 1] & 255) >> 7);
  2302:           }
  2303:           bb[a + o - 1] |= (byte) (b[a + o - 1] << 1);
  2304:         }
  2305:         //右にずらして重ねる
  2306:         for (int a = 0; a < oh; a += o) {
  2307:           bb[a] |= (byte) ((b[a] & 255) >> 1);
  2308:           for (int i = 1; i < o; i++) {
  2309:             bb[a + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2310:           }
  2311:         }
  2312:         //左下にずらして重ねる
  2313:         for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2314:           for (int i = 0; i < o - 1; i++) {
  2315:             bb[aa + i] |= (byte) (b[a + i] << 1 | (b[a + i + 1] & 255) >> 7);
  2316:           }
  2317:           bb[aa + o - 1] |= (byte) (b[a + o - 1] << 1);
  2318:         }
  2319:         //下にずらして重ねる
  2320:         for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2321:           for (int i = 0; i < o; i++) {
  2322:             bb[aa + i] |= b[a + i];
  2323:           }
  2324:         }
  2325:       }
  2326:       //元のパターンをくり抜く
  2327:       for (int i = 0; i < oh; i++) {
  2328:         bb[i] &= (byte) ~b[i];
  2329:       }
  2330:       //
  2331:       b = bb;
  2332:     }  //if 文字スタイルあり
  2333:     //左右スペースを確認する
  2334:     int leftSpace = 0;
  2335:     int rightSpace = 0;
  2336:     if (prnKanjiMode) {  //漢字モード
  2337:       if (w == 48) {  //全角
  2338:         leftSpace = prnFullWidthLeftSpace;
  2339:         rightSpace = prnFullWidthRightSpace;
  2340:       } else {  //半角
  2341:         leftSpace = prnHalfWidthLeftSpace;
  2342:         rightSpace = prnHalfWidthRightSpace;
  2343:       }
  2344:     } else if (prnCharacterType == PRN_SMALL) {  //縮小文字
  2345:       rightSpace = 3;  //18[dot]のフォントを印字して21[dot]進む
  2346:     }
  2347:     //行に収まるか
  2348:     if (prnCurrentPaper.marginLeftX < prnHeadX &&  //左端ではなくて
  2349:         prnCurrentPaper.marginRightX < prnHeadX + leftSpace + w + rightSpace) {  //右からはみ出す
  2350:       //改行する
  2351:       prnHeadX = prnCurrentPaper.marginLeftX;
  2352:       prnHeadY += prnLineHeight;
  2353:       prnHeadLine++;
  2354:     }
  2355:     //コンテント範囲に収まるか
  2356:     if (prnContentTopY < prnHeadY &&  //上端ではなくて
  2357:         prnContentBottomY < prnHeadY + h) {  //下からはみ出す
  2358:       //改ページする
  2359:       prnPrintFormFeed ();
  2360:     }
  2361:     //左スペース
  2362:     prnHeadX += leftSpace;
  2363:     //文字を描く
  2364:     byte[] bitmap = prnCurrentPaper.getBitmap ();
  2365:     int offset = prnCurrentPaper.paperWidth;
  2366:     int index = offset * (prnAliveTopY + prnHeadY) + (prnAliveLeftX + prnHeadX);
  2367:     for (int y = 0; y < h; y++) {
  2368:       for (int x = 0; x < w; x++) {
  2369:         if ((b[o * y + (x >> 3)] >> (~x & 7) & 1) != 0) {
  2370:           bitmap[index + x] &= prnCurrentColor;  //ANDで描く
  2371:         }
  2372:       }
  2373:       index += offset;
  2374:     }
  2375:     prnHeadX += w;
  2376:     //右スペース
  2377:     prnHeadX += rightSpace;
  2378:     //用紙の状態
  2379:     prnPrinted = true;  //印字あり
  2380:     //キャンバスを再描画する
  2381:     if (prnCanvas != null) {
  2382:       prnCanvas.repaint ();
  2383:     }
  2384:   }  //prnPrintCharacter(int)
  2385: 
  2386:   //prnPrintBackSpace ()
  2387:   //  BS  バックスペース  (p159)
  2388:   //  現在の文字の幅だけ後退する
  2389:   //  漢字モードのときは半角の幅
  2390:   //  横2倍が有効
  2391:   //  左マージンの位置で止まる
  2392:   public static void prnPrintBackSpace () {
  2393:     if (PRN_DEBUG_TRACE) {
  2394:       System.out.printf ("%08x prnPrintBackSpace()\n", XEiJ.regPC0);
  2395:     }
  2396:     if (prnCurrentPaper == null) {  //未給紙のとき
  2397:       prnFeedPaper ();  //給紙する
  2398:     }
  2399:     prnHeadX = Math.max (prnCurrentPaper.marginLeftX, prnHeadX - prnGetCharacterWidth ());
  2400:   }  //prnPrintBackSpace()
  2401: 
  2402:   //prnPrintHorizontalTab ()
  2403:   //  HT  水平タブ  (p92)
  2404:   //  現在のヘッドの位置よりも右側にある最初の水平タブアンカーの位置まで進む
  2405:   //  なければ何もしない
  2406:   public static void prnPrintHorizontalTab () {
  2407:     if (PRN_DEBUG_TRACE) {
  2408:       System.out.printf ("%08x prnPrintHorizontalTab()\n", XEiJ.regPC0);
  2409:     }
  2410:     if (prnCurrentPaper == null) {  //未給紙のとき
  2411:       prnFeedPaper ();  //給紙する
  2412:     }
  2413:     for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  2414:       int x = prnHorizontalTabAnchor[k];
  2415:       if (x == 0) {  //終わり
  2416:         break;
  2417:       }
  2418:       if (prnHeadX < x) {  //現在のヘッドの位置よりも右側にある
  2419:         prnHeadX = Math.min (x, prnCurrentPaper.marginRightX - 1);
  2420:         break;
  2421:       }
  2422:     }
  2423:   }  //prnPrintHorizontalTab()
  2424: 
  2425:   //prnSetStartColumn (n)
  2426:   //  POS n1 n2 n3  開始桁位置設定  (p97)
  2427:   //  0は左マージンの位置
  2428:   //  単位は現在の文字の幅
  2429:   //  横2倍が有効
  2430:   public static void prnSetStartColumn (int n) {
  2431:     if (PRN_DEBUG_TRACE) {
  2432:       System.out.printf ("%08x prnSetStartColumn(%d)\n", XEiJ.regPC0, n);
  2433:     }
  2434:     if (prnCurrentPaper == null) {  //未給紙のとき
  2435:       prnFeedPaper ();  //給紙する
  2436:     }
  2437:     if (0 <= n && n <= 999) {
  2438:       int startX = prnGetCharacterWidth () * n;
  2439:       if (prnCurrentPaper.marginLeftX + startX < prnCurrentPaper.marginRightX) {
  2440:         prnHeadX = prnCurrentPaper.marginLeftX + startX;
  2441:       }
  2442:     }
  2443:   }  //prnSetStartColumn(int)
  2444: 
  2445:   //prnPrintLineFeed (n)
  2446:   //  LF            1行改行  (p76)
  2447:   //  ESC VT n1 n2  n行改行  (p77)
  2448:   //  ヘッドのY座標に改行ピッチ*nを加える
  2449:   //  縦2倍が有効
  2450:   public static void prnPrintLineFeed (int n) {
  2451:     if (PRN_DEBUG_TRACE) {
  2452:       System.out.printf ("%08x prnPrintLineFeed(%d)\n", XEiJ.regPC0, n);
  2453:     }
  2454:     if (prnCurrentPaper == null) {  //未給紙のとき
  2455:       prnFeedPaper ();  //給紙する
  2456:     }
  2457:     if (n < 0) {
  2458:       n = 0;
  2459:     }
  2460:     if (prnVerticalDoubleSizeMode) {  //縦2倍
  2461:       n *= 2;
  2462:     }
  2463:     //改行する
  2464:     prnHeadY += prnLineHeight * n;
  2465:     prnHeadLine += n;
  2466:     //コンテント範囲に収まっているか
  2467:     if (prnContentBottomY <= prnHeadY) {  //下からはみ出した
  2468:       //改ページする
  2469:       prnPrintFormFeed ();
  2470:     }
  2471:     //カラーモードのとき単色モードに戻る
  2472:     if (prnColorMode) {  //カラーモードのとき
  2473:       prnColorMode = false;
  2474:       prnCurrentColor = prnSingleColor;  //現在の色
  2475:     }
  2476:   }  //prnPrintLineFeed(int)
  2477: 
  2478:   //prnPrintVerticalTab (n)
  2479:   //  VT n  垂直タブ  (p83)
  2480:   //  nはチャンネル番号
  2481:   //  現在の行より下にある指定されたチャンネル番号の垂直タブアンカーの行まで改行を繰り返す
  2482:   //  なければ何もしない
  2483:   public static void prnPrintVerticalTab (int n) {
  2484:     if (PRN_DEBUG_TRACE) {
  2485:       System.out.printf ("%08x prnPrintVerticalTab(%d)\n", XEiJ.regPC0, n);
  2486:     }
  2487:     if (prnCurrentPaper == null) {  //未給紙のとき
  2488:       prnFeedPaper ();  //給紙する
  2489:     }
  2490:     for (int k = prnHeadLine; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  2491:       if (prnVerticalTabAnchor[k] == n) {  //チャンネルが番号が一致した
  2492:         int d = k - prnHeadLine;  //進む行数
  2493:         //改行する
  2494:         prnHeadX = prnCurrentPaper.marginLeftX;
  2495:         prnHeadY += prnLineHeight * d;
  2496:         prnHeadLine += d;
  2497:         //コンテント範囲に収まっているか
  2498:         if (prnContentBottomY <= prnHeadY) {  //下からはみ出した
  2499:           //改ページする
  2500:           prnPrintFormFeed ();
  2501:         }
  2502:         return;
  2503:       }
  2504:     }
  2505:   }  //prnPrintVerticalTab(int)
  2506: 
  2507:   //prnPrintFormFeed ()
  2508:   //  FF  改ページ  (p80)
  2509:   //  ページの先頭でも次のページまで紙送りする
  2510:   public static void prnPrintFormFeed () {
  2511:     if (PRN_DEBUG_TRACE) {
  2512:       System.out.printf ("%08x prnPrintFormFeed()\n", XEiJ.regPC0);
  2513:     }
  2514:     //改ページする
  2515:     prnPageStart += prnPageLength;
  2516:     //コンテント範囲
  2517:     prnContentTopY = prnPageStart + prnCurrentPaper.marginTopHeight;
  2518:     prnContentBottomY = Math.min (prnPageStart + prnPageLength - prnCurrentPaper.marginBottomHeight,
  2519:                                   prnAliveBottomY - prnAliveTopY);
  2520:     //ヘッドの位置
  2521:     prnHeadX = prnCurrentPaper.marginLeftX;
  2522:     prnHeadY = prnContentTopY;
  2523:     prnHeadLine = 0;
  2524:     //印字可能範囲に収まっているか
  2525:     if (prnAliveBottomY <= prnAliveTopY + prnHeadY) {  //下からはみ出した
  2526:       prnEjectPaper ();  //排紙する
  2527:       prnFeedPaper ();  //給紙する
  2528:     }
  2529:   }  //prnPrintFormFeed()
  2530: 
  2531:   //prnPrintCarriageReturn ()
  2532:   //  CR  復帰  (p72)
  2533:   //  印字位置を左マージンまで戻す
  2534:   public static void prnPrintCarriageReturn () {
  2535:     if (PRN_DEBUG_TRACE) {
  2536:       System.out.printf ("%08x prnPrintCarriageReturn()\n", XEiJ.regPC0);
  2537:     }
  2538:     if (prnCurrentPaper == null) {  //未給紙のとき
  2539:       prnFeedPaper ();  //給紙する
  2540:     }
  2541:     //ヘッドを左端に移動させる
  2542:     prnHeadX = prnCurrentPaper.marginLeftX;
  2543:     //カラーモードのとき色を変更する
  2544:     if (prnColorMode) {  //カラーモードのとき
  2545:       prnCurrentColor = prnCurrentColor == 6 ? 5 : prnCurrentColor == 5 ? 3 : 6;  //6→5→3→6の順に切り替える
  2546:     }
  2547:   }  //prnPrintCarriageReturn()
  2548: 
  2549:   //prnSetHorizontalDoubleSizeMode (b)
  2550:   //  b  true   SO     横2倍ON  (p104)
  2551:   //            ESC U  横2倍ON  (p105)
  2552:   //     false  SI     横2倍OFF  (p106)
  2553:   public static void prnSetHorizontalDoubleSizeMode (boolean b) {
  2554:     if (PRN_DEBUG_TRACE) {
  2555:       System.out.printf ("%08x prnSetHorizontalDoubleSizeMode(%b)\n", XEiJ.regPC0, b);
  2556:     }
  2557:     prnHorizontalDoubleSizeMode = b;
  2558:   }  //prnSetHorizontalDoubleSizeMode(boolean)
  2559: 
  2560:   //prnSelect (b)
  2561:   //  b  true   DC1  セレクト  (p165)
  2562:   //     false  DC3  ディセレクト  (p166)
  2563:   public static void prnSelect (boolean b) {
  2564:     if (PRN_DEBUG_TRACE) {
  2565:       System.out.printf ("%08x prnSelect(%b)\n", XEiJ.regPC0, b);
  2566:     }
  2567:     //!!!
  2568:   }  //prnSelect(boolean)
  2569: 
  2570:   //prnSetVerticalTabAnchor (a, o, n)
  2571:   //  DC4 0 … 0 n1 0 … 0 n2 … nk ?  垂直タブアンカー設置  (p81)
  2572:   //  0は垂直タブ位置でない行
  2573:   //  1 2 3 4 5 6 7 8 9 : ; < = >は垂直タブ位置である行のチャンネル番号
  2574:   //  ?で終了
  2575:   //  チャンネル番号は昇順であること
  2576:   //  上下マージンが設定されると垂直タブアンカーはクリアされる
  2577:   //  現在の印字位置がページの先頭になる
  2578:   public static void prnSetVerticalTabAnchor (byte[] a, int o, int n) {
  2579:     if (PRN_DEBUG_TRACE) {
  2580:       prnDebugTracePrintBuffer ("prnSetVerticalTabAnchor", a, o, n);
  2581:     }
  2582:     if (prnCurrentPaper == null) {  //未給紙のとき
  2583:       prnFeedPaper ();  //給紙する
  2584:     }
  2585:     prnSetPageStartPosition ();  //ページ先頭設定
  2586:     int pp = '0';  //前回のチャンネル番号
  2587:     int k = 0;
  2588:     for (; k < PRN_VERTICAL_ANCHOR_LIMIT && k < n; k++) {
  2589:       int p = a[o + k];  //チャンネル番号
  2590:       if (p == '0') {
  2591:         prnVerticalTabAnchor[k] = 0;
  2592:       } else if ('1' <= p && p <= '<') {
  2593:         if (p <= pp) {  //昇順になっていない
  2594:           break;
  2595:         }
  2596:         prnVerticalTabAnchor[k] = p - '0';
  2597:         pp = p;
  2598:       } else {
  2599:         break;
  2600:       }
  2601:     }
  2602:     for (; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  2603:       prnVerticalTabAnchor[k] = 0;
  2604:     }
  2605:   }  //prnSetVerticalTabAnchor(byte[],int,int)
  2606: 
  2607:   //prnCancel ()
  2608:   //  CAN  キャンセル  (p158)
  2609:   public static void prnCancel () {
  2610:     if (PRN_DEBUG_TRACE) {
  2611:       System.out.printf ("%08x prnCancel()\n", XEiJ.regPC0);
  2612:     }
  2613:     //!!!
  2614:   }  //prnCancel()
  2615: 
  2616:   //prnSetVerticalDoubleSizeMode (b)
  2617:   //  b  true   SUB V  縦2倍ON  (p107)
  2618:   //     false  SUB W  縦2倍OFF  (p108)
  2619:   public static void prnSetVerticalDoubleSizeMode (boolean b) {
  2620:     if (PRN_DEBUG_TRACE) {
  2621:       System.out.printf ("%08x prnSetVerticalDoubleSizeMode(%b)\n", XEiJ.regPC0, b);
  2622:     }
  2623:     prnVerticalDoubleSizeMode = b;
  2624:   }  //prnSetVerticalDoubleSizeMode(boolean)
  2625: 
  2626:   //prnSetHorizontalStartPosition (n)
  2627:   //  ESC POS n1 n2 n3 n4  水平開始位置設定  (p98)
  2628:   //  水平開始位置をn/180[in]にする
  2629:   public static void prnSetHorizontalStartPosition (int n) {
  2630:     if (PRN_DEBUG_TRACE) {
  2631:       System.out.printf ("%08x prnSetHorizontalStartPosition(%d)\n", XEiJ.regPC0, n);
  2632:     }
  2633:     if (prnCurrentPaper == null) {  //未給紙のとき
  2634:       prnFeedPaper ();  //給紙する
  2635:     }
  2636:     if (0 <= n && n <= 9999) {
  2637:       int startX = 2 * n;
  2638:       if (prnCurrentPaper.marginLeftX + startX < prnCurrentPaper.marginRightX) {
  2639:         prnHeadX = prnCurrentPaper.marginLeftX + startX;
  2640:       }
  2641:     }
  2642:   }  //prnSetHorizontalStartPosition(int)
  2643: 
  2644:   //prnSetColorMode ()
  2645:   //  ESC EM  カラーモード  (p167)
  2646:   public static void prnSetColorMode () {
  2647:     if (PRN_DEBUG_TRACE) {
  2648:       System.out.printf ("%08x prnSetColorMode()\n", XEiJ.regPC0);
  2649:     }
  2650:     prnColorMode = true;  //カラーモード
  2651:     prnCurrentColor = 6;  //現在の色。6=イエロー
  2652:   }  //prnSetColorMode()
  2653: 
  2654:   //prnSetStrongMode (b)
  2655:   //  b  true   ESC !  強調文字設定  (p109)
  2656:   //     false  ESC "  強調文字解除  (p110)
  2657:   public static void prnSetStrongMode (boolean b) {
  2658:     if (PRN_DEBUG_TRACE) {
  2659:       System.out.printf ("%08x prnSetStrongMode(%b)\n", XEiJ.regPC0, b);
  2660:     }
  2661:     prnStrongMode = b;
  2662:   }  //prnSetStrongMode(boolean)
  2663: 
  2664:   //prnSetHiraganaMode (b)
  2665:   //  b  true   ESC &  ひらがなモード  (p164)
  2666:   //     false  ESC $  カタカナモード  (p163)
  2667:   public static void prnSetHiraganaMode (boolean b) {
  2668:     if (PRN_DEBUG_TRACE) {
  2669:       System.out.printf ("%08x prnSetHiraganaMode(%b)\n", XEiJ.regPC0, b);
  2670:     }
  2671:     prnHiraganaMode = b;
  2672:   }  //prnSetHiraganaMode(boolean)
  2673: 
  2674:   //prnSetLineHeight (n)
  2675:   //  ESC % 9 n  1/120[in]紙送り量設定  (p75)
  2676:   //  改行ピッチをn/120[in]にする
  2677:   //  0<=n<=127
  2678:   //  0はESC % 9 nを実行する前の1/6[in]または1/8[in]に戻す
  2679:   public static void prnSetLineHeight (int n) {
  2680:     if (PRN_DEBUG_TRACE) {
  2681:       System.out.printf ("%08x prnSetLineHeight(%d)\n", XEiJ.regPC0, n);
  2682:     }
  2683:     if (0 <= n && n <= 127) {
  2684:       if (n == 0) {
  2685:         prnLineHeight = prnDefaultLineHeight;
  2686:       } else {
  2687:         prnLineHeight = 3 * n;
  2688:       }
  2689:     }
  2690:   }  //prnSetLineHeight(int)
  2691: 
  2692:   //prn8DotBitImage (a, o, n)
  2693:   //  ESC % 2 n1 n2 d1 d2 … dk  8ドットビットイメージ  (p142)
  2694:   //  パイカのとき
  2695:   //    横方向を4.5倍に拡大する
  2696:   //    縦方向を4.5倍に拡大する。高さが36[dot]になる
  2697:   //    改行ピッチが15/120[in]または16/120[in]のとき12/120[in]にする
  2698:   //  エリートのとき
  2699:   //    横方向を3倍に拡大する
  2700:   //    縦方向を4.5倍に拡大する。高さが36[dot]になる
  2701:   //    改行ピッチが15/120[in]または16/120[in]のとき12/120[in]にする
  2702:   //  改行ピッチが1/120[in]のとき
  2703:   //    縦方向を6倍に拡大して上3bitだけバッファに展開する
  2704:   //    LFが来たら先頭に戻って今度は下3bitだけ展開する
  2705:   public static void prn8DotBitImage (byte[] a, int o, int n) {
  2706:     if (PRN_DEBUG_TRACE) {
  2707:       prnDebugTracePrintBuffer ("prn8DotBitImage", a, o, n);
  2708:     }
  2709:     if (prnCurrentPaper == null) {  //未給紙のとき
  2710:       prnFeedPaper ();  //給紙する
  2711:     }
  2712:     //!!!
  2713:   }  //prn8DotBitImage(byte[],int,int)
  2714: 
  2715:   //prnSetHorizontalTabAnchor (a, o, n)
  2716:   //  ESC ( n1 , n2 , n3 , … , nk .  水平タブアンカー設置  (p90)
  2717:   //  nkは3桁の10進数で1個から16個まで
  2718:   //  nkに現在の文字幅(漢字モードのときは半角、横2倍が有効)が掛けられて絶対位置で記憶される
  2719:   //  0は左マージンの位置。右マージンを超える位置は無視される
  2720:   //  HTで次の水平タブ位置まで進む
  2721:   //  電源投入時はパイカで8桁毎に設定されている
  2722:   //  左右マージンが設定されるとすべての水平タブ位置がクリアされる
  2723:   public static void prnSetHorizontalTabAnchor (byte[] a, int o, int n) {
  2724:     if (PRN_DEBUG_TRACE) {
  2725:       prnDebugTracePrintBuffer ("prnSetHorizontalTabAnchor", a, o, n);
  2726:     }
  2727:     if (prnCurrentPaper == null) {  //未給紙のとき
  2728:       prnFeedPaper ();  //給紙する
  2729:     }
  2730:     int characterWidth = prnGetCharacterWidth ();
  2731:     n += o;
  2732:     int k = 0;
  2733:     while (k < PRN_HORIZONTAL_ANCHOR_LIMIT &&
  2734:            o < n && '0' <= a[o] && a[o] <= '9') {
  2735:       int p = a[o] - '0';
  2736:       o++;
  2737:       while (o < n && '0' <= a[o] && a[o] <= '9') {  //本来は3桁固定
  2738:         p = p * 10 + (a[o] - '0');
  2739:         o++;
  2740:       }
  2741:       int x = prnCurrentPaper.marginLeftX + characterWidth * p;  //絶対位置
  2742:       if ((k == 0 ? prnCurrentPaper.marginLeftX :  //左マージンまたは
  2743:            prnHorizontalTabAnchor[k - 1]) < x) {  //直前の水平タブアンカーよりも右側になければならない
  2744:         prnHorizontalTabAnchor[k] = x;
  2745:         k++;
  2746:       }
  2747:       if (o < n && a[o] == ',') {  //継続
  2748:         o++;
  2749:       } else {  //終了
  2750:         break;
  2751:       }
  2752:     }
  2753:     for (; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  2754:       prnHorizontalTabAnchor[k] = 0;
  2755:     }
  2756:   }  //prnSetHorizontalTabAnchor(byte[],int,int)
  2757: 
  2758:   //prnClearHorizontalTabAnchor (a, o, n)
  2759:   //  ESC ) n1 , n2 , … nk .  水平タブアンカー除去  (p93)
  2760:   //  nkは3桁の10進数で1個から16個まで
  2761:   //  nkに現在の文字幅(漢字モードのときは半角、横2倍が有効)が掛けられて絶対位置で比較される
  2762:   //  設置したときと同じ条件で除去しなければならない
  2763:   public static void prnClearHorizontalTabAnchor (byte[] a, int o, int n) {
  2764:     if (PRN_DEBUG_TRACE) {
  2765:       prnDebugTracePrintBuffer ("prnClearHorizontalTabAnchor", a, o, n);
  2766:     }
  2767:     if (prnCurrentPaper == null) {  //未給紙のとき
  2768:       prnFeedPaper ();  //給紙する
  2769:     }
  2770:     int characterWidth = prnGetCharacterWidth ();
  2771:     n += o;
  2772:     while (o < n && '0' <= a[o] && a[o] <= '9') {
  2773:       int p = a[o] - '0';
  2774:       o++;
  2775:       while (o < n && '0' <= a[o] && a[o] <= '9') {  //本来は3桁固定
  2776:         p = p * 10 + (a[o] - '0');
  2777:         o++;
  2778:       }
  2779:       int x = prnCurrentPaper.marginLeftX + characterWidth * p;  //絶対位置
  2780:       for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  2781:         int t = prnHorizontalTabAnchor[k];
  2782:         if (t == 0 ||  //終わり
  2783:             x < t) {  //行き過ぎた。見つからなかった
  2784:           break;
  2785:         }
  2786:         if (t == x) {  //見つかった
  2787:           int j = k;
  2788:           for (; j < PRN_HORIZONTAL_ANCHOR_LIMIT - 1; j++) {
  2789:             prnHorizontalTabAnchor[j] = prnHorizontalTabAnchor[j + 1];  //詰める
  2790:           }
  2791:           prnHorizontalTabAnchor[j] = 0;
  2792:           break;  //1つしかないので終わり
  2793:         }
  2794:       }
  2795:       if (o < n && a[o] == ',') {  //継続
  2796:         o++;
  2797:       } else {  //終了
  2798:         break;
  2799:       }
  2800:     }
  2801:   }  //prnClearHorizontalTabAnchor(byte[],int,int)
  2802: 
  2803:   //prn16DotExtendedCharacterDefinition ()
  2804:   //  ESC * n1 n2 d1 d2 … d32  16ドット外字定義  (p134)
  2805:   //  外字定義エリアは0x7621..0x767eと0x7721..0x7726の100文字
  2806:   //  16x16[dot]のパターンが縦横3倍に拡大されて48x48[dot]で保存される
  2807:   //  ESC c 1でクリアされる
  2808:   //             0         1              14         15
  2809:   //        +---------+---------+----+----------+----------+
  2810:   //     0  | d1 bit7 | d3 bit7 | .. | d29 bit7 | d31 bit7 |
  2811:   //        +---------+---------+----+----------+----------+
  2812:   //     1  | d1 bit6 | d3 bit6 | .. | d29 bit6 | d31 bit6 |
  2813:   //        +---------+---------+----+----------+----------+
  2814:   //        |    :    |    :    |    |    :     |    :     |
  2815:   //        +---------+---------+----+----------+----------+
  2816:   //     6  | d1 bit1 | d3 bit1 | .. | d29 bit1 | d31 bit1 |
  2817:   //        +---------+---------+----+----------+----------+
  2818:   //     7  | d1 bit0 | d3 bit0 | .. | d29 bit0 | d31 bit0 |
  2819:   //        +---------+---------+----+----------+----------+
  2820:   //     8  | d2 bit7 | d4 bit7 | .. | d30 bit7 | d32 bit7 |
  2821:   //        +---------+---------+----+----------+----------+
  2822:   //     9  | d2 bit6 | d4 bit6 | .. | d30 bit6 | d32 bit6 |
  2823:   //        +---------+---------+----+----------+----------+
  2824:   //        |    :    |    :    |    |    :     |    :     |
  2825:   //        +---------+---------+----+----------+----------+
  2826:   //    14  | d2 bit1 | d4 bit1 | .. | d30 bit1 | d32 bit1 |
  2827:   //        +---------+---------+----+----------+----------+
  2828:   //    15  | d2 bit0 | d4 bit0 | .. | d30 bit0 | d32 bit0 |
  2829:   //        +---------+---------+----+----------+----------+
  2830:   public static void prn16DotExtendedCharacterDefinition (byte[] a, int o, int n) {
  2831:     if (PRN_DEBUG_TRACE) {
  2832:       prnDebugTracePrintBuffer ("prn16DotExtendedCharacterDefinition", a, o, n);
  2833:     }
  2834:     byte[] gaijiData = prnGetGaijiData ();
  2835:     int n1 = a[o] & 255;
  2836:     int n2 = a[o + 1] & 255;
  2837:     if (!((n1 == 0x76 && (0x21 <= n2 && n2 <= 0x7e)) ||
  2838:           (n1 == 0x77 && (0x21 <= n2 && n2 <= 0x26)))) {  //外字定義エリアではない
  2839:       return;
  2840:     }
  2841:     int i = 6 * 48 * ((n2 - 0x21) + 94 * (n1 - 0x76));
  2842:     int j = o + 2;
  2843:     for (int y = 0; y < 16; y++) {
  2844:       int t = 0;
  2845:       for (int x = 0; x < 8; x++) {
  2846:         t = t << 3 | (a[j + 2 * x + (y >> 3)] >> (~y & 7) & 1) * 7;
  2847:       }
  2848:       gaijiData[i    ] = gaijiData[i + 6] = gaijiData[i + 12] = (byte) (t >> 16);
  2849:       gaijiData[i + 1] = gaijiData[i + 7] = gaijiData[i + 13] = (byte) (t >> 8);
  2850:       gaijiData[i + 2] = gaijiData[i + 8] = gaijiData[i + 14] = (byte) t;
  2851:       t = 0;
  2852:       for (int x = 8; x < 16; x++) {
  2853:         t = t << 3 | (a[j + 2 * x + (y >> 3)] >> (~y & 7) & 1) * 7;
  2854:       }
  2855:       gaijiData[i + 3] = gaijiData[i +  9] = gaijiData[i + 15] = (byte) (t >> 16);
  2856:       gaijiData[i + 4] = gaijiData[i + 10] = gaijiData[i + 16] = (byte) (t >> 8);
  2857:       gaijiData[i + 5] = gaijiData[i + 11] = gaijiData[i + 17] = (byte) t;
  2858:       i += 18;
  2859:     }
  2860:   }  //prn16DotExtendedCharacterDefinition()
  2861: 
  2862:   //prn24DotExtendedCharacterDefinition ()
  2863:   //  ESC + n1 n2 d1 d2 … d72  24ドット外字定義  (p138)
  2864:   //  外字定義エリアは0x7621..0x767eと0x7721..0x7726の100文字
  2865:   //  24x24[dot]のパターンが縦横2倍に拡大されて48x48[dot]で保存される
  2866:   //  ESC c 1でクリアされる
  2867:   //             0         1              22         23
  2868:   //        +---------+---------+----+----------+----------+
  2869:   //     0  | d1 bit7 | d4 bit7 | .. | d67 bit7 | d70 bit7 |
  2870:   //        +---------+---------+----+----------+----------+
  2871:   //     1  | d1 bit6 | d4 bit6 | .. | d67 bit6 | d70 bit6 |
  2872:   //        +---------+---------+----+----------+----------+
  2873:   //        |    :    |    :    |    |    :     |    :     |
  2874:   //        +---------+---------+----+----------+----------+
  2875:   //     6  | d1 bit1 | d4 bit1 | .. | d67 bit1 | d70 bit1 |
  2876:   //        +---------+---------+----+----------+----------+
  2877:   //     7  | d1 bit0 | d4 bit0 | .. | d67 bit0 | d70 bit0 |
  2878:   //        +---------+---------+----+----------+----------+
  2879:   //     8  | d2 bit7 | d5 bit7 | .. | d68 bit7 | d71 bit7 |
  2880:   //        +---------+---------+----+----------+----------+
  2881:   //     9  | d2 bit6 | d5 bit6 | .. | d68 bit6 | d71 bit6 |
  2882:   //        +---------+---------+----+----------+----------+
  2883:   //        |    :    |    :    |    |    :     |    :     |
  2884:   //        +---------+---------+----+----------+----------+
  2885:   //    14  | d2 bit1 | d5 bit1 | .. | d68 bit1 | d71 bit1 |
  2886:   //        +---------+---------+----+----------+----------+
  2887:   //    15  | d2 bit0 | d5 bit0 | .. | d68 bit0 | d71 bit0 |
  2888:   //        +---------+---------+----+----------+----------+
  2889:   //    16  | d3 bit7 | d6 bit7 | .. | d69 bit7 | d72 bit7 |
  2890:   //        +---------+---------+----+----------+----------+
  2891:   //    17  | d3 bit6 | d6 bit6 | .. | d69 bit6 | d72 bit6 |
  2892:   //        +---------+---------+----+----------+----------+
  2893:   //        |    :    |    :    |    |    :     |    :     |
  2894:   //        +---------+---------+----+----------+----------+
  2895:   //    22  | d3 bit1 | d6 bit1 | .. | d69 bit1 | d72 bit1 |
  2896:   //        +---------+---------+----+----------+----------+
  2897:   //    23  | d3 bit0 | d6 bit0 | .. | d69 bit0 | d72 bit0 |
  2898:   //        +---------+---------+----+----------+----------+
  2899:   public static void prn24DotExtendedCharacterDefinition (byte[] a, int o, int n) {
  2900:     if (PRN_DEBUG_TRACE) {
  2901:       prnDebugTracePrintBuffer ("prn24DotExtendedCharacterDefinition", a, o, n);
  2902:     }
  2903:     byte[] gaijiData = prnGetGaijiData ();
  2904:     int n1 = a[o] & 255;
  2905:     int n2 = a[o + 1] & 255;
  2906:     if (!((n1 == 0x76 && (0x21 <= n2 && n2 <= 0x7e)) ||
  2907:           (n1 == 0x77 && (0x21 <= n2 && n2 <= 0x26)))) {  //外字定義エリアではない
  2908:       return;
  2909:     }
  2910:     int i = 6 * 48 * ((n2 - 0x21) + 94 * (n1 - 0x76));
  2911:     int j = o + 2;
  2912:     for (int y = 0; y < 24; y++) {
  2913:       int t = 0;
  2914:       for (int x = 0; x < 16; x++) {
  2915:         t = t << 2 | (a[j + 3 * x + (y >> 3)] >> (~y & 7) & 1) * 3;
  2916:       }
  2917:       gaijiData[i    ] = gaijiData[i + 6] = (byte) (t >> 24);
  2918:       gaijiData[i + 1] = gaijiData[i + 7] = (byte) (t >> 16);
  2919:       gaijiData[i + 2] = gaijiData[i + 8] = (byte) (t >> 8);
  2920:       gaijiData[i + 3] = gaijiData[i + 9] = (byte) t;
  2921:       t = 0;
  2922:       for (int x = 16; x < 24; x++) {
  2923:         t = t << 2 | (a[j + 3 * x + (y >> 3)] >> (~y & 7) & 1) * 3;
  2924:       }
  2925:       gaijiData[i + 4] = gaijiData[i + 10] = (byte) (t >> 8);
  2926:       gaijiData[i + 5] = gaijiData[i + 11] = (byte) t;
  2927:       i += 12;
  2928:     }
  2929:   }  //prn24DotExtendedCharacterDefinition()
  2930: 
  2931:   //prnSetRightMargin (n)
  2932:   //  ESC / n1 n2 n3  右マージン設定  (p88)
  2933:   //  右マージンをn桁にする
  2934:   //  最大数よりも大きいと無視される
  2935:   //  水平タブ位置はクリアされる
  2936:   //  単位は現在の文字の幅
  2937:   //  漢字モードのときは半角の幅
  2938:   //  横2倍は無視される
  2939:   public static void prnSetRightMargin (int n) {
  2940:     if (PRN_DEBUG_TRACE) {
  2941:       System.out.printf ("%08x prnSetRightMargin(%d)\n", XEiJ.regPC0, n);
  2942:     }
  2943:     if (prnCurrentPaper == null) {  //未給紙のとき
  2944:       prnFeedPaper ();  //給紙する
  2945:     }
  2946:     if (0 <= n && n <= 999) {
  2947:       int rightX = prnGetCharacterWidth () * n;
  2948:       if (prnCurrentPaper.marginLeftX < rightX) {
  2949:         prnCurrentPaper.marginRightX = rightX;
  2950:         //水平タブ位置をクリアする
  2951:         for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  2952:           prnHorizontalTabAnchor[k] = 0;
  2953:         }
  2954:       }
  2955:     }
  2956:   }  //prnSetRightMargin(int)
  2957: 
  2958:   //prnClearAllHorizontalTabAnchor ()
  2959:   //  ESC 2  全水平タブアンカー除去  (p95)
  2960:   public static void prnClearAllHorizontalTabAnchor () {
  2961:     if (PRN_DEBUG_TRACE) {
  2962:       System.out.printf ("%08x prnClearAllHorizontalTabAnchor()\n", XEiJ.regPC0);
  2963:     }
  2964:     if (prnCurrentPaper == null) {  //未給紙のとき
  2965:       prnFeedPaper ();  //給紙する
  2966:     }
  2967:     //水平タブ位置をクリアする
  2968:     for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  2969:       prnHorizontalTabAnchor[k] = 0;
  2970:     }
  2971:   }  //prnClearAllHorizontalTabAnchor()
  2972: 
  2973:   //prnSetPageStartPosition ()
  2974:   //  ESC 5  ページ先頭設定  (p79)
  2975:   //  現在の印字位置がページの先頭になる
  2976:   public static void prnSetPageStartPosition () {
  2977:     if (PRN_DEBUG_TRACE) {
  2978:       System.out.printf ("%08x prnSetPageStartPosition()\n", XEiJ.regPC0);
  2979:     }
  2980:     if (prnCurrentPaper == null) {  //未給紙のとき
  2981:       prnFeedPaper ();  //給紙する
  2982:     }
  2983:     //ページ範囲
  2984:     prnPageStart = prnHeadY;  //現在の印字位置がページの先頭になる
  2985:     //コンテント範囲
  2986:     prnContentTopY = prnPageStart + prnCurrentPaper.marginTopHeight;
  2987:     prnContentBottomY = Math.min (prnPageStart + prnPageLength - prnCurrentPaper.marginBottomHeight,
  2988:                                   prnAliveBottomY - prnAliveTopY);
  2989:     //ヘッドの位置
  2990:     prnHeadX = prnCurrentPaper.marginLeftX;
  2991:     prnHeadY = prnContentTopY;
  2992:     prnHeadLine = 0;
  2993:   }  //prnSetPageStartPosition()
  2994: 
  2995:   //prnSetOneSixth ()
  2996:   //  ESC 6  1/6[in]改行設定  (p73)
  2997:   public static void prnSetOneSixth () {
  2998:     if (PRN_DEBUG_TRACE) {
  2999:       System.out.printf ("%08x prnSetOneSixth()\n", XEiJ.regPC0);
  3000:     }
  3001:     prnLineHeight = 60;
  3002:     prnDefaultLineHeight = 60;
  3003:   }  //prnSetOneSixth()
  3004: 
  3005:   //prnSetOneEighth ()
  3006:   //  ESC 8  1/8[in]改行設定  (p74)
  3007:   public static void prnSetOneEighth () {
  3008:     if (PRN_DEBUG_TRACE) {
  3009:       System.out.printf ("%08x prnSetOneEighth()\n", XEiJ.regPC0);
  3010:     }
  3011:     prnLineHeight = 45;
  3012:     prnDefaultLineHeight = 45;
  3013:   }  //prnSetOneEighth()
  3014: 
  3015:   //prnSetBottomMargin (n)
  3016:   //  ESC C n1 n2  下マージン設定  (p84)
  3017:   //  下マージンをn行にする
  3018:   //  ページの高さよりも大きいと無視される
  3019:   public static void prnSetBottomMargin (int n) {
  3020:     if (PRN_DEBUG_TRACE) {
  3021:       System.out.printf ("%08x prnSetBottomMargin(%d)\n", XEiJ.regPC0, n);
  3022:     }
  3023:     if (prnCurrentPaper == null) {  //未給紙のとき
  3024:       prnFeedPaper ();  //給紙する
  3025:     }
  3026:     if (0 <= n && n <= 99) {
  3027:       int height = prnLineHeight * n;
  3028:       if (height < prnPageLength - prnCurrentPaper.marginTopHeight) {
  3029:         prnCurrentPaper.marginBottomHeight = height;
  3030:         //コンテント範囲
  3031:         prnContentBottomY = Math.min (prnPageStart + prnPageLength - height,
  3032:                                       prnAliveBottomY - prnAliveTopY);
  3033:         //コンテント範囲に収まっているか
  3034:         if (prnContentBottomY <= prnHeadY) {  //下からはみ出した
  3035:           //改ページする
  3036:           prnPrintFormFeed ();
  3037:         }
  3038:         //垂直タブ位置をクリアする
  3039:         for (int k = 0; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  3040:           prnVerticalTabAnchor[k] = 0;
  3041:         }
  3042:       }
  3043:     }
  3044:   }  //prnSetBottomMargin(int)
  3045: 
  3046:   //prnSetEliteCharacterMode ()
  3047:   //  ESC E  エリート文字設定  (p102)
  3048:   //  エリート文字(1/12[in])にする
  3049:   //  https://en.wikipedia.org/wiki/Typewriter#Character_sizes
  3050:   public static void prnSetEliteCharacterMode () {
  3051:     if (PRN_DEBUG_TRACE) {
  3052:       System.out.printf ("%08x prnSetEliteCharacterMode()\n", XEiJ.regPC0);
  3053:     }
  3054:     prnCharacterType = PRN_ELITE;  //エリート文字
  3055:   }  //prnSetEliteCharacterMode()
  3056: 
  3057:   //prnSetPageHeight (n)
  3058:   //  ESC F n1 n2  ページ高さ設定  (p78)
  3059:   //  ページの高さをn/2[in]にする
  3060:   //  現在の印字位置がページの先頭になる
  3061:   //  n=0は無視される
  3062:   //  下マージンはクリアされる
  3063:   public static void prnSetPageHeight (int n) {
  3064:     if (PRN_DEBUG_TRACE) {
  3065:       System.out.printf ("%08x prnSetPageHeight(%d)\n", XEiJ.regPC0, n);
  3066:     }
  3067:     if (prnCurrentPaper == null) {  //未給紙のとき
  3068:       prnFeedPaper ();  //給紙する
  3069:     }
  3070:     prnSetPageStartPosition ();  //ページ先頭設定
  3071:     if (1 <= n && n <= 99) {
  3072:       //ページ長
  3073:       prnPageLength = 180 * n;
  3074:       //下マージン
  3075:       prnCurrentPaper.marginBottomHeight = 0;
  3076:       //ページ開始位置
  3077:       prnSetPageStartPosition ();
  3078:     }
  3079:   }  //prnSetPageHeight(int)
  3080: 
  3081:   //prn16DotBitImage (a, o, n)
  3082:   //  ESC I n1 n2 n3 n4 d1 d2 … dk  16ドットビットイメージ  (p148)
  3083:   //  横方向を3倍に拡大する
  3084:   //  縦方向を3倍に拡大する。高さが48[dot]になる
  3085:   //  改行ピッチが15/120[in]のとき16/120[in]にする
  3086:   //  横2倍と縦2倍が有効
  3087:   //  行からはみ出した部分は無視される
  3088:   public static void prn16DotBitImage (byte[] a, int o, int n) {
  3089:     if (PRN_DEBUG_TRACE) {
  3090:       prnDebugTracePrintBuffer ("prn16DotBitImage", a, o, n);
  3091:     }
  3092:     if (prnCurrentPaper == null) {  //未給紙のとき
  3093:       prnFeedPaper ();  //給紙する
  3094:     }
  3095:     //改行ピッチが15/120[in]のとき16/120[in]にする
  3096:     if (prnLineHeight == 45) {
  3097:       prnLineHeight = 48;
  3098:     }
  3099:     byte[] bitmap = prnCurrentPaper.getBitmap ();
  3100:     int offset = prnCurrentPaper.paperWidth;
  3101:     int index = offset * (prnAliveTopY + prnHeadY) + (prnAliveLeftX + prnHeadX);
  3102:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  3103:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3104:         //横1倍,縦1倍
  3105:         int aw = n;  //横nビット→3*nドット
  3106:         int ah = 16;  //縦16ビット→48ドット
  3107:         aw = Math.min (3 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  3108:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  3109:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3110:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3111:             if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3112:               int i = index + 3 * ax;  //右へ3ドットずつ進む
  3113:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3114:               bitmap[i + 1] &= prnCurrentColor;
  3115:               bitmap[i + 2] &= prnCurrentColor;
  3116:               i += offset;
  3117:               bitmap[i    ] &= prnCurrentColor;
  3118:               bitmap[i + 1] &= prnCurrentColor;
  3119:               bitmap[i + 2] &= prnCurrentColor;
  3120:               i += offset;
  3121:               bitmap[i    ] &= prnCurrentColor;
  3122:               bitmap[i + 1] &= prnCurrentColor;
  3123:               bitmap[i + 2] &= prnCurrentColor;
  3124:             }
  3125:           }
  3126:           index += offset * 3;  //下へ3ドットずつ進む
  3127:         }
  3128:         prnHeadX += 3 * aw;
  3129:       } else {  //縦2倍
  3130:         //横1倍,縦2倍
  3131:         int aw = n;  //横nビット→3*nドット
  3132:         int ah = 16;  //縦16ビット→96ドット
  3133:         aw = Math.min (3 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  3134:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  3135:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3136:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3137:             if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3138:               int i = index + 3 * ax;  //右へ3ドットずつ進む
  3139:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3140:               bitmap[i + 1] &= prnCurrentColor;
  3141:               bitmap[i + 2] &= prnCurrentColor;
  3142:               i += offset;
  3143:               bitmap[i    ] &= prnCurrentColor;
  3144:               bitmap[i + 1] &= prnCurrentColor;
  3145:               bitmap[i + 2] &= prnCurrentColor;
  3146:               i += offset;
  3147:               bitmap[i    ] &= prnCurrentColor;
  3148:               bitmap[i + 1] &= prnCurrentColor;
  3149:               bitmap[i + 2] &= prnCurrentColor;
  3150:               i += offset;
  3151:               bitmap[i    ] &= prnCurrentColor;
  3152:               bitmap[i + 1] &= prnCurrentColor;
  3153:               bitmap[i + 2] &= prnCurrentColor;
  3154:               i += offset;
  3155:               bitmap[i    ] &= prnCurrentColor;
  3156:               bitmap[i + 1] &= prnCurrentColor;
  3157:               bitmap[i + 2] &= prnCurrentColor;
  3158:               i += offset;
  3159:               bitmap[i    ] &= prnCurrentColor;
  3160:               bitmap[i + 1] &= prnCurrentColor;
  3161:               bitmap[i + 2] &= prnCurrentColor;
  3162:             }
  3163:           }
  3164:           index += offset * 6;  //下へ6ドットずつ進む
  3165:         }
  3166:         prnHeadX += 3 * aw;
  3167:       }  //if 縦1倍/縦2倍
  3168:     } else {  //横2倍
  3169:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3170:         //横2倍,縦1倍
  3171:         int aw = n;  //横nビット→6*nドット
  3172:         int ah = 16;  //縦16ビット→48ドット
  3173:         aw = Math.min (6 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  3174:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  3175:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3176:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3177:             if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3178:               int i = index + 6 * ax;  //右へ6ドットずつ進む
  3179:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3180:               bitmap[i + 1] &= prnCurrentColor;
  3181:               bitmap[i + 2] &= prnCurrentColor;
  3182:               bitmap[i + 3] &= prnCurrentColor;
  3183:               bitmap[i + 4] &= prnCurrentColor;
  3184:               bitmap[i + 5] &= prnCurrentColor;
  3185:               i += offset;
  3186:               bitmap[i    ] &= prnCurrentColor;
  3187:               bitmap[i + 1] &= prnCurrentColor;
  3188:               bitmap[i + 2] &= prnCurrentColor;
  3189:               bitmap[i + 3] &= prnCurrentColor;
  3190:               bitmap[i + 4] &= prnCurrentColor;
  3191:               bitmap[i + 5] &= prnCurrentColor;
  3192:               i += offset;
  3193:               bitmap[i    ] &= prnCurrentColor;
  3194:               bitmap[i + 1] &= prnCurrentColor;
  3195:               bitmap[i + 2] &= prnCurrentColor;
  3196:               bitmap[i + 3] &= prnCurrentColor;
  3197:               bitmap[i + 4] &= prnCurrentColor;
  3198:               bitmap[i + 5] &= prnCurrentColor;
  3199:             }
  3200:           }
  3201:           index += offset * 3;  //下へ3ドットずつ進む
  3202:         }
  3203:         prnHeadX += 6 * aw;
  3204:       } else {  //縦2倍
  3205:         //横2倍,縦2倍
  3206:         int aw = n;  //横nビット→6*nドット
  3207:         int ah = 16;  //縦16ビット→96ドット
  3208:         aw = Math.min (6 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  3209:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  3210:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3211:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3212:             if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3213:               int i = index + 6 * ax;  //右へ6ドットずつ進む
  3214:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3215:               bitmap[i + 1] &= prnCurrentColor;
  3216:               bitmap[i + 2] &= prnCurrentColor;
  3217:               bitmap[i + 3] &= prnCurrentColor;
  3218:               bitmap[i + 4] &= prnCurrentColor;
  3219:               bitmap[i + 5] &= prnCurrentColor;
  3220:               i += offset;
  3221:               bitmap[i    ] &= prnCurrentColor;
  3222:               bitmap[i + 1] &= prnCurrentColor;
  3223:               bitmap[i + 2] &= prnCurrentColor;
  3224:               bitmap[i + 3] &= prnCurrentColor;
  3225:               bitmap[i + 4] &= prnCurrentColor;
  3226:               bitmap[i + 5] &= prnCurrentColor;
  3227:               i += offset;
  3228:               bitmap[i    ] &= prnCurrentColor;
  3229:               bitmap[i + 1] &= prnCurrentColor;
  3230:               bitmap[i + 2] &= prnCurrentColor;
  3231:               bitmap[i + 3] &= prnCurrentColor;
  3232:               bitmap[i + 4] &= prnCurrentColor;
  3233:               bitmap[i + 5] &= prnCurrentColor;
  3234:               i += offset;
  3235:               bitmap[i    ] &= prnCurrentColor;
  3236:               bitmap[i + 1] &= prnCurrentColor;
  3237:               bitmap[i + 2] &= prnCurrentColor;
  3238:               bitmap[i + 3] &= prnCurrentColor;
  3239:               bitmap[i + 4] &= prnCurrentColor;
  3240:               bitmap[i + 5] &= prnCurrentColor;
  3241:               i += offset;
  3242:               bitmap[i    ] &= prnCurrentColor;
  3243:               bitmap[i + 1] &= prnCurrentColor;
  3244:               bitmap[i + 2] &= prnCurrentColor;
  3245:               bitmap[i + 3] &= prnCurrentColor;
  3246:               bitmap[i + 4] &= prnCurrentColor;
  3247:               bitmap[i + 5] &= prnCurrentColor;
  3248:               i += offset;
  3249:               bitmap[i    ] &= prnCurrentColor;
  3250:               bitmap[i + 1] &= prnCurrentColor;
  3251:               bitmap[i + 2] &= prnCurrentColor;
  3252:               bitmap[i + 3] &= prnCurrentColor;
  3253:               bitmap[i + 4] &= prnCurrentColor;
  3254:               bitmap[i + 5] &= prnCurrentColor;
  3255:             }
  3256:           }
  3257:           index += offset * 6;  //下へ6ドットずつ進む
  3258:         }
  3259:         prnHeadX += 6 * aw;
  3260:       }  //if 縦1倍/縦2倍
  3261:     }  //if 横1倍/横2倍
  3262:     prnPrinted = true;  //印字あり
  3263:     //キャンバスを再描画する
  3264:     if (prnCanvas != null) {
  3265:       prnCanvas.repaint ();
  3266:     }
  3267:   }  //prn16DotBitImage(byte[],int,int)
  3268: 
  3269:   //prn24DotBitImage (a, o, n)
  3270:   //  ESC J n1 n2 d1 d2 … dk  24ドットビットイメージ  (p151)
  3271:   //  横方向を2倍に拡大する
  3272:   //  縦方向を2倍に拡大する。高さが48[dot]になる
  3273:   //  改行ピッチが15/120[in]のとき16/120[in]にする
  3274:   //  横2倍と縦2倍が有効
  3275:   //  行からはみ出した部分は無視される
  3276:   public static void prn24DotBitImage (byte[] a, int o, int n) {
  3277:     if (PRN_DEBUG_TRACE) {
  3278:       prnDebugTracePrintBuffer ("prn24DotBitImage", a, o, n);
  3279:     }
  3280:     if (prnCurrentPaper == null) {  //未給紙のとき
  3281:       prnFeedPaper ();  //給紙する
  3282:     }
  3283:     //改行ピッチが15/120[in]のとき16/120[in]にする
  3284:     if (prnLineHeight == 45) {
  3285:       prnLineHeight = 48;
  3286:     }
  3287:     byte[] bitmap = prnCurrentPaper.getBitmap ();
  3288:     int offset = prnCurrentPaper.paperWidth;
  3289:     int index = offset * (prnAliveTopY + prnHeadY) + (prnAliveLeftX + prnHeadX);
  3290:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  3291:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3292:         //横1倍,縦1倍
  3293:         int aw = n;  //横nビット→2*nドット
  3294:         int ah = 24;  //縦24ビット→48ドット
  3295:         aw = Math.min (2 * aw, prnCurrentPaper.marginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  3296:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  3297:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3298:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3299:             if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3300:               int i = index + 2 * ax;  //右へ2ドットずつ進む
  3301:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3302:               bitmap[i + 1] &= prnCurrentColor;
  3303:               i += offset;
  3304:               bitmap[i    ] &= prnCurrentColor;
  3305:               bitmap[i + 1] &= prnCurrentColor;
  3306:             }
  3307:           }
  3308:           index += offset * 2;  //下へ2ドットずつ進む
  3309:         }
  3310:         prnHeadX += 2 * aw;
  3311:       } else {  //縦2倍
  3312:         //横1倍,縦2倍
  3313:         int aw = n;  //横nビット→2*nドット
  3314:         int ah = 24;  //縦24ビット→96ドット
  3315:         aw = Math.min (2 * aw, prnCurrentPaper.marginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  3316:         ah = Math.min (4 * ah, prnContentBottomY - prnHeadY) >> 2;  //縦ahビット→4*ahドット
  3317:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3318:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3319:             if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3320:               int i = index + 2 * ax;  //右へ2ドットずつ進む
  3321:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3322:               bitmap[i + 1] &= prnCurrentColor;
  3323:               i += offset;
  3324:               bitmap[i    ] &= prnCurrentColor;
  3325:               bitmap[i + 1] &= prnCurrentColor;
  3326:               i += offset;
  3327:               bitmap[i    ] &= prnCurrentColor;
  3328:               bitmap[i + 1] &= prnCurrentColor;
  3329:               i += offset;
  3330:               bitmap[i    ] &= prnCurrentColor;
  3331:               bitmap[i + 1] &= prnCurrentColor;
  3332:             }
  3333:           }
  3334:           index += offset * 4;  //下へ4ドットずつ進む
  3335:         }
  3336:         prnHeadX += 2 * aw;
  3337:       }  //if 縦1倍/縦2倍
  3338:     } else {  //横2倍
  3339:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3340:         //横2倍,縦1倍
  3341:         int aw = n;  //横nビット→4*nドット
  3342:         int ah = 24;  //縦24ビット→48ドット
  3343:         aw = Math.min (4 * aw, prnCurrentPaper.marginRightX - prnHeadX) >> 2;  //横awビット→4*awドット
  3344:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  3345:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3346:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3347:             if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3348:               int i = index + 4 * ax;  //右へ4ドットずつ進む
  3349:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3350:               bitmap[i + 1] &= prnCurrentColor;
  3351:               bitmap[i + 2] &= prnCurrentColor;
  3352:               bitmap[i + 3] &= prnCurrentColor;
  3353:               i += offset;
  3354:               bitmap[i    ] &= prnCurrentColor;
  3355:               bitmap[i + 1] &= prnCurrentColor;
  3356:               bitmap[i + 2] &= prnCurrentColor;
  3357:               bitmap[i + 3] &= prnCurrentColor;
  3358:             }
  3359:           }
  3360:           index += offset * 2;  //下へ2ドットずつ進む
  3361:         }
  3362:         prnHeadX += 4 * aw;
  3363:       } else {  //縦2倍
  3364:         //横2倍,縦2倍
  3365:         int aw = n;  //横nビット→4*nドット
  3366:         int ah = 24;  //縦24ビット→96ドット
  3367:         aw = Math.min (4 * aw, prnCurrentPaper.marginRightX - prnHeadX) >> 2;  //横awビット→4*awドット
  3368:         ah = Math.min (4 * ah, prnContentBottomY - prnHeadY) >> 2;  //縦ahビット→4*ahドット
  3369:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3370:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3371:             if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3372:               int i = index + 4 * ax;  //右へ4ドットずつ進む
  3373:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3374:               bitmap[i + 1] &= prnCurrentColor;
  3375:               bitmap[i + 2] &= prnCurrentColor;
  3376:               bitmap[i + 3] &= prnCurrentColor;
  3377:               i += offset;
  3378:               bitmap[i    ] &= prnCurrentColor;
  3379:               bitmap[i + 1] &= prnCurrentColor;
  3380:               bitmap[i + 2] &= prnCurrentColor;
  3381:               bitmap[i + 3] &= prnCurrentColor;
  3382:               i += offset;
  3383:               bitmap[i    ] &= prnCurrentColor;
  3384:               bitmap[i + 1] &= prnCurrentColor;
  3385:               bitmap[i + 2] &= prnCurrentColor;
  3386:               bitmap[i + 3] &= prnCurrentColor;
  3387:               i += offset;
  3388:               bitmap[i    ] &= prnCurrentColor;
  3389:               bitmap[i + 1] &= prnCurrentColor;
  3390:               bitmap[i + 2] &= prnCurrentColor;
  3391:               bitmap[i + 3] &= prnCurrentColor;
  3392:             }
  3393:           }
  3394:           index += offset * 4;  //下へ4ドットずつ進む
  3395:         }
  3396:         prnHeadX += 4 * aw;
  3397:       }  //if 縦1倍/縦2倍
  3398:     }  //if 横1倍/横2倍
  3399:     prnPrinted = true;  //印字あり
  3400:     //キャンバスを再描画する
  3401:     if (prnCanvas != null) {
  3402:       prnCanvas.repaint ();
  3403:     }
  3404:   }  //prn24DotBitImage(byte[],int,int)
  3405: 
  3406:   //prnSetKanjiMode (b)
  3407:   //  b  true   ESC K  漢字モードON  (p118)
  3408:   //     false  ESC H  漢字モードOFF  (p121)
  3409:   //            ESC P  漢字モードOFF  (p121)
  3410:   public static void prnSetKanjiMode (boolean b) {
  3411:     if (PRN_DEBUG_TRACE) {
  3412:       System.out.printf ("%08x prnSetKanjiMode(%b)\n", XEiJ.regPC0, b);
  3413:     }
  3414:     prnKanjiMode = b;
  3415:   }  //prnSetKanjiMode(boolean)
  3416: 
  3417:   //prnSetLeftMargin (n)
  3418:   //  ESC L n1 n2 n3  左マージン設定  (p86)
  3419:   //  左マージンをn桁にする
  3420:   //  最大数よりも大きいと無視される
  3421:   //  水平タブ位置はクリアされる
  3422:   //  単位は現在の文字の幅
  3423:   //  漢字モードのときは半角の幅
  3424:   //  横2倍は無視される
  3425:   public static void prnSetLeftMargin (int n) {
  3426:     if (PRN_DEBUG_TRACE) {
  3427:       System.out.printf ("%08x prnSetLeftMargin(%d)\n", XEiJ.regPC0, n);
  3428:     }
  3429:     if (prnCurrentPaper == null) {  //未給紙のとき
  3430:       prnFeedPaper ();  //給紙する
  3431:     }
  3432:     if (0 <= n && n <= 999) {
  3433:       int leftX = prnGetCharacterWidth () * n;
  3434:       if (leftX < prnCurrentPaper.marginRightX) {
  3435:         prnCurrentPaper.marginLeftX = leftX;
  3436:         if (prnHeadX < prnCurrentPaper.marginLeftX) {
  3437:           prnHeadX = prnCurrentPaper.marginLeftX;
  3438:         }
  3439:         //水平タブ位置をクリアする
  3440:         for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3441:           prnHorizontalTabAnchor[k] = 0;
  3442:         }
  3443:       }
  3444:     }
  3445:   }  //prnSetLeftMargin(int)
  3446: 
  3447:   //prn48DotBitImage (a, o, n)
  3448:   //  ESC M n1 n2 d1 d2 … dk  48ドットビットイメージ  (p153)
  3449:   //  拡大しない
  3450:   //  改行ピッチが15/120[in]のとき47/360[in]にする
  3451:   //  横2倍と縦2倍が有効
  3452:   //  行からはみ出した部分は無視される
  3453:   public static void prn48DotBitImage (byte[] a, int o, int n) {
  3454:     if (PRN_DEBUG_TRACE) {
  3455:       prnDebugTracePrintBuffer ("prn48DotBitImage", a, o, n);
  3456:     }
  3457:     if (prnCurrentPaper == null) {  //未給紙のとき
  3458:       prnFeedPaper ();  //給紙する
  3459:     }
  3460:     //改行ピッチが15/120[in]のとき47/360[in]にする
  3461:     if (prnLineHeight == 45) {
  3462:       prnLineHeight = 47;
  3463:     }
  3464:     byte[] bitmap = prnCurrentPaper.getBitmap ();
  3465:     int offset = prnCurrentPaper.paperWidth;
  3466:     int index = offset * (prnAliveTopY + prnHeadY) + (prnAliveLeftX + prnHeadX);
  3467:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  3468:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3469:         //横1倍,縦1倍
  3470:         int aw = n;  //横nビット→nドット
  3471:         int ah = 48;  //縦48ビット→48ドット
  3472:         aw = Math.min (aw, prnCurrentPaper.marginRightX - prnHeadX);  //横awビット→awドット
  3473:         ah = Math.min (ah, prnContentBottomY - prnHeadY);  //縦ahビット→ahドット
  3474:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3475:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3476:             if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3477:               int i = index + ax;  //右へ1ドットずつ進む
  3478:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3479:             }
  3480:           }
  3481:           index += offset;  //下へ1ドットずつ進む
  3482:         }
  3483:         prnHeadX += aw;
  3484:       } else {  //縦2倍
  3485:         //横1倍,縦2倍
  3486:         int aw = n;  //横nビット→nドット
  3487:         int ah = 48;  //縦48ビット→96ドット
  3488:         aw = Math.min (aw, prnCurrentPaper.marginRightX - prnHeadX);  //横awビット→awドット
  3489:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  3490:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3491:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3492:             if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3493:               int i = index + ax;  //右へ1ドットずつ進む
  3494:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3495:               i += offset;
  3496:               bitmap[i    ] &= prnCurrentColor;
  3497:             }
  3498:           }
  3499:           index += offset * 2;  //下へ2ドットずつ進む
  3500:         }
  3501:         prnHeadX += aw;
  3502:       }  //if 縦1倍/縦2倍
  3503:     } else {  //横2倍
  3504:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3505:         //横2倍,縦1倍
  3506:         int aw = n;  //横nビット→2*nドット
  3507:         int ah = 48;  //縦48ビット→48ドット
  3508:         aw = Math.min (2 * aw, prnCurrentPaper.marginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  3509:         ah = Math.min (ah, prnContentBottomY - prnHeadY);  //縦ahビット→ahドット
  3510:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3511:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3512:             if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3513:               int i = index + 2 * ax;  //右へ2ドットずつ進む
  3514:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3515:               bitmap[i + 1] &= prnCurrentColor;
  3516:             }
  3517:           }
  3518:           index += offset;  //下へ1ドットずつ進む
  3519:         }
  3520:         prnHeadX += 2 * aw;
  3521:       } else {  //縦2倍
  3522:         //横2倍,縦2倍
  3523:         int aw = n;  //横nビット→2*nドット
  3524:         int ah = 24;  //縦48ビット→96ドット
  3525:         aw = Math.min (2 * aw, prnCurrentPaper.marginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  3526:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  3527:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3528:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3529:             if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3530:               int i = index + 2 * ax;  //右へ2ドットずつ進む
  3531:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3532:               bitmap[i + 1] &= prnCurrentColor;
  3533:               i += offset;
  3534:               bitmap[i    ] &= prnCurrentColor;
  3535:               bitmap[i + 1] &= prnCurrentColor;
  3536:             }
  3537:           }
  3538:           index += offset * 2;  //下へ2ドットずつ進む
  3539:         }
  3540:         prnHeadX += 2 * aw;
  3541:       }  //if 縦1倍/縦2倍
  3542:     }  //if 横1倍/横2倍
  3543:     prnPrinted = true;  //印字あり
  3544:     //キャンバスを再描画する
  3545:     if (prnCanvas != null) {
  3546:       prnCanvas.repaint ();
  3547:     }
  3548:   }  //prn48DotBitImage(byte[],int,int)
  3549: 
  3550:   //prnRepeatCharacter (n, d)
  3551:   //  ESC N n1 n2 n3 d  連続文字  (p162)
  3552:   //  文字dをn回印字する
  3553:   //  制御コードは無視する
  3554:   public static void prnRepeatCharacter (int n, int d) {
  3555:     if (PRN_DEBUG_TRACE) {
  3556:       System.out.printf ("%08x prnRepeatCharacter(%d,%d)\n", XEiJ.regPC0, n, d);
  3557:     }
  3558:     if (prnCurrentPaper == null) {  //未給紙のとき
  3559:       prnFeedPaper ();  //給紙する
  3560:     }
  3561:     if (0x20 <= d) {  //制御コードでない
  3562:       for (int i = 0; i < n; i++) {
  3563:         prnPrintCharacter (d);  //1文字印字
  3564:       }
  3565:     }
  3566:   }  //prnRepeatCharacter(int,int)
  3567: 
  3568:   //prnSetSmallCharacterMode ()
  3569:   //  ESC Q  縮小文字設定  (p103)
  3570:   //  縮小文字(1/17[in])にする
  3571:   public static void prnSetSmallCharacterMode () {
  3572:     if (PRN_DEBUG_TRACE) {
  3573:       System.out.printf ("%08x prnSetSmallCharacterMode()\n", XEiJ.regPC0);
  3574:     }
  3575:     prnCharacterType = PRN_SMALL;  //縮小文字
  3576:   }  //prnSetSmallCharacterMode()
  3577: 
  3578:   //prnSetPicaCharacterMode ()
  3579:   //  ESC R  パイカ文字設定  (p101)
  3580:   //  パイカ文字(1/10[in])にする
  3581:   //  https://en.wikipedia.org/wiki/Typewriter#Character_sizes
  3582:   public static void prnSetPicaCharacterMode () {
  3583:     if (PRN_DEBUG_TRACE) {
  3584:       System.out.printf ("%08x prnSetPicaCharacterMode()\n", XEiJ.regPC0);
  3585:     }
  3586:     prnCharacterType = PRN_PICA;  //パイカ文字
  3587:   }  //prnSetPicaCharacterMode()
  3588: 
  3589:   //prnRepeat8DotBitImage (n, d)
  3590:   //  ESC V n1 n2 n3 n4 d  連続8ドットビットメージ  (p155)
  3591:   public static void prnRepeat8DotBitImage (int n, int d) {
  3592:     if (PRN_DEBUG_TRACE) {
  3593:       System.out.printf ("%08x prnRepeat8DotBitImage(%d,%d)\n", XEiJ.regPC0, n, d);
  3594:     }
  3595:     if (prnCurrentPaper == null) {  //未給紙のとき
  3596:       prnFeedPaper ();  //給紙する
  3597:     }
  3598:     //!!!
  3599:   }  //prnRepeat8DotBitImage(int,int)
  3600: 
  3601:   //prnRepeat16DotBitImage (n, d)
  3602:   //  ESC W n1 n2 n3 n4 d1 d2  連続16ドットビットメージ  (p156)
  3603:   public static void prnRepeat16DotBitImage (int n, int d) {
  3604:     if (PRN_DEBUG_TRACE) {
  3605:       System.out.printf ("%08x prnRepeat16DotBitImage(%d,%d)\n", XEiJ.regPC0, n, d);
  3606:     }
  3607:     if (prnCurrentPaper == null) {  //未給紙のとき
  3608:       prnFeedPaper ();  //給紙する
  3609:     }
  3610:     //改行ピッチが15/120[in]のとき16/120[in]にする
  3611:     if (prnLineHeight == 45) {
  3612:       prnLineHeight = 48;
  3613:     }
  3614:     byte[] bitmap = prnCurrentPaper.getBitmap ();
  3615:     int offset = prnCurrentPaper.paperWidth;
  3616:     int index = offset * (prnAliveTopY + prnHeadY) + (prnAliveLeftX + prnHeadX);
  3617:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  3618:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3619:         //横1倍,縦1倍
  3620:         int aw = n;  //横nビット→3*nドット
  3621:         int ah = 16;  //縦16ビット→48ドット
  3622:         aw = Math.min (3 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  3623:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  3624:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3625:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3626:             if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  3627:               int i = index + 3 * ax;  //右へ3ドットずつ進む
  3628:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3629:               bitmap[i + 1] &= prnCurrentColor;
  3630:               bitmap[i + 2] &= prnCurrentColor;
  3631:               i += offset;
  3632:               bitmap[i    ] &= prnCurrentColor;
  3633:               bitmap[i + 1] &= prnCurrentColor;
  3634:               bitmap[i + 2] &= prnCurrentColor;
  3635:               i += offset;
  3636:               bitmap[i    ] &= prnCurrentColor;
  3637:               bitmap[i + 1] &= prnCurrentColor;
  3638:               bitmap[i + 2] &= prnCurrentColor;
  3639:             }
  3640:           }
  3641:           index += offset * 3;  //下へ3ドットずつ進む
  3642:         }
  3643:         prnHeadX += 3 * aw;
  3644:       } else {  //縦2倍
  3645:         //横1倍,縦2倍
  3646:         int aw = n;  //横nビット→3*nドット
  3647:         int ah = 16;  //縦16ビット→96ドット
  3648:         aw = Math.min (3 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  3649:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  3650:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3651:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3652:             if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  3653:               int i = index + 3 * ax;  //右へ3ドットずつ進む
  3654:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3655:               bitmap[i + 1] &= prnCurrentColor;
  3656:               bitmap[i + 2] &= prnCurrentColor;
  3657:               i += offset;
  3658:               bitmap[i    ] &= prnCurrentColor;
  3659:               bitmap[i + 1] &= prnCurrentColor;
  3660:               bitmap[i + 2] &= prnCurrentColor;
  3661:               i += offset;
  3662:               bitmap[i    ] &= prnCurrentColor;
  3663:               bitmap[i + 1] &= prnCurrentColor;
  3664:               bitmap[i + 2] &= prnCurrentColor;
  3665:               i += offset;
  3666:               bitmap[i    ] &= prnCurrentColor;
  3667:               bitmap[i + 1] &= prnCurrentColor;
  3668:               bitmap[i + 2] &= prnCurrentColor;
  3669:               i += offset;
  3670:               bitmap[i    ] &= prnCurrentColor;
  3671:               bitmap[i + 1] &= prnCurrentColor;
  3672:               bitmap[i + 2] &= prnCurrentColor;
  3673:               i += offset;
  3674:               bitmap[i    ] &= prnCurrentColor;
  3675:               bitmap[i + 1] &= prnCurrentColor;
  3676:               bitmap[i + 2] &= prnCurrentColor;
  3677:             }
  3678:           }
  3679:           index += offset * 6;  //下へ6ドットずつ進む
  3680:         }
  3681:         prnHeadX += 3 * aw;
  3682:       }  //if 縦1倍/縦2倍
  3683:     } else {  //横2倍
  3684:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3685:         //横2倍,縦1倍
  3686:         int aw = n;  //横nビット→6*nドット
  3687:         int ah = 16;  //縦16ビット→48ドット
  3688:         aw = Math.min (6 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  3689:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  3690:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3691:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3692:             if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  3693:               int i = index + 6 * ax;  //右へ6ドットずつ進む
  3694:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3695:               bitmap[i + 1] &= prnCurrentColor;
  3696:               bitmap[i + 2] &= prnCurrentColor;
  3697:               bitmap[i + 3] &= prnCurrentColor;
  3698:               bitmap[i + 4] &= prnCurrentColor;
  3699:               bitmap[i + 5] &= prnCurrentColor;
  3700:               i += offset;
  3701:               bitmap[i    ] &= prnCurrentColor;
  3702:               bitmap[i + 1] &= prnCurrentColor;
  3703:               bitmap[i + 2] &= prnCurrentColor;
  3704:               bitmap[i + 3] &= prnCurrentColor;
  3705:               bitmap[i + 4] &= prnCurrentColor;
  3706:               bitmap[i + 5] &= prnCurrentColor;
  3707:               i += offset;
  3708:               bitmap[i    ] &= prnCurrentColor;
  3709:               bitmap[i + 1] &= prnCurrentColor;
  3710:               bitmap[i + 2] &= prnCurrentColor;
  3711:               bitmap[i + 3] &= prnCurrentColor;
  3712:               bitmap[i + 4] &= prnCurrentColor;
  3713:               bitmap[i + 5] &= prnCurrentColor;
  3714:             }
  3715:           }
  3716:           index += offset * 3;  //下へ3ドットずつ進む
  3717:         }
  3718:         prnHeadX += 6 * aw;
  3719:       } else {  //縦2倍
  3720:         //横2倍,縦2倍
  3721:         int aw = n;  //横nビット→6*nドット
  3722:         int ah = 16;  //縦16ビット→96ドット
  3723:         aw = Math.min (6 * aw, prnCurrentPaper.marginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  3724:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  3725:         for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3726:           for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3727:             if ((short) (d << (ay & 15)) < 0) {  //ビットがセットされている
  3728:               int i = index + 6 * ax;  //右へ6ドットずつ進む
  3729:               bitmap[i    ] &= prnCurrentColor;  //ANDで描く
  3730:               bitmap[i + 1] &= prnCurrentColor;
  3731:               bitmap[i + 2] &= prnCurrentColor;
  3732:               bitmap[i + 3] &= prnCurrentColor;
  3733:               bitmap[i + 4] &= prnCurrentColor;
  3734:               bitmap[i + 5] &= prnCurrentColor;
  3735:               i += offset;
  3736:               bitmap[i    ] &= prnCurrentColor;
  3737:               bitmap[i + 1] &= prnCurrentColor;
  3738:               bitmap[i + 2] &= prnCurrentColor;
  3739:               bitmap[i + 3] &= prnCurrentColor;
  3740:               bitmap[i + 4] &= prnCurrentColor;
  3741:               bitmap[i + 5] &= prnCurrentColor;
  3742:               i += offset;
  3743:               bitmap[i    ] &= prnCurrentColor;
  3744:               bitmap[i + 1] &= prnCurrentColor;
  3745:               bitmap[i + 2] &= prnCurrentColor;
  3746:               bitmap[i + 3] &= prnCurrentColor;
  3747:               bitmap[i + 4] &= prnCurrentColor;
  3748:               bitmap[i + 5] &= prnCurrentColor;
  3749:               i += offset;
  3750:               bitmap[i    ] &= prnCurrentColor;
  3751:               bitmap[i + 1] &= prnCurrentColor;
  3752:               bitmap[i + 2] &= prnCurrentColor;
  3753:               bitmap[i + 3] &= prnCurrentColor;
  3754:               bitmap[i + 4] &= prnCurrentColor;
  3755:               bitmap[i + 5] &= prnCurrentColor;
  3756:               i += offset;
  3757:               bitmap[i    ] &= prnCurrentColor;
  3758:               bitmap[i + 1] &= prnCurrentColor;
  3759:               bitmap[i + 2] &= prnCurrentColor;
  3760:               bitmap[i + 3] &= prnCurrentColor;
  3761:               bitmap[i + 4] &= prnCurrentColor;
  3762:               bitmap[i + 5] &= prnCurrentColor;
  3763:               i += offset;
  3764:               bitmap[i    ] &= prnCurrentColor;
  3765:               bitmap[i + 1] &= prnCurrentColor;
  3766:               bitmap[i + 2] &= prnCurrentColor;
  3767:               bitmap[i + 3] &= prnCurrentColor;
  3768:               bitmap[i + 4] &= prnCurrentColor;
  3769:               bitmap[i + 5] &= prnCurrentColor;
  3770:             }
  3771:           }
  3772:           index += offset * 6;  //下へ6ドットずつ進む
  3773:         }
  3774:         prnHeadX += 6 * aw;
  3775:       }  //if 縦1倍/縦2倍
  3776:     }  //if 横1倍/横2倍
  3777:     prnPrinted = true;  //印字あり
  3778:     //キャンバスを再描画する
  3779:     if (prnCanvas != null) {
  3780:       prnCanvas.repaint ();
  3781:     }
  3782:   }  //prnRepeat16DotBitImage(int,int)
  3783: 
  3784:   //prnSetUnderlineMode (b)
  3785:   //  b  true   ESC X  アンダーラインあり  (p114)
  3786:   //     false  ESC Y  アンダーラインなし  (p115)
  3787:   public static void prnSetUnderlineMode (boolean b) {
  3788:     if (PRN_DEBUG_TRACE) {
  3789:       System.out.printf ("%08x prnSetUnderlineMode(%b)\n", XEiJ.regPC0, b);
  3790:     }
  3791:     prnUnderlineMode = b;
  3792:   }  //prnSetUnderlineMode(boolean)
  3793: 
  3794:   //prnHorizontalMove (n)
  3795:   //  ESC \\ n1 n2  水平移動  (p99)
  3796:   //  ESC n  ドットスペース  (p123)
  3797:   //  水平方向にn/180[in]移動する
  3798:   //  -1440<=n<=1440
  3799:   public static void prnHorizontalMove (int n) {
  3800:     if (PRN_DEBUG_TRACE) {
  3801:       System.out.printf ("%08x prnHorizontalMove(%d)\n", XEiJ.regPC0, n);
  3802:     }
  3803:     if (prnCurrentPaper == null) {  //未給紙のとき
  3804:       prnFeedPaper ();  //給紙する
  3805:     }
  3806:     if (-1440 <= n && n <= 1440) {
  3807:       int headX = prnHeadX + 2 * n;
  3808:       if (prnCurrentPaper.marginLeftX <= headX && headX < prnCurrentPaper.marginRightX) {
  3809:         prnHeadX = headX;
  3810:       }
  3811:     }
  3812:   }  //prnHorizontalMove(int)
  3813: 
  3814:   //prnResetSettings ()
  3815:   //  ESC c 1  設定リセット  (p157)
  3816:   public static void prnResetSettings () {
  3817:     if (PRN_DEBUG_TRACE) {
  3818:       System.out.printf ("%08x prnResetSettings()\n", XEiJ.regPC0);
  3819:     }
  3820:     prnEjectPaper ();  //排紙する
  3821:     //設定
  3822:     //  改行ピッチ
  3823:     prnDefaultLineHeight = 60;  //1/6[in]改行
  3824:     prnLineHeight = 60;  //1/6[in]改行
  3825:     //  文字種
  3826:     prnCharacterType = PRN_PICA;  //パイカ
  3827:     //  ひらがなモード
  3828:     prnHiraganaMode = false;  //カタカナ
  3829:     //  スクリプトモード
  3830:     prnScriptMode = PRN_NO_SCRIPT;  //スクリプト解除
  3831:     //  強調モード
  3832:     prnStrongMode = false;  //強調OFF
  3833:     //  アンダーラインモード
  3834:     prnUnderlineMode = false;  //アンダーラインOFF
  3835:     //  文字スタイル
  3836:     prnCharacterStyle = PRN_NORMAL_STYLE;  //標準文字
  3837:     //  漢字モード
  3838:     prnKanjiMode = false;  //漢字モードOFF
  3839:     //  外字データ
  3840:     if (prnGaijiData != null) {
  3841:       Arrays.fill (prnGaijiData, (byte) 0);
  3842:     }
  3843:     //  縦書きモード
  3844:     prnVerticalWritingMode = false;  //横書き
  3845:     //  左右スペース
  3846:     prnFullWidthLeftSpace = 2;  //全角左スペース[dot]
  3847:     prnFullWidthRightSpace = 6;  //全角右スペース[dot]
  3848:     prnHalfWidthLeftSpace = 0;  //半角左スペース[dot]
  3849:     prnHalfWidthRightSpace = 4;  //半角右スペース[dot]
  3850:     //  横2倍モード
  3851:     prnHorizontalDoubleSizeMode = false;  //横2倍OFF
  3852:     prnVerticalDoubleSizeMode = false;  //縦2倍OFF
  3853:     prnKanjiHorizontalDoubleSizeMode = false;  //漢字横2倍OFF
  3854:     //  水平タブ
  3855:     for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3856:       prnHorizontalTabAnchor[k] = 36 * 8 * (1 + k);
  3857:     }
  3858:     //  垂直タブ
  3859:     for (int k = 0; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  3860:       prnVerticalTabAnchor[k] = 0;
  3861:     }
  3862:     //  マージン
  3863:     for (Paper paper : prnPaperArray) {
  3864:       paper.marginLeftX = 0;
  3865:       paper.marginRightX = paper.aliveRightX - paper.aliveLeftX;
  3866:       paper.marginTopHeight = 0;
  3867:       paper.marginBottomHeight = 0;
  3868:     }
  3869:     //  カラーモード
  3870:     prnColorMode = false;  //単色モード
  3871:     //prnSingleColor = 0;  //ブラック
  3872:     prnCurrentColor = prnSingleColor;  //現在の色
  3873:     //コマンドバッファ
  3874:     prnCommandLength = 1;
  3875:     prnCommandPointer = 0;
  3876:   }  //prnResetSettings()
  3877: 
  3878:   //prnSenseOutOfPaper (b)
  3879:   //  b  true   ESC p 1  用紙切れ検出有効  (p161)
  3880:   //     false  ESC p 0  用紙切れ検出無効  (p160)
  3881:   //  用紙切れ検出無効のときは用紙の下端から約12[mm]、有効のときは約60[mm]でディセレクトになる
  3882:   public static void prnSenseOutOfPaper (boolean b) {
  3883:     if (PRN_DEBUG_TRACE) {
  3884:       System.out.printf ("%08x prnSenseOutOfPaper(%b)\n", XEiJ.regPC0, b);
  3885:     }
  3886:     //!!!
  3887:   }  //prnSenseOutOfPaper(boolean)
  3888: 
  3889:   //prnSetCharacterStyle (n)
  3890:   //  ESC q n  文字スタイル設定  (p116)
  3891:   //  n  0  標準文字
  3892:   //     1  袋文字
  3893:   //     2  影文字
  3894:   //     3  袋影文字
  3895:   public static void prnSetCharacterStyle (int n) {
  3896:     if (PRN_DEBUG_TRACE) {
  3897:       System.out.printf ("%08x prnSetCharacterStyle(%d)\n", XEiJ.regPC0, n);
  3898:     }
  3899:     if (0 <= n && n <= 3) {
  3900:       prnCharacterStyle = n;
  3901:     }
  3902:   }  //prnSetCharacterStyle(int)
  3903: 
  3904:   //prnSetScriptMode (n)
  3905:   //  n  0  ESC s 0  スクリプト解除  (p113)
  3906:   //     1  ESC s 1  スーパースクリプト設定  (p111)
  3907:   //     2  ESC s 2  サブスクリプト設定  (p112)
  3908:   public static void prnSetScriptMode (int n) {
  3909:     if (PRN_DEBUG_TRACE) {
  3910:       System.out.printf ("%08x prnSetScriptMode(%d)\n", XEiJ.regPC0, n);
  3911:     }
  3912:     if (0 <= n && n <= 2) {
  3913:       prnScriptMode = n;
  3914:     }
  3915:   }  //prnSetScriptMode(int)
  3916: 
  3917:   //prnSetVerticalWritingMode (b)
  3918:   //  b  true   FS J  縦書き  (p128)
  3919:   //     false  FS K  横書き  (p131)
  3920:   public static void prnSetVerticalWritingMode (boolean b) {
  3921:     if (PRN_DEBUG_TRACE) {
  3922:       System.out.printf ("%08x prnSetVerticalWritingMode(%b)\n", XEiJ.regPC0, b);
  3923:     }
  3924:     prnVerticalWritingMode = b;
  3925:   }  //prnSetVerticalWritingMode(boolean)
  3926: 
  3927:   //prnSetFullWidthLeftRightSpace (l, r)
  3928:   //  FS S n1 n2  全角左右スペース  (p124)
  3929:   public static void prnSetFullWidthLeftRightSpace (int l, int r) {
  3930:     if (PRN_DEBUG_TRACE) {
  3931:       System.out.printf ("%08x prnSetFullWidthLeftRightSpace(%d,%d)\n", XEiJ.regPC0, l, r);
  3932:     }
  3933:     prnFullWidthLeftSpace = l;
  3934:     prnFullWidthRightSpace = r;
  3935:   }  //prnSetFullWidthLeftRightSpace(int,int)
  3936: 
  3937:   //prnSetHalfWidthLeftRightSpace (l, r)
  3938:   //  FS T n1 n2  半角左右スペース  (p126)
  3939:   public static void prnSetHalfWidthLeftRightSpace (int l, int r) {
  3940:     if (PRN_DEBUG_TRACE) {
  3941:       System.out.printf ("%08x prnSetHalfWidthLeftRightSpace(%d,%d)\n", XEiJ.regPC0, l, r);
  3942:     }
  3943:     prnHalfWidthLeftSpace = l;
  3944:     prnHalfWidthRightSpace = r;
  3945:   }  //prnSetHalfWidthLeftRightSpace(int,int)
  3946: 
  3947:   //prnSetKanjiHorizontalDoubleSizeMode (b)
  3948:   //  b  true   FS p  漢字横2倍ON  (p132)
  3949:   //     false  FS q  漢字横2倍OFF  (p133)
  3950:   public static void prnSetKanjiHorizontalDoubleSizeMode (boolean b) {
  3951:     if (PRN_DEBUG_TRACE) {
  3952:       System.out.printf ("%08x prnSetKanjiHorizontalDoubleSizeMode(%b)\n", XEiJ.regPC0, b);
  3953:     }
  3954:     prnKanjiHorizontalDoubleSizeMode = b;
  3955:   }  //prnSetKanjiHorizontalDoubleSizeMode(boolean)
  3956: 
  3957: }  //class PrinterPort
  3958: 
  3959: 
  3960: