PrinterPort.java
     1: //========================================================================================
     2: //  Printer.java
     3: //    en:Printer Port -- It emulates the printer CZ-8PC4.
     4: //    ja:プリンタポート -- プリンタCZ-8PC4をエミュレートします。
     5: //  Copyright (C) 2003-2023 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: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: package xeij;
    14: 
    15: import java.awt.*;
    16: import java.awt.event.*;
    17: import java.awt.image.*;
    18: import java.io.*;
    19: import javax.imageio.*;
    20: import javax.imageio.metadata.*;
    21: import javax.imageio.stream.*;
    22: import javax.swing.*;
    23: import javax.swing.event.*;
    24: import java.util.*;
    25: 
    26: 
    27: //----------------------------------------------------------------------------------------
    28: //
    29: //  プリンタポート
    30: //    0x00e8c001  bit7-0  write  DATA    プリンタデータ
    31: //    0x00e8c003  bit0    write  STROBE  0→1=プリンタデータ受け取り指示
    32: //    0x00e9c001  bit0    write  INTEN   0=プリンタ割り込み禁止,1=プリンタ割り込み許可。INTENが1でREADYが0→1のとき割り込みがかかる
    33: //                bit5    read   READY   0=プリンタビジー,1=プリンタレディ。逆に書かれている資料があるので注意
    34: //                                       STROBEの0→1から0.5μs以内にREADYが1→0になる
    35: //                                       プリンタが次のデータを受け取る準備ができるとREADYが0→1になる
    36: //                                       オフラインのときは常にプリンタビジー
    37: //    0x00e9c003  bit7-2  write  VECTOR  割り込みベクタ番号
    38: //
    39: //  プリンタ出力手順
    40: //    準備
    41: //      (1)0x00e9c003(VECTOR)に割り込みベクタ番号0x63&0xfc=0x60を設定する
    42: //      (2)0x00e9c001のbit0(INTEN)を1にする
    43: //    ループ
    44: //      (3)プリンタ割り込みを待つか、0x00e9c001のbit5(READY)が1になるまで待つ
    45: //      (4)0x00e8c001(DATA)にデータをセットする
    46: //      (5)0x00e8c003のbit0(STROBE)を0にする
    47: //      (6)0x00e8c003のbit0(STROBE)を1にする
    48: //      (7)0x00e9c001のbit5(READY)が0になる
    49: //      (8)プリンタがデータを受け取る
    50: //      (9)プリンタが次のデータを受け取る準備ができる
    51: //      (10)0x00e9c001のbit5(READY)が1になる
    52: //      (11)0x00e9c001のbit0(INTEN)が1のときプリンタ割り込みがかかる
    53: //
    54: //----------------------------------------------------------------------------------------
    55: //
    56: //  CZ-8PC4
    57: //    48ドット熱転写カラー漢字プリンタ
    58: //    昔使っていた実機のマニュアルを参考にする
    59: //
    60: //  CZ-8PC5
    61: //    CZ-8PC4の後継機
    62: //    半角書体をローマン体とサンセリフ体から、全角書体を明朝体とゴシック体から選択できる
    63: //    Oh!X 1991年3月号に紹介記事
    64: //    書体に関するディップスイッチと制御コードは以下を参考にした
    65: //      http://software.aufheben.info/contents.html?contents_key=cz8pc5
    66: //
    67: //  電源スイッチ
    68: //
    69: //  操作パネルのランプ
    70: //    電源ランプ
    71: //      緑点灯  電源ON
    72: //      消灯    電源OFF
    73: //    リボン切れランプ
    74: //      赤点灯  リボン片面終了
    75: //    用紙切れランプ
    76: //      赤点灯  用紙切れ
    77: //    ハガキランプ
    78: //      橙点灯  はがきモードON
    79: //      消灯    はがきモードOFF
    80: //    特殊リボンランプ
    81: //      橙点灯  特殊リボンモード
    82: //    高速ランプ
    83: //      橙点灯  高速印字
    84: //      消灯    標準速度
    85: //    微小送りランプ
    86: //      橙点灯  微小送りモード
    87: //    セレクトランプ
    88: //      緑点灯  セレクト状態
    89: //      消灯    ディセレクト状態
    90: //
    91: //  操作パネルのスイッチ
    92: //    ハガキスイッチ
    93: //      はがきモードのON/OFF
    94: //    特殊リボンスイッチ
    95: //      特殊リボンモードのON/OFF
    96: //    高速スイッチ
    97: //      高速印字と標準速度の切り替え
    98: //    微小送りスイッチ
    99: //      微小送りモードのON/OFF
   100: //    改頁スイッチ
   101: //      微小送りモードのとき
   102: //        順方向に1/180[in]微小送りする
   103: //      さもなくば(微小送りモードでないとき)
   104: //        改頁する
   105: //    改行スイッチ
   106: //      微小送りモードのとき
   107: //        逆方向に1/180[in]微小送りする
   108: //      さもなくば(微小送りモードでないとき)
   109: //        改行する
   110: //    セレクトスイッチ
   111: //      セレクト状態とディセレクト状態の切り替え
   112: //
   113: //  ディップスイッチ
   114: //    電源投入時、INIT信号入力時、ESC c 1実行時の初期値を選択する
   115: //      SW1  ゼロ書体      OFF  スラッシュあり(工場出荷時)。パイカ、エリート、縮小、半角に有効
   116: //                         ON   スラッシュなし
   117: //      SW2  印字速度      OFF  標準速度(工場出荷時)
   118: //                         ON   高速印字
   119: //      SW3  はがきモード  OFF  OFF(工場出荷時)
   120: //                         ON   ON
   121: //      SW4  頁長          OFF  11[in](工場出荷時)
   122: //                         ON   12[in]
   123: //      SW5                OFF  (固定)
   124: //                         ON
   125: //      SW6  給紙位置      OFF  22mm(工場出荷時)
   126: //                         ON   8.5mm
   127: //      SW7                OFF  (固定)
   128: //                         ON
   129: //      SW8  書体          OFF  ローマン体/明朝体(工場出荷時)
   130: //                         ON   サンセリフ体/ゴシック体
   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: //    パイカ
   157: //      10文字/in
   158: //      36dot/文字
   159: //      floor(2880dot/行/36dot/文字)=80文字/行
   160: //      A4縦
   161: //        (210-14-9)/(25.4/10)=73文字/行
   162: //      B5縦
   163: //        (182-13-9)/(25.4/10)=63文字/行
   164: //    エリート
   165: //      12文字/in
   166: //      30dot/文字
   167: //      floor(2880dot/行/30dot/文字)=96文字/行
   168: //      A4縦
   169: //        (210-14-9)/(25.4/12))=88文字/行
   170: //      B5縦
   171: //        (182-13-9)/(25.4/12)=75文字/行
   172: //    縮小
   173: //      17文字/in
   174: //      21dot/文字
   175: //      floor(2880dot/行/21dot/文字)=137文字/行
   176: //      A4縦
   177: //        126文字/行
   178: //      B5縦
   179: //        108文字/行
   180: //    漢字
   181: //      2+48+6=56dot/文字
   182: //      floor(2880dot/行/56dot/文字)=51文字/行
   183: //    半角
   184: //      0+24+4=28dot/文字
   185: //      floor(2880dot/行/28dot/文字)=102文字/行
   186: //      A4縦
   187: //        94文字/行
   188: //      B5縦
   189: //        81文字/行
   190: //    スーパースクリプト、サブスクリプト
   191: //      15文字/in
   192: //      24dot/文字
   193: //      floor(2880dot/行/24dot/文字)=120文字/行
   194: //
   195: //  漢字モード
   196: //    漢字モードOFFのとき
   197: //      1バイトで1文字
   198: //      ANKとみなしてパイカ、エリート、縮小のいずれかで印字する
   199: //    漢字モードONのとき
   200: //      2バイトで1文字
   201: //      1バイト目が0x00のとき
   202: //        2バイト目をANKとみなして半角で印字する
   203: //      さもなくば(1バイト目が0x00でないとき)
   204: //        1バイト目が区(0x21~0x7e)、2バイト目が点(0x21~0x7e)のJISコードとみなして全角で印字する
   205: //
   206: //  黒リボン
   207: //    黒インクが塗布されたインクリボン
   208: //
   209: //  単色カラーリボン
   210: //    赤、青、緑、金、銀などのインクが塗布された単色のインクリボン
   211: //
   212: //  カラーリボン
   213: //    イエロー、マゼンタ、シアンの3色のインクが繰り返し塗布されたインクリボン
   214: //
   215: //  カラーモード
   216: //    カラーリボンをセットしてESC EMでカラーモードにするとCRを出力する度にリボンが送られてイエロー、マゼンタ、シアンの順に色が切り替わる
   217: //    1行分のデータをイエロー、マゼンタ、シアンの順に最大3回繰り返し出力して重ね合わせることで減法混色で7色印字できる
   218: //    色コードを直接指定するコマンドはない
   219: //
   220: //----------------------------------------------------------------------------------------
   221: 
   222: public class PrinterPort {
   223: 
   224: 
   225:   //プリンタポート
   226:   //  プリンタが繋がっていなくてもプリンタポートは存在する
   227:   //  プリンタが繋がっていないときは常にプリンタビシー
   228:   public static final int PRN_DATA   = 0x00e8c001;
   229:   public static final int PRN_STROBE = 0x00e8c003;
   230:   public static int prnData;  //PRN_DATAにwriteされたプリンタデータ
   231:   public static int prnStrobe;  //PRN_STROBEにwriteされたストローブ。0→1のときprnDataがプリンタまたはプリンタアダプタに出力される
   232: 
   233: 
   234:   //プリンタアダプタ
   235:   //  フォントの作成や展開に時間がかかるのでプリンタのスレッドを分ける
   236:   //  プリンタポートとプリンタの間にプリンタアダプタを挟む
   237:   //  データをプリンタに出力する代わりにプリンタアダプタに出力する
   238:   //  プリンタアダプタはプリンタアダプタバッファが一杯になるか一定時間出力がないとき、
   239:   //  プリンタアダプタスレッドでプリンタアダプタタスクを実行する
   240:   //  プリンタアダプタタスクがプリンタにデータを出力する
   241:   //
   242:   //  プリンタアダプタ出力
   243:   //    出力するデータをプリンタアダプタバッファに追加する
   244:   //    プリンタアダプタバッファが一杯にならなかったとき
   245:   //      プリンタアダプタティッカーをキューに入れ(直し)て10ms後に呼び出す
   246:   //    プリンタアダプタバッファが一杯になったとき
   247:   //      プリンタアダプタティッカーがキューにあれば取り除く
   248:   //      プリンタアダプタタスクランチャを呼び出す
   249:   //      プリンタアダプタバッファをクリアする
   250:   //
   251:   //  プリンタアダプタティッカー
   252:   //    プリンタアダプタタスクランチャを呼び出す
   253:   //
   254:   //  プリンタアダプタタスクランチャ
   255:   //    プリンタアダプタバッファのコピーを持ったプリンタアダプタタスクをプリンタアダプタスレッドで実行する
   256:   //
   257:   //  プリンタアダプタタスク
   258:   //    プリンタアダプタバッファのコピーの内容をプリンタに出力する
   259:   //
   260:   public static final boolean PRN_USE_ADAPTER = true;  //プリンタアダプタを使う
   261:   public static final int PRN_ADAPTER_CAPACITY = 1024;  //プリンタアダプタバッファの容量
   262:   public static final long PRN_ADAPTER_DELAY = XEiJ.TMR_FREQ * 10000 / 1000000;  //10ms。プリンタアダプタディレイタイム。プリンタアダプタバッファが一杯にならなくても最後のプリンタアダプタ出力からこの時間が経過したらプリンタアダプタタスクを実行する
   263:   public static byte[] prnAdapterBuffer;  //プリンタアダプタバッファ
   264:   public static int prnAdapterPointer;  //プリンタアダプタバッファの書き込み位置
   265:   public static TickerQueue.Ticker prnAdapterTicker;  //プリンタアダプタティッカー
   266:   public static java.util.Timer prnAdapterTimer;  //プリンタアダプタスレッド。Timerだけだとjavax.swing.Timerと紛らわしい
   267: 
   268:   //prnAdapterInit ()
   269:   //  プリンタアダプタ初期化
   270:   public static void prnAdapterInit () {
   271:     prnAdapterBuffer = new byte[PRN_ADAPTER_CAPACITY];  //プリンタアダプタバッファ
   272:     prnAdapterPointer = 0;  //プリンタアダプタバッファの書き込み位置
   273:     prnAdapterTicker = new PrinterAdapterTicker ();  //プリンタアダプタティッカー
   274:     prnAdapterTimer = new java.util.Timer ();  //プリンタアダプタスレッド。Timerだけだとjavax.swing.Timerと紛らわしい
   275:   }  //prnAdapterInit
   276: 
   277:   //prnAdapterOutput (data)
   278:   //  プリンタアダプタ出力
   279:   public static void prnAdapterOutput (int data) {
   280:     //出力するデータをプリンタアダプタバッファに追加する
   281:     prnAdapterBuffer[prnAdapterPointer++] = (byte) data;
   282:     if (prnAdapterPointer < PRN_ADAPTER_CAPACITY) {  //プリンタアダプタバッファが一杯にならなかったとき
   283:       //プリンタアダプタティッカーをキューに入れ(直し)て10ms後に呼び出す
   284:       TickerQueue.tkqAdd (prnAdapterTicker, XEiJ.mpuClockTime + PRN_ADAPTER_DELAY);
   285:     } else {  //プリンタアダプタバッファが一杯になったとき
   286:       //プリンタアダプタティッカーがキューにあれば取り除く
   287:       TickerQueue.tkqRemove (prnAdapterTicker);
   288:       //プリンタアダプタタスクランチャを呼び出す
   289:       prnAdapterTaskLauncher ();
   290:     }
   291:   }  //prnAdapterOutput
   292: 
   293:   //class PrinterAdapterTicker
   294:   //  プリンタアダプタティッカー
   295:   public static class PrinterAdapterTicker extends TickerQueue.Ticker {
   296:     @Override protected void tick () {
   297:       //プリンタアダプタタスクランチャを呼び出す
   298:       prnAdapterTaskLauncher ();
   299:     }  //tick
   300:   };
   301: 
   302:   //prnAdapterTaskLauncher ()
   303:   //  プリンタアダプタタスクランチャ
   304:   public static void prnAdapterTaskLauncher () {
   305:     //プリンタアダプタバッファをコピーする
   306:     byte[] copiedBuffer = Arrays.copyOf (prnAdapterBuffer, prnAdapterPointer);
   307:     //プリンタアダプタバッファをクリアする
   308:     prnAdapterPointer = 0;
   309:     //プリンタアダプタバッファのコピーを持ったプリンタアダプタタスクをプリンタアダプタスレッドで実行する
   310:     prnAdapterTimer.schedule (new PrinterAdapterTask (copiedBuffer), 100L);  //0Lだとログが重なってしまい読み難い
   311:   }  //prnAdapterTaskLauncher
   312: 
   313:   //class PrinterAdapterTask
   314:   //  プリンタアダプタタスク
   315:   public static class PrinterAdapterTask extends TimerTask {
   316:     private byte[] buffer;
   317:     public PrinterAdapterTask (byte[] copiedBuffer) {
   318:       buffer = copiedBuffer;
   319:     }  //PrinterAdapterTask
   320:     @Override public void run () {
   321:       //プリンタアダプタバッファのコピーの内容をプリンタに出力する
   322:       for (int i = 0; i < buffer.length; i++) {
   323:         prnOutput (buffer[i]);
   324:       }
   325:     }  //run
   326:   }  //class PrinterAdapterTask
   327: 
   328: 
   329:   //プリンタ
   330: 
   331:   //カラーモデル
   332:   //  1dotを1byteで表現する。下位3bitだけ使う
   333:   //    0  0xff000000  ブラック
   334:   //    1  0xff0000ff  ブルー
   335:   //    2  0xff00ff00  ライム
   336:   //    3  0xff00ffff  シアン
   337:   //    4  0xffff0000  レッド
   338:   //    5  0xffff00ff  マゼンタ
   339:   //    6  0xffffff00  イエロー
   340:   //    7  0xffffffff  ホワイト
   341:   //  最初に用紙の全体を7(ホワイト)で塗り潰す
   342:   //  黒リボンのときは0(ブラック)、カラーリボンのときは6(イエロー)、5(マゼンタ)、3(シアン)の順にANDで描画する
   343:   //  ダークモードは黒と白だけ入れ替える
   344:   public static IndexColorModel prnImageColorModel;  //ライトモードのカラーモデル
   345:   public static IndexColorModel prnDarkImageColorModel;  //ダークモードのカラーモデル
   346: 
   347: 
   348:   //用紙
   349: 
   350:   //  定数
   351:   public static final int PRN_MAX_WIDTH_DOT = 360 * 48;  //印字範囲の最大幅[dot]。B0縦の幅1030[mm]=40.6[in]が収まるサイズ。CZ-8PC4の8[in]の6倍
   352:   public static final int PRN_MAX_HEIGHT_DOT = 360 * 66;  //印字範囲の最大高さ[dot]。B0縦の高さ1456[mm]=57.3[in]が収まるサイズ。CZ-8PC4の11[in]の6倍
   353:   public static final int PRN_MAX_WIDTH_MM = (int) Math.floor ((double) PRN_MAX_WIDTH_DOT * 25.4 / 360.0);  //印字範囲の最大幅[mm]
   354:   public static final int PRN_MAX_HEIGHT_MM = (int) Math.floor ((double) PRN_MAX_HEIGHT_DOT * 25.4 / 360.0);  //印字範囲の最大高さ[mm]
   355: 
   356:   //  列
   357:   public static final int PRN_A_SERIES = 0;  //A列
   358:   public static final int PRN_B_SERIES = 1;  //B列
   359:   public static final int PRN_POSTCARD = 2;  //はがき
   360: 
   361:   //  方向
   362:   public static final int PRN_PORTRAIT  = 0;  //縦
   363:   public static final int PRN_LANDSCAPE = 1;  //横
   364: 
   365:   //class Paper
   366:   //  用紙クラス
   367:   //  参考
   368:   //    https://ja.wikipedia.org/wiki/%E7%B4%99%E3%81%AE%E5%AF%B8%E6%B3%95
   369:   public static class Paper {
   370: 
   371:     //サイズ
   372:     public String sizeEn;  //列の英語表記
   373:     public String sizeJa;  //列の日本語表記
   374:     //方向
   375:     public String orientationEn;  //方向の英語表記
   376:     public String orientationJa;  //方向の日本語表記
   377:     //用紙
   378:     public int paperWidthMm;  //用紙の幅[mm]
   379:     public int paperHeightMm;  //用紙の高さ[mm]
   380:     public int paperWidthDot;  //用紙の幅[dot]
   381:     public int paperHeightDot;  //用紙の高さ[dot]
   382:     //印字不可領域の初期値
   383:     //  用紙の端の印字できない部分。ヘッドが移動できない場所
   384:     public int initialDeadTopMm;  //用紙の上端の印字できない部分の高さの初期値[mm]
   385:     public int initialDeadLeftMm;  //用紙の左端の印字できない部分の幅の初期値[mm]
   386:     public int initialDeadRightMm;  //用紙の右端の印字できない部分の幅の初期値[mm]
   387:     public int initialDeadBottomMm;  //用紙の下端の印字できない部分の高さの初期値[mm]
   388:     //名前
   389:     public String nameEn;  //英語名
   390:     public String nameJa;  //日本語名
   391: 
   392:     //new Paper (series, n, orientation)
   393:     //  コンストラクタ
   394:     //  series       列
   395:     //               PRN_A_SERIES  A列
   396:     //               PRN_B_SERIES  B列
   397:     //               PRN_POSTCARD  はがき
   398:     //  n            サイズ
   399:     //               4  A4またはB4
   400:     //               5  A5またはB5
   401:     //               など
   402:     //  orientation  方向
   403:     //               PRN_PORTRAIT   縦長
   404:     //               PRN_LANDSCAPE  横長
   405:     public Paper (int series, int n, int orientation) {
   406: 
   407:       int narrowMm;  //短辺[mm]
   408:       int longMm;  //長辺[mm]
   409: 
   410:       if (series == PRN_A_SERIES) {  //A列
   411:         narrowMm = (int) Math.floor (1000.0 / Math.pow (2.0, (double) (2 * n + 1) * 0.25) + 0.2);
   412:         longMm = (int) Math.floor (1000.0 / Math.pow (2.0, (double) (2 * n - 1) * 0.25) + 0.2);
   413:         initialDeadTopMm = 11;  //A4縦210x297に名刺横91x55がちょうど10枚収まる
   414:         initialDeadLeftMm = 14;
   415:         initialDeadRightMm = 14;
   416:         initialDeadBottomMm = 11;
   417:         sizeEn = n < 0 ? (1 << -n) + "A0" : "A" + n;
   418:         sizeJa = sizeEn;
   419:       } else if (series == PRN_B_SERIES) {  //B列
   420:         narrowMm = (int) Math.floor (1000.0 * Math.sqrt (3.0) / Math.pow (2.0, (double) (2 * n + 3) * 0.25) + 0.2);
   421:         longMm = (int) Math.floor (1000.0 * Math.sqrt (3.0) / Math.pow (2.0, (double) (2 * n + 1) * 0.25) + 0.2);
   422:         initialDeadTopMm = 11;
   423:         initialDeadLeftMm = 24;
   424:         initialDeadRightMm = 24;
   425:         initialDeadBottomMm = 11;
   426:         sizeEn = n < 0 ? (1 << -n) + "B0" : "B" + n;
   427:         sizeJa = sizeEn;
   428:       } else {  //はがき
   429:         narrowMm = 100;
   430:         longMm = 148;
   431:         initialDeadTopMm = 10;
   432:         initialDeadLeftMm = 3;
   433:         initialDeadRightMm = 3;
   434:         initialDeadBottomMm = 10;
   435:         sizeEn = "Postcard";  //Japanese standard
   436:         sizeJa = "はがき";
   437:       }
   438:       if (orientation == PRN_PORTRAIT) {  //縦長
   439:         paperWidthMm = narrowMm;
   440:         paperHeightMm = longMm;
   441:         orientationEn = "portrait";
   442:         orientationJa = "縦";
   443:       } else {  //横長
   444:         paperWidthMm = longMm;
   445:         paperHeightMm = narrowMm;
   446:         orientationEn = "landscape";
   447:         orientationJa = "横";
   448:       }
   449:       paperWidthDot = (int) Math.floor ((double) paperWidthMm * (360.0 / 25.4) + 0.5);
   450:       paperHeightDot = (int) Math.floor ((double) paperHeightMm * (360.0 / 25.4) + 0.5);
   451: 
   452:       nameEn = sizeEn + " " + orientationEn + " " + paperWidthMm + "x" + paperHeightMm;
   453:       nameJa = sizeJa + " " + orientationJa + " " + paperWidthMm + "x" + paperHeightMm;
   454: 
   455:     }  //Paper
   456: 
   457:   }  //class Paper
   458: 
   459: 
   460: 
   461:   //用紙の配列
   462:   public static Paper[] prnPaperArray;
   463: 
   464:   //用紙
   465:   public static Paper prnNextPaper;  //次に給紙する用紙。nullではない
   466:   public static Paper prnCurrentPaper;  //現在の用紙。null=未給紙
   467: 
   468:   //回転
   469:   //  0=0°,1=90°,2=180°,3=270°
   470:   public static int prnNextRotation;  //次に給紙する用紙の回転
   471:   public static int prnRotation;  //現在の用紙の回転
   472:   public static int prnRotatedWidthDot;  //現在の用紙の回転後の幅[dot]
   473:   public static int prnRotatedHeightDot;  //現在の用紙の回転後の高さ[dot]
   474:   public static int prnM11;  //用紙座標からビットマップ座標へ変換する変換行列
   475:   public static int prnM12;  //  [m11 m12 m13]   [x]   [m11*x+m12*y+m13]
   476:   public static int prnM13;  //  [m21 m22 m23] * [y] = [m21*x+m22*y+m23]
   477:   public static int prnM21;  //  [ 0   0   1 ]   [1]   [       1       ]
   478:   public static int prnM22;
   479:   public static int prnM23;
   480:   public static int prnIncrementX;  //prnM11+prnRotatedWidthDot*prnM21。用紙座標でxが1増えたときのビットマップインデックスの増分
   481:   public static int prnIncrementY;  //prnM12+prnRotatedWidthDot*prnM22。用紙座標でyが1増えたときのビットマップインデックスの増分
   482: 
   483:   //ダークモード
   484:   //  白と黒を入れ替える
   485:   public static boolean prnNextDarkMode;  //次に給紙する用紙のダークモード
   486:   public static boolean prnDarkMode;  //現在の用紙のダークモード
   487: 
   488:   //オンライン
   489:   public static boolean prnOnlineOn;  //false=オフライン,true=オンライン
   490: 
   491:   //単色インクリボンの色
   492:   //  0=ブラック,1=ブルー,2=ライム,3=シアン,4=レッド,5=マゼンタ,6=イエロー,7=ホワイト
   493:   public static int prnSingleColor;
   494: 
   495:   //表示倍率
   496:   //  -4=1/16,-3=1/8,-2=1/4,-1=1/2,0=1,1=2,2=4,3=8,4=16
   497:   public static int prnScaleShift;
   498: 
   499:   //イメージとビットマップ
   500:   //  給紙する度に作り直す
   501:   public static BufferedImage prnImage;  //現在の用紙のイメージ
   502:   public static byte[] prnBitmap;  //現在の用紙のビットマップ
   503: 
   504:   //印字フラグ
   505:   //  印字ありのとき排紙するとイメージが保存される
   506:   public static boolean prnPrinted;  //false=印字なし,true=印字あり
   507: 
   508: 
   509: 
   510:   //設定
   511: 
   512:   //  マージン
   513:   public static int prnMarginLeftX;  //左マージンの印字可能範囲座標[dot]。初期値は0
   514:   public static int prnMarginRightX;  //右マージンの印字可能範囲座標[dot]。初期値は2879
   515:   public static int prnMarginBottomHeight;  //下マージンの高さ[dot]。初期値は0
   516: 
   517:   //改行ピッチ
   518:   //  ESC 6で1/6[in]=60[dot]、ESC 8で1/8[in]=45[dot]になる
   519:   //  ESC % 9 0で1/6[in]または1/8[in]に戻すときに使う
   520:   public static int prnDefaultLineHeight;  //デフォルトの改行ピッチ[dot]
   521:   public static int prnLineHeight;  //改行ピッチ[dot]
   522: 
   523:   //文字種
   524:   public static final int PRN_PICA  = 0;  //パイカ 1/10[in]=36[dot]
   525:   public static final int PRN_ELITE = 1;  //エリート 1/12[in]=30[dot]
   526:   public static final int PRN_SMALL = 2;  //縮小 1/20[in]=18[dot]。隙間が3[dot]あって1/17[in]=21[dot]になる
   527:   public static int prnCharacterType;  //文字種
   528: 
   529:   //ひらがなモード
   530:   public static boolean prnHiraganaMode;  //false=ひらがなOFF,true=ひらがなON
   531: 
   532:   //スクリプトモード
   533:   public static final int PRN_NO_SCRIPT    = 0;  //スクリプト解除
   534:   public static final int PRN_SUPER_SCRIPT = 1;  //スーパースクリプト
   535:   public static final int PRN_SUB_SCRIPT   = 2;  //サブスクリプト
   536:   public static int prnScriptMode;  //スクリプトモード
   537: 
   538:   //強調モード
   539:   public static boolean prnStrongMode;  //false=強調OFF,true=強調ON
   540: 
   541:   //アンダーラインモード
   542:   public static boolean prnUnderlineMode;  //false=アンダーラインOFF,true=アンダーラインON
   543: 
   544:   //文字スタイル
   545:   public static final int PRN_NORMAL_STYLE      = 0;  //標準文字
   546:   public static final int PRN_OPEN_STYLE        = 1;  //袋文字
   547:   public static final int PRN_SHADOW_STYLE      = 2;  //影文字
   548:   public static final int PRN_OPEN_SHADOW_STYLE = 3;  //袋影文字
   549:   public static int prnCharacterStyle;  //文字スタイル
   550: 
   551:   //漢字モード
   552:   public static boolean prnKanjiMode;  //false=漢字モードOFF,true=漢字モードON
   553: 
   554:   //外字データ
   555:   //  外字定義エリアは0x7621..0x767eと0x7721..0x7726の100文字
   556:   //  ESC c 1でクリアされる
   557:   public static byte[] prnGaijiData = null;
   558: 
   559:   //縦書きモード
   560:   public static boolean prnVerticalWritingMode;  //false=縦書きOFF,true=縦書きON
   561: 
   562:   //左右スペース
   563:   public static int prnFullWidthLeftSpace;  //全角左スペース[dot]
   564:   public static int prnFullWidthRightSpace;  //全角右スペース[dot]
   565:   public static int prnHalfWidthLeftSpace;  //半角左スペース[dot]
   566:   public static int prnHalfWidthRightSpace;  //半角右スペース[dot]
   567: 
   568:   //横2倍モード
   569:   public static boolean prnHorizontalDoubleSizeMode;  //false=横2倍OFF,true=横2倍ON。漢字モードの全角と半角もビットイメージも拡大する
   570:   public static boolean prnVerticalDoubleSizeMode;  //false=縦2倍OFF,true=縦2倍ON。漢字モードの全角と半角もビットイメージも拡大する
   571:   public static boolean prnKanjiHorizontalDoubleSizeMode;  //false=漢字横2倍OFF,true=漢字横2倍ON。漢字モードの全角と半角だけ拡大する
   572: 
   573:   //水平タブ
   574:   public static final int PRN_HORIZONTAL_ANCHOR_LIMIT = 16;
   575:   public static final int[] prnHorizontalTabAnchor = new int[PRN_HORIZONTAL_ANCHOR_LIMIT];  //水平タブアンカー[dot]
   576: 
   577:   //垂直タブ
   578:   public static final int PRN_VERTICAL_ANCHOR_LIMIT = 128;
   579:   public static final int[] prnVerticalTabAnchor = new int[PRN_VERTICAL_ANCHOR_LIMIT];  //垂直タブアンカー
   580: 
   581:   //カラーモード
   582:   public static boolean prnColorMode;  //false=単色モード,true=カラーモード
   583: 
   584:   //色
   585:   //  0=ブラック,1=ブルー,2=ライム,3=シアン,4=レッド,5=マゼンタ,6=イエロー,7=ホワイト
   586:   //  単色モードのときprnSingleColorと同じで0~7
   587:   //  カラーモードのときESC EMで6になりCRで6→5→3→6の順に切り替わる
   588:   public static int prnCurrentColor;
   589: 
   590:   //書体
   591:   public static int prnHalfWidthFont;  //半角書体。0=ローマン体,1=サンセリフ体
   592:   public static int prnFullWidthFont;  //全角書体。0=明朝体,1=ゴシック体
   593: 
   594: 
   595:   //印字不可領域
   596:   public static int prnNextDeadTopMm;  //次に給紙する用紙の上端の印字できない部分の高さ[mm]
   597:   public static int prnNextDeadLeftMm;  //次に給紙する用紙の左端の印字できない部分の幅[mm]
   598:   public static int prnNextDeadRightMm;  //次に給紙する用紙の右端の印字できない部分の幅[mm]
   599:   public static int prnNextDeadBottomMm;  //次に給紙する用紙の下端の印字できない部分の高さ[mm]
   600:   public static int prnDeadTopMm;  //現在の用紙の上端の印字できない部分の高さ[mm]
   601:   public static int prnDeadLeftMm;  //現在の用紙の左端の印字できない部分の幅[mm]
   602:   public static int prnDeadRightMm;  //現在の用紙の右端の印字できない部分の幅[mm]
   603:   public static int prnDeadBottomMm;  //現在の用紙の下端の印字できない部分の高さ[mm]
   604: 
   605:   //印字可能範囲
   606:   //  用紙から印字不可領域を除いた部分。ヘッドが移動できる場所
   607:   //  ヘッドの位置が印字可能範囲の下端からはみ出したら排紙する
   608:   public static int prnAliveTopY;  //印字可能範囲の上端の用紙座標[dot]
   609:   public static int prnAliveLeftX;  //印字可能範囲の左端の用紙座標[dot]
   610:   public static int prnAliveRightX;  //印字可能範囲の右端の用紙座標[dot]
   611:   public static int prnAliveBottomY;  //印字可能範囲の下端の用紙座標[dot]
   612: 
   613:   //ページ範囲
   614:   //  X方向は印字可能範囲の左端から右端まで
   615:   //  Y方向はページ開始位置からページ開始位置+ページ長まで
   616:   //  ページ範囲の下端
   617:   //    ページ開始位置+ページ長
   618:   //    下マージンの基準の位置
   619:   //    改ページの移動先
   620:   //    ページ範囲の下端が印字可能範囲の内側にあるとき
   621:   //      改ページを行うとヘッドがページ範囲の下端に移動してそこが新たなページ開始位置になる
   622:   //    ページ範囲の下端が印字可能範囲の外側にあるとき
   623:   //      改ページを行うとヘッドが印字可能範囲の下端からはみ出して排紙される
   624:   //      次に給紙された用紙の印刷可能範囲の先頭が新たなページ開始位置になる
   625:   //  ページ長
   626:   //    A4縦は上下の印字不可領域が17[mm]までのとき12[in]、18[mm]以上のとき11[in]
   627:   public static int prnPageStart;  //ページ開始位置の印字可能範囲座標[dot]。給紙したとき0
   628:   public static int prnPageLength;  //ページ長[dot]。給紙したとき印字可能範囲の高さを1[in]=360[dot]の倍数に切り上げた値
   629: 
   630:   //コンテント範囲
   631:   //  ページ範囲からマージンを除いた部分
   632:   //  ヘッドの位置がコンテント範囲の下端を超えると改ページされてページ範囲の下端に移動する
   633:   //  ページ範囲の下端が印字可能範囲の下端を超えていれば排紙される
   634:   public static int prnContentTopY;  //コンテント範囲の上端の印字可能範囲座標[dot]。給紙したときページ開始位置
   635:   public static int prnContentBottomY;  //コンテント範囲の下端の印字可能範囲座標[dot]。給紙したときページ開始位置+ページ長-下マージン
   636: 
   637:   //ヘッドの位置
   638:   public static int prnHeadX;  //ヘッドX座標[dot]。-1=未給紙。改行したとき左マージン
   639:   public static int prnHeadY;  //ヘッドY座標[dot]。-1=未給紙。改ページしたとき新しいページのコンテント範囲の上端
   640:   public static int prnHeadLine;  //ヘッド行番号。-1=未給紙。改ページしたとき0、改行でインクリメント。垂直タブで使う
   641: 
   642: 
   643:   //コマンドバッファ
   644:   //  先頭の数バイトで長さが確定するコマンド
   645:   //    対応しているコマンドはすべてバッファに収まる
   646:   //  終了コードが出てくるまで長さが分からないコマンド
   647:   //    コマンドがコマンドバッファに収まらないとき
   648:   //      書き込み位置をコマンドバッファの末尾で止めて末尾の1バイト以外のはみ出した部分のデータを無視する
   649:   public static final byte[] prnCommandBuffer = new byte[4 + 6 * PRN_MAX_WIDTH_DOT];  //ESC M n1 n2 d1 d2 … dkの最大幅2880ドット
   650:   public static int prnCommandLength;  //コマンドの長さ。次にコマンドを判別する位置。この位置まではバッファに書き込むだけ。prnCommandBuffer.length以上になることはない
   651:   public static int prnCommandPointer;  //コマンド書き込み位置。prnCommandBufferのサイズを超える場合があるので注意
   652: 
   653: 
   654:   //ウインドウ
   655:   public static ScrollCanvas prnCanvas;  //キャンバス
   656:   public static JFrame prnFrame;  //ウインドウ
   657: 
   658:   //メニュー
   659:   public static JCheckBoxMenuItem prnOnlineMenuItem;  //オンライン
   660:   public static JCheckBoxMenuItem prnAutosaveMenuItem;  //自動保存
   661:   //
   662:   public static int prnSpinnerLocked;
   663:   public static SpinnerNumberModel prnDeadTopModel;  //用紙の上端の印字できない部分の高さ[mm]
   664:   public static SpinnerNumberModel prnDeadLeftModel;  //用紙の左端の印字できない部分の幅[mm]
   665:   public static SpinnerNumberModel prnDeadRightModel;  //用紙の右端の印字できない部分の幅[mm]
   666:   public static SpinnerNumberModel prnDeadBottomModel;  //用紙の下端の印字できない部分の高さ[mm]
   667:   public static NumberSpinner prnDeadTopSpinner;  //用紙の上端の印字できない部分の高さ[mm]
   668:   public static NumberSpinner prnDeadLeftSpinner;  //用紙の左端の印字できない部分の幅[mm]
   669:   public static NumberSpinner prnDeadRightSpinner;  //用紙の右端の印字できない部分の幅[mm]
   670:   public static NumberSpinner prnDeadBottomSpinner;  //用紙の下端の印字できない部分の高さ[mm]
   671:   public static JRadioButtonMenuItem[] prnScaleMenuItem;
   672: 
   673:   //プリンタ出力
   674:   public static boolean prnAutosaveOn;  //true=プリンタ出力を自動保存する
   675:   public static String prnSavePath;  //プリンタ出力を保存するディレクトリのabsoluteパス
   676:   public static String prnSaveName;  //主ファイル名。フルパスのファイル名はprnSavePath+File.separator+prnSaveName
   677:   public static JDialog prnSaveDialog;  //ダイアログ
   678:   public static JFileChooser2 prnSaveFileChooser;  //ファイルチューザー
   679:   public static String[] prnWriterSuffixes;  //出力できるイメージファイルの拡張子の配列
   680:   public static javax.swing.filechooser.FileFilter prnSaveFileFilter;  //プリンタ出力イメージファイルフィルタ
   681:   public static JCheckBox prnAutosaveCheckBox;  //自動保存チェックボックス
   682: 
   683:   //ディップスイッチ
   684:   public static final int PRN_DIPSW_ZERO_STYLE       = 0x01;  //ゼロ書体。0=スラッシュあり,1=スラッシュなし
   685:   public static final int PRN_DIPSW_PRINTING_SPEED   = 0x02;  //印字速度。0=標準速度,1=高速印字
   686:   public static final int PRN_DIPSW_POSTCARD_MODE    = 0x04;  //はがきモード。0=OFF,1=ON
   687:   public static final int PRN_DIPSW_PAGE_LENGTH      = 0x08;  //頁長。0=11[in],1=12[in]
   688:   public static final int PRN_DIPSW_FEEDING_POSITION = 0x20;  //給紙位置。0=22mm,1=8.5mm
   689:   public static final int PRN_DIPSW_FONT_STYLE       = 0x80;  //書体。0=ローマン体/明朝体,1=サンセリフ体/ゴシック体
   690:   public static final int PRN_DIPSW_MASK             = 0xaf;
   691:   public static int prnDIPSW;  //ディップスイッチの状態
   692: 
   693: 
   694:   //ページの名前
   695:   //  英語
   696:   public static final String FNT_EN_Zen48x48G = "Full Kanji 48x48 Gothic";
   697:   public static final String FNT_EN_Pic36x46S = "CZ-8PC4 Pica 36x46 Sans-Serif";
   698:   public static final String FNT_EN_Eli30x46S = "CZ-8PC4 Elite 30x46 Sans-Serif";
   699:   public static final String FNT_EN_Sma18x46S = "CZ-8PC4 Small 18x46 Sans-Serif";
   700:   public static final String FNT_EN_Scr28x32S = "CZ-8PC4 Script 28x32 Sans-Serif";
   701:   public static final String FNT_EN_Pan24x48S = "CZ-8PC4 Half 24x48 Sans-Serif";
   702:   public static final String FNT_EN_Zen48x48M = "Full Kanji 48x48 Mincho";
   703:   public static final String FNT_EN_Pic36x46R = "CZ-8PC4 Pica 36x46 Roman";
   704:   public static final String FNT_EN_Eli30x46R = "CZ-8PC4 Elite 30x46 Roman";
   705:   public static final String FNT_EN_Sma18x46R = "CZ-8PC4 Small 18x46 Roman";
   706:   public static final String FNT_EN_Scr28x32R = "CZ-8PC4 Script 28x32 Roman";
   707:   public static final String FNT_EN_Pan24x48R = "CZ-8PC4 Half 24x48 Roman";
   708:   //  日本語
   709:   public static final String FNT_JA_Zen48x48G = "全角 漢字 48x48 ゴシック体";
   710:   public static final String FNT_JA_Pic36x46S = "CZ-8PC4 パイカ 36x46 サンセリフ体";
   711:   public static final String FNT_JA_Eli30x46S = "CZ-8PC4 エリート 30x46 サンセリフ体";
   712:   public static final String FNT_JA_Sma18x46S = "CZ-8PC4 縮小 18x46 サンセリフ体";
   713:   public static final String FNT_JA_Scr28x32S = "CZ-8PC4 スクリプト 28x32 サンセリフ体";
   714:   public static final String FNT_JA_Pan24x48S = "CZ-8PC4 半角 24x48 サンセリフ体";
   715:   public static final String FNT_JA_Zen48x48M = "全角 漢字 48x48 明朝体";
   716:   public static final String FNT_JA_Pic36x46R = "CZ-8PC4 パイカ 36x46 ローマン体";
   717:   public static final String FNT_JA_Eli30x46R = "CZ-8PC4 エリート 30x46 ローマン体";
   718:   public static final String FNT_JA_Sma18x46R = "CZ-8PC4 縮小 18x46 ローマン体";
   719:   public static final String FNT_JA_Scr28x32R = "CZ-8PC4 スクリプト 28x32 ローマン体";
   720:   public static final String FNT_JA_Pan24x48R = "CZ-8PC4 半角 24x48 ローマン体";
   721: 
   722:   //ページ
   723:   public static FontPage.Zen fntPageZen48x48G;
   724:   public static FontPage.Prn fntPagePic36x46S;
   725:   public static FontPage.Prn fntPageEli30x46S;
   726:   public static FontPage.Prn fntPageSma18x46S;
   727:   public static FontPage.Prn fntPageScr28x32S;
   728:   public static FontPage.Prn fntPagePan24x48S;
   729:   public static FontPage.Zen fntPageZen48x48M;
   730:   public static FontPage.Prn fntPagePic36x46R;
   731:   public static FontPage.Prn fntPageEli30x46R;
   732:   public static FontPage.Prn fntPageSma18x46R;
   733:   public static FontPage.Prn fntPageScr28x32R;
   734:   public static FontPage.Prn fntPagePan24x48R;
   735: 
   736:   //等幅フォントファミリ
   737:   public static final String[] FNT_GOTHIC_FAMILIES = {  //ゴシック
   738:     //"游ゴシック",  //Windows,Mac
   739:     "MS ゴシック", "MS Gothic",  //Windows
   740:     "ヒラギノ角ゴ ProN W3", "Hiragino Kaku Gothic ProN",  //Mac
   741:     "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro",
   742:     "Osaka-等幅", "Osaka-Mono",
   743:     "VL ゴシック", "VL Gothic",  //Linux
   744:     "Takaoゴシック", "TakaoGothic",
   745:     "IPAゴシック", "IPAGothic",
   746:   };
   747:   public static final String[] FNT_MINCHO_FAMILIES = {  //明朝
   748:     //"游明朝",  //Windows,Mac
   749:     "MS 明朝", "MS Mincho",  //Windows
   750:     "ヒラギノ明朝 ProN W3", "Hiragino Mincho ProN",  //Mac
   751:     "ヒラギノ明朝 Pro W3", "Hiragino Mincho Pro",
   752:     "さざなみ明朝", "Sazanami Mincho",  //Linux
   753:     "Takao明朝", "TakaoMincho",
   754:     "IPA明朝", "IPAMincho",
   755:   };
   756:   public static String[] fntAvailableFamilies;  //使えるフォントの一覧
   757:   public static String fntGothicFamily;  //ゴシック
   758:   public static String fntMinchoFamily;  //明朝
   759: 
   760: 
   761:   //prnInit ()
   762:   //  初期化
   763:   public static void prnInit () {
   764: 
   765:     //フォント
   766:     fntPageZen48x48G = new FontPage.Zen (48, 48, FNT_EN_Zen48x48G, FNT_JA_Zen48x48G, "./zen48x48g.f48", "./zen48x48g.png");
   767:     fntPagePic36x46S = new FontPage.Prn (36, 46, FNT_EN_Pic36x46S, FNT_JA_Pic36x46S, "./pic36x46s.dat", "./pic36x46s.png");
   768:     fntPageEli30x46S = new FontPage.Prn (30, 46, FNT_EN_Eli30x46S, FNT_JA_Eli30x46S, "./eli30x46s.dat", "./eli30x46s.png");
   769:     fntPageSma18x46S = new FontPage.Prn (18, 46, FNT_EN_Sma18x46S, FNT_JA_Sma18x46S, "./sma18x46s.dat", "./sma18x46s.png");
   770:     fntPageScr28x32S = new FontPage.Prn (28, 32, FNT_EN_Scr28x32S, FNT_JA_Scr28x32S, "./scr28x32s.dat", "./scr28x32s.png");
   771:     fntPagePan24x48S = new FontPage.Prn (24, 48, FNT_EN_Pan24x48S, FNT_JA_Pan24x48S, "./pan24x48s.dat", "./pan24x48s.png");
   772:     fntPageZen48x48M = new FontPage.Zen (48, 48, FNT_EN_Zen48x48M, FNT_JA_Zen48x48M, "./zen48x48m.f48", "./zen48x48m.png");
   773:     fntPagePic36x46R = new FontPage.Prn (36, 46, FNT_EN_Pic36x46R, FNT_JA_Pic36x46R, "./pic36x46r.dat", "./pic36x46r.png");
   774:     fntPageEli30x46R = new FontPage.Prn (30, 46, FNT_EN_Eli30x46R, FNT_JA_Eli30x46R, "./eli30x46r.dat", "./eli30x46r.png");
   775:     fntPageSma18x46R = new FontPage.Prn (18, 46, FNT_EN_Sma18x46R, FNT_JA_Sma18x46R, "./sma18x46r.dat", "./sma18x46r.png");
   776:     fntPageScr28x32R = new FontPage.Prn (28, 32, FNT_EN_Scr28x32R, FNT_JA_Scr28x32R, "./scr28x32r.dat", "./scr28x32r.png");
   777:     fntPagePan24x48R = new FontPage.Prn (24, 48, FNT_EN_Pan24x48R, FNT_JA_Pan24x48R, "./pan24x48r.dat", "./pan24x48r.png");
   778: 
   779:     //カラーモデル
   780:     prnImageColorModel = new IndexColorModel (
   781:       8, 8,
   782:       new byte[] {  0,  0,  0,  0, -1, -1, -1, -1 },  //red
   783:       new byte[] {  0,  0, -1, -1,  0,  0, -1, -1 },  //green
   784:       new byte[] {  0, -1,  0, -1,  0, -1,  0, -1 }  //blue
   785:       );
   786:     prnDarkImageColorModel = new IndexColorModel (
   787:       8, 8,
   788:       new byte[] { -1,  0,  0,  0, -1, -1, -1,  0 },  //red
   789:       new byte[] { -1,  0, -1, -1,  0,  0, -1,  0 },  //green
   790:       new byte[] { -1, -1,  0, -1,  0, -1,  0,  0 }  //blue
   791:       );
   792: 
   793:     //用紙の配列
   794:     prnPaperArray = new Paper[] {
   795:       //縦長
   796:       new Paper (PRN_A_SERIES, 3, PRN_PORTRAIT),  //0 A3縦
   797:       new Paper (PRN_A_SERIES, 4, PRN_PORTRAIT),  //1 A4縦
   798:       new Paper (PRN_A_SERIES, 5, PRN_PORTRAIT),  //2 A5縦
   799:       new Paper (PRN_A_SERIES, 6, PRN_PORTRAIT),  //3 A6縦
   800:       new Paper (PRN_B_SERIES, 3, PRN_PORTRAIT),  //4 B3縦
   801:       new Paper (PRN_B_SERIES, 4, PRN_PORTRAIT),  //5 B4縦
   802:       new Paper (PRN_B_SERIES, 5, PRN_PORTRAIT),  //6 B5縦
   803:       new Paper (PRN_B_SERIES, 6, PRN_PORTRAIT),  //7 B6縦
   804:       new Paper (PRN_POSTCARD, 0, PRN_PORTRAIT),  //8 はがき縦
   805:       //横長
   806:       new Paper (PRN_A_SERIES, 3, PRN_LANDSCAPE),  //9 A3横
   807:       new Paper (PRN_A_SERIES, 4, PRN_LANDSCAPE),  //10 A4横
   808:       new Paper (PRN_A_SERIES, 5, PRN_LANDSCAPE),  //11 A5横
   809:       new Paper (PRN_A_SERIES, 6, PRN_LANDSCAPE),  //12 A6横
   810:       new Paper (PRN_B_SERIES, 3, PRN_LANDSCAPE),  //13 B3横
   811:       new Paper (PRN_B_SERIES, 4, PRN_LANDSCAPE),  //14 B4横
   812:       new Paper (PRN_B_SERIES, 5, PRN_LANDSCAPE),  //15 B5横
   813:       new Paper (PRN_B_SERIES, 6, PRN_LANDSCAPE),  //16 B6横
   814:       new Paper (PRN_POSTCARD, 0, PRN_LANDSCAPE),  //17 はがき横
   815:     };
   816: 
   817:     //パラメータ
   818:     //  自動保存
   819:     prnAutosaveOn = Settings.sgsGetOnOff ("prnauto");
   820:     //  ディレクトリ
   821:     prnSavePath = Settings.sgsGetString ("prnpath");
   822:     //  ディップスイッチ
   823:     prnDIPSW = Settings.sgsGetInt ("prndipsw") & PRN_DIPSW_MASK;
   824:     //  用紙
   825:     String size = Settings.sgsGetString ("prnsize");
   826:     String orientation = Settings.sgsGetString ("prnorientation");
   827:     prnNextPaper = prnPaperArray[1];  //A4縦
   828:     for (Paper paper : prnPaperArray) {
   829:       if (size.equalsIgnoreCase (paper.sizeEn) &&
   830:           orientation.equalsIgnoreCase (paper.orientationEn)) {
   831:         prnNextPaper = paper;
   832:         break;
   833:       }
   834:     }
   835:     prnCurrentPaper = null;
   836:     //  印字不可領域
   837:     prnNextDeadTopMm = Math.max (0, Math.min (Settings.sgsGetInt ("prntopmargin"), prnNextPaper.paperHeightMm - 1));
   838:     prnNextDeadLeftMm = Math.max (0, Math.min (Settings.sgsGetInt ("prnleftmargin"), prnNextPaper.paperWidthMm - 1));
   839:     prnNextDeadRightMm = Math.max (0, Math.min (Settings.sgsGetInt ("prnrightmargin"), prnNextPaper.paperWidthMm - 1 - prnNextDeadLeftMm));
   840:     prnNextDeadBottomMm = Math.max (0, Math.min (Settings.sgsGetInt ("prnbottommargin"), prnNextPaper.paperHeightMm - 1 - prnNextDeadTopMm));
   841:     //  回転
   842:     prnNextRotation = Math.max (0, Math.min (Settings.sgsGetInt ("prnrotation"), 3));
   843:     prnRotation = 0;
   844:     prnRotatedWidthDot = 0;
   845:     prnRotatedHeightDot = 0;
   846:     prnM11 = 0;
   847:     prnM12 = 0;
   848:     prnM13 = 0;
   849:     prnM21 = 0;
   850:     prnM22 = 0;
   851:     prnM23 = 0;
   852:     prnIncrementX = 0;
   853:     prnIncrementY = 0;
   854:     //  ダークモード
   855:     prnNextDarkMode = Settings.sgsGetOnOff ("prndarkmode");
   856:     prnDarkMode = false;
   857:     //  オンライン
   858:     prnOnlineOn = Settings.sgsGetOnOff ("prnonline");
   859:     //  単色インクリボンの色
   860:     prnSingleColor = Math.max (0, Math.min (Settings.sgsGetInt ("prnsinglecolor"), 7));
   861:     //  表示倍率
   862:     prnScaleShift = Math.max (-4, Math.min (Settings.sgsGetInt ("prnscalefactor"), 4));
   863: 
   864:     //プリンタポート
   865:     prnReset ();
   866: 
   867:     //プリンタアダプタ
   868:     if (PRN_USE_ADAPTER) {
   869:       prnAdapterInit ();
   870:     }
   871: 
   872:     //イメージとビットマップ
   873:     prnImage = null;
   874:     prnBitmap = null;
   875: 
   876:     //印字フラグ
   877:     prnPrinted = false;
   878: 
   879:     //設定
   880:     prnResetSettings ();
   881: 
   882:     //出力
   883:     prnSaveName = "1.png";
   884: 
   885:   }  //prnInit
   886: 
   887:   //prnTini ()
   888:   public static void prnTini () {
   889: 
   890:     //パラメータ
   891:     //  自動保存
   892:     Settings.sgsPutOnOff ("prnauto", prnAutosaveOn);
   893:     //  ディレクトリ
   894:     Settings.sgsPutString ("prnpath", prnSavePath);
   895:     //  ディップスイッチ
   896:     Settings.sgsPutInt ("prndipsw", prnDIPSW);
   897:     //  用紙
   898:     Settings.sgsPutString ("prnsize", prnNextPaper.sizeEn);
   899:     Settings.sgsPutString ("prnorientation", prnNextPaper.orientationEn);
   900:     Settings.sgsPutInt ("prntopmargin", prnNextDeadTopMm);
   901:     Settings.sgsPutInt ("prnleftmargin", prnNextDeadLeftMm);
   902:     Settings.sgsPutInt ("prnrightmargin", prnNextDeadRightMm);
   903:     Settings.sgsPutInt ("prnbottommargin", prnNextDeadBottomMm);
   904:     //  回転
   905:     Settings.sgsPutInt ("prnrotation", prnNextRotation);
   906:     //  ダークモード
   907:     Settings.sgsPutOnOff ("prndarkmode", prnNextDarkMode);
   908:     //  オンライン
   909:     Settings.sgsPutOnOff ("prnonline", prnOnlineOn);
   910:     //  単色インクリボンの色
   911:     Settings.sgsPutInt ("prnsinglecolor", prnSingleColor);
   912:     //  表示倍率
   913:     Settings.sgsPutInt ("prnscalefactor", prnScaleShift);
   914: 
   915:     //プリンタアダプタ
   916:     if (PRN_USE_ADAPTER) {
   917:       prnAdapterTimer.cancel ();
   918:     }
   919: 
   920:   }
   921: 
   922: 
   923:   //fntGetAvailableFamilies ()
   924:   public static String[] fntGetAvailableFamilies () {
   925:     if (fntAvailableFamilies == null) {
   926:       //フォントファミリの一覧を用意する
   927:       fntAvailableFamilies = GraphicsEnvironment.getLocalGraphicsEnvironment ().getAvailableFontFamilyNames ();
   928:       Arrays.sort (fntAvailableFamilies, null);
   929:     }
   930:     return fntAvailableFamilies;
   931:   }  //fntGetAvailableFamilies
   932: 
   933:   //fntGetGothicFamily ()
   934:   public static String fntGetGothicFamily () {
   935:     if (fntGothicFamily == null) {
   936:       fntGothicFamily = "Monospaced";
   937:       //使えそうなフォントを探す
   938:       String[] availableFamilies = fntGetAvailableFamilies ();
   939:       for (String family : FNT_GOTHIC_FAMILIES) {
   940:         if (0 <= Arrays.binarySearch (availableFamilies, family, null)) {
   941:           fntGothicFamily = family;
   942:           break;
   943:         }
   944:       }
   945:       System.out.println ((Multilingual.mlnJapanese ? "ゴシック体のフォント: " : "Gothic font: ") + fntGothicFamily);
   946:     }
   947:     return fntGothicFamily;
   948:   }  //fntGetGothicFamily
   949: 
   950:   //fntGetMinchoFamily ()
   951:   public static String fntGetMinchoFamily () {
   952:     if (fntMinchoFamily == null) {
   953:       fntMinchoFamily = "Monospaced";
   954:       //使えそうなフォントを探す
   955:       String[] availableFamilies = fntGetAvailableFamilies ();
   956:       for (String family : FNT_MINCHO_FAMILIES) {
   957:         if (0 <= Arrays.binarySearch (availableFamilies, family, null)) {
   958:           fntMinchoFamily = family;
   959:           break;
   960:         }
   961:       }
   962:       System.out.println ((Multilingual.mlnJapanese ? "明朝体のフォント: " : "Mincho font: ") + fntMinchoFamily);
   963:     }
   964:     return fntMinchoFamily;
   965:   }  //fntGetMinchoFamily
   966: 
   967: 
   968:   //gaijiData = prnGetGaijiData ()
   969:   //  外字データ
   970:   public static byte[] prnGetGaijiData () {
   971:     if (prnGaijiData == null) {
   972:       prnGaijiData = new byte[6 * 48 * 100];
   973:     }
   974:     return prnGaijiData;
   975:   }  //prnGetGaijiData
   976: 
   977:   //prnStart ()
   978:   public static void prnStart () {
   979:     if (RestorableFrame.rfmGetOpened (Settings.SGS_PRN_FRAME_KEY)) {
   980:       prnOpen ();
   981:     }
   982:   }  //prnStart
   983: 
   984:   //prnOpen ()
   985:   //  ウインドウを開く
   986:   public static void prnOpen () {
   987:     if (prnFrame == null) {
   988:       prnMakeFrame ();
   989:     }
   990:     prnFrame.setVisible (true);
   991:   }  //prnOpen
   992: 
   993:   //prnMakeFrame ()
   994:   //  ウインドウを作る
   995:   //  ここでは開かない
   996:   public static void prnMakeFrame () {
   997: 
   998:     //キャンバス
   999:     prnCanvas = new ScrollCanvas (prnImage);
  1000:     prnCanvas.setMargin (10, 10);
  1001:     prnCanvas.setMatColor (new Color (LnF.LNF_RGB[4]));
  1002: 
  1003:     //アクションリスナー
  1004:     ActionListener listener = new ActionListener () {
  1005:       @Override public void actionPerformed (ActionEvent ae) {
  1006:         Object source = ae.getSource ();
  1007:         String command = ae.getActionCommand ();
  1008:         switch (command) {
  1009:         case "Online":  //オンライン
  1010:           prnSetOnlineOn (((JCheckBoxMenuItem) source).isSelected ());
  1011:           break;
  1012:         case "Eject":  //排紙
  1013:           if (PRN_USE_ADAPTER) {
  1014:             //!!! 印刷中に操作すると制御コードの途中に改ページコードが混ざることになる
  1015:             prnAdapterTimer.schedule (new PrinterAdapterTask (new byte[] { 0x1a, 0x0c }), 0L);
  1016:           }
  1017:           break;
  1018:         case "Destroy":  //破棄
  1019:           if (PRN_USE_ADAPTER) {
  1020:             //!!! 印刷中に操作すると制御コードの途中に改行コードが混ざることになる
  1021:             prnAdapterTimer.schedule (new PrinterAdapterTask (new byte[] { 0x1a, 0x1a, 0x1a, 0x0c }), 0L);
  1022:           }
  1023:           break;
  1024:         case "Reset":  //リセット
  1025:           if (PRN_USE_ADAPTER) {
  1026:             //!!! 印刷中に操作すると制御コードの途中に改行コードが混ざることになる
  1027:             prnAdapterTimer.schedule (new PrinterAdapterTask (new byte[] { 0x1a, 0x1a, 0x1b, 'c', '1' }), 0L);
  1028:           }
  1029:           break;
  1030:         case "Autosave":  //自動保存
  1031:           prnSetAutosaveOn (((JCheckBoxMenuItem) source).isSelected ());
  1032:           break;
  1033:         case "Close":  //閉じる
  1034:           prnFrame.setVisible (false);
  1035:           break;
  1036:           //
  1037:         case "No margins":  //余白なし
  1038:           prnNextDeadTopMm = 0;
  1039:           prnNextDeadLeftMm = 0;
  1040:           prnNextDeadRightMm = 0;
  1041:           prnNextDeadBottomMm = 0;
  1042:           prnSpinnerLocked++;
  1043:           prnDeadTopModel.setValue (Integer.valueOf (prnNextDeadTopMm));
  1044:           prnDeadLeftModel.setValue (Integer.valueOf (prnNextDeadLeftMm));
  1045:           prnDeadRightModel.setValue (Integer.valueOf (prnNextDeadRightMm));
  1046:           prnDeadBottomModel.setValue (Integer.valueOf (prnNextDeadBottomMm));
  1047:           prnSpinnerLocked--;
  1048:           break;
  1049:         case "Reset margins":  //初期値に戻す
  1050:           prnNextDeadTopMm = prnNextPaper.initialDeadTopMm;
  1051:           prnNextDeadLeftMm = prnNextPaper.initialDeadLeftMm;
  1052:           prnNextDeadRightMm = prnNextPaper.initialDeadRightMm;
  1053:           prnNextDeadBottomMm = prnNextPaper.initialDeadBottomMm;
  1054:           prnSpinnerLocked++;
  1055:           prnDeadTopModel.setValue (Integer.valueOf (prnNextDeadTopMm));
  1056:           prnDeadLeftModel.setValue (Integer.valueOf (prnNextDeadLeftMm));
  1057:           prnDeadRightModel.setValue (Integer.valueOf (prnNextDeadRightMm));
  1058:           prnDeadBottomModel.setValue (Integer.valueOf (prnNextDeadBottomMm));
  1059:           prnSpinnerLocked--;
  1060:           break;
  1061:         case "0°":
  1062:           prnNextRotation = 0;
  1063:           break;
  1064:         case "90°":
  1065:           prnNextRotation = 1;
  1066:           break;
  1067:         case "180°":
  1068:           prnNextRotation = 2;
  1069:           break;
  1070:         case "270°":
  1071:           prnNextRotation = 3;
  1072:           break;
  1073:         case "Dark mode":
  1074:           prnNextDarkMode = ((JCheckBoxMenuItem) source).isSelected ();
  1075:           break;
  1076:           //
  1077:         case "Black ink ribbon":  //黒色インクリボン
  1078:           prnSetSingleColor (0);
  1079:           break;
  1080:         case "Blue ink ribbon":  //青色インクリボン
  1081:           prnSetSingleColor (1);
  1082:           break;
  1083:         case "Lime ink ribbon":  //緑色インクリボン
  1084:           prnSetSingleColor (2);
  1085:           break;
  1086:         case "Cyan ink ribbon":  //水色インクリボン
  1087:           prnSetSingleColor (3);
  1088:           break;
  1089:         case "Red ink ribbon":  //赤色インクリボン
  1090:           prnSetSingleColor (4);
  1091:           break;
  1092:         case "Magenta ink ribbon":  //紫色インクリボン
  1093:           prnSetSingleColor (5);
  1094:           break;
  1095:         case "Yellow ink ribbon":  //黄色インクリボン
  1096:           prnSetSingleColor (6);
  1097:           break;
  1098:         case "White ink ribbon":  //白色インクリボン
  1099:           prnSetSingleColor (7);
  1100:           break;
  1101:           //
  1102:         case "6.25%":
  1103:           prnCanvas.setScaleShift (-4);
  1104:           break;
  1105:         case "12.5%":
  1106:           prnCanvas.setScaleShift (-3);
  1107:           break;
  1108:         case "25%":
  1109:           prnCanvas.setScaleShift (-2);
  1110:           break;
  1111:         case "50%":
  1112:           prnCanvas.setScaleShift (-1);
  1113:           break;
  1114:         case "100%":
  1115:           prnCanvas.setScaleShift (0);
  1116:           break;
  1117:         case "200%":
  1118:           prnCanvas.setScaleShift (1);
  1119:           break;
  1120:         case "400%":
  1121:           prnCanvas.setScaleShift (2);
  1122:           break;
  1123:         case "800%":
  1124:           prnCanvas.setScaleShift (3);
  1125:           break;
  1126:         case "1600%":
  1127:           prnCanvas.setScaleShift (4);
  1128:           break;
  1129:           //
  1130:         case "Roman / Mincho":
  1131:           prnDIPSW &= ~PRN_DIPSW_FONT_STYLE;
  1132:           break;
  1133:         case "Sans-Serif / Gothic":
  1134:           prnDIPSW |= PRN_DIPSW_FONT_STYLE;
  1135:           break;
  1136:           //
  1137:         default:
  1138:           for (Paper paper : prnPaperArray) {
  1139:             if (paper.nameEn.equals (command)) {
  1140:               prnNextPaper = paper;
  1141:               prnNextDeadTopMm = Math.min (prnNextDeadTopMm, prnNextPaper.paperHeightMm - 1);
  1142:               prnNextDeadLeftMm = Math.min (prnNextDeadLeftMm, prnNextPaper.paperWidthMm - 1);
  1143:               prnNextDeadRightMm = Math.min (prnNextDeadRightMm, prnNextPaper.paperWidthMm - 1 - prnNextDeadLeftMm);
  1144:               prnNextDeadBottomMm = Math.min (prnNextDeadBottomMm, prnNextPaper.paperHeightMm - 1 - prnNextDeadTopMm);
  1145:               prnSpinnerLocked++;
  1146:               prnDeadTopModel.setMaximum (Integer.valueOf (prnNextPaper.paperHeightMm - 1));
  1147:               prnDeadLeftModel.setMaximum (Integer.valueOf (prnNextPaper.paperWidthMm - 1));
  1148:               prnDeadRightModel.setMaximum (Integer.valueOf (prnNextPaper.paperWidthMm - 1 - prnNextDeadLeftMm));
  1149:               prnDeadBottomModel.setMaximum (Integer.valueOf (prnNextPaper.paperHeightMm - 1 - prnNextDeadTopMm));
  1150:               prnDeadTopModel.setValue (Integer.valueOf (prnNextDeadTopMm));
  1151:               prnDeadLeftModel.setValue (Integer.valueOf (prnNextDeadLeftMm));
  1152:               prnDeadRightModel.setValue (Integer.valueOf (prnNextDeadRightMm));
  1153:               prnDeadBottomModel.setValue (Integer.valueOf (prnNextDeadBottomMm));
  1154:               prnSpinnerLocked--;
  1155:               break;
  1156:             }
  1157:           }
  1158:         }
  1159:       }
  1160:     };
  1161: 
  1162:     //用紙メニュー
  1163:     ButtonGroup paperGroup = new ButtonGroup ();
  1164:     JMenu portraitMenu = Multilingual.mlnText (ComponentFactory.createMenu ("Portrait", 'P'), "ja", "縦長");
  1165:     JMenu landscapeMenu = Multilingual.mlnText (ComponentFactory.createMenu ("Landscape", 'L'), "ja", "横長");
  1166:     for (int i = 0; i < prnPaperArray.length; i++) {
  1167:       Paper paper = prnPaperArray[i];
  1168:       (i < prnPaperArray.length >> 1 ? portraitMenu : landscapeMenu).add (
  1169:         Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (
  1170:           paperGroup, paper == prnNextPaper, paper.nameEn, listener), "ja", paper.nameJa));
  1171:     }
  1172:     //  印字不可領域
  1173:     prnSpinnerLocked = 0;
  1174:     prnDeadTopModel = new SpinnerNumberModel (prnNextDeadTopMm, 0, prnNextPaper.paperHeightMm - 1, 1);
  1175:     prnDeadLeftModel = new SpinnerNumberModel (prnNextDeadLeftMm, 0, prnNextPaper.paperWidthMm - 1, 1);
  1176:     prnDeadRightModel = new SpinnerNumberModel (prnNextDeadRightMm, 0, prnNextPaper.paperWidthMm - 1 - prnNextDeadLeftMm, 1);
  1177:     prnDeadBottomModel = new SpinnerNumberModel (prnNextDeadBottomMm, 0, prnNextPaper.paperHeightMm - 1 - prnNextDeadTopMm, 1);
  1178:     prnDeadTopSpinner = ComponentFactory.createNumberSpinner (prnDeadTopModel, 4, new ChangeListener () {
  1179:       @Override public void stateChanged (ChangeEvent ce) {
  1180:         if (prnSpinnerLocked == 0) {
  1181:           prnNextDeadTopMm = prnDeadTopModel.getNumber ().intValue ();
  1182:           prnDeadBottomModel.setMaximum (Integer.valueOf (prnNextPaper.paperHeightMm - 1 - prnNextDeadTopMm));
  1183:         }
  1184:       }  //stateChanged
  1185:     });
  1186:     prnDeadLeftSpinner = ComponentFactory.createNumberSpinner (prnDeadLeftModel, 4, new ChangeListener () {
  1187:       @Override public void stateChanged (ChangeEvent ce) {
  1188:         if (prnSpinnerLocked == 0) {
  1189:           prnNextDeadLeftMm = prnDeadLeftModel.getNumber ().intValue ();
  1190:           prnDeadRightModel.setMaximum (Integer.valueOf (prnNextPaper.paperWidthMm - 1 - prnNextDeadLeftMm));
  1191:         }
  1192:       }  //stateChanged
  1193:     });
  1194:     prnDeadRightSpinner = ComponentFactory.createNumberSpinner (prnDeadRightModel, 4, new ChangeListener () {
  1195:       @Override public void stateChanged (ChangeEvent ce) {
  1196:         if (prnSpinnerLocked == 0) {
  1197:           prnNextDeadRightMm = prnDeadRightModel.getNumber ().intValue ();
  1198:           prnDeadLeftModel.setMaximum (Integer.valueOf (prnNextPaper.paperWidthMm - 1 - prnNextDeadRightMm));
  1199:         }
  1200:       }  //stateChanged
  1201:     });
  1202:     prnDeadBottomSpinner = ComponentFactory.createNumberSpinner (prnDeadBottomModel, 4, new ChangeListener () {
  1203:       @Override public void stateChanged (ChangeEvent ce) {
  1204:         if (prnSpinnerLocked == 0) {
  1205:           prnNextDeadBottomMm = prnDeadBottomModel.getNumber ().intValue ();
  1206:           prnDeadTopModel.setMaximum (Integer.valueOf (prnNextPaper.paperHeightMm - 1 - prnNextDeadBottomMm));
  1207:         }
  1208:       }  //stateChanged
  1209:     });
  1210: 
  1211:     //インクリボンメニュー
  1212:     ButtonGroup ribbonGroup = new ButtonGroup ();
  1213: 
  1214:     //表示メニュー
  1215:     ButtonGroup zoomGroup = new ButtonGroup ();
  1216:     prnScaleMenuItem = new JRadioButtonMenuItem[9];
  1217:     ButtonGroup directionGroup = new ButtonGroup ();
  1218:     ButtonGroup fontStyleGroup = new ButtonGroup ();
  1219: 
  1220:     //メニューバー
  1221:     JMenuBar menuBar = ComponentFactory.createMenuBar (
  1222: 
  1223:       //ファイルメニュー
  1224:       Multilingual.mlnText (
  1225:         ComponentFactory.createMenu (
  1226:           "File", 'F',
  1227:           prnOnlineMenuItem =
  1228:           Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (prnOnlineOn, "Online", listener), "ja", "オンライン"),
  1229:           ComponentFactory.createHorizontalSeparator (),
  1230:           !PRN_USE_ADAPTER ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("Eject", 'E', listener), "ja", "排紙"),
  1231:           !PRN_USE_ADAPTER ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("Destroy", 'D', listener), "ja", "破棄"),
  1232:           !PRN_USE_ADAPTER ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("Reset", 'R', listener), "ja", "リセット"),
  1233:           ComponentFactory.createHorizontalSeparator (),
  1234:           prnAutosaveMenuItem =
  1235:           Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (prnAutosaveOn, "Autosave", listener), "ja", "自動保存"),
  1236:           ComponentFactory.createHorizontalSeparator (),
  1237:           Multilingual.mlnText (ComponentFactory.createMenuItem ("Close", 'C', listener), "ja", "閉じる")
  1238:           ),
  1239:         "ja", "ファイル"),
  1240: 
  1241:       //用紙メニュー
  1242:       Multilingual.mlnText (
  1243:         ComponentFactory.createMenu (
  1244:           "Paper", 'P',
  1245:           portraitMenu,
  1246:           landscapeMenu,
  1247:           ComponentFactory.createHorizontalSeparator (),
  1248:           Multilingual.mlnText (
  1249:             ComponentFactory.createMenu (
  1250:               "Margin", 'M',
  1251:               ComponentFactory.createHorizontalBox (
  1252:                 Box.createHorizontalGlue (),
  1253:                 Multilingual.mlnText (ComponentFactory.createLabel ("Top "), "ja", "上 "),
  1254:                 prnDeadTopSpinner,
  1255:                 ComponentFactory.createLabel (" mm"),
  1256:                 Box.createHorizontalGlue ()
  1257:                 ),
  1258:               ComponentFactory.createHorizontalBox (
  1259:                 Box.createHorizontalGlue (),
  1260:                 Multilingual.mlnText (ComponentFactory.createLabel ("Left "), "ja", "左 "),
  1261:                 prnDeadLeftSpinner,
  1262:                 ComponentFactory.createLabel (" mm"),
  1263:                 Box.createHorizontalStrut (20),
  1264:                 Multilingual.mlnText (ComponentFactory.createLabel ("Right "), "ja", "右 "),
  1265:                 prnDeadRightSpinner,
  1266:                 ComponentFactory.createLabel (" mm"),
  1267:                 Box.createHorizontalGlue ()
  1268:                 ),
  1269:               ComponentFactory.createHorizontalBox (
  1270:                 Box.createHorizontalGlue (),
  1271:                 Multilingual.mlnText (ComponentFactory.createLabel ("Bottom "), "ja", "下 "),
  1272:                 prnDeadBottomSpinner,
  1273:                 ComponentFactory.createLabel (" mm"),
  1274:                 Box.createHorizontalGlue ()
  1275:                 ),
  1276:               ComponentFactory.createHorizontalSeparator (),
  1277:               Multilingual.mlnText (ComponentFactory.createMenuItem ("No margins", listener), "ja", "余白なし"),
  1278:               ComponentFactory.createHorizontalSeparator (),
  1279:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Reset margins", listener), "ja", "初期値に戻す")
  1280:               ),
  1281:             "ja", "余白"),
  1282:           ComponentFactory.createHorizontalSeparator (),
  1283:           ComponentFactory.createRadioButtonMenuItem (directionGroup, prnNextRotation == 0, "0°", listener),
  1284:           ComponentFactory.createRadioButtonMenuItem (directionGroup, prnNextRotation == 1, "90°", listener),
  1285:           ComponentFactory.createRadioButtonMenuItem (directionGroup, prnNextRotation == 2, "180°", listener),
  1286:           ComponentFactory.createRadioButtonMenuItem (directionGroup, prnNextRotation == 3, "270°", listener),
  1287:           ComponentFactory.createHorizontalSeparator (),
  1288:           Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (prnNextDarkMode, "Dark mode", listener), "ja", "ダークモード")
  1289:           ),
  1290:         "ja", "用紙"),
  1291: 
  1292:       //インクリボンメニュー
  1293:       Multilingual.mlnText (
  1294:         ComponentFactory.createMenu (
  1295:           "Ink ribbon", 'R',
  1296:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 0,
  1297:                                                                 "Black ink ribbon", '0', listener),
  1298:                                 "ja", "黒色インクリボン"),
  1299:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 1,
  1300:                                                                 "Blue ink ribbon", '1', listener),
  1301:                                 "ja", "青色インクリボン"),
  1302:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 2,
  1303:                                                                 "Lime ink ribbon", '2', listener),
  1304:                                 "ja", "緑色インクリボン"),
  1305:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 3,
  1306:                                                                 "Cyan ink ribbon", '3', listener),
  1307:                                 "ja", "水色インクリボン"),
  1308:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 4,
  1309:                                                                 "Red ink ribbon", '4', listener),
  1310:                                 "ja", "赤色インクリボン"),
  1311:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 5,
  1312:                                                                 "Magenta ink ribbon", '5', listener),
  1313:                                 "ja", "紫色インクリボン"),
  1314:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 6,
  1315:                                                                 "Yellow ink ribbon", '6', listener),
  1316:                                 "ja", "黄色インクリボン"),
  1317:           Multilingual.mlnText (ComponentFactory.createRadioButtonMenuItem (ribbonGroup, prnSingleColor == 7,
  1318:                                                                 "White ink ribbon", '7', listener),
  1319:                                 "ja", "白色インクリボン")
  1320:           ),
  1321:         "ja", "インクリボン"),
  1322: 
  1323:       //表示メニュー
  1324:       Multilingual.mlnText (
  1325:         ComponentFactory.createMenu (
  1326:           "Display", 'D',
  1327:           prnScaleMenuItem[0] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -4, "6.25%", '1', listener),
  1328:           prnScaleMenuItem[1] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -3, "12.5%", '2', listener),
  1329:           prnScaleMenuItem[2] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -2, "25%", '3', listener),
  1330:           prnScaleMenuItem[3] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift == -1, "50%", '4', listener),
  1331:           prnScaleMenuItem[4] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  0, "100%", '5', listener),
  1332:           prnScaleMenuItem[5] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  1, "200%", '6', listener),
  1333:           prnScaleMenuItem[6] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  2, "400%", '7', listener),
  1334:           prnScaleMenuItem[7] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  3, "800%", '8', listener),
  1335:           prnScaleMenuItem[8] = ComponentFactory.createRadioButtonMenuItem (zoomGroup, prnScaleShift ==  4, "1600%", '9', listener)
  1336:           ),
  1337:         "ja", "表示"),
  1338: 
  1339:       //DIPSWメニュー
  1340:       ComponentFactory.createMenu (
  1341:         "DIPSW", 'S',
  1342:         Multilingual.mlnText (
  1343:           ComponentFactory.createRadioButtonMenuItem (
  1344:             fontStyleGroup,
  1345:             (prnDIPSW & PRN_DIPSW_FONT_STYLE) == 0,
  1346:             "Roman / Mincho",
  1347:             listener
  1348:             ),
  1349:           "ja", "ローマン体/明朝体"
  1350:           ),
  1351:         Multilingual.mlnText (
  1352:           ComponentFactory.createRadioButtonMenuItem (
  1353:             fontStyleGroup,
  1354:             (prnDIPSW & PRN_DIPSW_FONT_STYLE) != 0,
  1355:             "Sans-Serif / Gothic",
  1356:             listener
  1357:             ),
  1358:           "ja", "サンセリフ体/ゴシック体"
  1359:           )
  1360:         )
  1361: 
  1362:       );
  1363: 
  1364:     //スケールシフトリスナー
  1365:     prnCanvas.addScaleShiftListener (new ScrollCanvas.ScaleShiftListener () {
  1366:       @Override public void scaleShiftChanged (int scaleShift) {
  1367:         if (prnScaleShift != scaleShift &&
  1368:             -4 <= scaleShift && scaleShift <= 4) {
  1369:           prnScaleShift = scaleShift;
  1370:           prnScaleMenuItem[4 + scaleShift].setSelected (true);
  1371:         }
  1372:       }
  1373:     });
  1374: 
  1375:     //ウインドウ
  1376:     prnFrame = Multilingual.mlnTitle (
  1377:       ComponentFactory.createRestorableSubFrame (
  1378:         Settings.SGS_PRN_FRAME_KEY,
  1379:         "Printer",
  1380:         menuBar,
  1381:         ComponentFactory.createBorderPanel (
  1382:           ComponentFactory.setPreferredSize (prnCanvas, 600, 400),
  1383:           null,
  1384:           null,
  1385:           null
  1386:           )
  1387:         ),
  1388:       "ja", "プリンタ");
  1389: 
  1390:   }  //prnMakeFrame
  1391: 
  1392:   //prnMakeSaveDialog ()
  1393:   //  プリンタ出力イメージ保存ダイアログを作る
  1394:   public static void prnMakeSaveDialog () {
  1395:     //出力できるイメージファイルの拡張子の配列を作る
  1396:     prnWriterSuffixes = ImageIO.getWriterFileSuffixes ();  //出力できるイメージファイルの拡張子の配列
  1397:     if (XEiJ.prgCaseIgnored) {  //ファイル名の大文字と小文字が区別されない
  1398:       for (int i = 0; i < prnWriterSuffixes.length; i++) {
  1399:         prnWriterSuffixes[i] = prnWriterSuffixes[i].toLowerCase ();  //小文字化しておく
  1400:       }
  1401:     }
  1402:     //プリンタ出力イメージファイルフィルタ
  1403:     prnSaveFileFilter = new javax.swing.filechooser.FileFilter () {  //java.io.FileFilterと紛らわしい
  1404:       @Override public boolean accept (File file) {
  1405:         if (file.isDirectory ()) {
  1406:           return true;
  1407:         }
  1408:         String name = file.getName ();
  1409:         if (XEiJ.prgCaseIgnored) {
  1410:           name = name.toLowerCase ();
  1411:         }
  1412:         for (String suffix : prnWriterSuffixes) {
  1413:           if (name.endsWith ("." + suffix)) {
  1414:             return true;
  1415:           }
  1416:         }
  1417:         return false;
  1418:       }
  1419:       @Override public String getDescription () {
  1420:         return Multilingual.mlnJapanese ? "プリンタ出力イメージ" : "Printer Output Image";
  1421:       }
  1422:     };
  1423:     //アクションリスナー
  1424:     ActionListener listener = new ActionListener () {
  1425:       @Override public void actionPerformed (ActionEvent ae) {
  1426:         switch (ae.getActionCommand ()) {
  1427:         case JFileChooser.APPROVE_SELECTION:
  1428:         case "Save":  //保存
  1429:           {
  1430:             File file = prnSaveFileChooser.getSelectedFile ().getAbsoluteFile ();
  1431:             prnSavePath = file.getParentFile ().getAbsolutePath ();
  1432:             prnSaveName = file.getName ();
  1433:           }
  1434:           if (prnSave ()) {  //保存できたとき
  1435:             //  ダイアログを閉じた瞬間に排紙処理が再開されてイメージが廃棄される(可能性がある)ので、
  1436:             //  イメージの保存が終わってからダイアログを閉じる
  1437:             prnSaveDialog.setVisible (false);
  1438:           }
  1439:           break;
  1440:         case JFileChooser.CANCEL_SELECTION:
  1441:         case "Discard":  //破棄
  1442:           prnSaveDialog.setVisible (false);
  1443:           break;
  1444:         case "Autosave from next time":  //次回から自動保存
  1445:           prnSetAutosaveOn (prnAutosaveCheckBox.isSelected ());
  1446:           break;
  1447:         }
  1448:       }
  1449:     };
  1450:     //ファイルチューザー
  1451:     prnSaveFileChooser = new JFileChooser2 (new File (prnSavePath + File.separator + prnSaveName));
  1452:     prnSaveFileChooser.setFileFilter (prnSaveFileFilter);
  1453:     prnSaveFileChooser.setMultiSelectionEnabled (false);
  1454:     prnSaveFileChooser.setControlButtonsAreShown (false);
  1455:     prnSaveFileChooser.addActionListener (listener);
  1456:     //ダイアログ
  1457:     prnSaveDialog = Multilingual.mlnTitle (
  1458:       ComponentFactory.createModalDialog (
  1459:         XEiJ.frmFrame,
  1460:         "Save printer output image",
  1461:         ComponentFactory.createBorderPanel (
  1462:           0, 0,
  1463:           ComponentFactory.createVerticalBox (
  1464:             prnSaveFileChooser,
  1465:             ComponentFactory.createHorizontalBox (
  1466:               Box.createHorizontalStrut (12),
  1467:               Box.createHorizontalGlue (),
  1468:               prnAutosaveCheckBox =
  1469:               Multilingual.mlnText (ComponentFactory.createCheckBox (prnAutosaveOn, "Autosave from next time", listener), "ja", "次回から自動保存"),
  1470:               Box.createHorizontalGlue (),
  1471:               Box.createHorizontalStrut (12),
  1472:               Multilingual.mlnText (ComponentFactory.createButton ("Save", KeyEvent.VK_S, listener), "ja", "保存"),
  1473:               Box.createHorizontalStrut (12),
  1474:               Multilingual.mlnText (ComponentFactory.createButton ("Discard", KeyEvent.VK_D, listener), "ja", "破棄"),
  1475:               Box.createHorizontalStrut (12)
  1476:               ),
  1477:             Box.createVerticalStrut (12)
  1478:             )
  1479:           )
  1480:         ),
  1481:       "ja", "プリンタ出力イメージの保存");
  1482:   }  //prnMakeSaveDialog
  1483: 
  1484:   //prnSetAutosaveOn (on)
  1485:   //  自動保存を設定する
  1486:   public static void prnSetAutosaveOn (boolean on) {
  1487:     if (prnAutosaveOn != on) {
  1488:       prnAutosaveOn = on;
  1489:       if (prnAutosaveCheckBox != null &&
  1490:           prnAutosaveCheckBox.isSelected () != prnAutosaveOn) {
  1491:         prnAutosaveCheckBox.setSelected (prnAutosaveOn);
  1492:       }
  1493:       if (prnAutosaveMenuItem != null &&
  1494:           prnAutosaveMenuItem.isSelected () != prnAutosaveOn) {
  1495:         prnAutosaveMenuItem.setSelected (prnAutosaveOn);
  1496:       }
  1497:     }
  1498:   }  //prnSetAutosaveOn
  1499: 
  1500: 
  1501:   //プリンタポート
  1502: 
  1503:   //prnReset ()
  1504:   //  リセット
  1505:   //  プリンタポートをリセットする
  1506:   public static void prnReset () {
  1507:     prnData = 0;
  1508:     prnStrobe = 1;
  1509:   }  //prnReset
  1510: 
  1511:   //prnReadData ()
  1512:   public static int prnReadData () {
  1513:     return prnData;
  1514:   }  //prnReadData
  1515: 
  1516:   //prnReadStrobe ()
  1517:   public static int prnReadStrobe () {
  1518:     return prnStrobe;
  1519:   }  //prnReadStrobe
  1520: 
  1521:   //prnWriteData (d)
  1522:   public static void prnWriteData (int d) {
  1523:     prnData = d & 255;
  1524:   }  //prnWriteData
  1525: 
  1526:   //prnWriteStrobe (d)
  1527:   public static void prnWriteStrobe (int d) {
  1528:     d &= 1;
  1529:     if (prnStrobe != d) {
  1530:       prnStrobe = d;
  1531:       if (prnOnlineOn) {
  1532:         if (d != 0) {  //0→1
  1533:           //プリンタビジー
  1534:           IOInterrupt.ioiPrnFall ();
  1535:           //出力
  1536:           if (PRN_USE_ADAPTER) {
  1537:             prnAdapterOutput (prnData);
  1538:           } else {
  1539:             prnOutput (prnData);
  1540:           }
  1541:           //プリンタレディ
  1542:           IOInterrupt.ioiPrnRise ();
  1543:         }
  1544:       }
  1545:     }
  1546:   }  //prnWriteStrobe
  1547: 
  1548:   //prnSetOnlineOn (online)
  1549:   //  オンラインを設定する
  1550:   public static void prnSetOnlineOn (boolean on) {
  1551:     if (prnOnlineOn != on) {
  1552:       prnOnlineOn = on;
  1553:       if (prnOnlineMenuItem != null) {
  1554:         prnOnlineMenuItem.setSelected (on);
  1555:       }
  1556:       if (on) {  //off→on
  1557:         //プリンタレディ
  1558:         IOInterrupt.ioiPrnRise ();
  1559:       } else {  //on→off
  1560:         //プリンタビジー
  1561:         IOInterrupt.ioiPrnFall ();
  1562:       }
  1563:     }
  1564:   }  //prnSetOnlineOn
  1565: 
  1566: 
  1567: 
  1568:   //プリンタ
  1569: 
  1570:   //prnOutput (x)
  1571:   //  プリンタ出力
  1572:   //  接続されていること
  1573:   public static void prnOutput (int x) {
  1574:     prnCommandBuffer[prnCommandPointer++] = (byte) x;
  1575:     if (prnCommandPointer < prnCommandLength) {
  1576:       return;  //コマンド継続
  1577:     }
  1578:   command:
  1579:     {
  1580:       int c = prnCommandBuffer[0] & 255;  //1バイト目
  1581:       int d, e, f, g, h, i, j, z, n;
  1582:       switch (c) {
  1583:       case 0x08:  //BS
  1584:         prnPrintBackSpace ();  //バックスペース
  1585:         break command;  //コマンド終了
  1586:       case 0x09:  //HT
  1587:         prnPrintHorizontalTab ();  //水平タブ
  1588:         break command;  //コマンド終了
  1589:       case 0x0a:  //LF
  1590:         prnPrintLineFeed (1);  //1行改行
  1591:         break command;  //コマンド終了
  1592:       case 0x0b:  //VT
  1593:         if (prnCommandLength < 2) {
  1594:           prnCommandLength = 2;
  1595:           return;  //コマンド継続
  1596:         }
  1597:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1598:         prnPrintVerticalTab (d & 15);  //垂直タブ
  1599:         break command;  //コマンド終了
  1600:       case 0x0c:  //FF
  1601:         prnPrintFormFeed ();  //改ページ
  1602:         break command;  //コマンド終了
  1603:       case 0x0d:  //CR
  1604:         prnPrintCarriageReturn ();  //復帰
  1605:         break command;  //コマンド終了
  1606:       case 0x0e:  //SO
  1607:         prnSetHorizontalDoubleSizeMode (true);  //横2倍ON
  1608:         break command;  //コマンド終了
  1609:       case 0x0f:  //SI
  1610:         prnSetHorizontalDoubleSizeMode (false);  //横2倍OFF
  1611:         break command;  //コマンド終了
  1612:       case 0x10:  //POS n1 n2 n3
  1613:         if (prnCommandLength < 4) {
  1614:           prnCommandLength = 4;
  1615:           return;  //コマンド継続
  1616:         }
  1617:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1618:         e = prnCommandBuffer[2] & 255;  //3バイト目
  1619:         f = prnCommandBuffer[3] & 255;  //4バイト目
  1620:         prnSetStartColumn ((d & 15) * 100 + (e & 15) * 10 + (f & 15));  //開始桁位置設定
  1621:         break command;  //コマンド終了
  1622:       case 0x11:  //DC1
  1623:         prnSelect (true);  //セレクト
  1624:         break command;  //コマンド終了
  1625:       case 0x13:  //DC3
  1626:         prnSelect (false);  //ディセレクト
  1627:         break command;  //コマンド終了
  1628:       case 0x14:  //DC4 … ?
  1629:         z = prnCommandBuffer[prnCommandLength - 1] & 255;  //末尾
  1630:         if (z != 0x3f) {
  1631:           if (prnCommandLength + 1 < prnCommandBuffer.length) {
  1632:             prnCommandLength++;
  1633:           }
  1634:           return;  //コマンド継続
  1635:         }
  1636:         prnSetVerticalTabAnchor (prnCommandBuffer, 1, prnCommandLength - 1);  //垂直タブアンカー設置
  1637:         break command;  //コマンド終了
  1638:       case 0x18:  //CAN
  1639:         prnCancel ();  //キャンセル
  1640:         break command;  //コマンド終了
  1641:       case 0x1a:  //SUB
  1642:         if (prnCommandLength < 2) {
  1643:           prnCommandLength = 2;
  1644:           return;  //コマンド継続
  1645:         }
  1646:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1647:         switch (d) {
  1648:         case 0x0c:  //SUB FF (拡張)
  1649:           prnEjectPaper ();  //排紙
  1650:           break command;  //コマンド終了
  1651:         case 0x1a:  //SUB SUB (拡張)
  1652:           prnErasePaper ();  //消去
  1653:           break command;  //コマンド終了
  1654:         case 0x56:  //SUB V
  1655:           prnSetVerticalDoubleSizeMode (true);  //縦2倍ON
  1656:           break command;  //コマンド終了
  1657:         case 0x57:  //SUB W
  1658:           prnSetVerticalDoubleSizeMode (false);  //縦2倍OFF
  1659:           break command;  //コマンド終了
  1660:         }
  1661:         break;  //コマンド不明
  1662:       case 0x1b:  //ESC
  1663:         if (prnCommandLength < 2) {
  1664:           prnCommandLength = 2;
  1665:           return;  //コマンド継続
  1666:         }
  1667:         d = prnCommandBuffer[1] & 255;  //2バイト目
  1668:         switch (d) {
  1669:         case 0x00:  //ESC n
  1670:         case 0x01:  //ESC n
  1671:         case 0x02:  //ESC n
  1672:         case 0x03:  //ESC n
  1673:         case 0x04:  //ESC n
  1674:         case 0x05:  //ESC n
  1675:         case 0x06:  //ESC n
  1676:           prnHorizontalMove (d);  //水平移動。バイナリ指定
  1677:           break command;  //コマンド終了
  1678:         case 0x0b:  //ESC VT n1 n2
  1679:           if (prnCommandLength < 4) {
  1680:             prnCommandLength = 4;
  1681:             return;  //コマンド継続
  1682:           }
  1683:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1684:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1685:           prnPrintLineFeed ((e & 15) * 10 + (f & 15));  //n行改行
  1686:           break command;  //コマンド終了
  1687:         case 0x10:  //ESC POS n1 n2 n3 n4
  1688:           if (prnCommandLength < 6) {
  1689:             prnCommandLength = 6;
  1690:             return;  //コマンド継続
  1691:           }
  1692:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1693:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1694:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1695:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1696:           prnSetHorizontalStartPosition ((e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15));  //水平開始位置設定
  1697:           break command;  //コマンド終了
  1698:         case 0x19:  //ESC EM
  1699:           prnSetColorMode ();  //カラーモード
  1700:           break command;  //コマンド終了
  1701:         case 0x21:  //ESC !
  1702:           prnSetStrongMode (true);  //強調文字設定
  1703:           break command;  //コマンド終了
  1704:         case 0x22:  //ESC "
  1705:           prnSetStrongMode (false);  //強調文字解除
  1706:           break command;  //コマンド終了
  1707:         case 0x24:  //ESC $
  1708:           prnSetHiraganaMode (false);  //カタカナモード
  1709:           break command;  //コマンド終了
  1710:         case 0x25:  //ESC %
  1711:           if (prnCommandLength < 3) {
  1712:             prnCommandLength = 3;
  1713:             return;  //コマンド継続
  1714:           }
  1715:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1716:           switch (e) {
  1717:           case 0x32:  //ESC % 2 n1 n2 d1 d2 … dk
  1718:             if (prnCommandLength < 5) {
  1719:               prnCommandLength = 5;
  1720:               return;  //コマンド継続
  1721:             }
  1722:             f = prnCommandBuffer[3] & 255;  //4バイト目
  1723:             g = prnCommandBuffer[4] & 255;  //5バイト目
  1724:             n = f << 8 | g;  //バイナリ指定
  1725:             if (prnCommandLength < 5 + n) {
  1726:               prnCommandLength = 5 + n;
  1727:               return;  //コマンド継続
  1728:             }
  1729:             prn8DotBitImage (prnCommandBuffer, 5, n);  //8ドットビットイメージ
  1730:             break command;  //コマンド終了
  1731:           case 0x39:  //ESC % 9 n
  1732:             if (prnCommandLength < 4) {
  1733:               prnCommandLength = 4;
  1734:               return;  //コマンド継続
  1735:             }
  1736:             f = prnCommandBuffer[3] & 255;  //4バイト目
  1737:             prnSetLineHeight (f);  //1/120[in]紙送り量設定
  1738:             break command;  //コマンド終了
  1739:           }
  1740:           break;  //コマンド不明
  1741:         case 0x26:  //ESC &
  1742:           prnSetHiraganaMode (true);  //ひらがなモード
  1743:           break command;  //コマンド終了
  1744:         case 0x28:  //ESC ( … .
  1745:           z = prnCommandBuffer[prnCommandLength - 1] & 255;  //末尾
  1746:           if (z != 0x2e) {
  1747:             if (prnCommandLength + 1 < prnCommandBuffer.length) {
  1748:               prnCommandLength++;
  1749:             }
  1750:             return;  //コマンド継続
  1751:           }
  1752:           prnSetHorizontalTabAnchor (prnCommandBuffer, 2, prnCommandLength - 2);  //水平タブアンカー設置
  1753:           break command;  //コマンド終了
  1754:         case 0x29:  //ESC ) … .
  1755:           z = prnCommandBuffer[prnCommandLength - 1] & 255;  //末尾
  1756:           if (z != 0x2e) {
  1757:             if (prnCommandLength + 1 < prnCommandBuffer.length) {
  1758:               prnCommandLength++;
  1759:             }
  1760:             return;  //コマンド継続
  1761:           }
  1762:           prnClearHorizontalTabAnchor (prnCommandBuffer, 2, prnCommandLength - 2);  //水平タブアンカー除去
  1763:           break command;  //コマンド終了
  1764:         case 0x2a:  //ESC * n1 n2 d1 d2 … d32
  1765:           if (prnCommandLength < 36) {
  1766:             prnCommandLength = 36;
  1767:             return;  //コマンド継続
  1768:           }
  1769:           prn16DotExtendedCharacterDefinition (prnCommandBuffer, 2, prnCommandLength - 2);  //16ドット外字定義
  1770:           break command;  //コマンド終了
  1771:         case 0x2b:  //ESC + n1 n2 d1 d2 … d72
  1772:           if (prnCommandLength < 76) {
  1773:             prnCommandLength = 76;
  1774:             return;  //コマンド継続
  1775:           }
  1776:           prn24DotExtendedCharacterDefinition (prnCommandBuffer, 2, prnCommandLength - 2);  //24ドット外字定義
  1777:           break command;  //コマンド終了
  1778:         case 0x2f:  //ESC / n1 n2 n3
  1779:           if (prnCommandLength < 5) {
  1780:             prnCommandLength = 5;
  1781:             return;  //コマンド継続
  1782:           }
  1783:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1784:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1785:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1786:           prnSetRightMargin ((e & 15) * 100 + (f & 15) * 10 + (g & 15));  //右マージン設定
  1787:           break command;  //コマンド終了
  1788:         case 0x32:  //ESC 2
  1789:           prnClearAllHorizontalTabAnchor ();  //全水平タブアンカー除去
  1790:           break command;  //コマンド終了
  1791:         case 0x35:  //ESC 5
  1792:           prnSetPageStartPosition ();  //ページ先頭設定
  1793:           break command;  //コマンド終了
  1794:         case 0x36:  //ESC 6
  1795:           prnSetOneSixth ();  //1/6[in]改行設定
  1796:           break command;  //コマンド終了
  1797:         case 0x38:  //ESC 8
  1798:           prnSetOneEighth ();  //1/8[in]改行設定
  1799:           break command;  //コマンド終了
  1800:         case 0x43:  //ESC C n1 n2
  1801:           if (prnCommandLength < 4) {
  1802:             prnCommandLength = 4;
  1803:             return;  //コマンド継続
  1804:           }
  1805:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1806:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1807:           prnSetBottomMargin ((e & 15) * 10 + (f & 15));  //下マージン設定
  1808:           break command;  //コマンド終了
  1809:         case 0x45:  //ESC E
  1810:           prnSetEliteCharacterMode ();  //エリート文字設定
  1811:           break command;  //コマンド終了
  1812:         case 0x46:  //ESC F n1 n2
  1813:           if (prnCommandLength < 4) {
  1814:             prnCommandLength = 4;
  1815:             return;  //コマンド継続
  1816:           }
  1817:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1818:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1819:           prnSetPageHeight ((e & 15) * 10 + (f & 15));  //ページ高さ設定
  1820:           break command;  //コマンド終了
  1821:         case 0x48:  //ESC H
  1822:           prnSetKanjiMode (false);  //漢字モードOFF
  1823:           break command;  //コマンド終了
  1824:         case 0x49:  //ESC I n1 n2 n3 n4 d1 d2 … dk
  1825:           if (prnCommandLength < 6) {
  1826:             prnCommandLength = 6;
  1827:             return;  //コマンド継続
  1828:           }
  1829:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1830:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1831:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1832:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1833:           n = (e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15);
  1834:           if (prnCommandLength < 6 + 2 * n) {
  1835:             prnCommandLength = 6 + 2 * n;
  1836:             return;  //コマンド継続
  1837:           }
  1838:           prn16DotBitImage (prnCommandBuffer, 6, n);  //16ドットビットイメージ
  1839:           break command;  //コマンド終了
  1840:         case 0x4a:  //ESC J n1 n2 d1 d2 … dk
  1841:           if (prnCommandLength < 4) {
  1842:             prnCommandLength = 4;
  1843:             return;  //コマンド継続
  1844:           }
  1845:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1846:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1847:           n = e << 8 | f;  //バイナリ指定
  1848:           if (prnCommandLength < 4 + 3 * n) {
  1849:             prnCommandLength = 4 + 3 * n;
  1850:             return;  //コマンド継続
  1851:           }
  1852:           prn24DotBitImage (prnCommandBuffer, 4, n);  //24ドットビットイメージ
  1853:           break command;  //コマンド終了
  1854:         case 0x4b:  //ESC K
  1855:           prnSetKanjiMode (true);  //漢字モードON
  1856:           break command;  //コマンド終了
  1857:         case 0x4c:  //ESC L n1 n2 n3
  1858:           if (prnCommandLength < 5) {
  1859:             prnCommandLength = 5;
  1860:             return;  //コマンド継続
  1861:           }
  1862:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1863:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1864:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1865:           prnSetLeftMargin ((e & 15) * 100 + (f & 15) * 10 + (g & 15));  //左マージン設定
  1866:           break command;  //コマンド終了
  1867:         case 0x4d:  //ESC M n1 n2 d1 d2 … dk
  1868:           if (prnCommandLength < 4) {
  1869:             prnCommandLength = 4;
  1870:             return;  //コマンド継続
  1871:           }
  1872:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1873:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1874:           n = e << 8 | f;  //バイナリ指定
  1875:           if (prnCommandLength < 4 + 6 * n) {
  1876:             prnCommandLength = 4 + 6 * n;
  1877:             return;  //コマンド継続
  1878:           }
  1879:           prn48DotBitImage (prnCommandBuffer, 4, n);  //48ドットビットイメージ
  1880:           break command;  //コマンド終了
  1881:         case 0x4e:  //ESC N n1 n2 n3 d
  1882:           if (prnCommandLength < 6) {
  1883:             prnCommandLength = 6;
  1884:             return;  //コマンド継続
  1885:           }
  1886:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1887:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1888:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1889:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1890:           prnRepeatCharacter ((e & 15) * 100 + (f & 15) * 10 + (g & 15), h);  //連続文字
  1891:           break command;  //コマンド終了
  1892:         case 0x50:  //ESC P
  1893:           prnSetKanjiMode (false);  //漢字モードOFF
  1894:           break command;  //コマンド終了
  1895:         case 0x51:  //ESC Q
  1896:           prnSetSmallCharacterMode ();  //縮小文字設定
  1897:           break command;  //コマンド終了
  1898:         case 0x52:  //ESC R
  1899:           prnSetPicaCharacterMode ();  //パイカ文字設定
  1900:           break command;  //コマンド終了
  1901:         case 0x55:  //ESC U
  1902:           prnSetHorizontalDoubleSizeMode (true);  //横2倍ON
  1903:           break command;  //コマンド終了
  1904:         case 0x56:  //ESC V n1 n2 n3 n4 d
  1905:           if (prnCommandLength < 7) {
  1906:             prnCommandLength = 7;
  1907:             return;  //コマンド継続
  1908:           }
  1909:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1910:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1911:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1912:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1913:           i = prnCommandBuffer[6] & 255;  //7バイト目
  1914:           prnRepeat8DotBitImage ((e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15), i);  //連続8ドットビットメージ
  1915:           break command;  //コマンド終了
  1916:         case 0x57:  //ESC W n1 n2 n3 n4 d1 d2
  1917:           if (prnCommandLength < 8) {
  1918:             prnCommandLength = 8;
  1919:             return;  //コマンド継続
  1920:           }
  1921:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1922:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1923:           g = prnCommandBuffer[4] & 255;  //5バイト目
  1924:           h = prnCommandBuffer[5] & 255;  //6バイト目
  1925:           i = prnCommandBuffer[6] & 255;  //7バイト目
  1926:           j = prnCommandBuffer[7] & 255;  //8バイト目
  1927:           prnRepeat16DotBitImage ((e & 15) * 1000 + (f & 15) * 100 + (g & 15) * 10 + (h & 15), i << 8 | j);  //連続16ドットビットメージ
  1928:           break command;  //コマンド終了
  1929:         case 0x58:  //ESC X
  1930:           prnSetUnderlineMode (true);  //アンダーラインあり
  1931:           break command;  //コマンド終了
  1932:         case 0x59:  //ESC Y
  1933:           prnSetUnderlineMode (false);  //アンダーラインなし
  1934:           break command;  //コマンド終了
  1935:         case 0x5c:  //ESC \\ n1 n2
  1936:           if (prnCommandLength < 4) {
  1937:             prnCommandLength = 4;
  1938:             return;  //コマンド継続
  1939:           }
  1940:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1941:           f = prnCommandBuffer[3] & 255;  //4バイト目
  1942:           prnHorizontalMove ((short) (f << 8 | e));  //水平移動。バイナリ指定。下位、上位。符号あり
  1943:           break command;  //コマンド終了
  1944:         case 0x63:  //ESC c
  1945:           if (prnCommandLength < 3) {
  1946:             prnCommandLength = 3;
  1947:             return;  //コマンド継続
  1948:           }
  1949:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1950:           switch (e) {
  1951:           case 0x31:  //ESC c 1
  1952:             prnResetSettings ();  //設定リセット
  1953:             break command;  //コマンド終了
  1954:           }
  1955:           break;  //コマンド不明
  1956:         case 0x6b:  //ESC k
  1957:           if (prnCommandLength < 3) {
  1958:             prnCommandLength = 3;
  1959:             return;  //コマンド継続
  1960:           }
  1961:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1962:           prnSetHalfWidthFont (e);  //半角書体。バイナリ指定
  1963:           break command;  //コマンド終了
  1964:         case 0x70:  //ESC p
  1965:           if (prnCommandLength < 3) {
  1966:             prnCommandLength = 3;
  1967:             return;  //コマンド継続
  1968:           }
  1969:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1970:           switch (e) {
  1971:           case 0x30:  //ESC p 0
  1972:             prnSenseOutOfPaper (false);  //用紙切れ検出無効
  1973:             break command;  //コマンド終了
  1974:           case 0x31:  //ESC p 1
  1975:             prnSenseOutOfPaper (true);  //用紙切れ検出有効
  1976:             break command;  //コマンド終了
  1977:           }
  1978:           break;  //コマンド不明
  1979:         case 0x71:  //ESC q n
  1980:           if (prnCommandLength < 3) {
  1981:             prnCommandLength = 3;
  1982:             return;  //コマンド継続
  1983:           }
  1984:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1985:           prnSetCharacterStyle (e);  //文字スタイル設定。バイナリ指定
  1986:           break command;  //コマンド終了
  1987:         case 0x73:  //ESC s
  1988:           if (prnCommandLength < 3) {
  1989:             prnCommandLength = 3;
  1990:             return;  //コマンド継続
  1991:           }
  1992:           e = prnCommandBuffer[2] & 255;  //3バイト目
  1993:           switch (e) {
  1994:           case 0x30:  //ESC s 0
  1995:             prnSetScriptMode (0);  //スクリプト解除
  1996:             break command;  //コマンド終了
  1997:           case 0x31:  //ESC s 1
  1998:             prnSetScriptMode (1);  //スーパースクリプト設定
  1999:             break command;  //コマンド終了
  2000:           case 0x32:  //ESC s 2
  2001:             prnSetScriptMode (2);  //サブスクリプト設定
  2002:             break command;  //コマンド終了
  2003:           }
  2004:           break;  //コマンド不明
  2005:         }
  2006:         break;  //コマンド不明
  2007:       case 0x1c:  //FS
  2008:         if (prnCommandLength < 2) {
  2009:           prnCommandLength = 2;
  2010:           return;  //コマンド継続
  2011:         }
  2012:         d = prnCommandBuffer[1] & 255;  //2バイト目
  2013:         switch (d) {
  2014:         case 0x4a:  //FS J
  2015:           prnSetVerticalWritingMode (true);  //縦書き
  2016:           break command;  //コマンド終了
  2017:         case 0x4b:  //FS K
  2018:           prnSetVerticalWritingMode (false);  //横書き
  2019:           break command;  //コマンド終了
  2020:         case 0x53:  //FS S n1 n2
  2021:           if (prnCommandLength < 4) {
  2022:             prnCommandLength = 4;
  2023:             return;  //コマンド継続
  2024:           }
  2025:           e = prnCommandBuffer[2] & 255;  //3バイト目
  2026:           f = prnCommandBuffer[3] & 255;  //4バイト目
  2027:           prnSetFullWidthLeftRightSpace (e, f);  //全角左右スペース。バイナリ指定
  2028:           break command;  //コマンド終了
  2029:         case 0x54:  //FS T n1 n2
  2030:           if (prnCommandLength < 4) {
  2031:             prnCommandLength = 4;
  2032:             return;  //コマンド継続
  2033:           }
  2034:           e = prnCommandBuffer[2] & 255;  //3バイト目
  2035:           f = prnCommandBuffer[3] & 255;  //4バイト目
  2036:           prnSetHalfWidthLeftRightSpace (e, f);  //半角左右スペース。バイナリ指定
  2037:           break command;  //コマンド終了
  2038:         case 0x6b:  //FS k
  2039:           if (prnCommandLength < 3) {
  2040:             prnCommandLength = 3;
  2041:             return;  //コマンド継続
  2042:           }
  2043:           e = prnCommandBuffer[2] & 255;  //3バイト目
  2044:           prnSetFullWidthFont (e);  //全角書体。バイナリ指定
  2045:           break command;  //コマンド終了
  2046:         case 0x70:  //FS p
  2047:           prnSetKanjiHorizontalDoubleSizeMode (true);  //漢字横2倍ON
  2048:           break command;  //コマンド終了
  2049:         case 0x71:  //FS q
  2050:           prnSetKanjiHorizontalDoubleSizeMode (false);  //漢字横2倍OFF
  2051:           break command;  //コマンド終了
  2052:         }  //switch d
  2053:         break;  //コマンド不明
  2054:       default:
  2055:         if (prnKanjiMode) {  //漢字モードONのとき
  2056:           if (prnCommandLength < 2) {
  2057:             prnCommandLength = 2;
  2058:             return;  //コマンド継続
  2059:           }
  2060:           d = prnCommandBuffer[1] & 255;  //2バイト目
  2061:           c = c << 8 | d;
  2062:         }
  2063:         if (c != 0) {  //0のときは何もしない
  2064:           prnPrintCharacter (c);  //1文字印字
  2065:         }
  2066:         break command;  //コマンド終了
  2067:       }  //switch c
  2068:       //コマンド不明
  2069:       for (int k = 0; k < prnCommandLength; k++) {
  2070:         prnPrintCharacter (prnCommandBuffer[k] & 255);  //1文字印字
  2071:       }
  2072:     }  //command
  2073:     //コマンド終了
  2074:     prnCommandLength = 1;
  2075:     prnCommandPointer = 0;
  2076:   }  //prnOutput
  2077: 
  2078:   //prnFeedPaper ()
  2079:   //  給紙
  2080:   public static void prnFeedPaper () {
  2081:     if (prnCurrentPaper != null) {  //既に給紙されているとき
  2082:       return;  //何もしない
  2083:     }
  2084:     //用紙
  2085:     prnCurrentPaper = prnNextPaper;
  2086:     //印字不可領域
  2087:     prnDeadTopMm = Math.min (prnNextDeadTopMm, prnCurrentPaper.paperHeightMm - 1);
  2088:     prnDeadLeftMm = Math.min (prnNextDeadLeftMm, prnCurrentPaper.paperWidthMm - 1);
  2089:     prnDeadRightMm = Math.min (prnNextDeadRightMm, prnCurrentPaper.paperWidthMm - 1 - prnDeadLeftMm);
  2090:     prnDeadBottomMm = Math.min (prnNextDeadBottomMm, prnCurrentPaper.paperHeightMm - 1 - prnDeadTopMm);
  2091:     //印字可能範囲
  2092:     prnAliveTopY = (int) Math.floor ((double) prnDeadTopMm * (360.0 / 25.4) + 0.5);
  2093:     prnAliveLeftX = (int) Math.floor ((double) prnDeadLeftMm * (360.0 / 25.4) + 0.5);
  2094:     prnAliveRightX = (int) Math.floor ((double) (prnCurrentPaper.paperWidthMm - prnDeadRightMm) * (360.0 / 25.4) + 0.5);
  2095:     prnAliveBottomY = (int) Math.floor ((double) (prnCurrentPaper.paperHeightMm - prnDeadBottomMm) * (360.0 / 25.4) + 0.5);
  2096:     //回転
  2097:     prnRotation = prnNextRotation;
  2098:     if (prnRotation == 0) {  //0°
  2099:       prnRotatedWidthDot = prnCurrentPaper.paperWidthDot;
  2100:       prnRotatedHeightDot = prnCurrentPaper.paperHeightDot;
  2101:       //  [1 0 0]
  2102:       //  [0 1 0]
  2103:       //  [0 0 1]
  2104:       prnM11 = 1;
  2105:       prnM12 = 0;
  2106:       prnM13 = 0;
  2107:       prnM21 = 0;
  2108:       prnM22 = 1;
  2109:       prnM23 = 0;
  2110:     } else if (prnRotation == 1) {  //90°
  2111:       prnRotatedWidthDot = prnCurrentPaper.paperHeightDot;
  2112:       prnRotatedHeightDot = prnCurrentPaper.paperWidthDot;
  2113:       //  [0 -1 w]
  2114:       //  [1  0 0]
  2115:       //  [0  0 1]
  2116:       prnM11 = 0;
  2117:       prnM12 = -1;
  2118:       prnM13 = prnRotatedWidthDot;
  2119:       prnM21 = 1;
  2120:       prnM22 = 0;
  2121:       prnM23 = 0;
  2122:     } else if (prnRotation == 2) {  //180°
  2123:       prnRotatedWidthDot = prnCurrentPaper.paperWidthDot;
  2124:       prnRotatedHeightDot = prnCurrentPaper.paperHeightDot;
  2125:       //  [-1  0 w]
  2126:       //  [ 0 -1 h]
  2127:       //  [ 0  0 1]
  2128:       prnM11 = -1;
  2129:       prnM12 = 0;
  2130:       prnM13 = prnRotatedWidthDot;
  2131:       prnM21 = 0;
  2132:       prnM22 = -1;
  2133:       prnM23 = prnRotatedHeightDot;
  2134:     } else {  //270°
  2135:       prnRotatedWidthDot = prnCurrentPaper.paperHeightDot;
  2136:       prnRotatedHeightDot = prnCurrentPaper.paperWidthDot;
  2137:       //  [ 0 1 0]
  2138:       //  [-1 0 h]
  2139:       //  [ 0 0 1]
  2140:       prnM11 = 0;
  2141:       prnM12 = 1;
  2142:       prnM13 = 0;
  2143:       prnM21 = -1;
  2144:       prnM22 = 0;
  2145:       prnM23 = prnRotatedHeightDot;
  2146:     }
  2147:     prnIncrementX = prnM11 + prnRotatedWidthDot * prnM21;
  2148:     prnIncrementY = prnM12 + prnRotatedWidthDot * prnM22;
  2149:     //ダークモード
  2150:     prnDarkMode = prnNextDarkMode;
  2151:     //イメージとビットマップ
  2152:     prnImage = new BufferedImage (prnRotatedWidthDot,
  2153:                                   prnRotatedHeightDot,
  2154:                                   BufferedImage.TYPE_BYTE_INDEXED, prnDarkMode ? prnDarkImageColorModel : prnImageColorModel);
  2155:     prnBitmap = ((DataBufferByte) prnImage.getRaster ().getDataBuffer ()).getData ();
  2156:     if (prnCanvas != null) {
  2157:       prnCanvas.setImage (prnImage);
  2158:     }
  2159:     //消去
  2160:     prnErasePaper ();
  2161:   }  //prnFeedPaper
  2162: 
  2163:   //prnErasePaper ()
  2164:   //  消去
  2165:   //  印刷済みの用紙を保存せずに破棄する
  2166:   public static void prnErasePaper () {
  2167:     if (prnCurrentPaper == null) {  //給紙されていないとき
  2168:       prnFeedPaper ();  //給紙する
  2169:     } else {  //給紙されているとき
  2170:       //ページ範囲
  2171:       prnPageStart = 0;
  2172:       prnPageLength = ((prnAliveBottomY - prnAliveTopY + (360 - 1)) / 360) * 360;
  2173:       //コンテント範囲
  2174:       prnContentTopY = prnPageStart;
  2175:       prnContentBottomY = prnPageStart + prnPageLength - prnMarginBottomHeight;
  2176:       //ヘッドの位置
  2177:       prnHeadX = prnMarginLeftX;
  2178:       prnHeadY = prnContentTopY;
  2179:       prnHeadLine = 0;
  2180:       //白で塗り潰す
  2181:       Arrays.fill (prnBitmap, 0, prnRotatedWidthDot * prnRotatedHeightDot, (byte) 7);
  2182:       //印字なし
  2183:       prnPrinted = false;
  2184:       //キャンバスを再描画する
  2185:       if (prnCanvas != null) {
  2186:         prnCanvas.repaint ();
  2187:       }
  2188:     }
  2189:   }  //prnErasePaper
  2190: 
  2191:   //prnEjectPaper ()
  2192:   //  排紙
  2193:   public static void prnEjectPaper () {
  2194:     if (prnCurrentPaper == null) {  //既に排紙されているとき
  2195:       return;  //何もしない
  2196:     }
  2197:     if (prnPrinted) {  //印字されているとき
  2198:       prnPrinted = false;
  2199:       prnSavePaper ();  //保存する
  2200:     }
  2201:     prnCurrentPaper = null;  //未給紙にする
  2202:     prnHeadX = -1;  //ヘッドX座標[dot]
  2203:     prnHeadY = -1;  //ヘッドY座標[dot]
  2204:     prnHeadLine = -1;  //ヘッド行番号
  2205:     if (prnCanvas != null) {
  2206:       prnCanvas.setImage (null);
  2207:     }
  2208:   }  //prnEjectPaper
  2209: 
  2210:   //prnSavePaper ()
  2211:   //  保存する
  2212:   //  ファイル名はprnSavePath+File.separator+prnSaveName
  2213:   //  ファイルが既にあるとき
  2214:   //    主ファイル名の末尾に数字があるとき
  2215:   //      主ファイル名の末尾の数字をインクリメントする
  2216:   //    主ファイル名の末尾に数字がないとき
  2217:   //      主ファイル名の末尾に"2"を追加する
  2218:   public static void prnSavePaper () {
  2219:     //存在しないファイル名に書き換える
  2220:     while (new File (prnSavePath + File.separator + prnSaveName).isFile ()) {  //ファイルが既にある
  2221:       int j = prnSaveName.lastIndexOf ('.');  //主ファイル名の末尾
  2222:       if (j < 0) {
  2223:         j = prnSaveName.length ();
  2224:       }
  2225:       int i = j;
  2226:       int n = 2;
  2227:       if (0 < j && Character.isDigit (prnSaveName.charAt (j - 1))) {  //主ファイル名の末尾に数字がある
  2228:         //主ファイル名の末尾の数字を最大8桁取り出してインクリメントする
  2229:         i--;
  2230:         while (j - 8 < i &&
  2231:                0 < i && Character.isDigit (prnSaveName.charAt (i - 1))) {
  2232:           i--;
  2233:         }
  2234:         n = Integer.parseInt (prnSaveName.substring (i, j));
  2235:         n = (n + 1) % 100000000;  //1億個すべて使い切ると無限ループに陥るがそんなことはないだろう
  2236:       }
  2237:       prnSaveName = prnSaveName.substring (0, i) + n + prnSaveName.substring (j);
  2238:     }
  2239:     //親ディレクトリを掘る
  2240:     File file = new File (prnSavePath + File.separator + prnSaveName).getAbsoluteFile ();
  2241:     File parent = file.getParentFile ();
  2242:     prnSavePath = parent.getAbsolutePath ();  //区切り直す
  2243:     prnSaveName = file.getName ();
  2244:     parent.mkdirs ();
  2245:     //保存する
  2246:     if (prnAutosaveOn) {  //自動保存のとき
  2247:       if (!prnSave ()) {  //保存できなかったとき
  2248:         prnSetAutosaveOn (false);  //手動保存に切り替える
  2249:       }
  2250:     }
  2251:     if (!prnAutosaveOn) {  //手動保存のとき
  2252:       if (prnSaveDialog == null) {
  2253:         prnMakeSaveDialog ();  //ダイアログを作る
  2254:       }
  2255:       prnSaveFileChooser.setCurrentDirectory (parent);  //親ディレクトリを設定する
  2256:       prnSaveFileChooser.rescanCurrentDirectory ();  //親ディレクトリのファイルのリストを更新する。これをやらないと前回保存したファイルが表示されない
  2257:       prnSaveFileChooser.setSelectedFile (file);  //主ファイル名を設定する
  2258:       //ダイアログを表示する
  2259:       //  モーダルダイアログなのでダイアログを閉じるまでここでブロックされる
  2260:       prnSaveDialog.setVisible (true);
  2261:     }
  2262:   }  //prnSavePaper
  2263: 
  2264:   private static final byte[] PRN_DOUBLE_4BIT = {
  2265:     0b00_00_00_00,
  2266:     0b00_00_00_11,
  2267:     0b00_00_11_00,
  2268:     0b00_00_11_11,
  2269:     0b00_11_00_00,
  2270:     0b00_11_00_11,
  2271:     0b00_11_11_00,
  2272:     0b00_11_11_11,
  2273:     (byte) 0b11_00_00_00,
  2274:     (byte) 0b11_00_00_11,
  2275:     (byte) 0b11_00_11_00,
  2276:     (byte) 0b11_00_11_11,
  2277:     (byte) 0b11_11_00_00,
  2278:     (byte) 0b11_11_00_11,
  2279:     (byte) 0b11_11_11_00,
  2280:     (byte) 0b11_11_11_11,
  2281:   };
  2282: 
  2283:   //prnSetSingleColor (color)
  2284:   //  単色インクリボンの色を設定する
  2285:   public static void prnSetSingleColor (int color) {
  2286:     prnSingleColor = color;
  2287:     if (!prnColorMode) {  //単色モードのとき
  2288:       prnCurrentColor = color;
  2289:     }
  2290:   }  //prnSetSingleColor
  2291: 
  2292:   //prnGetCharacterWidth ()
  2293:   //  現在の文字の幅[dot]を返す
  2294:   public static int prnGetCharacterWidth () {
  2295:     return (prnKanjiMode ?
  2296:             (prnHalfWidthLeftSpace + 24 + prnHalfWidthRightSpace) *
  2297:             (prnHorizontalDoubleSizeMode || prnKanjiHorizontalDoubleSizeMode ? 2 : 1) :
  2298:             (prnCharacterType == PRN_PICA ? 36 :
  2299:              prnCharacterType == PRN_ELITE ? 30 :
  2300:              prnCharacterType == PRN_SMALL ? 21 : 0) *
  2301:             (prnHorizontalDoubleSizeMode ? 2 : 1));
  2302:   }  //prnGetCharacterWidth
  2303: 
  2304:   //prnPrintCharacter (c)
  2305:   //  1文字印字
  2306:   //  コントロールコードは処理しない
  2307:   public static void prnPrintCharacter (int c) {
  2308:     c = (char) c;
  2309:     if (prnCurrentPaper == null) {  //未給紙のとき
  2310:       prnFeedPaper ();  //給紙する
  2311:     }
  2312:     //フォントを選ぶ
  2313:     FontPage page = null;
  2314:     int y0 = 0;  //開始ラスタ。サブスクリプトのとき14、それ以外は0
  2315:     int col = 0;  //文字コードの桁番号
  2316:     int row = 0;  //文字コードの行番号
  2317:     int w;  //フォントの幅
  2318:     int h;  //フォントの高さ
  2319:     int o;  //フォントの1ラスタのバイト数
  2320:     int oh;  //フォントのバイト数
  2321:     byte[] b;  //フォントのビットマップ
  2322:   gaiji:
  2323:     {
  2324:       if (c <= 0x00ff) {  //ANK
  2325:         col = c & 15;
  2326:         row = c >> 4;
  2327:         if (prnKanjiMode) {  //漢字モードの半角。ひらがなは無効
  2328:           page = prnHalfWidthFont == 0 ? fntPagePan24x48R : fntPagePan24x48S;
  2329:         } else {
  2330:           if (prnHiraganaMode) {  //ひらがな
  2331:             row += 16;
  2332:           }
  2333:           if (prnCharacterType == PRN_PICA) {  //パイカ
  2334:             page = prnHalfWidthFont == 0 ? fntPagePic36x46R : fntPagePic36x46S;
  2335:           } else if (prnCharacterType == PRN_ELITE) {  //エリート
  2336:             page = prnHalfWidthFont == 0 ? fntPageEli30x46R : fntPageEli30x46S;
  2337:           } else if (prnCharacterType == PRN_SMALL) {  //縮小
  2338:             page = prnHalfWidthFont == 0 ? fntPageSma18x46R : fntPageSma18x46S;
  2339:           } else {  //スクリプト
  2340:             page = prnHalfWidthFont == 0 ? fntPageScr28x32R : fntPageScr28x32S;
  2341:             if (prnScriptMode == 2) {  //サブスクリプト
  2342:               y0 = 14;
  2343:             }
  2344:           }
  2345:         }
  2346:       } else {  //漢字
  2347:         page = prnFullWidthFont == 0 ? fntPageZen48x48M : fntPageZen48x48G;
  2348:         row = c >> 8;
  2349:         col = c & 255;
  2350:         if (((0x81 <= row && row <= 0x9f) ||
  2351:              (0xe0 <= row && row <= 0xef)) &&
  2352:             ((0x40 <= col && col <= 0x7e) ||
  2353:              (0x80 <= col && col <= 0xfc))) {  //SJIS
  2354:           //  SJIS                           JIS
  2355:           //  8140-817E 8180-819E 819F-81FC  2121-215F 2160-217E 2221-227E
  2356:           //  9F40-9F7E 9F80-9F9E 9F9F-9FFC  5D21-5D5F 5D60-5D7E 5E21-5E7E
  2357:           //  E040-E07E E080-E09E E09F-E0FC  5F21-5F5F 5F60-5F7E 6021-607E
  2358:           //  EF40-EF7E EF80-EF9E EF9F-EFFC  7D21-7D5F 7D60-7D7E 7E21-7E7E
  2359:           if (0xe0 <= row) {
  2360:             row -= 0xe0 - 0xa0;
  2361:           }
  2362:           row -= 0x81;
  2363:           if (0x80 <= col) {
  2364:             col -= 0x80 - 0x7f;
  2365:           }
  2366:           col -= 0x40;
  2367:           row *= 2;
  2368:           if (94 <= col) {
  2369:             row += 1;
  2370:             col -= 94;
  2371:           }
  2372:           row += 0x21;
  2373:           col += 0x21;
  2374:         }
  2375:         if ((row == 0x76 && (0x21 <= col && col <= 0x7e)) ||
  2376:             (row == 0x77 && (0x21 <= col && col <= 0x26))) {  //外字定義エリア
  2377:           w = 48;  //フォントの幅
  2378:           h = 48;  //フォントの高さ
  2379:           o = 6;  //フォントの1ラスタのバイト数
  2380:           oh = o * h;  //フォントのバイト数
  2381:           b = new byte[oh];
  2382:           System.arraycopy (prnGetGaijiData (), oh * ((col - 0x21) + 94 * (row - 0x76)), b, 0, oh);
  2383:           break gaiji;
  2384:         }
  2385:         if (0x21 <= col && col <= 0x7e) {
  2386:           col -= 0x21;
  2387:           if (0x21 <= row && row <= 0x28) {
  2388:             row -= 0x21;
  2389:           } else if (0x30 <= row && row <= 0x74) {
  2390:             //row -= 0x30 - 8;  //77区のとき
  2391:             row -= 0x21;  //94区のとき
  2392:           } else {
  2393:             row = 0;
  2394:             col = 0;
  2395:           }
  2396:         } else {
  2397:           row = 0;
  2398:           col = 0;
  2399:         }
  2400:       }
  2401:       if (!page.fnpReady) {  //フォントの準備ができていない
  2402:         page.fnpCreateImage ((c <= 0x00ff ? prnHalfWidthFont : prnFullWidthFont) == 0 ? fntGetMinchoFamily () : fntGetGothicFamily ());  //フォントを作る
  2403:       }
  2404:       w = page.fnpCharacterWidth;  //フォントの幅
  2405:       h = page.fnpCharacterHeight;  //フォントの高さ
  2406:       o = page.fnpCharacterHorizontalBytes;  //フォントの1ラスタのバイト数
  2407:       oh = o * h;  //フォントのバイト数
  2408:       b = new byte[o * y0 + oh];
  2409:       System.arraycopy (page.fnpBinaryArray, oh * (col + page.fnpImageCols * row), b, o * y0, oh);
  2410:     }  //gaiji
  2411:     h += y0;
  2412:     oh = o * h;
  2413:     //縦書き
  2414:     //  漢字モードで全角のとき48x48のパターンを左に90度回転させる
  2415:     //  横2倍は回転してから横に拡大するので文字は縦長になる
  2416:     //  回転させない文字
  2417:     //    2126-2128  ・:;
  2418:     //    215d       -
  2419:     //    2162-2166  ≠<>≦≧
  2420:     //    222a-222d  →←↑↓
  2421:     //    2821-2840  ─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂
  2422:     //  縦書き用のパターンが存在する文字
  2423:     //    2122-2123  、  句読点。左下1/3を右上へ移動してから回転
  2424:     //    2123       。  〃
  2425:     //    2131-2132   ̄_
  2426:     //    213c       ー  長音と波ダッシュ。上下反転
  2427:     //    213d-213e  ―‐
  2428:     //    2141       ~  〃
  2429:     //    2142-2145  ∥|…‥
  2430:     //    214a-215b  ()〔〕[]{}〈〉《》「」『』【】
  2431:     //    2161       =
  2432:     //    2421       ぁ  小さいひらがな・カタカナ。左下7/8を右上へ移動してから回転
  2433:     //    2423       ぃ  〃
  2434:     //    2425       ぅ  〃
  2435:     //    2427       ぇ  〃
  2436:     //    2429       ぉ  〃
  2437:     //    2443       っ  〃
  2438:     //    2463       ゃ  〃
  2439:     //    2465       ゅ  〃
  2440:     //    2467       ょ  〃
  2441:     //    246e       ゎ  〃
  2442:     //    2521       ァ  〃
  2443:     //    2523       ィ  〃
  2444:     //    2525       ゥ  〃
  2445:     //    2527       ェ  〃
  2446:     //    2529       ォ  〃
  2447:     //    2543       ッ  〃
  2448:     //    2563       ャ  〃
  2449:     //    2565       ュ  〃
  2450:     //    2567       ョ  〃
  2451:     //    256e       ヮ  〃
  2452:     //    2575       ヵ  〃
  2453:     //    2576       ヶ  〃
  2454:     //    括弧の多くは回転させないだけでよさそうに思われるが縦書き用のパターンが存在する
  2455:     //  参考
  2456:     //    http://www.unicode.org/reports/tr50/
  2457:     //    http://www.unicode.org/charts/PDF/UFE10.pdf
  2458:     if (prnVerticalWritingMode &&  //縦書き
  2459:         page != null && page.fnpImageCols == 94 &&  //全角 漢字
  2460:         !((row == 0x21 - 0x21 && ((0x26 - 0x21 <= col && col <= 0x28 - 0x21) ||
  2461:                                   (col == 0x5d - 0x21) ||
  2462:                                   (0x62 - 0x21 <= col && col <= 0x66 - 0x21))) ||
  2463:           (row == 0x22 - 0x21 && (0x2a - 0x21 <= col && col <= 0x2d - 0x21)) ||
  2464:           (row == 0x28 - 0x21 && (0x21 - 0x21 <= col && col <= 0x40 - 0x21)))) {  //回転させる
  2465:       boolean rotate;
  2466:       if (row == 0x21 - 0x21 && (0x22 - 0x21 <= col && col <= 0x23 - 0x21)) {
  2467:         //句読点。左下1/3を右上へ移動してから回転
  2468:         byte[] bb = new byte[6 * 48];
  2469:         //Arrays.fill (bb, (byte) 0);
  2470:         //!!! 冗長
  2471:         for (int yy = 0; yy < 48 / 3; yy++) {
  2472:           int y = yy + 48 * 2 / 3;
  2473:           for (int xx = 48 * 2 / 3; xx < 48; xx++) {
  2474:             int x = xx - 48 * 2 / 3;
  2475:             bb[6 * yy + (xx >> 3)] |= (byte) ((b[6 * y + (x >> 3)] >> (~x & 7) & 1) << (~xx & 7));
  2476:           }
  2477:         }
  2478:         b = bb;
  2479:         rotate = true;
  2480:       } else if (row == 0x21 - 0x21 && (col == 0x3c - 0x21 ||
  2481:                                         col == 0x41 - 0x21)) {
  2482:         //長音と波ダッシュ。上下反転
  2483:         byte[] bb = new byte[6 * 48];
  2484:         //Arrays.fill (bb, (byte) 0);
  2485:         //!!! 冗長
  2486:         for (int yy = 0; yy < 48; yy++) {
  2487:           int y = 48 - 1 - yy;
  2488:           for (int xx = 0; xx < 48; xx++) {
  2489:             int x = xx;
  2490:             bb[6 * yy + (xx >> 3)] |= (byte) ((b[6 * y + (x >> 3)] >> (~x & 7) & 1) << (~xx & 7));
  2491:           }
  2492:         }
  2493:         b = bb;
  2494:         rotate = false;
  2495:       } else if ((row == 0x24 - 0x21 && (col == 0x21 - 0x21 ||
  2496:                                          col == 0x23 - 0x21 ||
  2497:                                          col == 0x25 - 0x21 ||
  2498:                                          col == 0x27 - 0x21 ||
  2499:                                          col == 0x29 - 0x21 ||
  2500:                                          col == 0x43 - 0x21 ||
  2501:                                          col == 0x63 - 0x21 ||
  2502:                                          col == 0x65 - 0x21 ||
  2503:                                          col == 0x67 - 0x21 ||
  2504:                                          col == 0x6e - 0x21)) ||
  2505:                  (row == 0x25 - 0x21 && (col == 0x21 - 0x21 ||
  2506:                                          col == 0x23 - 0x21 ||
  2507:                                          col == 0x25 - 0x21 ||
  2508:                                          col == 0x27 - 0x21 ||
  2509:                                          col == 0x29 - 0x21 ||
  2510:                                          col == 0x43 - 0x21 ||
  2511:                                          col == 0x63 - 0x21 ||
  2512:                                          col == 0x65 - 0x21 ||
  2513:                                          col == 0x67 - 0x21 ||
  2514:                                          col == 0x6e - 0x21 ||
  2515:                                          col == 0x75 - 0x21 ||
  2516:                                          col == 0x76 - 0x21))) {
  2517:         //小さいひらがな・カタカナ。左下7/8を右上へ移動してから回転
  2518:         byte[] bb = new byte[6 * 48];
  2519:         //Arrays.fill (bb, (byte) 0);
  2520:         //!!! 冗長
  2521:         for (int yy = 0; yy < 48 * 7 / 8; yy++) {
  2522:           int y = yy + 48 / 8;
  2523:           for (int xx = 48 / 8; xx < 48; xx++) {
  2524:             int x = xx - 48 / 8;
  2525:             bb[6 * yy + (xx >> 3)] |= (byte) ((b[6 * y + (x >> 3)] >> (~x & 7) & 1) << (~xx & 7));
  2526:           }
  2527:         }
  2528:         b = bb;
  2529:         rotate = true;
  2530:       } else if (row == 0x21 - 0x21 && ((0x31 - 0x21 <= col && col <= 0x32 - 0x21) ||
  2531:                                         (0x3d - 0x21 <= col && col <= 0x3e - 0x21) ||
  2532:                                         (0x42 - 0x21 <= col && col <= 0x45 - 0x21) ||
  2533:                                         (0x4a - 0x21 <= col && col <= 0x5b - 0x21) ||
  2534:                                         col == 0x61 - 0x21)) {
  2535:         rotate = false;
  2536:       } else {
  2537:         rotate = true;
  2538:       }
  2539:       if (rotate) {
  2540:         //左に90度回転させる
  2541:         //  デスティネーションを左上から右へ走査する
  2542:         //  ソースを右上から下へ走査する
  2543:         byte[] bb = new byte[6 * 48];
  2544:         //Arrays.fill (bb, (byte) 0);
  2545:         //!!! 冗長
  2546:         for (int yy = 0; yy < 48; yy++) {
  2547:           int x = 48 - 1 - yy;
  2548:           for (int xx = 0; xx < 48; xx++) {
  2549:             int y = xx;
  2550:             bb[6 * yy + (xx >> 3)] |= (byte) ((b[6 * y + (x >> 3)] >> (~x & 7) & 1) << (~xx & 7));
  2551:           }
  2552:         }
  2553:         b = bb;
  2554:       }
  2555:     }  //if 縦書き
  2556:     if (false) {
  2557:       //高さを最低48[dot]にする
  2558:       //  パイカは46[dot]なので48[dot]にしておくと袋文字、影文字、袋影文字の下端が切れなくなる
  2559:       //  マニュアルのサンプルを見ると下端が切れているのでCZ-8PC4は46[dot]のままなのだと思われる
  2560:       if (h < 48) {
  2561:         int hh = 48;
  2562:         int ohh = o * hh;
  2563:         byte[] bb = new byte[ohh];
  2564:         System.arraycopy (b, 0, bb, 0, oh);
  2565:         //Arrays.fill (bb, oh, ohh - oh, (byte) 0);
  2566:         h = hh;
  2567:         oh = ohh;
  2568:         b = bb;
  2569:       }
  2570:     }
  2571:     //左右スペース
  2572:     {
  2573:       int lw = 0;
  2574:       int rw = 0;
  2575:       if (prnKanjiMode) {  //漢字モード
  2576:         if (w == 48) {  //全角
  2577:           lw = prnFullWidthLeftSpace;
  2578:           rw = prnFullWidthRightSpace;
  2579:         } else {  //半角
  2580:           lw = prnHalfWidthLeftSpace;
  2581:           rw = prnHalfWidthRightSpace;
  2582:         }
  2583:       } else if (prnCharacterType == PRN_SMALL) {  //縮小文字
  2584:         rw = 3;  //18[dot]のフォントを印字して21[dot]進む
  2585:       }
  2586:       if (lw != 0 || rw != 0) {
  2587:         int ww = lw + w + rw;
  2588:         int oo = (ww + 7) >> 3;
  2589:         int ooh = oo * h;
  2590:         byte[] bb = new byte[ooh];
  2591:         Arrays.fill (bb, (byte) 0);
  2592:         //右にlwビットずらしながらコピーする
  2593:         int lq = lw >> 3;
  2594:         int lr = lw & 7;
  2595:         if (lr == 0) {
  2596:           for (int a = 0, aa = lq; a < oh; a += o, aa += oo) {
  2597:             for (int i = o - 1; 0 <= i; i--) {
  2598:               bb[aa + i] = b[a + i];
  2599:             }
  2600:           }
  2601:         } else {
  2602:           for (int a = 0, aa = lq; a < oh; a += o, aa += oo) {
  2603:             bb[aa + o] = (byte) (b[a + o - 1] << (8 - lr));
  2604:             for (int i = o - 1; 0 < i; i--) {
  2605:               bb[aa + i] = (byte) ((b[a + i - 1] << (8 - lr)) | (b[a + i] & 255) >> lr);
  2606:             }
  2607:             bb[aa] = (byte) ((b[a] & 255) >> lr);
  2608:           }
  2609:         }
  2610:         w = ww;
  2611:         o = oo;
  2612:         oh = ooh;
  2613:         b = bb;
  2614:       }
  2615:     }
  2616:     //強調
  2617:     if (prnStrongMode) {
  2618:       //右にずらして重ねる
  2619:       //!!! 縦書きのとき下にずらして重ねることになる
  2620:       for (int a = 0; a < oh; a += o) {
  2621:         for (int i = o - 1; 0 < i; i--) {
  2622:           b[a + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2623:         }
  2624:         b[a] |= (byte) ((b[a] & 255) >> 1);
  2625:       }
  2626:     }  //if 強調
  2627:     //文字スタイル
  2628:     if (prnCharacterStyle != 0) {  //袋文字または影文字または袋影文字
  2629:       //  横書き
  2630:       //    1  袋文字    左上 上 右上 左 右 左下 下 右下           ずらしたパターンを重ねてから元のパターンをくり抜く
  2631:       //    2  影文字                               右下 右右下下  ずらしたパターンを重ねてから元のパターンをくり抜く
  2632:       //    3  袋影文字  左上 上 右上 左 右 左下 下 右下 右右下下  ずらしたパターンを重ねてから元のパターンをくり抜く
  2633:       //  縦書き
  2634:       //    1  袋文字    左下 下 右下 左 右 左上 上 右上           ずらしたパターンを重ねてから元のパターンをくり抜く
  2635:       //    2  影文字                               右上 右右上上  ずらしたパターンを重ねてから元のパターンをくり抜く
  2636:       //    3  袋影文字  左下 下 右下 左 右 左上 上 右上 右右上上  ずらしたパターンを重ねてから元のパターンをくり抜く
  2637:       byte[] bb = new byte[oh];
  2638:       Arrays.fill (bb, (byte) 0);
  2639:       if (prnVerticalWritingMode) {  //縦書き
  2640:         //右上にずらして重ねる
  2641:         for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2642:           bb[aa] |= (byte) ((b[a] & 255) >> 1);
  2643:           for (int i = 1; i < o; i++) {
  2644:             bb[aa + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2645:           }
  2646:         }
  2647:       } else {  //横書き
  2648:         //右下にずらして重ねる
  2649:         for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2650:           bb[aa] |= (byte) ((b[a] & 255) >> 1);
  2651:           for (int i = 1; i < o; i++) {
  2652:             bb[aa + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2653:           }
  2654:         }
  2655:       }
  2656:       if (prnCharacterStyle == PRN_SHADOW_STYLE ||  //影文字
  2657:           prnCharacterStyle == PRN_OPEN_SHADOW_STYLE) {  //袋影文字
  2658:         if (prnVerticalWritingMode) {  //縦書き
  2659:           //右右上上にずらして重ねる
  2660:           for (int a = o * 2, aa = 0; a < oh; a += o, aa += o) {
  2661:             bb[aa] |= (byte) ((b[a] & 255) >> 2);
  2662:             for (int i = 1; i < o; i++) {
  2663:               bb[aa + i] |= (byte) (b[a + i - 1] << 6 | (b[a + i] & 255) >> 2);
  2664:             }
  2665:           }
  2666:         } else {
  2667:           //右右下下にずらして重ねる
  2668:           for (int a = 0, aa = o * 2; aa < oh; a += o, aa += o) {
  2669:             bb[aa] |= (byte) ((b[a] & 255) >> 2);
  2670:             for (int i = 1; i < o; i++) {
  2671:               bb[aa + i] |= (byte) (b[a + i - 1] << 6 | (b[a + i] & 255) >> 2);
  2672:             }
  2673:           }
  2674:         }
  2675:       }
  2676:       if (prnCharacterStyle == PRN_OPEN_STYLE ||  //袋文字
  2677:           prnCharacterStyle == PRN_OPEN_SHADOW_STYLE) {  //袋影文字
  2678:         //左上にずらして重ねる
  2679:         for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2680:           for (int i = 0; i < o - 1; i++) {
  2681:             bb[aa + i] |= (byte) (b[a + i] << 1 | (b[a + i + 1] & 255) >> 7);
  2682:           }
  2683:           bb[aa + o - 1] |= (byte) (b[a + o - 1] << 1);
  2684:         }
  2685:         //上にずらして重ねる
  2686:         for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2687:           for (int i = 0; i < o; i++) {
  2688:             bb[aa + i] |= b[a + i];
  2689:           }
  2690:         }
  2691:         if (prnVerticalWritingMode) {  //縦書き
  2692:           //右下にずらして重ねる
  2693:           for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2694:             bb[aa] |= (byte) ((b[a] & 255) >> 1);
  2695:             for (int i = 1; i < o; i++) {
  2696:               bb[aa + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2697:             }
  2698:           }
  2699:         } else {  //横書き
  2700:           //右上にずらして重ねる
  2701:           for (int a = o, aa = 0; a < oh; a += o, aa += o) {
  2702:             bb[aa] |= (byte) ((b[a] & 255) >> 1);
  2703:             for (int i = 1; i < o; i++) {
  2704:               bb[aa + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2705:             }
  2706:           }
  2707:         }
  2708:         //左にずらして重ねる
  2709:         for (int a = 0; a < oh; a += o) {
  2710:           for (int i = 0; i < o - 1; i++) {
  2711:             bb[a + i] |= (byte) (b[a + i] << 1 | (b[a + i + 1] & 255) >> 7);
  2712:           }
  2713:           bb[a + o - 1] |= (byte) (b[a + o - 1] << 1);
  2714:         }
  2715:         //右にずらして重ねる
  2716:         for (int a = 0; a < oh; a += o) {
  2717:           bb[a] |= (byte) ((b[a] & 255) >> 1);
  2718:           for (int i = 1; i < o; i++) {
  2719:             bb[a + i] |= (byte) (b[a + i - 1] << 7 | (b[a + i] & 255) >> 1);
  2720:           }
  2721:         }
  2722:         //左下にずらして重ねる
  2723:         for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2724:           for (int i = 0; i < o - 1; i++) {
  2725:             bb[aa + i] |= (byte) (b[a + i] << 1 | (b[a + i + 1] & 255) >> 7);
  2726:           }
  2727:           bb[aa + o - 1] |= (byte) (b[a + o - 1] << 1);
  2728:         }
  2729:         //下にずらして重ねる
  2730:         for (int a = 0, aa = o; aa < oh; a += o, aa += o) {
  2731:           for (int i = 0; i < o; i++) {
  2732:             bb[aa + i] |= b[a + i];
  2733:           }
  2734:         }
  2735:       }
  2736:       //元のパターンをくり抜く
  2737:       for (int i = 0; i < oh; i++) {
  2738:         bb[i] &= (byte) ~b[i];
  2739:       }
  2740:       b = bb;
  2741:     }  //if 袋文字または影文字または袋影文字
  2742:     //アンダーライン
  2743:     //  アンダーラインを袋文字や影文字にすることはできない
  2744:     if (prnUnderlineMode) {  //アンダーライン
  2745:       if (prnVerticalWritingMode) {  //縦書き
  2746:         int a = 0;
  2747:         for (int i = 0; i < o - 1; i++) {
  2748:           b[a + i] = -1;
  2749:         }
  2750:         b[a + o - 1] |= (byte) (-256 >> (((w - 1) & 7) + 1));
  2751:       } else {  //横書き
  2752:         int a = o * (h - 1);
  2753:         for (int i = 0; i < o - 1; i++) {
  2754:           b[a + i] = -1;
  2755:         }
  2756:         b[a + o - 1] |= (byte) (-256 >> (((w - 1) & 7) + 1));
  2757:       }
  2758:     }  //if アンダーライン
  2759:     //横2倍
  2760:     if (prnHorizontalDoubleSizeMode ||
  2761:         (prnKanjiMode && prnKanjiHorizontalDoubleSizeMode)) {  //横2倍
  2762:       int ww = w * 2;
  2763:       int oo = (ww + 7) >> 3;  //o*2またはo*2-1
  2764:       int ooh = oo * h;
  2765:       byte[] bb = new byte[ooh];
  2766:       for (int a = 0, aa = 0; a < oh; a += o, aa += oo) {  //ラスタの先頭
  2767:         for (int i = 0, ii = 0; i < o; i++, ii += 2) {  //ラスタ内インデックス
  2768:           int d = b[a + i] & 255;
  2769:           bb[aa + ii] = PRN_DOUBLE_4BIT[d >> 4];
  2770:           if (ii + 1 < oo) {
  2771:             bb[aa + ii + 1] = PRN_DOUBLE_4BIT[d & 15];
  2772:           }
  2773:         }
  2774:       }
  2775:       w = ww;
  2776:       o = oo;
  2777:       oh = ooh;
  2778:       b = bb;
  2779:     }  //if 横2倍
  2780:     //縦2倍
  2781:     if (prnVerticalDoubleSizeMode) {  //縦2倍
  2782:       int hh = h * 2;
  2783:       int ohh = o * hh;
  2784:       byte[] bb = new byte[ohh];
  2785:       for (int a = 0, aa = 0; a < oh; a += o, aa += o * 2) {
  2786:         for (int i = 0; i < o; i++) {
  2787:           bb[aa + o + i] = bb[aa + i] = b[a + i];
  2788:         }
  2789:       }
  2790:       h = hh;
  2791:       oh = ohh;
  2792:       b = bb;
  2793:     }  //if 縦2倍
  2794:     //行に収まるか
  2795:     if (prnMarginLeftX < prnHeadX &&  //左端ではなくて
  2796:         prnMarginRightX < prnHeadX + w) {  //右からはみ出す
  2797:       //改行する
  2798:       prnHeadX = prnMarginLeftX;
  2799:       prnHeadY += prnLineHeight;
  2800:       prnHeadLine++;
  2801:     }
  2802:     //コンテント範囲に収まるか
  2803:     if (prnContentTopY < prnHeadY &&  //上端ではなくて
  2804:         prnContentBottomY < prnHeadY + h) {  //下からはみ出す
  2805:       //改ページする
  2806:       prnPrintFormFeed ();
  2807:     }
  2808:     //文字を描く
  2809:     int bi = prnCheckRect (w, h);
  2810:     if (0 <= bi) {
  2811:       int ix = prnIncrementX;
  2812:       int iy = prnIncrementY;
  2813:       for (int y = 0; y < h; y++) {
  2814:         int i = bi;
  2815:         for (int x = 0; x < w; x++) {
  2816:           if ((b[(x >> 3) + o * y] >> (~x & 7) & 1) != 0) {
  2817:             prnBitmap[i] &= (byte) prnCurrentColor;  //ANDで描く
  2818:           }
  2819:           i += ix;
  2820:         }
  2821:         bi += iy;
  2822:       }
  2823:     } else {
  2824:       for (int y = 0; y < h; y++) {
  2825:         for (int x = 0; x < w; x++) {
  2826:           if ((b[(x >> 3) + o * y] >> (~x & 7) & 1) != 0) {
  2827:             prnPaintDot (x, y);
  2828:           }
  2829:         }
  2830:       }
  2831:     }
  2832:     prnHeadX += w;
  2833:     //印字あり
  2834:     prnPrinted = true;
  2835:     //キャンバスを再描画する
  2836:     if (prnCanvas != null) {
  2837:       prnCanvas.repaint ();
  2838:     }
  2839:   }  //prnPrintCharacter
  2840: 
  2841:   //prnPrintBackSpace ()
  2842:   //  BS  バックスペース  (p159)
  2843:   //  現在の文字の幅だけ後退する
  2844:   //  漢字モードのときは半角の幅
  2845:   //  横2倍が有効
  2846:   //  左マージンの位置で止まる
  2847:   public static void prnPrintBackSpace () {
  2848:     if (prnCurrentPaper == null) {  //未給紙のとき
  2849:       prnFeedPaper ();  //給紙する
  2850:     }
  2851:     prnHeadX = Math.max (prnMarginLeftX, prnHeadX - prnGetCharacterWidth ());
  2852:   }  //prnPrintBackSpace
  2853: 
  2854:   //prnPrintHorizontalTab ()
  2855:   //  HT  水平タブ  (p92)
  2856:   //  現在のヘッドの位置よりも右側にある最初の水平タブアンカーの位置まで進む
  2857:   //  なければ何もしない
  2858:   public static void prnPrintHorizontalTab () {
  2859:     if (prnCurrentPaper == null) {  //未給紙のとき
  2860:       prnFeedPaper ();  //給紙する
  2861:     }
  2862:     for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  2863:       int x = prnHorizontalTabAnchor[k];
  2864:       if (x == 0) {  //終わり
  2865:         break;
  2866:       }
  2867:       if (prnHeadX < x) {  //現在のヘッドの位置よりも右側にある
  2868:         prnHeadX = Math.min (x, prnMarginRightX - 1);
  2869:         break;
  2870:       }
  2871:     }
  2872:   }  //prnPrintHorizontalTab
  2873: 
  2874:   //prnSetStartColumn (n)
  2875:   //  POS n1 n2 n3  開始桁位置設定  (p97)
  2876:   //  0は左マージンの位置
  2877:   //  単位は現在の文字の幅
  2878:   //  横2倍が有効
  2879:   public static void prnSetStartColumn (int n) {
  2880:     if (prnCurrentPaper == null) {  //未給紙のとき
  2881:       prnFeedPaper ();  //給紙する
  2882:     }
  2883:     if (0 <= n && n <= 999) {
  2884:       int startX = prnGetCharacterWidth () * n;
  2885:       if (prnMarginLeftX + startX < prnMarginRightX) {
  2886:         prnHeadX = prnMarginLeftX + startX;
  2887:       }
  2888:     }
  2889:   }  //prnSetStartColumn
  2890: 
  2891:   //prnPrintLineFeed (n)
  2892:   //  LF            1行改行  (p76)
  2893:   //  ESC VT n1 n2  n行改行  (p77)
  2894:   //  ヘッドのY座標に改行ピッチ*nを加える
  2895:   //  縦2倍が有効
  2896:   public static void prnPrintLineFeed (int n) {
  2897:     if (prnCurrentPaper == null) {  //未給紙のとき
  2898:       prnFeedPaper ();  //給紙する
  2899:     }
  2900:     if (n < 0) {
  2901:       n = 0;
  2902:     }
  2903:     if (prnVerticalDoubleSizeMode) {  //縦2倍
  2904:       n *= 2;
  2905:     }
  2906:     //改行する
  2907:     prnHeadY += prnLineHeight * n;
  2908:     prnHeadLine += n;
  2909:     //コンテント範囲に収まっているか
  2910:     if (prnContentBottomY <= prnHeadY) {  //下からはみ出した
  2911:       //改ページする
  2912:       prnPrintFormFeed ();
  2913:     }
  2914:     //カラーモードのとき単色モードに戻る
  2915:     if (prnColorMode) {  //カラーモードのとき
  2916:       prnColorMode = false;
  2917:       prnCurrentColor = prnSingleColor;  //現在の色
  2918:     }
  2919:   }  //prnPrintLineFeed
  2920: 
  2921:   //prnPrintVerticalTab (n)
  2922:   //  VT n  垂直タブ  (p83)
  2923:   //  nはチャンネル番号
  2924:   //  現在の行より下にある指定されたチャンネル番号の垂直タブアンカーの行まで改行を繰り返す
  2925:   //  なければ何もしない
  2926:   public static void prnPrintVerticalTab (int n) {
  2927:     if (prnCurrentPaper == null) {  //未給紙のとき
  2928:       prnFeedPaper ();  //給紙する
  2929:     }
  2930:     for (int k = prnHeadLine; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  2931:       if (prnVerticalTabAnchor[k] == n) {  //チャンネルが番号が一致した
  2932:         int d = k - prnHeadLine;  //進む行数
  2933:         //改行する
  2934:         prnHeadX = prnMarginLeftX;
  2935:         prnHeadY += prnLineHeight * d;
  2936:         prnHeadLine += d;
  2937:         //コンテント範囲に収まっているか
  2938:         if (prnContentBottomY <= prnHeadY) {  //下からはみ出した
  2939:           //改ページする
  2940:           prnPrintFormFeed ();
  2941:         }
  2942:         return;
  2943:       }
  2944:     }
  2945:   }  //prnPrintVerticalTab
  2946: 
  2947:   //prnPrintFormFeed ()
  2948:   //  FF  改ページ  (p80)
  2949:   //  ページの先頭でも次のページまで紙送りする
  2950:   public static void prnPrintFormFeed () {
  2951:     //改ページする
  2952:     prnPageStart += prnPageLength;
  2953:     //コンテント範囲
  2954:     prnContentTopY = prnPageStart;
  2955:     prnContentBottomY = Math.min (prnPageStart + prnPageLength - prnMarginBottomHeight,
  2956:                                   prnAliveBottomY - prnAliveTopY);
  2957:     //ヘッドの位置
  2958:     prnHeadX = prnMarginLeftX;
  2959:     prnHeadY = prnContentTopY;
  2960:     prnHeadLine = 0;
  2961:     //印字可能範囲に収まっているか
  2962:     if (prnAliveBottomY <= prnAliveTopY + prnHeadY) {  //下からはみ出した
  2963:       prnEjectPaper ();  //排紙する
  2964:       prnFeedPaper ();  //給紙する
  2965:     }
  2966:   }  //prnPrintFormFeed
  2967: 
  2968:   //prnPrintCarriageReturn ()
  2969:   //  CR  復帰  (p72)
  2970:   //  印字位置を左マージンまで戻す
  2971:   public static void prnPrintCarriageReturn () {
  2972:     if (prnCurrentPaper == null) {  //未給紙のとき
  2973:       prnFeedPaper ();  //給紙する
  2974:     }
  2975:     //ヘッドを左端に移動させる
  2976:     prnHeadX = prnMarginLeftX;
  2977:     //カラーモードのとき色を変更する
  2978:     if (prnColorMode) {  //カラーモードのとき
  2979:       prnCurrentColor = prnCurrentColor == 6 ? 5 : prnCurrentColor == 5 ? 3 : 6;  //6→5→3→6の順に切り替える
  2980:     }
  2981:   }  //prnPrintCarriageReturn
  2982: 
  2983:   //prnSetHorizontalDoubleSizeMode (b)
  2984:   //  b  true   SO     横2倍ON  (p104)
  2985:   //            ESC U  横2倍ON  (p105)
  2986:   //     false  SI     横2倍OFF  (p106)
  2987:   public static void prnSetHorizontalDoubleSizeMode (boolean b) {
  2988:     prnHorizontalDoubleSizeMode = b;
  2989:   }  //prnSetHorizontalDoubleSizeMode
  2990: 
  2991:   //prnSelect (b)
  2992:   //  b  true   DC1  セレクト  (p165)
  2993:   //     false  DC3  ディセレクト  (p166)
  2994:   public static void prnSelect (boolean b) {
  2995:     //!!!
  2996:   }  //prnSelect
  2997: 
  2998:   //prnSetVerticalTabAnchor (a, o, n)
  2999:   //  DC4 0 … 0 n1 0 … 0 n2 … nk ?  垂直タブアンカー設置  (p81)
  3000:   //  0は垂直タブ位置でない行
  3001:   //  1 2 3 4 5 6 7 8 9 : ; < = >は垂直タブ位置である行のチャンネル番号
  3002:   //  ?で終了
  3003:   //  チャンネル番号は昇順であること
  3004:   //  頁長または下マージンが設定されると垂直タブアンカーはクリアされる
  3005:   //  現在の印字位置がページの先頭になる
  3006:   public static void prnSetVerticalTabAnchor (byte[] a, int o, int n) {
  3007:     if (prnCurrentPaper == null) {  //未給紙のとき
  3008:       prnFeedPaper ();  //給紙する
  3009:     }
  3010:     prnSetPageStartPosition ();  //ページ先頭設定
  3011:     int pp = '0';  //前回のチャンネル番号
  3012:     int k = 0;
  3013:     for (; k < PRN_VERTICAL_ANCHOR_LIMIT && k < n; k++) {
  3014:       int p = a[o + k];  //チャンネル番号
  3015:       if (p == '0') {
  3016:         prnVerticalTabAnchor[k] = 0;
  3017:       } else if ('1' <= p && p <= '<') {
  3018:         if (p <= pp) {  //昇順になっていない
  3019:           break;
  3020:         }
  3021:         prnVerticalTabAnchor[k] = p - '0';
  3022:         pp = p;
  3023:       } else {
  3024:         break;
  3025:       }
  3026:     }
  3027:     for (; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  3028:       prnVerticalTabAnchor[k] = 0;
  3029:     }
  3030:   }  //prnSetVerticalTabAnchor
  3031: 
  3032:   //prnCancel ()
  3033:   //  CAN  キャンセル  (p158)
  3034:   public static void prnCancel () {
  3035:     //!!!
  3036:   }  //prnCancel
  3037: 
  3038:   //prnSetVerticalDoubleSizeMode (b)
  3039:   //  b  true   SUB V  縦2倍ON  (p107)
  3040:   //     false  SUB W  縦2倍OFF  (p108)
  3041:   public static void prnSetVerticalDoubleSizeMode (boolean b) {
  3042:     prnVerticalDoubleSizeMode = b;
  3043:   }  //prnSetVerticalDoubleSizeMode
  3044: 
  3045:   //prnSetHorizontalStartPosition (n)
  3046:   //  ESC POS n1 n2 n3 n4  水平開始位置設定  (p98)
  3047:   //  水平開始位置をn/180[in]にする
  3048:   public static void prnSetHorizontalStartPosition (int n) {
  3049:     if (prnCurrentPaper == null) {  //未給紙のとき
  3050:       prnFeedPaper ();  //給紙する
  3051:     }
  3052:     if (0 <= n && n <= 9999) {
  3053:       int startX = 2 * n;
  3054:       if (prnMarginLeftX + startX < prnMarginRightX) {
  3055:         prnHeadX = prnMarginLeftX + startX;
  3056:       }
  3057:     }
  3058:   }  //prnSetHorizontalStartPosition
  3059: 
  3060:   //prnSetColorMode ()
  3061:   //  ESC EM  カラーモード  (p167)
  3062:   public static void prnSetColorMode () {
  3063:     prnColorMode = true;  //カラーモード
  3064:     prnCurrentColor = 6;  //現在の色。6=イエロー
  3065:   }  //prnSetColorMode
  3066: 
  3067:   //prnSetStrongMode (b)
  3068:   //  b  true   ESC !  強調文字設定  (p109)
  3069:   //     false  ESC "  強調文字解除  (p110)
  3070:   public static void prnSetStrongMode (boolean b) {
  3071:     prnStrongMode = b;
  3072:   }  //prnSetStrongMode
  3073: 
  3074:   //prnSetHiraganaMode (b)
  3075:   //  b  true   ESC &  ひらがなモード  (p164)
  3076:   //     false  ESC $  カタカナモード  (p163)
  3077:   public static void prnSetHiraganaMode (boolean b) {
  3078:     prnHiraganaMode = b;
  3079:   }  //prnSetHiraganaMode
  3080: 
  3081:   //prnSetLineHeight (n)
  3082:   //  ESC % 9 n  1/120[in]紙送り量設定  (p75)
  3083:   //  改行ピッチをn/120[in]にする
  3084:   //  0<=n<=127
  3085:   //  0はESC % 9 nを実行する前の1/6[in]または1/8[in]に戻す
  3086:   public static void prnSetLineHeight (int n) {
  3087:     if (0 <= n && n <= 127) {
  3088:       if (n == 0) {
  3089:         prnLineHeight = prnDefaultLineHeight;
  3090:       } else {
  3091:         prnLineHeight = 3 * n;
  3092:       }
  3093:     }
  3094:   }  //prnSetLineHeight
  3095: 
  3096:   //prn8DotBitImage (a, o, n)
  3097:   //  ESC % 2 n1 n2 d1 d2 … dk  8ドットビットイメージ  (p142)
  3098:   //  パイカのとき
  3099:   //    横方向を4.5倍に拡大する
  3100:   //    縦方向を4.5倍に拡大する。高さが36[dot]になる
  3101:   //    改行ピッチが15/120[in]または16/120[in]のとき12/120[in]にする
  3102:   //  エリートのとき
  3103:   //    横方向を3倍に拡大する
  3104:   //    縦方向を4.5倍に拡大する。高さが36[dot]になる
  3105:   //    改行ピッチが15/120[in]または16/120[in]のとき12/120[in]にする
  3106:   //  改行ピッチが1/120[in]のとき
  3107:   //    縦方向を6倍に拡大して上3bitだけバッファに展開する
  3108:   //    LFが来たら先頭に戻って今度は下3bitだけ展開する
  3109:   public static void prn8DotBitImage (byte[] a, int o, int n) {
  3110:     if (prnCurrentPaper == null) {  //未給紙のとき
  3111:       prnFeedPaper ();  //給紙する
  3112:     }
  3113:     //!!!
  3114:   }  //prn8DotBitImage
  3115: 
  3116:   //prnSetHorizontalTabAnchor (a, o, n)
  3117:   //  ESC ( n1 , n2 , n3 , … , nk .  水平タブアンカー設置  (p90)
  3118:   //  nkは3桁の10進数で1個から16個まで
  3119:   //  nkに現在の文字幅(漢字モードのときは半角、横2倍が有効)が掛けられて絶対位置で記憶される
  3120:   //  0は左マージンの位置。右マージンを超える位置は無視される
  3121:   //  HTで次の水平タブ位置まで進む
  3122:   //  電源投入時はパイカで8桁毎に設定されている
  3123:   //  左右マージンが設定されるとすべての水平タブ位置がクリアされる
  3124:   public static void prnSetHorizontalTabAnchor (byte[] a, int o, int n) {
  3125:     if (prnCurrentPaper == null) {  //未給紙のとき
  3126:       prnFeedPaper ();  //給紙する
  3127:     }
  3128:     int characterWidth = prnGetCharacterWidth ();
  3129:     n += o;
  3130:     int k = 0;
  3131:     while (k < PRN_HORIZONTAL_ANCHOR_LIMIT &&
  3132:            o < n && '0' <= a[o] && a[o] <= '9') {
  3133:       int p = a[o] - '0';
  3134:       o++;
  3135:       while (o < n && '0' <= a[o] && a[o] <= '9') {  //本来は3桁固定
  3136:         p = p * 10 + (a[o] - '0');
  3137:         o++;
  3138:       }
  3139:       int x = prnMarginLeftX + characterWidth * p;  //絶対位置
  3140:       if ((k == 0 ? prnMarginLeftX :  //左マージンまたは
  3141:            prnHorizontalTabAnchor[k - 1]) < x) {  //直前の水平タブアンカーよりも右側になければならない
  3142:         prnHorizontalTabAnchor[k] = x;
  3143:         k++;
  3144:       }
  3145:       if (o < n && a[o] == ',') {  //継続
  3146:         o++;
  3147:       } else {  //終了
  3148:         break;
  3149:       }
  3150:     }
  3151:     for (; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3152:       prnHorizontalTabAnchor[k] = 0;
  3153:     }
  3154:   }  //prnSetHorizontalTabAnchor
  3155: 
  3156:   //prnClearHorizontalTabAnchor (a, o, n)
  3157:   //  ESC ) n1 , n2 , … nk .  水平タブアンカー除去  (p93)
  3158:   //  nkは3桁の10進数で1個から16個まで
  3159:   //  nkに現在の文字幅(漢字モードのときは半角、横2倍が有効)が掛けられて絶対位置で比較される
  3160:   //  設置したときと同じ条件で除去しなければならない
  3161:   public static void prnClearHorizontalTabAnchor (byte[] a, int o, int n) {
  3162:     if (prnCurrentPaper == null) {  //未給紙のとき
  3163:       prnFeedPaper ();  //給紙する
  3164:     }
  3165:     int characterWidth = prnGetCharacterWidth ();
  3166:     n += o;
  3167:     while (o < n && '0' <= a[o] && a[o] <= '9') {
  3168:       int p = a[o] - '0';
  3169:       o++;
  3170:       while (o < n && '0' <= a[o] && a[o] <= '9') {  //本来は3桁固定
  3171:         p = p * 10 + (a[o] - '0');
  3172:         o++;
  3173:       }
  3174:       int x = prnMarginLeftX + characterWidth * p;  //絶対位置
  3175:       for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3176:         int t = prnHorizontalTabAnchor[k];
  3177:         if (t == 0 ||  //終わり
  3178:             x < t) {  //行き過ぎた。見つからなかった
  3179:           break;
  3180:         }
  3181:         if (t == x) {  //見つかった
  3182:           int j = k;
  3183:           for (; j < PRN_HORIZONTAL_ANCHOR_LIMIT - 1; j++) {
  3184:             prnHorizontalTabAnchor[j] = prnHorizontalTabAnchor[j + 1];  //詰める
  3185:           }
  3186:           prnHorizontalTabAnchor[j] = 0;
  3187:           break;  //1つしかないので終わり
  3188:         }
  3189:       }
  3190:       if (o < n && a[o] == ',') {  //継続
  3191:         o++;
  3192:       } else {  //終了
  3193:         break;
  3194:       }
  3195:     }
  3196:   }  //prnClearHorizontalTabAnchor
  3197: 
  3198:   //prn16DotExtendedCharacterDefinition ()
  3199:   //  ESC * n1 n2 d1 d2 … d32  16ドット外字定義  (p134)
  3200:   //  外字定義エリアは0x7621..0x767eと0x7721..0x7726の100文字
  3201:   //  16x16[dot]のパターンが縦横3倍に拡大されて48x48[dot]で保存される
  3202:   //  ESC c 1でクリアされる
  3203:   //             0         1              14         15
  3204:   //        +---------+---------+----+----------+----------+
  3205:   //     0  | d1 bit7 | d3 bit7 | .. | d29 bit7 | d31 bit7 |
  3206:   //        +---------+---------+----+----------+----------+
  3207:   //     1  | d1 bit6 | d3 bit6 | .. | d29 bit6 | d31 bit6 |
  3208:   //        +---------+---------+----+----------+----------+
  3209:   //        |    :    |    :    |    |    :     |    :     |
  3210:   //        +---------+---------+----+----------+----------+
  3211:   //     6  | d1 bit1 | d3 bit1 | .. | d29 bit1 | d31 bit1 |
  3212:   //        +---------+---------+----+----------+----------+
  3213:   //     7  | d1 bit0 | d3 bit0 | .. | d29 bit0 | d31 bit0 |
  3214:   //        +---------+---------+----+----------+----------+
  3215:   //     8  | d2 bit7 | d4 bit7 | .. | d30 bit7 | d32 bit7 |
  3216:   //        +---------+---------+----+----------+----------+
  3217:   //     9  | d2 bit6 | d4 bit6 | .. | d30 bit6 | d32 bit6 |
  3218:   //        +---------+---------+----+----------+----------+
  3219:   //        |    :    |    :    |    |    :     |    :     |
  3220:   //        +---------+---------+----+----------+----------+
  3221:   //    14  | d2 bit1 | d4 bit1 | .. | d30 bit1 | d32 bit1 |
  3222:   //        +---------+---------+----+----------+----------+
  3223:   //    15  | d2 bit0 | d4 bit0 | .. | d30 bit0 | d32 bit0 |
  3224:   //        +---------+---------+----+----------+----------+
  3225:   public static void prn16DotExtendedCharacterDefinition (byte[] a, int o, int n) {
  3226:     byte[] gaijiData = prnGetGaijiData ();
  3227:     int n1 = a[o] & 255;
  3228:     int n2 = a[o + 1] & 255;
  3229:     if (!((n1 == 0x76 && (0x21 <= n2 && n2 <= 0x7e)) ||
  3230:           (n1 == 0x77 && (0x21 <= n2 && n2 <= 0x26)))) {  //外字定義エリアではない
  3231:       return;
  3232:     }
  3233:     int i = 6 * 48 * ((n2 - 0x21) + 94 * (n1 - 0x76));
  3234:     int j = o + 2;
  3235:     for (int y = 0; y < 16; y++) {
  3236:       int t = 0;
  3237:       for (int x = 0; x < 8; x++) {
  3238:         t = t << 3 | (a[j + 2 * x + (y >> 3)] >> (~y & 7) & 1) * 7;
  3239:       }
  3240:       gaijiData[i    ] = gaijiData[i + 6] = gaijiData[i + 12] = (byte) (t >> 16);
  3241:       gaijiData[i + 1] = gaijiData[i + 7] = gaijiData[i + 13] = (byte) (t >> 8);
  3242:       gaijiData[i + 2] = gaijiData[i + 8] = gaijiData[i + 14] = (byte) t;
  3243:       t = 0;
  3244:       for (int x = 8; x < 16; x++) {
  3245:         t = t << 3 | (a[j + 2 * x + (y >> 3)] >> (~y & 7) & 1) * 7;
  3246:       }
  3247:       gaijiData[i + 3] = gaijiData[i +  9] = gaijiData[i + 15] = (byte) (t >> 16);
  3248:       gaijiData[i + 4] = gaijiData[i + 10] = gaijiData[i + 16] = (byte) (t >> 8);
  3249:       gaijiData[i + 5] = gaijiData[i + 11] = gaijiData[i + 17] = (byte) t;
  3250:       i += 18;
  3251:     }
  3252:   }  //prn16DotExtendedCharacterDefinition
  3253: 
  3254:   //prn24DotExtendedCharacterDefinition ()
  3255:   //  ESC + n1 n2 d1 d2 … d72  24ドット外字定義  (p138)
  3256:   //  外字定義エリアは0x7621..0x767eと0x7721..0x7726の100文字
  3257:   //  24x24[dot]のパターンが縦横2倍に拡大されて48x48[dot]で保存される
  3258:   //  ESC c 1でクリアされる
  3259:   //             0         1              22         23
  3260:   //        +---------+---------+----+----------+----------+
  3261:   //     0  | d1 bit7 | d4 bit7 | .. | d67 bit7 | d70 bit7 |
  3262:   //        +---------+---------+----+----------+----------+
  3263:   //     1  | d1 bit6 | d4 bit6 | .. | d67 bit6 | d70 bit6 |
  3264:   //        +---------+---------+----+----------+----------+
  3265:   //        |    :    |    :    |    |    :     |    :     |
  3266:   //        +---------+---------+----+----------+----------+
  3267:   //     6  | d1 bit1 | d4 bit1 | .. | d67 bit1 | d70 bit1 |
  3268:   //        +---------+---------+----+----------+----------+
  3269:   //     7  | d1 bit0 | d4 bit0 | .. | d67 bit0 | d70 bit0 |
  3270:   //        +---------+---------+----+----------+----------+
  3271:   //     8  | d2 bit7 | d5 bit7 | .. | d68 bit7 | d71 bit7 |
  3272:   //        +---------+---------+----+----------+----------+
  3273:   //     9  | d2 bit6 | d5 bit6 | .. | d68 bit6 | d71 bit6 |
  3274:   //        +---------+---------+----+----------+----------+
  3275:   //        |    :    |    :    |    |    :     |    :     |
  3276:   //        +---------+---------+----+----------+----------+
  3277:   //    14  | d2 bit1 | d5 bit1 | .. | d68 bit1 | d71 bit1 |
  3278:   //        +---------+---------+----+----------+----------+
  3279:   //    15  | d2 bit0 | d5 bit0 | .. | d68 bit0 | d71 bit0 |
  3280:   //        +---------+---------+----+----------+----------+
  3281:   //    16  | d3 bit7 | d6 bit7 | .. | d69 bit7 | d72 bit7 |
  3282:   //        +---------+---------+----+----------+----------+
  3283:   //    17  | d3 bit6 | d6 bit6 | .. | d69 bit6 | d72 bit6 |
  3284:   //        +---------+---------+----+----------+----------+
  3285:   //        |    :    |    :    |    |    :     |    :     |
  3286:   //        +---------+---------+----+----------+----------+
  3287:   //    22  | d3 bit1 | d6 bit1 | .. | d69 bit1 | d72 bit1 |
  3288:   //        +---------+---------+----+----------+----------+
  3289:   //    23  | d3 bit0 | d6 bit0 | .. | d69 bit0 | d72 bit0 |
  3290:   //        +---------+---------+----+----------+----------+
  3291:   public static void prn24DotExtendedCharacterDefinition (byte[] a, int o, int n) {
  3292:     byte[] gaijiData = prnGetGaijiData ();
  3293:     int n1 = a[o] & 255;
  3294:     int n2 = a[o + 1] & 255;
  3295:     if (!((n1 == 0x76 && (0x21 <= n2 && n2 <= 0x7e)) ||
  3296:           (n1 == 0x77 && (0x21 <= n2 && n2 <= 0x26)))) {  //外字定義エリアではない
  3297:       return;
  3298:     }
  3299:     int i = 6 * 48 * ((n2 - 0x21) + 94 * (n1 - 0x76));
  3300:     int j = o + 2;
  3301:     for (int y = 0; y < 24; y++) {
  3302:       int t = 0;
  3303:       for (int x = 0; x < 16; x++) {
  3304:         t = t << 2 | (a[j + 3 * x + (y >> 3)] >> (~y & 7) & 1) * 3;
  3305:       }
  3306:       gaijiData[i    ] = gaijiData[i + 6] = (byte) (t >> 24);
  3307:       gaijiData[i + 1] = gaijiData[i + 7] = (byte) (t >> 16);
  3308:       gaijiData[i + 2] = gaijiData[i + 8] = (byte) (t >> 8);
  3309:       gaijiData[i + 3] = gaijiData[i + 9] = (byte) t;
  3310:       t = 0;
  3311:       for (int x = 16; x < 24; x++) {
  3312:         t = t << 2 | (a[j + 3 * x + (y >> 3)] >> (~y & 7) & 1) * 3;
  3313:       }
  3314:       gaijiData[i + 4] = gaijiData[i + 10] = (byte) (t >> 8);
  3315:       gaijiData[i + 5] = gaijiData[i + 11] = (byte) t;
  3316:       i += 12;
  3317:     }
  3318:   }  //prn24DotExtendedCharacterDefinition
  3319: 
  3320:   //prnSetRightMargin (n)
  3321:   //  ESC / n1 n2 n3  右マージン設定  (p88)
  3322:   //  右マージンをn桁にする
  3323:   //  最大数よりも大きいと無視される
  3324:   //  水平タブ位置はクリアされる
  3325:   //  単位は現在の文字の幅
  3326:   //  漢字モードのときは半角の幅
  3327:   //  横2倍は無視される
  3328:   public static void prnSetRightMargin (int n) {
  3329:     if (prnCurrentPaper == null) {  //未給紙のとき
  3330:       prnFeedPaper ();  //給紙する
  3331:     }
  3332:     if (0 <= n && n <= 999) {
  3333:       int rightX = prnGetCharacterWidth () * n;
  3334:       if (prnMarginLeftX < rightX) {
  3335:         prnMarginRightX = rightX;
  3336:         //水平タブ位置をクリアする
  3337:         for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3338:           prnHorizontalTabAnchor[k] = 0;
  3339:         }
  3340:       }
  3341:     }
  3342:   }  //prnSetRightMargin
  3343: 
  3344:   //prnClearAllHorizontalTabAnchor ()
  3345:   //  ESC 2  全水平タブアンカー除去  (p95)
  3346:   public static void prnClearAllHorizontalTabAnchor () {
  3347:     if (prnCurrentPaper == null) {  //未給紙のとき
  3348:       prnFeedPaper ();  //給紙する
  3349:     }
  3350:     //水平タブ位置をクリアする
  3351:     for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3352:       prnHorizontalTabAnchor[k] = 0;
  3353:     }
  3354:   }  //prnClearAllHorizontalTabAnchor
  3355: 
  3356:   //prnSetPageStartPosition ()
  3357:   //  ESC 5  ページ先頭設定  (p79)
  3358:   //  現在の印字位置がページの先頭になる
  3359:   public static void prnSetPageStartPosition () {
  3360:     if (prnCurrentPaper == null) {  //未給紙のとき
  3361:       prnFeedPaper ();  //給紙する
  3362:     }
  3363:     //ページ範囲
  3364:     prnPageStart = prnHeadY;  //現在の印字位置がページの先頭になる
  3365:     //コンテント範囲
  3366:     prnContentTopY = prnPageStart;
  3367:     prnContentBottomY = Math.min (prnPageStart + prnPageLength - prnMarginBottomHeight,
  3368:                                   prnAliveBottomY - prnAliveTopY);
  3369:     //ヘッドの位置
  3370:     prnHeadX = prnMarginLeftX;
  3371:     prnHeadY = prnContentTopY;
  3372:     prnHeadLine = 0;
  3373:   }  //prnSetPageStartPosition
  3374: 
  3375:   //prnSetOneSixth ()
  3376:   //  ESC 6  1/6[in]改行設定  (p73)
  3377:   public static void prnSetOneSixth () {
  3378:     prnLineHeight = 60;
  3379:     prnDefaultLineHeight = 60;
  3380:   }  //prnSetOneSixth
  3381: 
  3382:   //prnSetOneEighth ()
  3383:   //  ESC 8  1/8[in]改行設定  (p74)
  3384:   public static void prnSetOneEighth () {
  3385:     prnLineHeight = 45;
  3386:     prnDefaultLineHeight = 45;
  3387:   }  //prnSetOneEighth
  3388: 
  3389:   //prnSetBottomMargin (n)
  3390:   //  ESC C n1 n2  下マージン設定  (p84)
  3391:   //  下マージンをn行にする
  3392:   //  頁長が設定されるとクリアされる
  3393:   //  頁長よりも長く設定しようとすると無視される
  3394:   //  頁長と下マージンの差が1行の改行ピッチより短くても1行は印字される
  3395:   public static void prnSetBottomMargin (int n) {
  3396:     if (prnCurrentPaper == null) {  //未給紙のとき
  3397:       prnFeedPaper ();  //給紙する
  3398:     }
  3399:     if (0 <= n && n <= 99) {
  3400:       int height = prnLineHeight * n;
  3401:       if (height < prnPageLength) {
  3402:         prnMarginBottomHeight = height;
  3403:         //コンテント範囲
  3404:         prnContentBottomY = Math.min (prnPageStart + prnPageLength - height,
  3405:                                       prnAliveBottomY - prnAliveTopY);
  3406:         //コンテント範囲に収まっているか
  3407:         if (prnContentBottomY <= prnHeadY) {  //下からはみ出した
  3408:           //改ページする
  3409:           prnPrintFormFeed ();
  3410:         }
  3411:         //垂直タブ位置をクリアする
  3412:         for (int k = 0; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  3413:           prnVerticalTabAnchor[k] = 0;
  3414:         }
  3415:       }
  3416:     }
  3417:   }  //prnSetBottomMargin
  3418: 
  3419:   //prnSetEliteCharacterMode ()
  3420:   //  ESC E  エリート文字設定  (p102)
  3421:   //  エリート文字(1/12[in])にする
  3422:   //  https://en.wikipedia.org/wiki/Typewriter#Character_sizes
  3423:   public static void prnSetEliteCharacterMode () {
  3424:     prnCharacterType = PRN_ELITE;  //エリート文字
  3425:   }  //prnSetEliteCharacterMode
  3426: 
  3427:   //prnSetPageHeight (n)
  3428:   //  ESC F n1 n2  ページ高さ設定  (p78)
  3429:   //  ページの高さをn/2[in]にする
  3430:   //  現在の印字位置がページの先頭になる
  3431:   //  n=0は無視される
  3432:   //  下マージンはクリアされる
  3433:   public static void prnSetPageHeight (int n) {
  3434:     if (prnCurrentPaper == null) {  //未給紙のとき
  3435:       prnFeedPaper ();  //給紙する
  3436:     }
  3437:     prnSetPageStartPosition ();  //ページ先頭設定
  3438:     if (1 <= n && n <= 99) {
  3439:       //ページ長
  3440:       prnPageLength = 180 * n;
  3441:       //下マージン
  3442:       prnMarginBottomHeight = 0;
  3443:       //ページ開始位置
  3444:       prnSetPageStartPosition ();
  3445:     }
  3446:   }  //prnSetPageHeight
  3447: 
  3448:   //prn16DotBitImage (a, o, n)
  3449:   //  ESC I n1 n2 n3 n4 d1 d2 … dk  16ドットビットイメージ  (p148)
  3450:   //  横方向を3倍に拡大する
  3451:   //  縦方向を3倍に拡大する。高さが48[dot]になる
  3452:   //  改行ピッチが15/120[in]のとき16/120[in]にする
  3453:   //  横2倍と縦2倍が有効
  3454:   //  行からはみ出した部分は無視される
  3455:   public static void prn16DotBitImage (byte[] a, int o, int n) {
  3456:     if (prnCurrentPaper == null) {  //未給紙のとき
  3457:       prnFeedPaper ();  //給紙する
  3458:     }
  3459:     //改行ピッチが15/120[in]のとき16/120[in]にする
  3460:     if (prnLineHeight == 45) {
  3461:       prnLineHeight = 48;
  3462:     }
  3463:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  3464:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3465:         //横1倍,縦1倍
  3466:         int aw = n;  //横nビット→3*nドット
  3467:         int ah = 16;  //縦16ビット→48ドット
  3468:         aw = Math.min (3 * aw, prnMarginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  3469:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  3470:         int bi = prnCheckRect (3 * aw, 3 * ah);
  3471:         if (0 <= bi) {
  3472:           int ix = prnIncrementX;
  3473:           int iy = prnIncrementY;
  3474:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3475:             int i = bi;
  3476:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3477:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3478:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3479:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3480:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  3481:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3482:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3483:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  3484:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  3485:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  3486:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3487:               }
  3488:               i += 3 * ix;
  3489:             }
  3490:             bi += 3 * iy;
  3491:           }
  3492:         } else {
  3493:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3494:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3495:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3496:                 prnPaintDot (3 * ax    , 3 * ay    );
  3497:                 prnPaintDot (3 * ax + 1, 3 * ay    );
  3498:                 prnPaintDot (3 * ax + 2, 3 * ay    );
  3499:                 prnPaintDot (3 * ax    , 3 * ay + 1);
  3500:                 prnPaintDot (3 * ax + 1, 3 * ay + 1);
  3501:                 prnPaintDot (3 * ax + 2, 3 * ay + 1);
  3502:                 prnPaintDot (3 * ax    , 3 * ay + 2);
  3503:                 prnPaintDot (3 * ax + 1, 3 * ay + 2);
  3504:                 prnPaintDot (3 * ax + 2, 3 * ay + 2);
  3505:               }
  3506:             }
  3507:           }
  3508:         }
  3509:         prnHeadX += 3 * aw;
  3510:       } else {  //縦2倍
  3511:         //横1倍,縦2倍
  3512:         int aw = n;  //横nビット→3*nドット
  3513:         int ah = 16;  //縦16ビット→96ドット
  3514:         aw = Math.min (3 * aw, prnMarginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  3515:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  3516:         int bi = prnCheckRect (3 * aw, 6 * ah);
  3517:         if (0 <= bi) {
  3518:           int ix = prnIncrementX;
  3519:           int iy = prnIncrementY;
  3520:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3521:             int i = bi;
  3522:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3523:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3524:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3525:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3526:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  3527:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3528:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3529:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  3530:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  3531:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  3532:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3533:                 prnBitmap[i          + 3 * iy] &= (byte) prnCurrentColor;
  3534:                 prnBitmap[i +     ix + 3 * iy] &= (byte) prnCurrentColor;
  3535:                 prnBitmap[i + 2 * ix * 3 * iy] &= (byte) prnCurrentColor;
  3536:                 prnBitmap[i          + 4 * iy] &= (byte) prnCurrentColor;
  3537:                 prnBitmap[i +     ix + 4 * iy] &= (byte) prnCurrentColor;
  3538:                 prnBitmap[i + 2 * ix + 4 * iy] &= (byte) prnCurrentColor;
  3539:                 prnBitmap[i          + 5 * iy] &= (byte) prnCurrentColor;
  3540:                 prnBitmap[i +     ix + 5 * iy] &= (byte) prnCurrentColor;
  3541:                 prnBitmap[i + 2 * ix + 5 * iy] &= (byte) prnCurrentColor;
  3542:               }
  3543:               i += 3 * ix;
  3544:             }
  3545:             bi += 6 * iy;
  3546:           }
  3547:         } else {
  3548:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3549:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3550:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3551:                 prnPaintDot (3 * ax    , 6 * ay    );
  3552:                 prnPaintDot (3 * ax + 1, 6 * ay    );
  3553:                 prnPaintDot (3 * ax + 2, 6 * ay    );
  3554:                 prnPaintDot (3 * ax    , 6 * ay + 1);
  3555:                 prnPaintDot (3 * ax + 1, 6 * ay + 1);
  3556:                 prnPaintDot (3 * ax + 2, 6 * ay + 1);
  3557:                 prnPaintDot (3 * ax    , 6 * ay + 2);
  3558:                 prnPaintDot (3 * ax + 1, 6 * ay + 2);
  3559:                 prnPaintDot (3 * ax + 2, 6 * ay + 2);
  3560:                 prnPaintDot (3 * ax    , 6 * ay + 3);
  3561:                 prnPaintDot (3 * ax + 1, 6 * ay + 3);
  3562:                 prnPaintDot (3 * ax + 2, 6 * ay + 3);
  3563:                 prnPaintDot (3 * ax    , 6 * ay + 4);
  3564:                 prnPaintDot (3 * ax + 1, 6 * ay + 4);
  3565:                 prnPaintDot (3 * ax + 2, 6 * ay + 4);
  3566:                 prnPaintDot (3 * ax    , 6 * ay + 5);
  3567:                 prnPaintDot (3 * ax + 1, 6 * ay + 5);
  3568:                 prnPaintDot (3 * ax + 2, 6 * ay + 5);
  3569:               }
  3570:             }
  3571:           }
  3572:         }
  3573:         prnHeadX += 3 * aw;
  3574:       }  //if 縦1倍/縦2倍
  3575:     } else {  //横2倍
  3576:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3577:         //横2倍,縦1倍
  3578:         int aw = n;  //横nビット→6*nドット
  3579:         int ah = 16;  //縦16ビット→48ドット
  3580:         aw = Math.min (6 * aw, prnMarginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  3581:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  3582:         int bi = prnCheckRect (6 * aw, 3 * ah);
  3583:         if (0 <= bi) {
  3584:           int ix = prnIncrementX;
  3585:           int iy = prnIncrementY;
  3586:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3587:             int i = bi;
  3588:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3589:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3590:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3591:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3592:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  3593:                 prnBitmap[i + 3 * ix         ] &= (byte) prnCurrentColor;
  3594:                 prnBitmap[i + 4 * ix         ] &= (byte) prnCurrentColor;
  3595:                 prnBitmap[i + 5 * ix         ] &= (byte) prnCurrentColor;
  3596:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3597:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3598:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  3599:                 prnBitmap[i + 3 * ix +     iy] &= (byte) prnCurrentColor;
  3600:                 prnBitmap[i + 4 * ix +     iy] &= (byte) prnCurrentColor;
  3601:                 prnBitmap[i + 5 * ix +     iy] &= (byte) prnCurrentColor;
  3602:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  3603:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  3604:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3605:                 prnBitmap[i + 3 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3606:                 prnBitmap[i + 4 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3607:                 prnBitmap[i + 5 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3608:               }
  3609:               i += 6 * ix;
  3610:             }
  3611:             bi += 3 * iy;
  3612:           }
  3613:         } else {
  3614:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3615:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3616:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3617:                 prnPaintDot (6 * ax    , 3 * ay    );
  3618:                 prnPaintDot (6 * ax + 1, 3 * ay    );
  3619:                 prnPaintDot (6 * ax + 2, 3 * ay    );
  3620:                 prnPaintDot (6 * ax + 3, 3 * ay    );
  3621:                 prnPaintDot (6 * ax + 4, 3 * ay    );
  3622:                 prnPaintDot (6 * ax + 5, 3 * ay    );
  3623:                 prnPaintDot (6 * ax    , 3 * ay + 1);
  3624:                 prnPaintDot (6 * ax + 1, 3 * ay + 1);
  3625:                 prnPaintDot (6 * ax + 2, 3 * ay + 1);
  3626:                 prnPaintDot (6 * ax + 3, 3 * ay + 1);
  3627:                 prnPaintDot (6 * ax + 4, 3 * ay + 1);
  3628:                 prnPaintDot (6 * ax + 5, 3 * ay + 1);
  3629:                 prnPaintDot (6 * ax    , 3 * ay + 2);
  3630:                 prnPaintDot (6 * ax + 1, 3 * ay + 2);
  3631:                 prnPaintDot (6 * ax + 2, 3 * ay + 2);
  3632:                 prnPaintDot (6 * ax + 3, 3 * ay + 2);
  3633:                 prnPaintDot (6 * ax + 4, 3 * ay + 2);
  3634:                 prnPaintDot (6 * ax + 5, 3 * ay + 2);
  3635:               }
  3636:             }
  3637:           }
  3638:         }
  3639:         prnHeadX += 6 * aw;
  3640:       } else {  //縦2倍
  3641:         //横2倍,縦2倍
  3642:         int aw = n;  //横nビット→6*nドット
  3643:         int ah = 16;  //縦16ビット→96ドット
  3644:         aw = Math.min (6 * aw, prnMarginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  3645:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  3646:         int bi = prnCheckRect (6 * aw, 6 * ah);
  3647:         if (0 <= bi) {
  3648:           int ix = prnIncrementX;
  3649:           int iy = prnIncrementY;
  3650:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3651:             int i = bi;
  3652:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3653:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3654:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3655:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3656:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  3657:                 prnBitmap[i + 3 * ix         ] &= (byte) prnCurrentColor;
  3658:                 prnBitmap[i + 4 * ix         ] &= (byte) prnCurrentColor;
  3659:                 prnBitmap[i + 5 * ix         ] &= (byte) prnCurrentColor;
  3660:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3661:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3662:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  3663:                 prnBitmap[i + 3 * ix +     iy] &= (byte) prnCurrentColor;
  3664:                 prnBitmap[i + 4 * ix +     iy] &= (byte) prnCurrentColor;
  3665:                 prnBitmap[i + 5 * ix +     iy] &= (byte) prnCurrentColor;
  3666:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  3667:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  3668:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3669:                 prnBitmap[i + 3 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3670:                 prnBitmap[i + 4 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3671:                 prnBitmap[i + 5 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3672:                 prnBitmap[i          + 3 * iy] &= (byte) prnCurrentColor;
  3673:                 prnBitmap[i +     ix + 3 * iy] &= (byte) prnCurrentColor;
  3674:                 prnBitmap[i + 2 * ix * 3 * iy] &= (byte) prnCurrentColor;
  3675:                 prnBitmap[i + 3 * ix * 3 * iy] &= (byte) prnCurrentColor;
  3676:                 prnBitmap[i + 4 * ix * 3 * iy] &= (byte) prnCurrentColor;
  3677:                 prnBitmap[i + 5 * ix * 3 * iy] &= (byte) prnCurrentColor;
  3678:                 prnBitmap[i          + 4 * iy] &= (byte) prnCurrentColor;
  3679:                 prnBitmap[i +     ix + 4 * iy] &= (byte) prnCurrentColor;
  3680:                 prnBitmap[i + 2 * ix + 4 * iy] &= (byte) prnCurrentColor;
  3681:                 prnBitmap[i + 3 * ix + 4 * iy] &= (byte) prnCurrentColor;
  3682:                 prnBitmap[i + 4 * ix + 4 * iy] &= (byte) prnCurrentColor;
  3683:                 prnBitmap[i + 5 * ix + 4 * iy] &= (byte) prnCurrentColor;
  3684:                 prnBitmap[i          + 5 * iy] &= (byte) prnCurrentColor;
  3685:                 prnBitmap[i +     ix + 5 * iy] &= (byte) prnCurrentColor;
  3686:                 prnBitmap[i + 2 * ix + 5 * iy] &= (byte) prnCurrentColor;
  3687:                 prnBitmap[i + 3 * ix + 5 * iy] &= (byte) prnCurrentColor;
  3688:                 prnBitmap[i + 4 * ix + 5 * iy] &= (byte) prnCurrentColor;
  3689:                 prnBitmap[i + 5 * ix + 5 * iy] &= (byte) prnCurrentColor;
  3690:               }
  3691:               i += 6 * ix;
  3692:             }
  3693:             bi += 6 * iy;
  3694:           }
  3695:         } else {
  3696:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3697:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3698:               if ((a[o + 2 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3699:                 prnPaintDot (6 * ax    , 6 * ay    );
  3700:                 prnPaintDot (6 * ax + 1, 6 * ay    );
  3701:                 prnPaintDot (6 * ax + 2, 6 * ay    );
  3702:                 prnPaintDot (6 * ax + 3, 6 * ay    );
  3703:                 prnPaintDot (6 * ax + 4, 6 * ay    );
  3704:                 prnPaintDot (6 * ax + 5, 6 * ay    );
  3705:                 prnPaintDot (6 * ax    , 6 * ay + 1);
  3706:                 prnPaintDot (6 * ax + 1, 6 * ay + 1);
  3707:                 prnPaintDot (6 * ax + 2, 6 * ay + 1);
  3708:                 prnPaintDot (6 * ax + 3, 6 * ay + 1);
  3709:                 prnPaintDot (6 * ax + 4, 6 * ay + 1);
  3710:                 prnPaintDot (6 * ax + 5, 6 * ay + 1);
  3711:                 prnPaintDot (6 * ax    , 6 * ay + 2);
  3712:                 prnPaintDot (6 * ax + 1, 6 * ay + 2);
  3713:                 prnPaintDot (6 * ax + 2, 6 * ay + 2);
  3714:                 prnPaintDot (6 * ax + 3, 6 * ay + 2);
  3715:                 prnPaintDot (6 * ax + 4, 6 * ay + 2);
  3716:                 prnPaintDot (6 * ax + 5, 6 * ay + 2);
  3717:                 prnPaintDot (6 * ax    , 6 * ay + 3);
  3718:                 prnPaintDot (6 * ax + 1, 6 * ay + 3);
  3719:                 prnPaintDot (6 * ax + 2, 6 * ay + 3);
  3720:                 prnPaintDot (6 * ax + 3, 6 * ay + 3);
  3721:                 prnPaintDot (6 * ax + 4, 6 * ay + 3);
  3722:                 prnPaintDot (6 * ax + 5, 6 * ay + 3);
  3723:                 prnPaintDot (6 * ax    , 6 * ay + 4);
  3724:                 prnPaintDot (6 * ax + 1, 6 * ay + 4);
  3725:                 prnPaintDot (6 * ax + 2, 6 * ay + 4);
  3726:                 prnPaintDot (6 * ax + 3, 6 * ay + 4);
  3727:                 prnPaintDot (6 * ax + 4, 6 * ay + 4);
  3728:                 prnPaintDot (6 * ax + 5, 6 * ay + 4);
  3729:                 prnPaintDot (6 * ax    , 6 * ay + 5);
  3730:                 prnPaintDot (6 * ax + 1, 6 * ay + 5);
  3731:                 prnPaintDot (6 * ax + 2, 6 * ay + 5);
  3732:                 prnPaintDot (6 * ax + 3, 6 * ay + 5);
  3733:                 prnPaintDot (6 * ax + 4, 6 * ay + 5);
  3734:                 prnPaintDot (6 * ax + 5, 6 * ay + 5);
  3735:               }
  3736:             }
  3737:           }
  3738:         }
  3739:         prnHeadX += 6 * aw;
  3740:       }  //if 縦1倍/縦2倍
  3741:     }  //if 横1倍/横2倍
  3742:     //印字あり
  3743:     prnPrinted = true;
  3744:     //キャンバスを再描画する
  3745:     if (prnCanvas != null) {
  3746:       prnCanvas.repaint ();
  3747:     }
  3748:   }  //prn16DotBitImage
  3749: 
  3750:   //prn24DotBitImage (a, o, n)
  3751:   //  ESC J n1 n2 d1 d2 … dk  24ドットビットイメージ  (p151)
  3752:   //  横方向を2倍に拡大する
  3753:   //  縦方向を2倍に拡大する。高さが48[dot]になる
  3754:   //  改行ピッチが15/120[in]のとき16/120[in]にする
  3755:   //  横2倍と縦2倍が有効
  3756:   //  行からはみ出した部分は無視される
  3757:   public static void prn24DotBitImage (byte[] a, int o, int n) {
  3758:     if (prnCurrentPaper == null) {  //未給紙のとき
  3759:       prnFeedPaper ();  //給紙する
  3760:     }
  3761:     //改行ピッチが15/120[in]のとき16/120[in]にする
  3762:     if (prnLineHeight == 45) {
  3763:       prnLineHeight = 48;
  3764:     }
  3765:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  3766:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3767:         //横1倍,縦1倍
  3768:         int aw = n;  //横nビット→2*nドット
  3769:         int ah = 24;  //縦24ビット→48ドット
  3770:         aw = Math.min (2 * aw, prnMarginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  3771:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  3772:         int bi = prnCheckRect (2 * aw, 2 * ah);
  3773:         if (0 <= bi) {
  3774:           int ix = prnIncrementX;
  3775:           int iy = prnIncrementY;
  3776:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3777:             int i = bi;
  3778:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3779:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3780:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3781:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3782:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3783:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3784:               }
  3785:               i += 2 * ix;
  3786:             }
  3787:             bi += 2 * iy;
  3788:           }
  3789:         } else {
  3790:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3791:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3792:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3793:                 prnPaintDot (2 * ax    , 2 * ay    );
  3794:                 prnPaintDot (2 * ax + 1, 2 * ay    );
  3795:                 prnPaintDot (2 * ax    , 2 * ay + 1);
  3796:                 prnPaintDot (2 * ax + 1, 2 * ay + 1);
  3797:               }
  3798:             }
  3799:           }
  3800:         }
  3801:         prnHeadX += 2 * aw;
  3802:       } else {  //縦2倍
  3803:         //横1倍,縦2倍
  3804:         int aw = n;  //横nビット→2*nドット
  3805:         int ah = 24;  //縦24ビット→96ドット
  3806:         aw = Math.min (2 * aw, prnMarginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  3807:         ah = Math.min (4 * ah, prnContentBottomY - prnHeadY) >> 2;  //縦ahビット→4*ahドット
  3808:         int bi = prnCheckRect (2 * aw, 4 * ah);
  3809:         if (0 <= bi) {
  3810:           int ix = prnIncrementX;
  3811:           int iy = prnIncrementY;
  3812:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3813:             int i = bi;
  3814:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3815:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3816:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3817:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3818:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3819:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3820:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  3821:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  3822:                 prnBitmap[i          + 3 * iy] &= (byte) prnCurrentColor;
  3823:                 prnBitmap[i +     ix + 3 * iy] &= (byte) prnCurrentColor;
  3824:               }
  3825:               i += 2 * ix;
  3826:             }
  3827:             bi += 4 * iy;
  3828:           }
  3829:         } else {
  3830:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3831:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3832:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3833:                 prnPaintDot (2 * ax    , 4 * ay    );
  3834:                 prnPaintDot (2 * ax + 1, 4 * ay    );
  3835:                 prnPaintDot (2 * ax    , 4 * ay + 1);
  3836:                 prnPaintDot (2 * ax + 1, 4 * ay + 1);
  3837:                 prnPaintDot (2 * ax    , 4 * ay + 2);
  3838:                 prnPaintDot (2 * ax + 1, 4 * ay + 2);
  3839:                 prnPaintDot (2 * ax    , 4 * ay + 3);
  3840:                 prnPaintDot (2 * ax + 1, 4 * ay + 3);
  3841:               }
  3842:             }
  3843:           }
  3844:         }
  3845:         prnHeadX += 2 * aw;
  3846:       }  //if 縦1倍/縦2倍
  3847:     } else {  //横2倍
  3848:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  3849:         //横2倍,縦1倍
  3850:         int aw = n;  //横nビット→4*nドット
  3851:         int ah = 24;  //縦24ビット→48ドット
  3852:         aw = Math.min (4 * aw, prnMarginRightX - prnHeadX) >> 2;  //横awビット→4*awドット
  3853:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  3854:         int bi = prnCheckRect (4 * aw, 2 * ah);
  3855:         if (0 <= bi) {
  3856:           int ix = prnIncrementX;
  3857:           int iy = prnIncrementY;
  3858:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3859:             int i = bi;
  3860:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3861:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3862:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3863:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3864:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  3865:                 prnBitmap[i + 3 * ix         ] &= (byte) prnCurrentColor;
  3866:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3867:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3868:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  3869:                 prnBitmap[i + 3 * ix +     iy] &= (byte) prnCurrentColor;
  3870:               }
  3871:               i += 4 * ix;
  3872:             }
  3873:             bi += 2 * iy;
  3874:           }
  3875:         } else {
  3876:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3877:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3878:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3879:                 prnPaintDot (4 * ax    , 2 * ay    );
  3880:                 prnPaintDot (4 * ax + 1, 2 * ay    );
  3881:                 prnPaintDot (4 * ax + 2, 2 * ay    );
  3882:                 prnPaintDot (4 * ax + 3, 2 * ay    );
  3883:                 prnPaintDot (4 * ax    , 2 * ay + 1);
  3884:                 prnPaintDot (4 * ax + 1, 2 * ay + 1);
  3885:                 prnPaintDot (4 * ax + 2, 2 * ay + 1);
  3886:                 prnPaintDot (4 * ax + 3, 2 * ay + 1);
  3887:               }
  3888:             }
  3889:           }
  3890:         }
  3891:         prnHeadX += 4 * aw;
  3892:       } else {  //縦2倍
  3893:         //横2倍,縦2倍
  3894:         int aw = n;  //横nビット→4*nドット
  3895:         int ah = 24;  //縦24ビット→96ドット
  3896:         aw = Math.min (4 * aw, prnMarginRightX - prnHeadX) >> 2;  //横awビット→4*awドット
  3897:         ah = Math.min (4 * ah, prnContentBottomY - prnHeadY) >> 2;  //縦ahビット→4*ahドット
  3898:         int bi = prnCheckRect (4 * aw, 4 * ah);
  3899:         if (0 <= bi) {
  3900:           int ix = prnIncrementX;
  3901:           int iy = prnIncrementY;
  3902:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3903:             int i = bi;
  3904:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3905:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3906:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  3907:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  3908:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  3909:                 prnBitmap[i + 3 * ix         ] &= (byte) prnCurrentColor;
  3910:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  3911:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  3912:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  3913:                 prnBitmap[i + 3 * ix +     iy] &= (byte) prnCurrentColor;
  3914:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  3915:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  3916:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3917:                 prnBitmap[i + 3 * ix + 2 * iy] &= (byte) prnCurrentColor;
  3918:                 prnBitmap[i          + 3 * iy] &= (byte) prnCurrentColor;
  3919:                 prnBitmap[i +     ix + 3 * iy] &= (byte) prnCurrentColor;
  3920:                 prnBitmap[i + 2 * ix + 3 * iy] &= (byte) prnCurrentColor;
  3921:                 prnBitmap[i + 3 * ix + 3 * iy] &= (byte) prnCurrentColor;
  3922:               }
  3923:               i += 4 * ix;
  3924:             }
  3925:             bi += 4 * iy;
  3926:           }
  3927:         } else {
  3928:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  3929:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  3930:               if ((a[o + 3 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  3931:                 prnPaintDot (4 * ax    , 4 * ay    );
  3932:                 prnPaintDot (4 * ax + 1, 4 * ay    );
  3933:                 prnPaintDot (4 * ax + 2, 4 * ay    );
  3934:                 prnPaintDot (4 * ax + 3, 4 * ay    );
  3935:                 prnPaintDot (4 * ax    , 4 * ay + 1);
  3936:                 prnPaintDot (4 * ax + 1, 4 * ay + 1);
  3937:                 prnPaintDot (4 * ax + 2, 4 * ay + 1);
  3938:                 prnPaintDot (4 * ax + 3, 4 * ay + 1);
  3939:                 prnPaintDot (4 * ax    , 4 * ay + 2);
  3940:                 prnPaintDot (4 * ax + 1, 4 * ay + 2);
  3941:                 prnPaintDot (4 * ax + 2, 4 * ay + 2);
  3942:                 prnPaintDot (4 * ax + 3, 4 * ay + 2);
  3943:                 prnPaintDot (4 * ax    , 4 * ay + 3);
  3944:                 prnPaintDot (4 * ax + 1, 4 * ay + 3);
  3945:                 prnPaintDot (4 * ax + 2, 4 * ay + 3);
  3946:                 prnPaintDot (4 * ax + 3, 4 * ay + 3);
  3947:               }
  3948:             }
  3949:           }
  3950:         }
  3951:         prnHeadX += 4 * aw;
  3952:       }  //if 縦1倍/縦2倍
  3953:     }  //if 横1倍/横2倍
  3954:     //印字あり
  3955:     prnPrinted = true;
  3956:     //キャンバスを再描画する
  3957:     if (prnCanvas != null) {
  3958:       prnCanvas.repaint ();
  3959:     }
  3960:   }  //prn24DotBitImage
  3961: 
  3962:   //prnSetKanjiMode (b)
  3963:   //  b  true   ESC K  漢字モードON  (p118)
  3964:   //     false  ESC H  漢字モードOFF  (p121)
  3965:   //            ESC P  漢字モードOFF  (p121)
  3966:   public static void prnSetKanjiMode (boolean b) {
  3967:     prnKanjiMode = b;
  3968:   }  //prnSetKanjiMode
  3969: 
  3970:   //prnSetLeftMargin (n)
  3971:   //  ESC L n1 n2 n3  左マージン設定  (p86)
  3972:   //  左マージンをn桁にする
  3973:   //  最大数よりも大きいと無視される
  3974:   //  水平タブ位置はクリアされる
  3975:   //  単位は現在の文字の幅
  3976:   //  漢字モードのときは半角の幅
  3977:   //  横2倍は無視される
  3978:   public static void prnSetLeftMargin (int n) {
  3979:     if (prnCurrentPaper == null) {  //未給紙のとき
  3980:       prnFeedPaper ();  //給紙する
  3981:     }
  3982:     if (0 <= n && n <= 999) {
  3983:       int leftX = prnGetCharacterWidth () * n;
  3984:       if (leftX < prnMarginRightX) {
  3985:         prnMarginLeftX = leftX;
  3986:         if (prnHeadX < prnMarginLeftX) {
  3987:           prnHeadX = prnMarginLeftX;
  3988:         }
  3989:         //水平タブ位置をクリアする
  3990:         for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  3991:           prnHorizontalTabAnchor[k] = 0;
  3992:         }
  3993:       }
  3994:     }
  3995:   }  //prnSetLeftMargin
  3996: 
  3997:   //prn48DotBitImage (a, o, n)
  3998:   //  ESC M n1 n2 d1 d2 … dk  48ドットビットイメージ  (p153)
  3999:   //  拡大しない
  4000:   //  改行ピッチが15/120[in]のとき47/360[in]にする
  4001:   //  横2倍と縦2倍が有効
  4002:   //  行からはみ出した部分は無視される
  4003:   public static void prn48DotBitImage (byte[] a, int o, int n) {
  4004:     if (prnCurrentPaper == null) {  //未給紙のとき
  4005:       prnFeedPaper ();  //給紙する
  4006:     }
  4007:     //改行ピッチが15/120[in]のとき47/360[in]にする
  4008:     if (prnLineHeight == 45) {
  4009:       prnLineHeight = 47;
  4010:     }
  4011:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  4012:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  4013:         //横1倍,縦1倍
  4014:         int aw = n;  //横nビット→nドット
  4015:         int ah = 48;  //縦48ビット→48ドット
  4016:         aw = Math.min (aw, prnMarginRightX - prnHeadX);  //横awビット→awドット
  4017:         ah = Math.min (ah, prnContentBottomY - prnHeadY);  //縦ahビット→ahドット
  4018:         int bi = prnCheckRect (    aw,     ah);
  4019:         if (0 <= bi) {
  4020:           int ix = prnIncrementX;
  4021:           int iy = prnIncrementY;
  4022:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4023:             int i = bi;
  4024:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4025:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4026:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4027:               }
  4028:               i +=     ix;
  4029:             }
  4030:             bi +=     iy;
  4031:           }
  4032:         } else {
  4033:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4034:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4035:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4036:                 prnPaintDot (    ax    ,     ay    );
  4037:               }
  4038:             }
  4039:           }
  4040:         }
  4041:         prnHeadX += aw;
  4042:       } else {  //縦2倍
  4043:         //横1倍,縦2倍
  4044:         int aw = n;  //横nビット→nドット
  4045:         int ah = 48;  //縦48ビット→96ドット
  4046:         aw = Math.min (aw, prnMarginRightX - prnHeadX);  //横awビット→awドット
  4047:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  4048:         int bi = prnCheckRect (    aw, 2 * ah);
  4049:         if (0 <= bi) {
  4050:           int ix = prnIncrementX;
  4051:           int iy = prnIncrementY;
  4052:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4053:             int i = bi;
  4054:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4055:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4056:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4057:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  4058:               }
  4059:               i +=     ix;
  4060:             }
  4061:             bi += 2 * iy;
  4062:           }
  4063:         } else {
  4064:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4065:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4066:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4067:                 prnPaintDot (    ax    , 2 * ay    );
  4068:                 prnPaintDot (    ax    , 2 * ay + 1);
  4069:               }
  4070:             }
  4071:           }
  4072:         }
  4073:         prnHeadX += aw;
  4074:       }  //if 縦1倍/縦2倍
  4075:     } else {  //横2倍
  4076:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  4077:         //横2倍,縦1倍
  4078:         int aw = n;  //横nビット→2*nドット
  4079:         int ah = 48;  //縦48ビット→48ドット
  4080:         aw = Math.min (2 * aw, prnMarginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  4081:         ah = Math.min (ah, prnContentBottomY - prnHeadY);  //縦ahビット→ahドット
  4082:         int bi = prnCheckRect (2 * aw,     ah);
  4083:         if (0 <= bi) {
  4084:           int ix = prnIncrementX;
  4085:           int iy = prnIncrementY;
  4086:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4087:             int i = bi;
  4088:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4089:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4090:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4091:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  4092:               }
  4093:               i += 2 * ix;
  4094:             }
  4095:             bi +=     iy;
  4096:           }
  4097:         } else {
  4098:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4099:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4100:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4101:                 prnPaintDot (2 * ax    ,     ay    );
  4102:                 prnPaintDot (2 * ax + 1,     ay    );
  4103:               }
  4104:             }
  4105:           }
  4106:         }
  4107:         prnHeadX += 2 * aw;
  4108:       } else {  //縦2倍
  4109:         //横2倍,縦2倍
  4110:         int aw = n;  //横nビット→2*nドット
  4111:         int ah = 24;  //縦48ビット→96ドット
  4112:         aw = Math.min (2 * aw, prnMarginRightX - prnHeadX) >> 1;  //横awビット→2*awドット
  4113:         ah = Math.min (2 * ah, prnContentBottomY - prnHeadY) >> 1;  //縦ahビット→2*ahドット
  4114:         int bi = prnCheckRect (2 * aw, 2 * ah);
  4115:         if (0 <= bi) {
  4116:           int ix = prnIncrementX;
  4117:           int iy = prnIncrementY;
  4118:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4119:             int i = bi;
  4120:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4121:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4122:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4123:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  4124:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  4125:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  4126:               }
  4127:               i += 2 * ix;
  4128:             }
  4129:             bi += 2 * iy;
  4130:           }
  4131:         } else {
  4132:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4133:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4134:               if ((a[o + 6 * ax + (ay >> 3)] >> (~ay & 7) & 1) != 0) {  //ビットがセットされている
  4135:                 prnPaintDot (2 * ax    , 2 * ay    );
  4136:                 prnPaintDot (2 * ax + 1, 2 * ay    );
  4137:                 prnPaintDot (2 * ax    , 2 * ay + 1);
  4138:                 prnPaintDot (2 * ax + 1, 2 * ay + 1);
  4139:               }
  4140:             }
  4141:           }
  4142:         }
  4143:         prnHeadX += 2 * aw;
  4144:       }  //if 縦1倍/縦2倍
  4145:     }  //if 横1倍/横2倍
  4146:     //印字あり
  4147:     prnPrinted = true;
  4148:     //キャンバスを再描画する
  4149:     if (prnCanvas != null) {
  4150:       prnCanvas.repaint ();
  4151:     }
  4152:   }  //prn48DotBitImage
  4153: 
  4154:   //prnRepeatCharacter (n, d)
  4155:   //  ESC N n1 n2 n3 d  連続文字  (p162)
  4156:   //  文字dをn回印字する
  4157:   //  制御コードは無視する
  4158:   public static void prnRepeatCharacter (int n, int d) {
  4159:     if (prnCurrentPaper == null) {  //未給紙のとき
  4160:       prnFeedPaper ();  //給紙する
  4161:     }
  4162:     if (0x20 <= d) {  //制御コードでない
  4163:       for (int i = 0; i < n; i++) {
  4164:         prnPrintCharacter (d);  //1文字印字
  4165:       }
  4166:     }
  4167:   }  //prnRepeatCharacter
  4168: 
  4169:   //prnSetSmallCharacterMode ()
  4170:   //  ESC Q  縮小文字設定  (p103)
  4171:   //  縮小文字(1/17[in])にする
  4172:   public static void prnSetSmallCharacterMode () {
  4173:     prnCharacterType = PRN_SMALL;  //縮小文字
  4174:   }  //prnSetSmallCharacterMode
  4175: 
  4176:   //prnSetPicaCharacterMode ()
  4177:   //  ESC R  パイカ文字設定  (p101)
  4178:   //  パイカ文字(1/10[in])にする
  4179:   //  https://en.wikipedia.org/wiki/Typewriter#Character_sizes
  4180:   public static void prnSetPicaCharacterMode () {
  4181:     prnCharacterType = PRN_PICA;  //パイカ文字
  4182:   }  //prnSetPicaCharacterMode
  4183: 
  4184:   //prnRepeat8DotBitImage (n, d)
  4185:   //  ESC V n1 n2 n3 n4 d  連続8ドットビットメージ  (p155)
  4186:   public static void prnRepeat8DotBitImage (int n, int d) {
  4187:     if (prnCurrentPaper == null) {  //未給紙のとき
  4188:       prnFeedPaper ();  //給紙する
  4189:     }
  4190:     //!!!
  4191:   }  //prnRepeat8DotBitImage
  4192: 
  4193:   //prnRepeat16DotBitImage (n, d)
  4194:   //  ESC W n1 n2 n3 n4 d1 d2  連続16ドットビットメージ  (p156)
  4195:   public static void prnRepeat16DotBitImage (int n, int d) {
  4196:     if (prnCurrentPaper == null) {  //未給紙のとき
  4197:       prnFeedPaper ();  //給紙する
  4198:     }
  4199:     //改行ピッチが15/120[in]のとき16/120[in]にする
  4200:     if (prnLineHeight == 45) {
  4201:       prnLineHeight = 48;
  4202:     }
  4203:     if (!prnHorizontalDoubleSizeMode) {  //横1倍
  4204:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  4205:         //横1倍,縦1倍
  4206:         int aw = n;  //横nビット→3*nドット
  4207:         int ah = 16;  //縦16ビット→48ドット
  4208:         aw = Math.min (3 * aw, prnMarginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  4209:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  4210:         int bi = prnCheckRect (3 * aw, 3 * ah);
  4211:         if (0 <= bi) {
  4212:           int ix = prnIncrementX;
  4213:           int iy = prnIncrementY;
  4214:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4215:             int i = bi;
  4216:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4217:               if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  4218:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4219:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  4220:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  4221:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  4222:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  4223:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  4224:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  4225:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  4226:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4227:               }
  4228:               i += 3 * ix;
  4229:             }
  4230:             bi += 3 * iy;
  4231:           }
  4232:         } else {
  4233:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4234:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4235:               if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  4236:                 prnPaintDot (3 * ax    , 3 * ay    );
  4237:                 prnPaintDot (3 * ax + 1, 3 * ay    );
  4238:                 prnPaintDot (3 * ax + 2, 3 * ay    );
  4239:                 prnPaintDot (3 * ax    , 3 * ay + 1);
  4240:                 prnPaintDot (3 * ax + 1, 3 * ay + 1);
  4241:                 prnPaintDot (3 * ax + 2, 3 * ay + 1);
  4242:                 prnPaintDot (3 * ax    , 3 * ay + 2);
  4243:                 prnPaintDot (3 * ax + 1, 3 * ay + 2);
  4244:                 prnPaintDot (3 * ax + 2, 3 * ay + 2);
  4245:               }
  4246:             }
  4247:           }
  4248:         }
  4249:         prnHeadX += 3 * aw;
  4250:       } else {  //縦2倍
  4251:         //横1倍,縦2倍
  4252:         int aw = n;  //横nビット→3*nドット
  4253:         int ah = 16;  //縦16ビット→96ドット
  4254:         aw = Math.min (3 * aw, prnMarginRightX - prnHeadX) / 3;  //横awビット→3*awドット
  4255:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  4256:         int bi = prnCheckRect (3 * aw, 6 * ah);
  4257:         if (0 <= bi) {
  4258:           int ix = prnIncrementX;
  4259:           int iy = prnIncrementY;
  4260:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4261:             int i = bi;
  4262:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4263:               if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  4264:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4265:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  4266:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  4267:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  4268:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  4269:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  4270:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  4271:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  4272:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4273:                 prnBitmap[i          + 3 * iy] &= (byte) prnCurrentColor;
  4274:                 prnBitmap[i +     ix + 3 * iy] &= (byte) prnCurrentColor;
  4275:                 prnBitmap[i + 2 * ix + 3 * iy] &= (byte) prnCurrentColor;
  4276:                 prnBitmap[i          + 4 * iy] &= (byte) prnCurrentColor;
  4277:                 prnBitmap[i +     ix + 4 * iy] &= (byte) prnCurrentColor;
  4278:                 prnBitmap[i + 2 * ix + 4 * iy] &= (byte) prnCurrentColor;
  4279:                 prnBitmap[i          + 5 * iy] &= (byte) prnCurrentColor;
  4280:                 prnBitmap[i +     ix + 5 * iy] &= (byte) prnCurrentColor;
  4281:                 prnBitmap[i + 2 * ix + 5 * iy] &= (byte) prnCurrentColor;
  4282:               }
  4283:               i += 3 * ix;
  4284:             }
  4285:             bi += 6 * iy;
  4286:           }
  4287:         } else {
  4288:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4289:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4290:               if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  4291:                 prnPaintDot (3 * ax    , 6 * ay    );
  4292:                 prnPaintDot (3 * ax + 1, 6 * ay    );
  4293:                 prnPaintDot (3 * ax + 2, 6 * ay    );
  4294:                 prnPaintDot (3 * ax    , 6 * ay + 1);
  4295:                 prnPaintDot (3 * ax + 1, 6 * ay + 1);
  4296:                 prnPaintDot (3 * ax + 2, 6 * ay + 1);
  4297:                 prnPaintDot (3 * ax    , 6 * ay + 2);
  4298:                 prnPaintDot (3 * ax + 1, 6 * ay + 2);
  4299:                 prnPaintDot (3 * ax + 2, 6 * ay + 2);
  4300:                 prnPaintDot (3 * ax    , 6 * ay + 3);
  4301:                 prnPaintDot (3 * ax + 1, 6 * ay + 3);
  4302:                 prnPaintDot (3 * ax + 2, 6 * ay + 3);
  4303:                 prnPaintDot (3 * ax    , 6 * ay + 4);
  4304:                 prnPaintDot (3 * ax + 1, 6 * ay + 4);
  4305:                 prnPaintDot (3 * ax + 2, 6 * ay + 4);
  4306:                 prnPaintDot (3 * ax    , 6 * ay + 5);
  4307:                 prnPaintDot (3 * ax + 1, 6 * ay + 5);
  4308:                 prnPaintDot (3 * ax + 2, 6 * ay + 5);
  4309:               }
  4310:             }
  4311:           }
  4312:         }
  4313:         prnHeadX += 3 * aw;
  4314:       }  //if 縦1倍/縦2倍
  4315:     } else {  //横2倍
  4316:       if (!prnVerticalDoubleSizeMode) {  //縦1倍
  4317:         //横2倍,縦1倍
  4318:         int aw = n;  //横nビット→6*nドット
  4319:         int ah = 16;  //縦16ビット→48ドット
  4320:         aw = Math.min (6 * aw, prnMarginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  4321:         ah = Math.min (3 * ah, prnContentBottomY - prnHeadY) / 3;  //縦ahビット→3*ahドット
  4322:         int bi = prnCheckRect (6 * aw, 3 * ah);
  4323:         if (0 <= bi) {
  4324:           int ix = prnIncrementX;
  4325:           int iy = prnIncrementY;
  4326:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4327:             int i = bi;
  4328:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4329:               if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  4330:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4331:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  4332:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  4333:                 prnBitmap[i + 3 * ix         ] &= (byte) prnCurrentColor;
  4334:                 prnBitmap[i + 4 * ix         ] &= (byte) prnCurrentColor;
  4335:                 prnBitmap[i + 5 * ix         ] &= (byte) prnCurrentColor;
  4336:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  4337:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  4338:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  4339:                 prnBitmap[i + 3 * ix +     iy] &= (byte) prnCurrentColor;
  4340:                 prnBitmap[i + 4 * ix +     iy] &= (byte) prnCurrentColor;
  4341:                 prnBitmap[i + 5 * ix +     iy] &= (byte) prnCurrentColor;
  4342:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  4343:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  4344:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4345:                 prnBitmap[i + 3 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4346:                 prnBitmap[i + 4 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4347:                 prnBitmap[i + 5 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4348:               }
  4349:               i += 6 * ix;
  4350:             }
  4351:             bi += 3 * iy;
  4352:           }
  4353:         } else {
  4354:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4355:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4356:               if ((d >> (~ay & 15) & 1) != 0) {  //ビットがセットされている
  4357:                 prnPaintDot (6 * ax    , 3 * ay    );
  4358:                 prnPaintDot (6 * ax + 1, 3 * ay    );
  4359:                 prnPaintDot (6 * ax + 2, 3 * ay    );
  4360:                 prnPaintDot (6 * ax + 3, 3 * ay    );
  4361:                 prnPaintDot (6 * ax + 4, 3 * ay    );
  4362:                 prnPaintDot (6 * ax + 5, 3 * ay    );
  4363:                 prnPaintDot (6 * ax    , 3 * ay + 1);
  4364:                 prnPaintDot (6 * ax + 1, 3 * ay + 1);
  4365:                 prnPaintDot (6 * ax + 2, 3 * ay + 1);
  4366:                 prnPaintDot (6 * ax + 3, 3 * ay + 1);
  4367:                 prnPaintDot (6 * ax + 4, 3 * ay + 1);
  4368:                 prnPaintDot (6 * ax + 5, 3 * ay + 1);
  4369:                 prnPaintDot (6 * ax    , 3 * ay + 2);
  4370:                 prnPaintDot (6 * ax + 1, 3 * ay + 2);
  4371:                 prnPaintDot (6 * ax + 2, 3 * ay + 2);
  4372:                 prnPaintDot (6 * ax + 3, 3 * ay + 2);
  4373:                 prnPaintDot (6 * ax + 4, 3 * ay + 2);
  4374:                 prnPaintDot (6 * ax + 5, 3 * ay + 2);
  4375:               }
  4376:             }
  4377:           }
  4378:         }
  4379:         prnHeadX += 6 * aw;
  4380:       } else {  //縦2倍
  4381:         //横2倍,縦2倍
  4382:         int aw = n;  //横nビット→6*nドット
  4383:         int ah = 16;  //縦16ビット→96ドット
  4384:         aw = Math.min (6 * aw, prnMarginRightX - prnHeadX) / 6;  //横awビット→6*awドット
  4385:         ah = Math.min (6 * ah, prnContentBottomY - prnHeadY) / 6;  //縦ahビット→6*ahドット
  4386:         int bi = prnCheckRect (6 * aw, 6 * ah);
  4387:         if (0 <= bi) {
  4388:           int ix = prnIncrementX;
  4389:           int iy = prnIncrementY;
  4390:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4391:             int i = bi;
  4392:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4393:               if ((short) (d << (ay & 15)) < 0) {  //ビットがセットされている
  4394:                 prnBitmap[i                  ] &= (byte) prnCurrentColor;
  4395:                 prnBitmap[i +     ix         ] &= (byte) prnCurrentColor;
  4396:                 prnBitmap[i + 2 * ix         ] &= (byte) prnCurrentColor;
  4397:                 prnBitmap[i + 3 * ix         ] &= (byte) prnCurrentColor;
  4398:                 prnBitmap[i + 4 * ix         ] &= (byte) prnCurrentColor;
  4399:                 prnBitmap[i + 5 * ix         ] &= (byte) prnCurrentColor;
  4400:                 prnBitmap[i          +     iy] &= (byte) prnCurrentColor;
  4401:                 prnBitmap[i +     ix +     iy] &= (byte) prnCurrentColor;
  4402:                 prnBitmap[i + 2 * ix +     iy] &= (byte) prnCurrentColor;
  4403:                 prnBitmap[i + 3 * ix +     iy] &= (byte) prnCurrentColor;
  4404:                 prnBitmap[i + 4 * ix +     iy] &= (byte) prnCurrentColor;
  4405:                 prnBitmap[i + 5 * ix +     iy] &= (byte) prnCurrentColor;
  4406:                 prnBitmap[i          + 2 * iy] &= (byte) prnCurrentColor;
  4407:                 prnBitmap[i +     ix + 2 * iy] &= (byte) prnCurrentColor;
  4408:                 prnBitmap[i + 2 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4409:                 prnBitmap[i + 3 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4410:                 prnBitmap[i + 4 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4411:                 prnBitmap[i + 5 * ix + 2 * iy] &= (byte) prnCurrentColor;
  4412:                 prnBitmap[i          + 3 * iy] &= (byte) prnCurrentColor;
  4413:                 prnBitmap[i +     ix + 3 * iy] &= (byte) prnCurrentColor;
  4414:                 prnBitmap[i + 2 * ix + 3 * iy] &= (byte) prnCurrentColor;
  4415:                 prnBitmap[i + 3 * ix + 3 * iy] &= (byte) prnCurrentColor;
  4416:                 prnBitmap[i + 4 * ix + 3 * iy] &= (byte) prnCurrentColor;
  4417:                 prnBitmap[i + 5 * ix + 3 * iy] &= (byte) prnCurrentColor;
  4418:                 prnBitmap[i          + 4 * iy] &= (byte) prnCurrentColor;
  4419:                 prnBitmap[i +     ix + 4 * iy] &= (byte) prnCurrentColor;
  4420:                 prnBitmap[i + 2 * ix + 4 * iy] &= (byte) prnCurrentColor;
  4421:                 prnBitmap[i + 3 * ix + 4 * iy] &= (byte) prnCurrentColor;
  4422:                 prnBitmap[i + 4 * ix + 4 * iy] &= (byte) prnCurrentColor;
  4423:                 prnBitmap[i + 5 * ix + 4 * iy] &= (byte) prnCurrentColor;
  4424:                 prnBitmap[i          + 5 * iy] &= (byte) prnCurrentColor;
  4425:                 prnBitmap[i +     ix + 5 * iy] &= (byte) prnCurrentColor;
  4426:                 prnBitmap[i + 2 * ix + 5 * iy] &= (byte) prnCurrentColor;
  4427:                 prnBitmap[i + 3 * ix + 5 * iy] &= (byte) prnCurrentColor;
  4428:                 prnBitmap[i + 4 * ix + 5 * iy] &= (byte) prnCurrentColor;
  4429:                 prnBitmap[i + 5 * ix + 5 * iy] &= (byte) prnCurrentColor;
  4430:               }
  4431:               i += 6 * ix;
  4432:             }
  4433:             bi += 6 * iy;
  4434:           }
  4435:         } else {
  4436:           for (int ay = 0; ay < ah; ay++) {  //縦ビット位置
  4437:             for (int ax = 0; ax < aw; ax++) {  //横ビット位置
  4438:               if ((short) (d << (ay & 15)) < 0) {  //ビットがセットされている
  4439:                 prnPaintDot (6 * ax    , 6 * ay    );
  4440:                 prnPaintDot (6 * ax + 1, 6 * ay    );
  4441:                 prnPaintDot (6 * ax + 2, 6 * ay    );
  4442:                 prnPaintDot (6 * ax + 3, 6 * ay    );
  4443:                 prnPaintDot (6 * ax + 4, 6 * ay    );
  4444:                 prnPaintDot (6 * ax + 5, 6 * ay    );
  4445:                 prnPaintDot (6 * ax    , 6 * ay + 1);
  4446:                 prnPaintDot (6 * ax + 1, 6 * ay + 1);
  4447:                 prnPaintDot (6 * ax + 2, 6 * ay + 1);
  4448:                 prnPaintDot (6 * ax + 3, 6 * ay + 1);
  4449:                 prnPaintDot (6 * ax + 4, 6 * ay + 1);
  4450:                 prnPaintDot (6 * ax + 5, 6 * ay + 1);
  4451:                 prnPaintDot (6 * ax    , 6 * ay + 2);
  4452:                 prnPaintDot (6 * ax + 1, 6 * ay + 2);
  4453:                 prnPaintDot (6 * ax + 2, 6 * ay + 2);
  4454:                 prnPaintDot (6 * ax + 3, 6 * ay + 2);
  4455:                 prnPaintDot (6 * ax + 4, 6 * ay + 2);
  4456:                 prnPaintDot (6 * ax + 5, 6 * ay + 2);
  4457:                 prnPaintDot (6 * ax    , 6 * ay + 3);
  4458:                 prnPaintDot (6 * ax + 1, 6 * ay + 3);
  4459:                 prnPaintDot (6 * ax + 2, 6 * ay + 3);
  4460:                 prnPaintDot (6 * ax + 3, 6 * ay + 3);
  4461:                 prnPaintDot (6 * ax + 4, 6 * ay + 3);
  4462:                 prnPaintDot (6 * ax + 5, 6 * ay + 3);
  4463:                 prnPaintDot (6 * ax    , 6 * ay + 4);
  4464:                 prnPaintDot (6 * ax + 1, 6 * ay + 4);
  4465:                 prnPaintDot (6 * ax + 2, 6 * ay + 4);
  4466:                 prnPaintDot (6 * ax + 3, 6 * ay + 4);
  4467:                 prnPaintDot (6 * ax + 4, 6 * ay + 4);
  4468:                 prnPaintDot (6 * ax + 5, 6 * ay + 4);
  4469:                 prnPaintDot (6 * ax    , 6 * ay + 5);
  4470:                 prnPaintDot (6 * ax + 1, 6 * ay + 5);
  4471:                 prnPaintDot (6 * ax + 2, 6 * ay + 5);
  4472:                 prnPaintDot (6 * ax + 3, 6 * ay + 5);
  4473:                 prnPaintDot (6 * ax + 4, 6 * ay + 5);
  4474:                 prnPaintDot (6 * ax + 5, 6 * ay + 5);
  4475:               }
  4476:             }
  4477:           }
  4478:         }
  4479:         prnHeadX += 6 * aw;
  4480:       }  //if 縦1倍/縦2倍
  4481:     }  //if 横1倍/横2倍
  4482:     //印字あり
  4483:     prnPrinted = true;
  4484:     //キャンバスを再描画する
  4485:     if (prnCanvas != null) {
  4486:       prnCanvas.repaint ();
  4487:     }
  4488:   }  //prnRepeat16DotBitImage
  4489: 
  4490:   //prnSetUnderlineMode (b)
  4491:   //  b  true   ESC X  アンダーラインあり  (p114)
  4492:   //     false  ESC Y  アンダーラインなし  (p115)
  4493:   public static void prnSetUnderlineMode (boolean b) {
  4494:     prnUnderlineMode = b;
  4495:   }  //prnSetUnderlineMode
  4496: 
  4497:   //prnHorizontalMove (n)
  4498:   //  ESC \\ n1 n2  水平移動  (p99)
  4499:   //  ESC n  ドットスペース  (p123)
  4500:   //  水平方向にn/180[in]移動する
  4501:   //  -1440<=n<=1440
  4502:   public static void prnHorizontalMove (int n) {
  4503:     if (prnCurrentPaper == null) {  //未給紙のとき
  4504:       prnFeedPaper ();  //給紙する
  4505:     }
  4506:     if (-1440 <= n && n <= 1440) {
  4507:       int headX = prnHeadX + 2 * n;
  4508:       if (prnMarginLeftX <= headX && headX < prnMarginRightX) {
  4509:         prnHeadX = headX;
  4510:       }
  4511:     }
  4512:   }  //prnHorizontalMove
  4513: 
  4514:   //prnResetSettings ()
  4515:   //  ESC c 1  設定リセット  (p157)
  4516:   public static void prnResetSettings () {
  4517:     prnEjectPaper ();  //排紙する
  4518:     //マージン
  4519:     prnMarginLeftX = 0;
  4520:     prnMarginRightX = 2879;
  4521:     prnMarginBottomHeight = 0;
  4522:     //改行ピッチ
  4523:     prnDefaultLineHeight = 60;  //1/6[in]改行
  4524:     prnLineHeight = 60;  //1/6[in]改行
  4525:     //文字種
  4526:     prnCharacterType = PRN_PICA;  //パイカ
  4527:     //ひらがなモード
  4528:     prnHiraganaMode = false;  //カタカナ
  4529:     //スクリプトモード
  4530:     prnScriptMode = PRN_NO_SCRIPT;  //スクリプト解除
  4531:     //強調モード
  4532:     prnStrongMode = false;  //強調OFF
  4533:     //アンダーラインモード
  4534:     prnUnderlineMode = false;  //アンダーラインOFF
  4535:     //文字スタイル
  4536:     prnCharacterStyle = PRN_NORMAL_STYLE;  //標準文字
  4537:     //漢字モード
  4538:     prnKanjiMode = false;  //漢字モードOFF
  4539:     //外字データ
  4540:     if (prnGaijiData != null) {
  4541:       Arrays.fill (prnGaijiData, (byte) 0);
  4542:     }
  4543:     //縦書きモード
  4544:     prnVerticalWritingMode = false;  //横書き
  4545:     //左右スペース
  4546:     prnFullWidthLeftSpace = 2;  //全角左スペース[dot]
  4547:     prnFullWidthRightSpace = 6;  //全角右スペース[dot]
  4548:     prnHalfWidthLeftSpace = 0;  //半角左スペース[dot]
  4549:     prnHalfWidthRightSpace = 4;  //半角右スペース[dot]
  4550:     //横2倍モード
  4551:     prnHorizontalDoubleSizeMode = false;  //横2倍OFF
  4552:     prnVerticalDoubleSizeMode = false;  //縦2倍OFF
  4553:     prnKanjiHorizontalDoubleSizeMode = false;  //漢字横2倍OFF
  4554:     //水平タブ
  4555:     for (int k = 0; k < PRN_HORIZONTAL_ANCHOR_LIMIT; k++) {
  4556:       prnHorizontalTabAnchor[k] = 36 * 8 * (1 + k);
  4557:     }
  4558:     //垂直タブ
  4559:     for (int k = 0; k < PRN_VERTICAL_ANCHOR_LIMIT; k++) {
  4560:       prnVerticalTabAnchor[k] = 0;
  4561:     }
  4562:     //カラーモード
  4563:     prnColorMode = false;  //単色モード
  4564:     //書体
  4565:     prnHalfWidthFont =
  4566:       prnFullWidthFont = (prnDIPSW & PRN_DIPSW_FONT_STYLE) == 0 ? 0 : 1;
  4567:     //色
  4568:     prnCurrentColor = prnSingleColor;
  4569:     //コマンドバッファ
  4570:     prnCommandLength = 1;
  4571:     prnCommandPointer = 0;
  4572:   }  //prnResetSettings
  4573: 
  4574:   //prnSetHalfWidthFont (n)
  4575:   //  半角書体
  4576:   //  n  0  ローマン体
  4577:   //     1  サンセリフ体
  4578:   public static void prnSetHalfWidthFont (int n) {
  4579:     if (0 <= n && n <= 1) {
  4580:       prnHalfWidthFont = n;
  4581:     }
  4582:   }  //prnSetHalfWidthFont
  4583: 
  4584:   //prnSenseOutOfPaper (b)
  4585:   //  b  true   ESC p 1  用紙切れ検出有効  (p161)
  4586:   //     false  ESC p 0  用紙切れ検出無効  (p160)
  4587:   //  用紙切れ検出無効のときは用紙の下端から約12[mm]、有効のときは約60[mm]でディセレクトになる
  4588:   public static void prnSenseOutOfPaper (boolean b) {
  4589:     //!!!
  4590:   }  //prnSenseOutOfPaper
  4591: 
  4592:   //prnSetCharacterStyle (n)
  4593:   //  ESC q n  文字スタイル設定  (p116)
  4594:   //  n  0  標準文字
  4595:   //     1  袋文字
  4596:   //     2  影文字
  4597:   //     3  袋影文字
  4598:   public static void prnSetCharacterStyle (int n) {
  4599:     if (0 <= n && n <= 3) {
  4600:       prnCharacterStyle = n;
  4601:     }
  4602:   }  //prnSetCharacterStyle
  4603: 
  4604:   //prnSetScriptMode (n)
  4605:   //  n  0  ESC s 0  スクリプト解除  (p113)
  4606:   //     1  ESC s 1  スーパースクリプト設定  (p111)
  4607:   //     2  ESC s 2  サブスクリプト設定  (p112)
  4608:   public static void prnSetScriptMode (int n) {
  4609:     if (0 <= n && n <= 2) {
  4610:       prnScriptMode = n;
  4611:     }
  4612:   }  //prnSetScriptMode
  4613: 
  4614:   //prnSetVerticalWritingMode (b)
  4615:   //  b  true   FS J  縦書き  (p128)
  4616:   //     false  FS K  横書き  (p131)
  4617:   public static void prnSetVerticalWritingMode (boolean b) {
  4618:     prnVerticalWritingMode = b;
  4619:   }  //prnSetVerticalWritingMode
  4620: 
  4621:   //prnSetFullWidthLeftRightSpace (l, r)
  4622:   //  FS S n1 n2  全角左右スペース  (p124)
  4623:   public static void prnSetFullWidthLeftRightSpace (int l, int r) {
  4624:     prnFullWidthLeftSpace = l;
  4625:     prnFullWidthRightSpace = r;
  4626:   }  //prnSetFullWidthLeftRightSpace
  4627: 
  4628:   //prnSetHalfWidthLeftRightSpace (l, r)
  4629:   //  FS T n1 n2  半角左右スペース  (p126)
  4630:   public static void prnSetHalfWidthLeftRightSpace (int l, int r) {
  4631:     prnHalfWidthLeftSpace = l;
  4632:     prnHalfWidthRightSpace = r;
  4633:   }  //prnSetHalfWidthLeftRightSpace
  4634: 
  4635:   //prnSetFullWidthFont (n)
  4636:   //  全角書体
  4637:   //  n  0  明朝体
  4638:   //     1  ゴシック体
  4639:   public static void prnSetFullWidthFont (int n) {
  4640:     if (0 <= n && n <= 1) {
  4641:       prnFullWidthFont = n;
  4642:     }
  4643:   }  //prnSetFullWidthFont
  4644: 
  4645:   //prnSetKanjiHorizontalDoubleSizeMode (b)
  4646:   //  b  true   FS p  漢字横2倍ON  (p132)
  4647:   //     false  FS q  漢字横2倍OFF  (p133)
  4648:   public static void prnSetKanjiHorizontalDoubleSizeMode (boolean b) {
  4649:     prnKanjiHorizontalDoubleSizeMode = b;
  4650:   }  //prnSetKanjiHorizontalDoubleSizeMode
  4651: 
  4652: 
  4653: 
  4654:   //bi = prnCheckRect (rw, rh)
  4655:   //  矩形は印字可能範囲内か
  4656:   //  bi  印字可能範囲内のとき左上のビットマップインデックス。-1=印字可能範囲内ではない
  4657:   //  rw  矩形の幅
  4658:   //  rh  矩形の高さ
  4659:   public static int prnCheckRect (int rw, int rh) {
  4660:     int px0 = prnAliveLeftX + prnHeadX;  //左上の用紙座標
  4661:     int py0 = prnAliveTopY + prnHeadY;
  4662:     int px1 = px0 + rw - 1;  //右下の用紙座標
  4663:     int py1 = py0 + rh - 1;
  4664:     int bx0 = prnM11 * px0 + prnM12 * py0 + prnM13;  //左上のビットマップ座標
  4665:     int by0 = prnM21 * px0 + prnM22 * py0 + prnM23;
  4666:     int bx1 = prnM11 * px1 + prnM12 * py1 + prnM13;  //右下のビットマップ座標
  4667:     int by1 = prnM21 * px1 + prnM22 * py1 + prnM23;
  4668:     return (0 <= bx0 && bx0 < prnRotatedWidthDot &&
  4669:             0 <= by0 && by0 < prnRotatedHeightDot &&
  4670:             0 <= bx1 && bx1 < prnRotatedWidthDot &&
  4671:             0 <= by1 && by1 < prnRotatedHeightDot ?  //印字可能範囲内
  4672:             bx0 + prnRotatedWidthDot * by0 :  //左上のビットマップインデックス
  4673:             -1);
  4674:   }  //prnCheckRect
  4675: 
  4676:   //prnPaintDot (rx, ry)
  4677:   //  1ドット塗る
  4678:   //  rx  ヘッド座標
  4679:   //  ry
  4680:   public static void prnPaintDot (int rx, int ry) {
  4681:     int px = prnAliveLeftX + prnHeadX + rx;  //用紙座標
  4682:     int py = prnAliveTopY + prnHeadY + ry;
  4683:     int bx = prnM11 * px + prnM12 * py + prnM13;  //ビットマップ座標
  4684:     int by = prnM21 * px + prnM22 * py + prnM23;
  4685:     if (0 <= bx && bx < prnRotatedWidthDot &&
  4686:         0 <= by && by < prnRotatedHeightDot) {  //印字可能範囲内
  4687:       prnBitmap[bx + prnRotatedWidthDot * by] &= (byte) prnCurrentColor;  //ANDで描く
  4688:     }
  4689:   }  //prnPaintDot
  4690: 
  4691: 
  4692: 
  4693:   //success = prnSave ()
  4694:   //  保存
  4695:   public static boolean prnSave () {
  4696:     //ImageWriterを探す
  4697:     //  参考
  4698:     //    http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
  4699:     //    http://docs.oracle.com/javase/8/docs/api/javax/imageio/metadata/doc-files/standard_metadata.html
  4700:     int index = prnSaveName.lastIndexOf ('.');
  4701:     if (index < 0) {  //拡張子がないとき
  4702:       prnSaveName += ".png";  //pngにする
  4703:       index = prnSaveName.lastIndexOf ('.');
  4704:     }
  4705:     String full = prnSavePath + File.separator + prnSaveName;  //フルパスのファイル名
  4706:     File imageFile = new File (full);
  4707:     if (imageFile.isFile ()) {  //既に存在するとき
  4708:       //ファイルが既に存在するとき読み取り専用属性が付いていないことを確認する
  4709:       //  Windows10のエクスプローラの読み取り専用属性は保護機能ではないので無視して上書きできる
  4710:       //  canWrite()は読み取り専用属性が付いているとfalseを返す
  4711:       //  ファイルが存在するときcanWrite()がtrueでなければ上書きしてはならない
  4712:       //  canWrite()は「存在して書き込める」なので!canWrite()は「存在しないか書き込めない」であることに注意
  4713:       if (!imageFile.canWrite ()) {  //既に存在するが書き込めないとき
  4714:         JOptionPane.showMessageDialog (
  4715:           null,
  4716:           full + (Multilingual.mlnJapanese ?
  4717:                   "\nは既に存在します。上書きできません。" :
  4718:                   "\nalreay exists. You cannot overwrite it."));
  4719:         return false;
  4720:       }
  4721:       //上書きしてよいか確認する
  4722:       if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog (
  4723:         null,
  4724:         full + (Multilingual.mlnJapanese ?
  4725:                 "\nは既に存在します。上書きしますか?" :
  4726:                 "\nalreay exists. Do you want to overwrite it?"),
  4727:         Multilingual.mlnJapanese ? "ファイルの上書きの確認" : "Confirmation of overwriting file",
  4728:         JOptionPane.YES_NO_OPTION,
  4729:         JOptionPane.PLAIN_MESSAGE)) {
  4730:         return false;
  4731:       }
  4732:     }
  4733:     for (Iterator<ImageWriter> iterator = ImageIO.getImageWritersBySuffix (prnSaveName.substring (index + 1));
  4734:          //拡張子に対応するImageWriterがないときは空のIteratorを返すのでiteratorはnullにならない
  4735:          iterator.hasNext (); ) {
  4736:       ImageWriter imageWriter = iterator.next ();
  4737:       ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam ();
  4738:       if (false) {
  4739:         if (imageWriteParam.canWriteCompressed ()) {
  4740:           imageWriteParam.setCompressionMode (ImageWriteParam.MODE_EXPLICIT);
  4741:           imageWriteParam.setCompressionQuality (0.75F);
  4742:         }
  4743:       }
  4744:       IIOMetadata imageMetadata = imageWriter.getDefaultImageMetadata (
  4745:         ImageTypeSpecifier.createFromBufferedImageType (prnImage.getType ()),
  4746:         imageWriteParam);
  4747:       if (imageMetadata.isStandardMetadataFormatSupported ()) {
  4748:         //解像度を設定する
  4749:         //  PNGファイルの仕様では解像度の単位は[dot/m]だが
  4750:         //  javax_imageio_1.0のHorizontalPixelSizeとVerticalPixelSizeの単位は[dot/mm]なので
  4751:         //    360[dot/in] → 360/25.4[dot/mm]
  4752:         //  とする
  4753:         //  これを[dot/m]にしてしまうとペイントのプロパティで360000 DPIなどと表示されておかしなことになる
  4754:         IIOMetadataNode rootNode = new IIOMetadataNode ("javax_imageio_1.0");
  4755:         IIOMetadataNode dimensionNode = new IIOMetadataNode ("Dimension");
  4756:         IIOMetadataNode horizontalPixelSizeNode = new IIOMetadataNode("HorizontalPixelSize");
  4757:         IIOMetadataNode verticalPixelSizeNode = new IIOMetadataNode ("VerticalPixelSize");
  4758:         horizontalPixelSizeNode.setAttribute ("value", String.valueOf (360.0 / 25.4));
  4759:         verticalPixelSizeNode.setAttribute ("value", String.valueOf (360.0 / 25.4));
  4760:         dimensionNode.appendChild (horizontalPixelSizeNode);
  4761:         dimensionNode.appendChild (verticalPixelSizeNode);
  4762:         rootNode.appendChild (dimensionNode);
  4763:         try {
  4764:           imageMetadata.mergeTree ("javax_imageio_1.0", rootNode);
  4765:         } catch (IIOInvalidTreeException iioite) {
  4766:           continue;
  4767:         }
  4768:         imageFile.delete ();
  4769:         try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream (imageFile)) {
  4770:           imageWriter.setOutput (imageOutputStream);
  4771:           imageWriter.write (imageMetadata, new IIOImage (prnImage, null, imageMetadata), imageWriteParam);
  4772:         } catch (IOException ioe) {
  4773:           continue;
  4774:         }
  4775:         return true;
  4776:       }
  4777:     }  //for iterator
  4778:     JOptionPane.showMessageDialog (
  4779:       null,
  4780:       full + (Multilingual.mlnJapanese ?
  4781:               "\nを更新できませんでした。" :
  4782:               "\nwas not updated")
  4783:       );
  4784:     return false;
  4785:   }  //prnSave
  4786: 
  4787: 
  4788: 
  4789: }  //class PrinterPort
  4790: 
  4791: 
  4792: