◆注意事項

EPUBファイルの閲覧には、各種の電子書籍ビューア（EPUBビューア）を利用して下さい。表示テストに関しては、「Windows (Ver. 11)」の環境下で、以下の電子書籍ビューアで、正常に表示されることを確認しました。読み込ませる電子書籍データとしては、文字コードに「UTF-8」を用いた『思考方法概論』の第30版を使用しました。また、文字コードに「UTF-8」を用いた『Java 実例 プログラミング　描画処理編』の第10版でも、同様の結果になります。
１．「Calibre (Ver. 8.13)」：「UTF-8」で表示可能
２．「Adobe Digital Editions (Ver. 4.5.12.112)」：「UTF-8」で表示可能
３．「SumatraPDF (Ver. 3.6.16779)」：「UTF-8」で表示可能
４．「Icecream Ebook Reader (Ver. 6.49)」：「UTF-8」で表示可能
因みに、文字コードに「UTF-16」を用いた『思考方法概論』の第29版を上記四種類の電子書籍ビューアで表示させたところ、以下の結果を得ました。
１．「Calibre (Ver. 8.13)」：「UTF-16」で表示可能
２．「Adobe Digital Editions (Ver. 4.5.12.112)」：「UTF-16」で表示不能
３．「SumatraPDF (Ver. 3.6.16779)」：「UTF-16」で表示可能
４．「Icecream Ebook Reader (Ver. 6.49)」：「UTF-16」で表示不能
なお、それぞれの使い勝手は、かなりの違いがありますので、自分に合ったものを選んで下さい。今後、推奨する電子書籍ビューアは、使い勝手が良いと感じる「Calibre」および「Adobe Digital Editions」です。「SumatraPDF」と「Icecream Ebook Reader」とに関しては、使用経験が乏しく、基本的な表示テストをしただけです。なお、「Calibre」の古いバージョン（Ver.7以前）は、プログラムの起動が一貫して非常に低速なため、高速化された最新バージョン（Ver.8以降）を用いて下さい。ただし、「Calibre」（Ver.8）でも、多彩なファイル形式変換機能搭載のためか、最初の起動だけは、まだ相当に低速で、二回目以降の起動が、高速になります。上記の電子書籍ビューア（EPUBビューア）以外では、表示テストを行なっていないため、表示の正常性を確認できていません。なお、『思考方法概論』に限っては、第29版以前は、EPUBファイルのサイズを少しでも小さくする目的で、EPUBに「UTF-16」の文字コードを用いていましたが、第30版以降は、サイズの膨張を覚悟の上で「UTF-8」に変更し、「Adobe Digital Editions」など幅広い電子書籍ビューアで閲覧できるようにしました。第29版以前は、「Calibre」のみを推奨する電子書籍ビューアに指定していました。そもそも、EPUBの規約では、「UTF-8」または「UTF-16」が使用可能とされ、どちらかの文字コードをEPUBファイルの中で指定することになっていますが、「UTF-8」の使用が推奨されているため、現状の電子書籍ビューアは、「UTF-8」にしか対応していないものが少なくないようです。コンピューターやソフトウェアの業界では、公式の国際規格に合致しているかよりも、デファクト・スタンダードに合致しているかが重要になることがあります。

筆者執筆発行の電子書籍の閲覧に関し、推奨する電子書籍ビューアは、以下の通りです。
『思考方法概論』第29版以前のEPUB：「Calibre」
『思考方法概論』第30版以降のEPUB：「Calibre」または「Adobe Digital Editions」
『Java 実例 プログラミング　描画処理編』第9版以前のEPUB：「Calibre」
『Java 実例 プログラミング　描画処理編』第10版以降のEPUB：「Calibre」または「Adobe Digital Editions」
『Java 実例 プログラミング　事務処理編』第1版のEPUB：「Calibre」または「Adobe Digital Editions」

◆はじめに

▲本書の内容

本書『Java 実例 プログラミング』「描画処理編」（第十版）は、プログラムの実例ソース・コードを提示し、その具体的方法を解説する「Javaプログラミング解説書」（中級者対象）です。ただし、Javaの言語としての文法規則の説明は、省略しています。Javaに関しての基本的知識が、読者に既にあるものとします。姉妹編の『Java 実例 プログラミング』「事務処理編」（初級者対象）と比べて、それなりに複雑長大なプログラムになっています。 Javaプログラミングの方法解説に際し、著者が開発した実際に動く描画プログラム（GCreator：ジークリエイター）をソース・コードの形で公開し、そのソース・コード内の大量の注釈文によって、プログラミング・テクニックを実践的に解説する形式とします。そのため、日本語の注釈文を埋め込んだソース・コードを読んでいただくことになります。

描画プログラム「GCreator」がユーザーに提供する機能は、「線描画機能」（面描画を含む）、「点描画機能」（スプレー機能を含む）、「模様自動生成機能」（マトリックス・パターン自動生成機能を含む）、この三種類です。線描画機能、点描画機能、模様自動生成機能、いずれの機能に関しても、機能充実によって実用水準に達しています。本書（第十版）で公開するプログラム（GCreator Ver.4.1）は、旧バージョン（Ver.4.0）との比較で、既存画像からの「輪郭線抽出機能」および既存画像の「畳み込み機能（鮮鋭化、朦朧化）」が追加されました。これ以外でも、機能補足や機能拡張が若干行なわれています。特に、スプライン曲線に関する追加補助機能が、利便性向上に寄与しています。

「GCreator」は、新規画像を生成する「描画」を目的としたプログラムであり、既存画像（写真など）に対する「補正」を主たる目的とはしないため、「画像補正」に関わる機能は、「描画」に関わる過程で必要となる基本的で補助的なものに限定しています。なお、本書（第十版）の表紙意匠は、「GCreator Ver.4.1」によって作成しました。「GCreator」にどれだけの描画表現力があるかについては、「GCreator」によって作成した本書の表紙（別途、各種作例画像も掲載）を御覧下さい。また、筆者のホームページでは、高精細の画像作例を多数掲載しています。

スプライン曲線アルゴリズムに関しては、奥村晴彦および他七名共著『Javaによるアルゴリズム事典』の「スプライン補間」の項目（技術評論社刊）を参照し利用しました。単に曲線を描画するだけでなく、トーン・カーブ式調色機能でも、このスプライン補間のアルゴリズムを活用しています。『Javaによるアルゴリズム事典』の著者諸氏（奥村晴彦氏、首藤一幸氏、杉浦方紀氏、土村展之氏、津留和生氏、細田隆之氏、松井吉光氏、光成滋生氏）の事典編纂およびその公刊による学術貢献に対し、謝意を表します。また、『Javaによるアルゴリズム事典』の「スプライン補間」の項目の末尾では、参考文献として、市田浩三、吉本富士市、共著『スプライン関数とその応用』（教育出版刊）が掲載されていますが、この文献は、参照できませんでした。『スプライン関数とその応用』では、「Java」ではなく、「FORTRAN」によるスプライン関数プログラム実装例の提示がなされているようです。

「GCreator Ver.4.1」が想定する用途は、ブック・カバー・デザイン、ポスター・デザイン、ウォール・ペーパー・デザイン、ラッピング・ペーパー・デザイン、テキスタイル・デザイン、パッチワーク・デザイン、ステンドグラス・デザイン、エクステリア・デザイン、ロゴマーク・デザイン、シンボルマーク・デザイン、その他、デコラティブ・アート（装飾芸術）分野の各種デザイン（意匠製作、意匠試作）です。簡単な製図（設計図作成）の用途でも、利用できます。様々な用途に耐えられるように多機能を目指していますが、それでも不足や未熟やバグが潜んでいることでしょう。不足や未熟やバグの対処に関しては、Javaを使いこなせる読者諸氏による独自の機能充実（独自改造）に委ねることとします。「GCreator Ver.4.1」は、Javaの基礎知識を有するユーザーによって、独自改造されることを想定した基礎的なプログラムです。

本書が扱う内容は、具体的なプログラミング（アプリケーション作成）の基本的技法であって、グラフィックスを操作するものです。さらに具体的に言えば、「Swing」を用いて操作画面を構築し、「Java 2D」を用いて任意画像（二次元画像）の作成を行ないます。ただし、基本機能としては、ドローウィング（ペンによる製図タイプ）であって、ペインティング（絵筆による絵画タイプ）ではありませんが、スプレー機能の追加（GCreator Ver.3.4の段階）で、ペインティングの機能要素を部分的に実現しました。

直線や曲線による描画、文字列の描画、長方形や真円（楕円）や自由図形による描画（内部彩色可能）、点描画機能、模様自動生成、これらの機能を組み合わせて描画（デコラティブ・アート）を実現するものです。なお、拡張子が「bmp」や「gif」や「jpeg」や「png」の画像を取り込んで、その画像に加工変形を加える操作も含みます。さらに、画像の背景透明化（スタンプ機能）、画像の切り貼り（マルチ・マスクおよびカット・アンド・ペースト機能）、指定色の色修正（カラー・チェンジ機能）、画像の階調表現加工（線形グラデーション加工）、ソフト・フォーカス加工、色彩の混色（パレット機能）、画像の印刷（プリント・アウト）、そして、比較的最近追加した新機能として、画像の部分切り取り保存（CutAndSaveImage命令）、画像の鏡像反転（ReverseImage命令）、複数指定色の連続色修正（ChangeColorMulti命令）、スプライン曲線描画、輪郭線内部彩色機能、スプレー描画機能、トーン・カーブ式調色機能、などがあります。さらに、これら以外にも各種特殊画像処理を含んでいて、機能多彩です。「GCreator」が実装している「命令仕様」については、マニュアル（GCreator_Manual.txt）を参照して下さい。また、使い方は、「メニュー」にある「見本」やマウス操作による各種機能を参考にし実験して下さい。トーン・カーブ式調色機能だけは、その機能的特殊性により、その命令文書を「見本」として例示できませんので、「原画」や「調色」や「終了」のボタン操作を実際に行ない、その操作方法を試行錯誤的に習得するしかありません。

本書が提供する描画プログラム「GCreator」は、言わば「描画インタープリター」（あるいは「描画スクリプト言語実行環境」）と呼ぶべきものであり、しかも、マウス操作によってメニューから描画機能（直線描画機能など各種あり）を選び、起点と終点（場合により中間点もあり）とをマウス・クリックするなどで、描画命令（スクリプト言語に相当）を自動的に生成し、この描画命令を複数行書き上げ、必要に応じて数値の修正（キーボードまたはマウスでの修正）を加えた上で、「描画」ボタンを押すことで、これら命令全行を逐次解析し、解析結果をJavaの機能（主に「Java 2D」）によって画像として実現するものです。マウス・クリックは、基本的に左ボタン・クリックですが、「自由図形」の描画や「スプライン曲線」や「折れ線」の描画では、右ボタン・クリックも併用します。命令文にシンタックス・エラー（文法間違い）があれば、エラーの種類をユーザーに告知する機能もあります。

線描画機能での描画命令は、マウス操作で自動生成され、JTextAreaに表示されると同時に、解析され実行されます。例えば、「DrawLine(200, 300, 500, 600);」の命令文1行で、ある座標点（x:200, y:300）から別の座標点（x:500, y:600）まで、自動的に直線が描画されます。この命令文は、マウスの操作で自動生成されるだけでなく、キーボードの操作で手作業入力（手作業修正）することも出来、「描画」ボタンで解析され実行されます。画像表示を見て、座標位置が不適切であれば、キーボード操作で文字（座標数値）を修正するか、マウス操作で位置修正（命令文の自動書き換え）を実行します。だが、これら諸機能は、Javaに付属する機能を分かりやすくし使いやすくする形で「通訳」の機能を果たしているだけであって、「インタープリター」らしく振る舞う機能を実現しているだけです。正確に言えば、「インタープリター」として、書かれた命令の順序で実行しているわけではなく、命令文の全部を一度に読み込み、それから命令の種類で分類整理し、このプログラムの趣旨に合うように、実行順序を組み替えて実行しています。

模様自動生成機能は、マウス操作によらず、JTextAreaへのキーボードによる手作業で、模様生成命令（模様番号指定）を数行記述することによって行ないます。なお、模様データは、ファイル「GCreator_Pattern.txt」に「CSV」形式で多種類が記録されていて、テキスト・エディタによって、容易に追加や変更ができます。「描画」ボタンまたは「乱数」ボタンを押すことで、模様が自動的に画面に描画されます。模様生成命令の引数を書き換えることで、微妙な模様配置変更を行ない、「乱数」ボタンの連打で、配色自動変更の作業を行ない、気に入った配色になった時点で、画像のファイル保存を行なう手順となります。メニューの「見本」から各種見本命令文書を選ぶことで、描画命令文書を表示しながら、必要に応じ「描画」または「乱数」ボタンを押し、描画を試すことができます。見本の命令文書は、命令（メソッド）の引数を書き換えることで、画像の変更処理も試せます。

著者が開発した描画プログラム「GCreator」は、ソース・コードの形で提供されるため、読者によって私的に機能拡張し私的に利用することができます。なお、そのプログラム（無改造または改造済み）で作成された画像は、模倣ではなく独自の創作的意匠となって自己完結していることを条件に、その画像を新たな著作物と見なし、営利か非営利かを問わず、法令や良識に従う限り、その利用を画像著作者の自由とします。ソース・コードは、機能別に別ファイルに分割されているため、理解しやすく整理されています。ただし、「GCreatorCanvasEngine.java」は、細かく分割しないままで、長大なコードになっています。大量の説明コメントが、ソース・コードに埋め込まれているため、Javaの基本的知識さえあれば、誰でも理解可能です。もし、理解しにくい部分があれば、「とにかく、そのような手続きで上手く行くのだ。」と理解するしかありません。

Javaプログラミングに関しては、その難しさの本質が、付属のライブラリー（プログラム部品集）の膨大さにあり、そのブラック・ボックスの内部構造の難解さにあります。しかし、この付属ライブラリーがなければ、プログラミングがもっと困難になります。プログラミングは、プラモデルの組み立てと同じで、既製部品を使って完成品を組み立てるのが基本作業です。適当な部品がない場合だけ、部品作りから自分で行なうことになります。部品作りを大幅に省略できる点で、ライブラリーは、極めて偉大です。

Javaの文法規則は、それほど膨大でも難解でもないものの、JDK付属ライブラリーに関しては、全貌を見渡せないほどに膨大かつ難解（ブラック・ボックス）です。そのため、付属ライブラリーは、誰でもそうですが、当面使用するものから順に、少しづつ理解を積み上げていくことになります。ブラック・ボックスは、その内部構造を詳細に知ろうとしても、その趣旨からして困難で、その外形的な使い方を知るだけで満足するしかありません。そのため、ライブラリーの使い方のパターンを機械的に憶えることも、ブラック・ボックス的理解の一つであって、ブラック・ボックスの内部にまで深く踏み込むのは、上級者の範囲になります。なお、「GCreator」は、JDKに付属するランタイム・ライブラリー（実行形式のライブラリー）しか使用せず、サード・パーティー製のランタイム・ライブラリーは、使用しません。

▲本書の構成

本書は、第一部の「解説編」と第二部の「ソース・コード編」との二部構成です。

「解説編」では、「GCreator」の機能説明や使用法説明を概略的に行ないます。「解説編」では、「GCreator」の稼働状態をスクリーン・ショットしたものを挿絵に用います。どんな画像が生成されるのか、具体例で、ひと目で分かるようにします。ただし、解説それ自体は、至って簡素なもので、必要最小限とします。詳しい解説は、ソース・コード内にコメント（注釈）として埋め込んでいます。つまり、既にJavaに関する基礎知識のある読者は、ソース・コードを読むことにより、解説も読む形になるわけです。

「ソース・コード編」では、必要なソース・コードの全部を公開します。ソース・コード以外に「GCreator_Manual.txt」も添付していますが、この機能解説書（コマンド仕様書）であるテキスト・ファイルは、プログラムの内部から参照され使用される必須のデータ・ファイルであって、これもプログラムの稼働に必要なものです。メニューの「ヘルプ」の「命令仕様書」を押すことで、「GCreator_Manual.txt」の内容がポップアップ表示されます。また、他にも模様生成のためのパターン・データ・ファイルもあり、「GCreator_Pattern.txt」として用意されています。これも、「ヘルプ」から参照できます。

ソース・コードの中に、個別具体的な解説をコメント形式で解説する方法を採用しているため、「ソース・コード編」では、ソース・コードの中以外に、詳しい解説はありません。ソース・コードの所定位置で、その場にふさわしい解説を行ないますので、ソース・コードを丹念に読んでください。ソース・コードは、トリッキーな書き方やテクニカルな書き方を一切していません。最も基本的で分かりやすい方法により、記述効率が悪かろうと、愚直に記述しています。そのため、複雑な部分や難解な部分が少なく、読みやすくなっています。

「GCreator」の具体的な使用法に関しては、「メニュー・バー」の中に「見本」の項目を入れ、命令文書の書き方の見本を提示しています。基礎的な命令の記述法は、ソース・コードをコンパイルした上で、この「見本」を実行して、その振る舞いを見たり、命令文の一部を書き替えて、その振る舞いの変化を実験的に試して、理解していただくことになります。

■第一部　解説編

◆第一章　ファイル解説

GCreatorは、ソース・コード・ファイルおよび補助テキスト・ファイルとして、次に示すファイルが必要です。これらは、「ソース・コード編」でその全てを公開しています。なお、他にも必要となるディレクトリー（フォルダー）を書き加えます。これらのディレクトリー名およびファイル名は、ソース・コードの中でも使われているため、勝手に変更できません。

/user/java/GCreator/src/new　【ソース・ファイル・ディレクトリー】
　GCreator.java
　　Swingの各種部品を集めて操作と表示の画面を構築する
　GCreatorCanvasEngine.java
　　画像を描くキャンバスとして機能する
　GCreatorAnalyzeEngine.java
　　画像を描く命令を解析して、Javaの機能に置き換える準備を行なう
　GCreatorPalleteEngine.java
　　描画の基本色を混色するパレットとして、必要な色彩を作り出す
　GCreatorToneCurveEngine.java
　　トーン・カーブによる色彩変更を行なう主要機能を実現
　GCreatorPrintEngine.java
　　完成された画像をプリンターで印刷する機能を実現する
　GCreatorFileIO.java
　　描画命令テキスト・ファイルや画像ファイルの入出力を行なう
　GCreatorMenuLis.java
　　メニューで要求された機能実現を外部に差配する
　GCreatorButtonLis.java
　　ボタンで要求された機能実現を外部に差配する
　GCreatorCanMouseLis.java
　　キャンバス上でのマウス・クリックに反応し、機能実現に寄与する
　GCreatorPalMouseLis.java
　　パレット上でのマウス・クリックと連繋し、機能実現に寄与する
　GCreatorSliderLis.java
　　混色された色彩をスライダーで微調整する機能を実現
　GCreatorToneCurveMouseLis.java
　　トーン・カーブ図表に対するマウス・クリックに応じるリスナー
/user/java/Lib/src/new　【ライブラリー・ソース・ファイル・ディレクトリー】
　StackTraceMonitor.java
　　Java実行環境が出力するエラー・メッセージを横取りする
　SystemMessage.java
　　StackTraceMonitorおよびGCreator.javaと協調動作する
　Util.java
　　ユーティリティーの提供（GCreatorにとって余分な機能も含む）
　SingleFileFilter.java
　　ファイル選択の補助を行なう
　TextIO.java
　　テキスト・ファイルの入出力を行なう（GCreatorにとって余分な機能も含む）
　Spline.java
　Spline2.java
　Spline3.java
　　スプライン曲線を描画する機能を実現する三種セット
/user/java/GCreator/sys　　【GCreatorシステム・ファイル・ディレクトリー】
　GCreator_Manual.txt
　　命令文の仕様書であるテキスト・ファイル
　GCreator_Pattern.txt
　　マトリックス・パターンの紋柄データベース
/user/java/GCreator/gcc　　【汎用命令文書ファイル・ディレクトリー(gcc)】
/user/java/GCreator/image　【汎用画像ファイル・ディレクトリー（jpeg,png,bmp,gif）】
/user/java/GCreator/project【プロジェクト単位のディレクトリー(gcc,png)
/user/class　　　　　　　　【クラス・ファイル・ディレクトリー(class)】
/user/bat　　　　　　　　　【バッチ・ファイル・ディレクトリー(bat)】
/user/java/GCreator/src/old【旧バージョンのソース・ファイル・ディレクトリー(java)】

◆第二章　操作法解説

以下に、GCreatorの稼働状態の実例をスクリーン・ショットで示し、操作法の概要を説明します。スクリーン・ショットされた大画面画像の縮小表示となると、文字が見えにくくなることがありますので、以下の説明文で確認してください。

上の図は、「標準画面モード」にして、線描図形を描画している状態（マウス描画有効モードに切り替えること）です。

上の図は、「パレット表示画面モード」にして、点描画機能で描画している状態です。

まずは、GCreatorの画面構成（Swingの配置）を説明します。複雑な画面モードの「パレット表示画面モード」で説明します。一段目は、タイトル・バーであって、左端に「Gcreator Ver.4.1」と表示しているだけです。無論、右端には、ウィンドウ操作ボタン（最大化ボタンや終了ボタンなど）があります。二段目は、メニュー・バーであって、各種機能を配置しています。左端から、「ファイル」「消去」「見本１」「見本２」「見本３」「見本４」「倍率」「画面モード」「マウス描画モード」「マウス描画機能」「ヘルプ」のメニューがあり、それより右には、各種ラベルを表示しています。三段目は、ボタン・バーであって、「パレット表示画面モード」にした場合、左から順に「削除」「複写」「挿入」「保存」のボタンあり、さらに「取消」があり、さらにテキスト・フィールドの入力欄（混色なしの色相直接指定用）があり、さらに「復元」があり、さらに「描画」「乱数」「切取」「保存」のボタンがあります。これらのボタンは、次の四段目の横分割の領域区分と連動しています。四段目は、最も広い画面領域を占めていて、この図では、左から順に、「コマンド・エリア」「パレット・エリア」「スライダー・エリア」「キャンバス・エリア」となります。ただし、「パレット・エリア」と「スライダー・エリア」とを表示しない設定（標準画面モード）も可能で、その場合、部品の配置は、「コマンド・エリア」「キャンバス・エリア」の二つです。その場合、「パレット・エリア」付属の「取消」ボタンや「スライダー・エリア」付属の「復元」ボタンも表示されません。「パレット・エリア」および「スライダー・エリア」は、必要な時にだけ表示するもので、「メニュー・バー」の「画面モード」メニューで切り替えられます。五段目は、「メッセージ・エリア」で、エラー・メッセージや作業報告メッセージを表示します。「画面モード」には、「トーン・カーブ表示画面モード」もあり、ボタンの種類が一部変更されます。

メニュー・バーの「メニュー」および「メニュー・アイテム」の詳細は、以下のようになります。

ファイル
　　命令文書開く
　　命令文書保存
　　背景画像表示
　　スタンプ押印
　　画像保存
　　画像印刷
消去
　　命令文消去
　　警告文消去
　　全消去
見本１
　　各種図形描画
　　スプライン曲線描画
　　折れ線描画
    スプレー描画
　　全体レイアウト・スケール
　　部品レイアウト・スケール
　　多段階回転画像作成用スケール
　　印刷試験A4
　　カード印刷
　　フォント表示テスト１
　　フォント表示テスト２
見本２
　　模様画像生成（統一配色）
　　模様画像生成（個別配色）
　　模様画像生成（二重混用）
　　模様画像生成（シフト）
　　模様画像生成（ドロップ）
　　模様画像生成（スキップ）
　　模様画像生成（間欠描画）
　　模様画像生成（傾斜元画像）
　　模様画像生成（画像傾斜加工）
　　模様画像生成（傾斜画像サイズ調整）
　　模様画像生成（複雑指定１）
　　模様画像生成（複雑指定２）
見本３
　　ロゴ画像（スタンプ用グレー・マスク）
　　ロゴ入り画像（スタンプ押印）
　　切り貼り用マルチ・マスク
　　切り貼り処理
　　画像鏡像反転
　　画像部分切り取り保存
　　二重画像用グレー・マスク
　　二重画像処理
　　ソフト・フォーカス元絵
　　ソフト・フォーカス処理
　　畳み込み処理（鮮鋭化／朦朧化）
　　輪郭線抽出処理
　　連続色相変更
　　単独色相変更
　　色相調整
　　色相階調加工
　　画像鏡像反転
　　画像部分切り取り保存
見本４
    スプライン曲線図形１
    輪郭線図形単独彩色
    スプライン曲線図形２
    輪郭線図形連続彩色
    輪郭線図形連続彩色SF
    輪郭線図形連続彩色仕上
    スプライン曲線図形３
    輪郭線図形高速連続彩色
倍率
　　表示:x4
　　表示:x3
　　表示:x2
　　表示:x1.5
　　表示:x1
　　表示:x1/1.5
　　表示:x1/2
　　表示:x1/3
　　表示:x1/4
画面モード
　　標準表示
　　パレット表示
　　トーン・カーブ表示
マウス描画機能
　　直線
　　直線消去
　　折れ線
　　ベジェ曲線
　　スプライン曲線
　　スプライン曲線制御点消去
　　スプライン曲線制御点増殖
　　文字列
　　真円
　　真円消去
　　楕円
　　四角形
　　自由図形
　　目印線消去
　　目印線復活
　　位置確認
　　位置修正
　　色相確認
　　図形彩色変更
　　命令文検索
　　点描画筆（大）
　　点描画筆（中）
　　点描画筆（小）
　　スプレー
　　スプレー飛沫円盤中間点消去
ヘルプ
　　命令仕様書
　　模様データ

「コマンド・エリア」には、描画命令文が複数行表示されます。描画命令文は、マウス操作で自動的に記述する方法と、キーボードから直接入力する方法とがあります。マウス操作で命令文を作成する場合、メニューの「マウス機能」を選び、さらに「直線」や「曲線」や「楕円」や「四角形」などの線種別や図形種別を指定してから、「キャンバス・エリア」の範囲内でマウス・クリックすることで、指定の線や図形が描かれると共に、命令文も自動生成され「コマンド・エリア」に追加されます。いずれにせよ、「描画」ボタンが押されると、「コマンド・エリア」の命令文の全部（命令文書：マクロ・プログラム）を読み取り、これを順次解析し、「キャンバス・エリア」に指定通りに描画します。命令文に記述間違いがあれば、間違いの種類が、警告文として「メッセージ・エリア」に表示されます。

「コマンド・エリア」に表示された複数の命令文は、それ自体がマクロ・プログラム（命令文書）であって、ファイル保存ができ、再利用もできます。それは、メニューの「ファイル」の中の「命令文書開く」と「命令文書保存」とによって行ないます。画像の入出力も、同様に「背景画像表示」、「スタンプ押印」、「画像保存」、「画像印刷」、これらの選択で行ないます。

マウス操作による「直線」の描き方は、始点と終点との二箇所を左クリックするだけですが、「ベジェ曲線」の場合、四箇所を左クリックすることになります。「ベジェ曲線」のＵ字曲線で言えば、台形を描くつもりで、始点、第一制御点（中間点）、第二制御点（中間点）、終点、この四箇所を左クリックすれば、補助線も表示しながら、台形の内側に曲線が表示されます。「スプライン曲線」の場合、始点および制御点（一箇所以上）は左クリックで、終点が右クリックです。「折れ線」も同様です。曲線の場合、一度で望みの曲線になることはないので、マウスを使って、補助線（目印線）で示された始点や制御点や終点を位置修正することになります。なお、ベジェ曲線を含む「自由図形」（メニューにある「自由図形」の機能）を描く場合、直線部は左クリックで、曲線部は右クリックとなりますが、詳しい操作の仕方は、ソース・コード（GCreatorCanMouseLis.java]）およびマニュアル（GCreator_Manual.txt）を参照下さい。複雑な曲線で囲まれた図形を描くのであれば、ベジェ曲線を利用するよりもスプライン曲線を利用する方が、表現しやすく便利です。座標点の位置修正は、メニューの中の「マウス描画機能」を選び、メニュー・アイテムの「位置修正」を選び、問題の制御点（あるいは始点や終点）をクリックし、新しい制御点（あるいは始点や終点）をクリックすることで、曲線も補助線も自動修正され命令文も自動修正されます。キャンバス画面上におけるマウス・クリックによって、どのようにデータが処理され、どのように描画命令が自動記述または自動修正されるかを理解するには、「GCreatorCanMouseLis.java」のソース・コードをコメントと共に読んでいただかねばなりません。

上の図は、模様生成機能を実行している様子（マウス描画無効モード）です。この場合、色彩は、「コマンド・エリア」内の命令文で、基準色とランダム変動範囲が指定されているだけなので、指定された基準色に基づきつつも、ランダムで配色を決めています。「乱数」ボタンを押すたびに、異なる配色で図柄が自動生成されます。パターン模様（柄紋）の描画は、全て命令文によって行ないますので、マウス操作による描画はしません。ただし、「描画」ボタンと「乱数」ボタンは、話が別です。また、マウス描画無効モードからマウス描画有効モードに切り替え、線描画（面描画を含む）や点描画（スプレーを含む）を付け加えることも可能です。推奨する方法は、模様生成機能を使い、命令文書を作成し、乱数を何度も発生させ、好みの図柄や配色を決定し、その決定した模様図柄をpng形式でファイル保存し、その後に、その図柄をキャンバスにImage命令によって改めて表示し、線描画や点描画や文字を加えて加工する方法が、失敗も少なく効果的です。なお、図柄パターンは、データ・ファイル（GCreator_Pattern.txt）として保持していて、命令文の引数で図柄パターン番号を指定する形になります。「乱数」ボタンを繰り返し押し、好みの配色が実現すれば、「ファイル」メニューを押して画像ファイルとして保存します。乱数で配色を決定するため、二度と同じ配色を再現できず、画像で固定保存するしかありません。

上の図は、点描画機能を実行している様子（マウス描画有効モードにすること）です。ただし、輪郭線内部彩色の事前準備に点描画機能を活用する例です。この場合、パレット使用が必須になりますので、パレットが非表示状態になっていれば、メニューにより表示してください。パレットで必要な絵具を選び、混色し、出来た混色に対して、さらにスライダーで色調を微調整します。パレットの説明をしますと、上から四段分は、十六色の基本色で、このどれかをマウスで選んで混色します。パレットの五段目は、選んだ絵具の色で、一色から四色までの混色が自由に選べます。六段目の左半分は、単純な混合色で、右半分は、その混合色をスライダーで微調整した調整色です。調整色が、点描画の筆の色になります。なお、パレットで混色せず、数値で点描画筆の色彩（RGB）を直接指定する方法（テキスト・フィールド入力）もあります。テキスト・フィールドへの入力形式は、RGBの数値（十進数）をコンマで区切るCSV形式で、「120,55,220」のように入力します。

点描画を行なう時は、「点描画筆」を選んだ上で、「キャンバス・エリア」をマウス・クリックすると、パレットでの調整色を用い、小さな円が描かれます。無論、「コマンド・エリア」には、クリックに対応する描画命令が逐次追加されます。なお、何もない空白のキャンバスに点描するのは容易ではないため、予め下絵（写真などのデジタル画像データ）を用意しておき、「キャンバス・エリア」にそれをImage命令で表示し、点描で下絵が隠れてしまうほど、点描で埋め尽くすようにします。ただし、背景を一色で統一するつもりなら、背景に対して単純反復の点描操作を行なわずとも、背景色を指定するだけで、それが可能になります。その場合、最終段階で指定画像表示命令（Image命令）をコメント・アウトし、背景色指定命令（BackgroundColor命令）を書き加えます。スプレー機能を利用する場合も、線描画の下絵（輪郭線図など）を予め表示（Image命令やStamp命令の活用）させておきます。

なお、色彩（色）に関する知覚原理を、ここで念のため確認しておきます。「色の三属性」として、「色相」「明度」「彩度」が「色の知覚」の原理として、一般に説明されます。それぞれの意味は、以下の通りです。

色相：光のスペクトルにマゼンタ系を加えた「色相環による明るい原色系の連続的変化」（レッド、イエロー、グリーン、シアン、ブルー、マゼンタ）。

明度：光の光量が原因となる色彩の明暗変化で表わされる「暗い特定色相（極限は黒色）から明るい特定色相（白色は除外）に至る連続的変化」。

彩度：光の三原色（レッド、グリーン、ブルー）の分量が均等（黒色や灰色や白色）に加味されることで変化する「色の鮮やかさが失われる連続的変化」。

しかし、この「色の三属性」つまり「色相、明度、彩度」の組み合わせで色彩を理解しようとすると、「色の三属性」が明晰に切り分けられず、概念の混じり合いがあって、逆に理解が難しくなってしまう。「色相」は、光の三原色の一色または二色の明るい光量での混合であり、「明度」は、光の三原色の一色または二色の混色比率を維持しつつ色相に明暗変化（光量変化）を与えるものであり、「彩度」は、光の三原色の三色が色相に均等加味されて色彩の鮮やかさを変化（黒色を適量加えて色を濁らせることに相当）させるものです。このように、「色の三属性理論」は、全体的に混乱した不規則な秩序になっています。「色相」や「明度」や「彩度」の概念は、理論的に非常に分かりにくい。この三つの概念を整然と厳密に定義すること自体が、非常に難しい。簡単に言えば、「色彩」＝「色相」＋「明度」＋「彩度」の関係なのだが、「色彩」と「三原色」との関係が複雑に入り組んでいて、全然分かりやすくない。ディスプレーで表わされる色彩も、光の三原色の成分比率の違いによる混合（加法混色）に過ぎないわけで、色彩は、単純な規則性の「RGB理論」で捉えるべきです。つまり、「色彩」は、「三属性」の組み合わせで複雑に考えるよりも、「三原色」の組み合わせで単純に考える方が、断然分かりやすいのです。

トーン・カーブ式調色を行なう場合、メニューから「トーン・カーブ表示」を選択し、まず「原画」ボタンを押下し、調色を行なう元画像（原画）を選択して表示し、新たに表示された「トーン・カーブ図表」で小さな丸印で目印された座標点（起点、制御点3点、終点）のどれかを、左クリックして、次に変更を希望する座標点を左クリックすることで、自動的に新たな曲線が、そこに描かれます。トーン・カーブ曲線が決定したら、「調色」ボタンを押下することで、「トーン・カーブ図表」に沿った色彩変更（調色）がなされます。トーン・カーブ調色に関する作業（画像保存を含む）が完了すれば、「終了」ボタンを押して下さい。「終了」ボタンを押さずに、いきなり別の作業に移行すると、メモリー開放がなされず、画像が二重表示になって乱れることがあります。なお、曲線表示の「トーン・カーブ図表」には、棒グラフ形式で、RGB別の「ヒストグラム」（色彩成分濃度別分布図）が重ねて表示されますので、トーン・カーブ曲線を決める目安とします。以下に、「トーン・カーブ表示」の様子を示します。

典型的な画像作成法に関し、本の表紙の作成過程の進行状況を念頭に置いて、説明します。その概要は、予め作成した好みの模様画像を切り貼りして組み合わせ、これに額縁や銘板（題簽）や文字を描き加えつつ、何度も試行錯誤を行なうことになります。典型的作業としては、線描画機能（直線と曲線の組み合わせ）で輪郭線を描画し、点描画機能でスポット彩色し、さらに輪郭線の内部を塗りつぶす操作を行ない、カラー・マスク（塗り絵状態の画像）を完成させます。その後、カラー・マスクを使った模様の切り貼り（嵌め込み）は、「画像カット・アンド・ペースト機能」で実現します。また、額縁や銘板（題簽）やロゴ・マークの貼り付けは、「スタンプ機能」で実現できます。「メニュー・バー」の「見本」にも、本の表紙の作成見本を用意しておきました。「画像カット・アンド・ペースト機能」や「スタンプ機能」を何度も重ねれば、複雑なデザインが可能になります。「スタンプ機能」は、ロゴ・マークの配置を想定した特殊命令ですが、他の用途にも幅広く使えます。

以下に、表紙意匠の作例を、幾つか示します。ただし、作例の画像は、本来のサイズより大幅に縮小し、480×672 px としているため、精細度がかなり低下しています。本書の冒頭と末尾とにある表紙および奥付の画像は、高精細度で作成しています。

■第二部　ソース・コード編

ソース・コード編の内容は、GCreator専用コードと、ライブラリーとしての汎用コードと、GCreatorのマニュアル等との、三種類から成り立っています。再掲載になりますが、以下に、関連ディレクトリーをも含め、これらを列挙します。

/user/java/GCreator/src/new　【ソース・ファイル・ディレクトリー】
　GCreator.java
　　Swingの各種部品を集めて操作と表示の画面を構築する
　GCreatorCanvasEngine.java
　　画像を描くキャンバスとして機能する
　GCreatorAnalyzeEngine.java
　　画像を描く命令を解析して、Javaの機能に置き換える準備を行なう
　GCreatorPalleteEngine.java
　　描画の基本色を混色するパレットとして、必要な色彩を作り出す
　GCreatorToneCurveEngine.java
　　トーン・カーブによる色彩変更を行なう主要機能を実現
　GCreatorPrintEngine.java
　　完成された画像をプリンターで印刷する機能を実現する
　GCreatorFileIO.java
　　描画命令テキスト・ファイルや画像ファイルの入出力を行なう
　GCreatorMenuLis.java
　　メニューで要求された機能実現を外部に差配する
　GCreatorButtonLis.java
　　ボタンで要求された機能実現を外部に差配する
　GCreatorCanMouseLis.java
　　キャンバス上でのマウス・クリックに反応し、機能実現に寄与する
　GCreatorPalMouseLis.java
　　パレット上でのマウス・クリックと連繋し、機能実現に寄与する
　GCreatorSliderLis.java
　　混色された色彩をスライダーで微調整する機能を実現
　GCreatorToneCurveMouseLis.java
　　トーン・カーブ図表に対するマウス・クリックに応じるリスナー
/user/java/Lib/src/new　【ライブラリー・ソース・ファイル・ディレクトリー】
　StackTraceMonitor.java
　　Java実行環境が出力するエラー・メッセージを横取りする
　SystemMessage.java
　　StackTraceMonitorおよびGCreator.javaと協調動作する
　Util.java
　　ユーティリティーの提供（GCreatorにとって余分な機能も含む）
　SingleFileFilter.java
　　ファイル選択の補助を行なう
　TextIO.java
　　テキスト・ファイルの入出力を行なう（GCreatorにとって余分な機能も含む）
　Spline.java
　Spline2.java
　Spline3.java
　　スプライン曲線を描画する機能を実現する三種セット
/user/java/GCreator/sys　　【GCreatorシステム・ファイル・ディレクトリー】
　GCreator_Manual.txt
　　命令文仕様書のテキスト・ファイル
　GCreator_Pattern.txt
　　マトリックス・パターンの紋柄データベース（欄数不統一CSV形式）
/user/java/GCreator/gcc　　【汎用命令文書ファイル・ディレクトリー(gcc)】
/user/java/GCreator/image　【汎用画像ファイル・ディレクトリー（jpeg,png,bmp,gif）】
/user/java/GCreator/project【プロジェクト単位のディレクトリー(gcc,png)
/user/class　　　　　　　　【クラス・ファイル・ディレクトリー(class)】
/user/bat　　　　　　　　　【バッチ・ファイル・ディレクトリー(bat)】
/user/java/GCreator/src/old【旧バージョンのソース・ファイル・ディレクトリー(java)】

『Java 実例 プログラミング』の「描画処理編」は、何度か改訂されるたびに、新バージョンの「GCreator」のソース・コードを掲載して来ましたが、両者の対応関係は、以下の通りです。

第一版（2022年04月22日発行）掲載は、「GCreator Ver.1.0」
改訂版（2022年07月14日発行）掲載は、「GCreator Ver.1.1」
第三版（2023年04月03日発行）掲載は、「GCreator Ver.2.0」
第四版（2024年01月23日発行）掲載は、「GCreator Ver.3.0」
第五版（2024年09月17日発行）掲載は、「GCreator Ver.3.1」
第六版（2024年10月17日発行）掲載は、「GCreator Ver.3.2」
第七版（2024年12月02日発行）掲載は、「GCreator Ver.3.3」
第八版（2025年04月24日発行）掲載は、「GCreator Ver.3.4」
第九版（2025年07月22日発行）掲載は、「GCreator Ver.4.0」
第十版（2026年01月27日発行）掲載は、「GCreator Ver.4.1」

ところで、日本語対応「Windows11」から、テキスト・ファイルの入出力において、文字コードのデフォルトが、「Shift_JIS」から「UTF-8」になりました。正確に言えば、「Windows10」であっても、「Windows10 21H2」から「UTF-8」に変更されています。なお、バージョン番号の「21H2」は、「2021年下半期」の意味です。「Windows10」であれ「Windows11」であれ、「UTF-8」がデフォルトの環境である場合、この点に注意が必要です。「UTF-8」がOSレベルで標準仕様となる今後は、プログラム・ソース・コード（.java）も命令文書（.gcc）も「GCreator_Manual.txt」も「GCreator_Pattern.txt」も、それがテキスト・データであり、特別な理由がない限り、全て「UTF-8」で保存することが望まれます。各種テキスト・エディターには、文字コードを指定してファイル保存する機能があるはずです。一方、「Java」が「UTF-8」を文字入出力のデフォルトにしたのは、「JDK18」のバージョンからです。本書の内容も、「JDK18」以降を想定しています。

なお、コンピューターのストレージ（HDDやSSD）にJavaの実行環境（JDK18以降）がインストール済みで、 「javac.exe」や「java.exe」が実行できるよう、また、拡張子が「class」のファイルにアクセスできるよう、ＯＳに対してシステム環境変数（「PATH」および「CLASSPATH」）が適切に設定されているものとします。「PATH」は、多くのプログラムが必要とする性質のもので、既に幾つも事前に設定されているはずですが、「javac.exe」や「java.exe」が必要とするものを、さらに追加することになります。「環境変数」の「PATH」および「CLASSPATH」は、バッチ・ファイルの中でその都度指定することも可能ですが、利便性のため、ＯＳの「コントロール パネル」を通じて、指定することを推奨します。

「システム環境変数」設定の一例（各自が中身を調整すること）
「PATH」 　　　―――　「c:\Progrem Files\java\jdk-18.0.2.1\bin」を含むこと
「CLASSPATH」　―――　「c:\user\class」

「システム環境変数」が適切に設定済みであることを条件に、Windows11の環境下でコンパイルするバッチ・ファイルの一例（参考）を、以下に示します。見落としやすいピリオド記号に、注意して下さい。この一例は、「UTF-8」で記述されたソース・コードをコンパイルする場合です。

まずは、ライブラリーのコンパイル。

rem ライブラリーのコンパイル
c:
del \user\class\SystemMessage*.class
del \user\class\StackTraceMonitor*.class
del \user\class\SingleFileFilter*.class
del \user\class\Util*.class
del \user\class\TextIO*.class
del \user\class\Spline*.class
cd \user\java\Lib\src\new
javac -d \user\class -sourcepath . -encoding UTF-8 SystemMessage.java
javac -d \user\class -sourcepath . -encoding UTF-8 StackTraceMonitor.java
javac -d \user\class -sourcepath . -encoding UTF-8 SingleFileFilter.java
javac -d \user\class -sourcepath . -encoding UTF-8 Util.java
javac -d \user\class -sourcepath . -encoding UTF-8 TextIO.java
javac -d \user\class -sourcepath . -encoding UTF-8 Spline.java
javac -d \user\class -sourcepath . -encoding UTF-8 Spline2.java
javac -d \user\class -sourcepath . -encoding UTF-8 Spline3.java
pause

続いて、GCreatorのコンパイル。

rem GCreatorのコンパイル
c:
del \user\class\GCreator*.class
cd \user\java\GCreator\src\new
javac -d \user\class -sourcepath . -encoding UTF-8 GCreator.java
pause

コンパイル済みのプログラムに対して、Windows11の環境下で実行するバッチ・ファイルの一例（参考）を、以下に示します。この一例は、ヒープ・メモリーをかなり大き目（最大6GB＝6144MB）に確保するオプションを含んでいます。マシンに実装しているメモリーを考慮しつつ、ヒープ・メモリーを潤沢に設定することを推奨します。

rem GCreatorの実行
c:
cd \user\java\GCreator
java -Xmx6144m GCreator
pause

いずれのバッチ・ファイルであっても、各自のコンピューティング環境に合わせて、中身を調整する必要があります。

なお、「GCreator Ver.4.1」の実行環境としては、以下の条件で安定動作することを確認しています。ただし、メモリー実装不足（4GB未満）の環境下で、巨大データ（巨大画像や巨大配列）を生成し操作すれば、ヒープ・メモリー不足のエラーになる可能性があります。「GCreator Ver.4.1」は、「Windows」がＯＳとして機能している環境を、想定しています。それ以外のＯＳは、未検証であり、正常に機能しない可能性があります。ファイル・システムやカラー・モデルや搭載フォント等で、ＯＳにおける標準規格の不一致が考えられます。

CPU:     intel Core i3-1005G1
MEMORY:  8GB
STRAGE:  117GB SSD
DISPLAY: 1920x1080px (set up 150%)
OS:      Windows11 Home
JDK:     JDK18

◆GCreator.java

//■■GCreator.java
//Ver.4.1

//■■TEST ENVIRONMENT
//CPU:     intel Core i3-1005G1
//MEMORY:  8 GB
//STRAGE:  117 GB SSD
//DISPLAY: 1920×1080 px (setup 150%: 1280×720 px)
//OS:      Windows11 Home
//JDK:     JDK18

//一般的なディスプレイの解像度は、以下の通り。
//8K（7680×4320 dot）
//4K（3840×2160）
//WQHD（2560×1440）
//FHD（1920×1080）
//WXGA++(1600×900）
//HD（1280×720）
//ただし、
//FHD（1920×1080）が最多であり標準である。

/*
■■DIRECTORIES & FILES
/user/java/GCreator/src/new　　ソース・ファイル
  GCreator.java
  GCreatorMenuLis.java
  GCreatorButtonLis.java
  GCreatorCanMouseLis.java
  GCreatorPalMouseLis.java
  GCreatorCanvasEngine.java
  GCreatorAnalyzeEngine.java
  GCreatorPalleteEngine.java
  GCreatorSliderLis.java
  GCreatorToneCurveEngine.java
  GCreatorToneCurveMouseLis.java
  GCreatorPrintEngine.java
  GCreatorFileIO.java
/user/java/Lib/src/new　　ライブラリー・ソース・ファイル
  SystemMessage.java
  StackTraceMonitor.java
  SingleFileFilter.java
  Util.java
  TextIO.java
  Spline.java
  Spline2.java
  Spline3.java
/user/java/GCreator/sys　　　システム・サポート・ファイル
  GCreator_Manual.txt
  GCreator_Pattern.txt
/user/java/GCreator/gcc　　　汎用命令文書ファイル(gcc)
/user/java/GCreator/image　　汎用画像ファイル(png,jpeg,gif,bmp)
/user/java/GCreator/project　プロジェクトごとにサブ・ディレクトリーを作成し、ファイル(gcc,png)を格納
/user/class　　　　　　　　　クラス・ファイル(class)
*/

//■■インポート
import java.awt.*;  //必須
import java.awt.event.*;  //必須
import javax.swing.*;  //必須
import java.util.*;  //必須
import java.io.*;  //必須

//■■フレーム定義
class GCreator extends JFrame implements SystemMessage
{
  //■メンバー変数
  //●プログラム・バージョン
  final static String version = "Ver.4.1";

  //●基本的な変数
  GCreator f;
  Container pane;
  GCreatorCanvasEngine canvas;    //画像描画制御
  GCreatorAnalyzeEngine analyze;  //命令文解析
  GCreatorPaletteEngine palette;  //パレット混色制御
  GCreatorToneCurveEngine toneCurve; //トーン・カーブ色彩制御
  GCreatorToneCurveMouseLis tMouseLis; //トーン・カーブ・マウス・リスナー
  GCreatorPrintEngine printer;    //印刷制御
  GCreatorMenuLis menuLis;        //メニュー・リスナー
  GCreatorButtonLis buttonLis;    //ボタン・リスナー
  GCreatorCanMouseLis cMouseLis;  //画像表示部での命令文生成マウス・リスナー
  GCreatorPalMouseLis pMouseLis;  //パレット表示部での混色マウス・リスナー
  GCreatorSliderLis sliderLis;    //混色微調整用のスライダー・リスナー
  GCreatorFileIO io;              //ファイル入出力

  JMenuBar menuBar;                   //メニュー配置
  JPanel buttonBarC   = new JPanel(); //制御命令系ボタンを配置
  JPanel buttonBarG   = new JPanel(); //画像表示系ボタンを配置
  JPanel buttonBarP   = new JPanel(); //パレット系ボタンを配置
  JPanel buttonBarS   = new JPanel(); //スライダー系ボタンを配置
  JPanel buttonBarT   = new JPanel(); //トーン・カーブ系ボタンを配置
  JPanel sliderPanel  = new JPanel(); //パレット系スライダーを配置
  JSlider sldR;
  JSlider sldG;
  JSlider sldB;
  JTextField paletteRGB; //パレット色を直接に数値指定（混色不可、スライダー調整不可）

  JLabel fillerLabel   = new JLabel("　　　");      //埋草の空白
  JLabel scaleLabel    = new JLabel("　(a:x1.0)");  //表示スケール（AffineScale）
  JLabel scaleLabel2   = new JLabel("　(f:x1.0 )"); //表示スケール（FreeScale）
  JLabel pixelLabel    = new JLabel("　(i: )");     //画像ピクセル数(px)
  JLabel mmLabel       = new JLabel("　(p: )");     //印刷サイズ(mm)

  JLabel matrixStUnitLabel = new JLabel(""); //紋柄ユニットStの構成
  JLabel matrixExUnitLabel = new JLabel(""); //紋柄ユニットExの構成
  JLabel mouseModeLabel    = new JLabel("マウス描画無効モード");

  JTextArea cArea, mArea;
  JScrollPane scrollC, scrollG, scrollP, scrollS, scrollT, scrollM;
  final int scrollCWidth;  //サイズ基準値
  final int scrollCHeight; //サイズ基準値
  final int scrollMHeight; //サイズ基準値

  //●画面表示と画像保存とに反映される図形倍率。
  //画像印刷には反映されない。
  final double xL4 = 4.0D;
  final double xL3 = 3.0D;
  final double xL2 = 2.0D;
  final double xML = 1.5D;
  final double xM1 = 1;
  final double xMS = 1/1.5D;
  final double xS2 = 1/2.0D;
  final double xS3 = 1/3.0D;
  final double xS4 = 1/4.0D;

  //●スウィングに表示される文字数や行数
  int cdLines, cdCols, mLines, mCols;

  //■エントリーポイント
  public static void main(String[] args)
  {
    //●画面構築部の生成
    new GCreator(null, null);
  }

  //■フレームのコンストラクタ
  GCreator(final SystemMessage sm, final StackTraceMonitor st)
  { //SystemMessageおよびStackTraceMonitorは、私的ライブラリー所収
    super("GCreator  " + version);
    f = this;
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    //●クローズアイコンの動作定義、及び実行モード設定
    setDefaultCloseOperation(EXIT_ON_CLOSE);  //単に終了
    new StackTraceMonitor(this).start(); //標準エラー出力の監視

    //●要求判定部（リスナー）の生成
    menuLis   = new GCreatorMenuLis(this);
    buttonLis = new GCreatorButtonLis(this);
    cMouseLis = new GCreatorCanMouseLis(this);
    pMouseLis = new GCreatorPalMouseLis(this);
    sliderLis = new GCreatorSliderLis(this);
    tMouseLis = new GCreatorToneCurveMouseLis(this);
    //●主要機能部の生成
    canvas    = new GCreatorCanvasEngine(this);
    toneCurve = new GCreatorToneCurveEngine(this);
    analyze   = new GCreatorAnalyzeEngine(this);
    palette   = new GCreatorPaletteEngine(this);
    printer   = new GCreatorPrintEngine(this);
    io        = new GCreatorFileIO(this);

    //●スウィングで表示される文字数や行数や大きさ。
    //それぞれの実行環境に合わせて数値を調整すること。
    //下記の数値設定は、簡易設定。
    if(getToolkit().getScreenSize().width >= 1280 &&
       getToolkit().getScreenSize().height >= 720)
    {
        cdLines =  32; //この数値は、実機に合わせて変更する
        cdCols  =  39; //この数値は、実機に合わせて変更する
        mLines  =   4; //この数値は、実機に合わせて変更する
        mCols   =  70; //この数値は、実機に合わせて変更する
    }
    else
    {
        cdLines =  21; //この数値は、実機に合わせて変更する
        cdCols  =  21; //この数値は、実機に合わせて変更する
        mLines  =   3; //この数値は、実機に合わせて変更する
        mCols   =  46; //この数値は、実機に合わせて変更する
    }

    //●MENU BAR:メニュー表示部品
    JMenu menu;
    setJMenuBar(menuBar = new JMenuBar());

    addA(menuBar, menu = new JMenu("ファイル"));
    addB(menu, new JMenuItem("命令文書開く"), menuLis, "LoD");
    addB(menu, new JMenuItem("命令文書保存"), menuLis, "SaD");
    menu.addSeparator();
    addB(menu, new JMenuItem("背景画像表示"), menuLis, "LoI");
    addB(menu, new JMenuItem("スタンプ押印"), menuLis, "Stm");
    menu.addSeparator();
    addB(menu, new JMenuItem("画像保存"),     menuLis, "Sa2");
    addB(menu, new JMenuItem("画像印刷"),     menuLis, "Pri");

    addA(menuBar, menu = new JMenu("消去"));
    addB(menu, new JMenuItem("命令文消去"), menuLis,   "Cl2");
    addB(menu, new JMenuItem("警告文消去"), menuLis,   "Cl3");
    addB(menu, new JMenuItem("全消去"),     menuLis,   "Cl4");

    addA(menuBar, menu = new JMenu("見本１"));
    addB(menu, new JMenuItem("各種図形描画"),             menuLis, "FrS");
    addB(menu, new JMenuItem("スプレー描画"),             menuLis, "SpD");
    addB(menu, new JMenuItem("全体レイアウト・スケール"), menuLis, "Lay");
    addB(menu, new JMenuItem("部品レイアウト・スケール"), menuLis, "La2");
    addB(menu, new JMenuItem("多段階回転画像作成用スケール"), menuLis, "RLS");
    addB(menu, new JMenuItem("印刷試験A4"),               menuLis, "TA4");
    addB(menu, new JMenuItem("カード印刷"),               menuLis, "NCP");
    addB(menu, new JMenuItem("フォント表示テスト1"),      menuLis, "Pht");
    addB(menu, new JMenuItem("フォント表示テスト2"),      menuLis, "Ph2");

    addA(menuBar, menu = new JMenu("見本２"));
    addB(menu, new JMenuItem("模様画像生成（統一配色）"), menuLis, "BG1");
    addB(menu, new JMenuItem("模様画像生成（個別配色）"), menuLis, "BG2");
    addB(menu, new JMenuItem("模様画像生成（二重混用）"), menuLis, "BG3");
    addB(menu, new JMenuItem("模様画像生成（シフト）"),   menuLis, "BG4");
    addB(menu, new JMenuItem("模様画像生成（ドロップ）"), menuLis, "BG5");
    addB(menu, new JMenuItem("模様画像生成（スキップ）"), menuLis, "BG6");
    addB(menu, new JMenuItem("模様画像生成（間欠描画）"), menuLis, "BG7");
    addB(menu, new JMenuItem("模様画像生成（傾斜元画像）"),menuLis,"BG8a");
    addB(menu, new JMenuItem("模様画像生成（画像傾斜加工）"),menuLis,"BG8b");
    addB(menu, new JMenuItem("模様画像生成（傾斜画像サイズ調整）"),menuLis,"BG8c");
    addB(menu, new JMenuItem("模様画像生成（複雑指定１）"),menuLis,"BG9");
    addB(menu, new JMenuItem("模様画像生成（複雑指定２）"),menuLis,"BG10");

    addA(menuBar, menu = new JMenu("見本３"));
    addB(menu, new JMenuItem("ロゴ画像（スタンプ用グレー・マスク）"),menuLis, "Log");
    addB(menu, new JMenuItem("ロゴ入り画像（スタンプ押印）"), menuLis, "LBG");
    addB(menu, new JMenuItem("切り貼り用マルチ・マスク"), menuLis, "MSK");
    addB(menu, new JMenuItem("切り貼り"),                 menuLis, "CAP");
    addB(menu, new JMenuItem("二重像用グレー・マスク"),   menuLis, "MiM");
    addB(menu, new JMenuItem("二重像処理"),               menuLis, "Mix");
    addB(menu, new JMenuItem("ソフト・フォーカス用元絵"), menuLis, "SFx");
    addB(menu, new JMenuItem("ソフト・フォーカス処理"),   menuLis, "SFo");
    addB(menu, new JMenuItem("畳み込み処理（鮮鋭化／朦朧化）"), menuLis, "Con");
    addB(menu, new JMenuItem("輪郭線抽出"),               menuLis, "GOL");
    addB(menu, new JMenuItem("画像多段階回転描画の準備"), menuLis, "RoI");
    addB(menu, new JMenuItem("画像多段階回転描画"),       menuLis, "RoM");
    addB(menu, new JMenuItem("連続色相変更"),             menuLis, "CCM");
    addB(menu, new JMenuItem("単独色相変更"),             menuLis, "ChC");
    addB(menu, new JMenuItem("色相階調加工"),             menuLis, "Grd");
    addB(menu, new JMenuItem("画像鏡像反転"),             menuLis, "REV");
    addB(menu, new JMenuItem("画像切り取り保存"),         menuLis, "CAS");

    addA(menuBar, menu = new JMenu("見本４"));
    addB(menu, new JMenuItem("スプライン曲線図形１"),     menuLis, "Sp1");
    addB(menu, new JMenuItem("輪郭線図形単独彩色"),       menuLis, "SpP");
    addB(menu, new JMenuItem("スプライン曲線図形２"),     menuLis, "Sp2");
    addB(menu, new JMenuItem("輪郭線図形連続彩色"),       menuLis, "SpM");
    addB(menu, new JMenuItem("輪郭線図形連続彩色SF"),     menuLis, "SpS");
    addB(menu, new JMenuItem("輪郭線図形連続彩色仕上"),   menuLis, "SpF");
    addB(menu, new JMenuItem("スプライン曲線図形３"),     menuLis, "Sp3");
    addB(menu, new JMenuItem("輪郭線図形連続自動彩色"),   menuLis, "SpA");

    addA(menuBar, menu = new JMenu("倍率"));
    addB(menu, new JMenuItem("表示:x4"),    menuLis, "XL4");
    addB(menu, new JMenuItem("表示:x3"),    menuLis, "XL3");
    addB(menu, new JMenuItem("表示:x2"),    menuLis, "XL2");
    addB(menu, new JMenuItem("表示:x1.5"),  menuLis, "XML");
    addB(menu, new JMenuItem("表示:x1"),    menuLis, "XM1");
    addB(menu, new JMenuItem("表示:x1/1.5"),menuLis, "XMS");
    addB(menu, new JMenuItem("表示:x1/2"),  menuLis, "XS2");
    addB(menu, new JMenuItem("表示:x1/3"),  menuLis, "XS3");
    addB(menu, new JMenuItem("表示:x1/4"),  menuLis, "XS4");

    addA(menuBar, menu = new JMenu("画面モード"));
    addB(menu, new JMenuItem("標準表示"),   menuLis, "Sc1");
    addB(menu, new JMenuItem("パレット表示"), menuLis, "Sc2");
    addB(menu, new JMenuItem("トーン・カーブ表示"), menuLis, "Sc3");

    addA(menuBar, menu = new JMenu("マウス描画モード"));
    addB(menu, new JMenuItem("マウス描画有効モード"), menuLis,"Of1");
    addB(menu, new JMenuItem("マウス描画無効モード"), menuLis,"Of2");

    addA(menuBar, menu = new JMenu("マウス描画機能"));
    addB(menu, new JMenuItem("直線"),       menuLis, "Lin");
    addB(menu, new JMenuItem("直線消去"),   menuLis, "Eli");
    addB(menu, new JMenuItem("折れ線"),     menuLis, "LLi");
    addB(menu, new JMenuItem("ベジェ曲線"), menuLis, "Cur");
    addB(menu, new JMenuItem("スプライン曲線"), menuLis,"Spl");
    addB(menu, new JMenuItem("スプライン曲線制御点消去"), menuLis,"SpE");
    addB(menu, new JMenuItem("スプライン曲線制御点増殖"), menuLis,"SpZ");
    menu.addSeparator();
    addB(menu, new JMenuItem("文字列"),     menuLis, "St2");
    menu.addSeparator();
    addB(menu, new JMenuItem("真円"),       menuLis, "Cir");
    addB(menu, new JMenuItem("真円消去"),   menuLis, "CiE");
    addB(menu, new JMenuItem("楕円"),       menuLis, "Ell");
    addB(menu, new JMenuItem("四角形"),     menuLis, "Rec");
    addB(menu, new JMenuItem("自由図形"),   menuLis, "Fre");
    menu.addSeparator();
    addB(menu, new JMenuItem("目印線消去"), menuLis, "ECu");
    addB(menu, new JMenuItem("目印線復活"), menuLis, "DCu");
    addB(menu, new JMenuItem("位置確認"),   menuLis, "Pos");
    addB(menu, new JMenuItem("位置修正"),   menuLis, "AC3");
    addB(menu, new JMenuItem("色相確認"),   menuLis, "Clx");
    addB(menu, new JMenuItem("図形彩色指定変更"), menuLis, "CoP");
    addB(menu, new JMenuItem("命令文検索"), menuLis, "Ref");
    menu.addSeparator();
    addB(menu, new JMenuItem("点描画筆（大）"), menuLis, "BrL");
    addB(menu, new JMenuItem("点描画筆（中）"), menuLis, "BrM");
    addB(menu, new JMenuItem("点描画筆（小）"), menuLis, "BrS");
    menu.addSeparator();
    addB(menu, new JMenuItem("スプレー"),   menuLis, "Spr");
    addB(menu, new JMenuItem("スプレー飛沫円盤中間点消去"),   menuLis, "SpX");

    addA(menuBar, menu = new JMenu("ヘルプ"));
    addB(menu, new JMenuItem("命令仕様書"), menuLis, "Usa");
    addB(menu, new JMenuItem("模様データ"), menuLis, "Ptn");

    menuBar.add(fillerLabel); //空白の設置
    menuBar.add(scaleLabel);  //倍率表示（affine scale）
    menuBar.add(scaleLabel2); //倍率表示（free scale）
    menuBar.add(pixelLabel);  //サイズ表示（px）
    menuBar.add(mmLabel);     //サイズ表示（mm）

    //●BUTTON BAR:ボタン表示部品
    //以下は、命令文操作に用いるボタン・バーのレイアウト
    buttonBarC.setLayout(new FlowLayout(FlowLayout.LEFT));
    addB(buttonBarC, new JButton("削除"),
      new ActionListener()
      { public void actionPerformed(ActionEvent event)
        { cArea.cut(); } } ,"");
    addB(buttonBarC, new JButton("複写"),
      new ActionListener()
      { public void actionPerformed(ActionEvent event)
        { cArea.copy(); } } ,"");
    addB(buttonBarC, new JButton("挿入"),
      new ActionListener()
      { public void actionPerformed(ActionEvent event)
        { cArea.paste(); } } ,"");
    addB(buttonBarC, new JButton("保存"),   buttonLis, "SvC");

    //以下は、キャンバス画像表示に用いるボタン・バーのレイアウト
    buttonBarG.setLayout(new FlowLayout(FlowLayout.LEFT));
    addB(buttonBarG, new JButton("描画"),   buttonLis, "Rep");
    addB(buttonBarG, new JButton("乱数"),   buttonLis, "Rp2");
    addB(buttonBarG, new JButton("切取"),   buttonLis, "SvP");
    addB(buttonBarG, new JButton("保存"),   buttonLis, "SvI");
    buttonBarG.add(matrixStUnitLabel);
    buttonBarG.add(matrixExUnitLabel);
    buttonBarG.add(mouseModeLabel);

    //二種類の「保存」ボタンは、命令文書に「SaveCommands」命令や
    //「SaveImage」命令を含む時、該当するファイル保存操作を半自動で実行する。
    //なお、ボタン操作でなく、メニュー操作によるファイル保存も、常に可能。

    //以下は、パレット混色に用いるボタン・バーのレイアウト
    buttonBarP.setLayout(new FlowLayout(FlowLayout.LEFT));
    addB(buttonBarP, new JButton("取消"), buttonLis, "Can");
    //パレットで、「混色なし混色補正なし」で色相を直接数値で指定する場合、
    //以下のJTextFieldに、色彩のRGBを「255,100,50」の形式で入力する。（鍵括弧不用）
    paletteRGB = new JTextField(12);
    addC(buttonBarP, paletteRGB, buttonLis, "TFP");

    //以下は、スライダーのキャンセルに用いるボタン・バーのレイアウト
    buttonBarS.setLayout(new FlowLayout(FlowLayout.LEFT));
    addB(buttonBarS, new JButton("復元"), buttonLis, "Adj");

    //以下は、トーン・カーブ調色に用いるボタン・バーのレイアウト
    buttonBarT.setLayout(new FlowLayout(FlowLayout.LEFT));
    addB(buttonBarT, new JButton("原画"), buttonLis, "TC1");
    addB(buttonBarT, new JButton("調色"), buttonLis, "TC2");
    addB(buttonBarT, new JButton("終了"), buttonLis, "TC3");

    //●COMMAND AREA:命令文表示
    cArea = new JTextArea(cdLines,cdCols);
    scrollC = new JScrollPane(cArea,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    cArea.setBackground(new Color(230,230,255));
    cArea.setMargin(new Insets(3, 3, 3, 3)); //余白
    cArea.setEditable(true);  //編集可能

    //●PALETTE AREA:パレット表示
    scrollP = new JScrollPane(palette,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    palette.setPreferredSize(new Dimension(300,600));
    palette.setOpaque(true); //不透明化
    palette.addMouseListener(pMouseLis);

    //●SLIDER AREA:スライダー表示
    scrollS = new JScrollPane(sliderPanel,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    sliderPanel.setPreferredSize(new Dimension(50,600));
    sliderPanel.setLayout(new GridLayout(4,1));
    sliderPanel.setOpaque(true); //不透明化

    sldR = new JSlider(JSlider.VERTICAL,-50,50,0); //赤
    sldR.addChangeListener(sliderLis);
    sldR.setMajorTickSpacing(10);
    sldR.setMinorTickSpacing(5);
    sldR.setPaintTicks(true);
    sldR.setPaintLabels(true);
    sldR.setBackground(Color.red);
    sldR.setForeground(Color.white);
    f.sliderPanel.add(sldR);

    sldG = new JSlider(JSlider.VERTICAL,-50,50,0); //緑
    sldG.addChangeListener(sliderLis);
    sldG.setMajorTickSpacing(10);
    sldG.setMinorTickSpacing(5);
    sldG.setPaintTicks(true);
    sldG.setPaintLabels(true);
    sldG.setBackground(Color.green);
    sldG.setForeground(Color.white);
    f.sliderPanel.add(sldG);

    sldB = new JSlider(JSlider.VERTICAL,-50,50,0); //青
    sldB.addChangeListener(sliderLis);
    sldB.setMajorTickSpacing(10);
    sldB.setMinorTickSpacing(5);
    sldB.setPaintTicks(true);
    sldB.setPaintLabels(true);
    sldB.setBackground(Color.blue);
    sldB.setForeground(Color.white);
    f.sliderPanel.add(sldB);

    //●TORN CURVE AREA:トーン・カーブ表示
    scrollT = new JScrollPane(toneCurve,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    toneCurve.setPreferredSize(new Dimension(300,600));
    toneCurve.setOpaque(true); //不透明化
    toneCurve.addMouseListener(tMouseLis);

    //●CANVAS AREA:キャンバス表示
    scrollG = new JScrollPane(canvas,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollG.setPreferredSize(new Dimension(
      (int)(scrollC.getPreferredSize().getWidth()*2.5),
      (int)scrollC.getPreferredSize().getHeight()));
    canvas.setPreferredSize(new Dimension(10000,10000));
    canvas.setOpaque(true); //不透明化
    canvas.addMouseListener(cMouseLis);

    //●MESSAGE AREA:警告文表示
    mArea = new JTextArea(mLines,mCols);
    mArea.setBackground(new Color(230,230,255));
    mArea.setMargin(new Insets(3, 3, 3, 3)); //余白
    scrollM = new JScrollPane(mArea,
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    mArea.setAutoscrolls(true);  //自動スクロール

    //●全体レイアウト初期設定（パレット非表示画面）
    //ボックス・レイアウトを利用
    pane = getContentPane();
    Box vBox = Box.createVerticalBox();
    Box vBoxC = Box.createVerticalBox();
    Box vBoxG = Box.createVerticalBox();
    Box hBox = Box.createHorizontalBox();
    pane.add(vBox);
    vBox.add(hBox);
    vBox.add(scrollM);
    hBox.add(vBoxC);
    hBox.add(vBoxG);
    vBoxC.add(buttonBarC);
    vBoxC.add(scrollC);
    vBoxG.add(buttonBarG);
    vBoxG.add(scrollG);
    scrollCWidth =  (int)scrollC.getPreferredSize().getWidth();
    scrollCHeight = (int)scrollC.getPreferredSize().getHeight();
    scrollMHeight = (int)scrollM.getPreferredSize().getHeight();
    scrollC.setPreferredSize(new Dimension(
      (int)(scrollCWidth), scrollCHeight ));
    scrollG.setPreferredSize(new Dimension(
      (int)(scrollCWidth *1.8), scrollCHeight ));
    pack();
    setVisible(true);

    GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    int screenW = gd.getDisplayMode().getWidth();
    int screenH = gd.getDisplayMode().getHeight();
    message("hardware screen size = " + screenW + " × " + screenH + " px");
    //上記スクリーン・サイズは、ハードウェアとしての本来の数値。

    screenW = getToolkit().getScreenSize().width;
    screenH = getToolkit().getScreenSize().height;
    message("software screen size = " + screenW + " × " + screenH + " px");
    //上記スクリーン・サイズは、OSでセットアップされたソフトウェアでの数値。

    int barH = 10; //この数値は適当に小さい数（丈固定統一）
    buttonBarC.setMaximumSize(new Dimension(Short.MAX_VALUE, barH));
    buttonBarG.setMaximumSize(new Dimension(Short.MAX_VALUE, barH));
    buttonBarP.setMaximumSize(new Dimension(Short.MAX_VALUE, barH));
    buttonBarS.setMaximumSize(new Dimension(Short.MAX_VALUE, barH));
  }

  //■全体レイアウトの切り替え（画面切り替え）
  public void changeLayout(int mode)
  {
    pane.removeAll();
    if(mode==1) //●標準画面
    {
      Box vBox = Box.createVerticalBox();
      Box vBoxC = Box.createVerticalBox();
      Box vBoxG = Box.createVerticalBox();
      Box hBox = Box.createHorizontalBox();
      pane.add(vBox);
      vBox.add(hBox);
      vBox.add(scrollM);
      hBox.add(vBoxC);
      hBox.add(vBoxG);
      vBoxC.add(buttonBarC);
      vBoxC.add(scrollC);
      vBoxG.add(buttonBarG);
      vBoxG.add(scrollG);
      scrollC.setPreferredSize(new Dimension(
        (int)(scrollCWidth), scrollCHeight ));
      scrollG.setPreferredSize(new Dimension(
        (int)(scrollCWidth *1.8), scrollCHeight ));
      f.pack();
      f.setVisible(true);
    }
    else if(mode==2)//●パレット表示画面
    {
      Box vBox = Box.createVerticalBox();
      Box vBoxC = Box.createVerticalBox();
      Box vBoxP = Box.createVerticalBox();
      Box vBoxS = Box.createVerticalBox();
      Box vBoxG = Box.createVerticalBox();
      Box hBox = Box.createHorizontalBox();
      pane.add(vBox);
      vBox.add(hBox);
      vBox.add(scrollM);
      hBox.add(vBoxC);
      hBox.add(vBoxP);
      hBox.add(vBoxS);
      hBox.add(vBoxG);
      vBoxC.add(buttonBarC);
      vBoxC.add(scrollC);
      vBoxP.add(buttonBarP);
      vBoxP.add(scrollP);
      vBoxS.add(buttonBarS);
      vBoxS.add(scrollS);
      vBoxG.add(buttonBarG);
      vBoxG.add(scrollG);
      scrollC.setPreferredSize(new Dimension(
         (int)(scrollCWidth*0.6), scrollCHeight));
      scrollP.setPreferredSize(new Dimension(
         (int)(scrollCWidth*0.5), scrollCHeight));
      scrollS.setPreferredSize(new Dimension(
         (int)(scrollCWidth*0.15), scrollCHeight));
      scrollG.setPreferredSize(new Dimension(
         (int)(scrollCWidth*1.55), scrollCHeight));
      f.pack();
      f.setVisible(true);
    }
    else if(mode==3)//●トーン・カーブ表示画面
    {
      Box vBox = Box.createVerticalBox();
      Box vBoxC = Box.createVerticalBox();
      Box vBoxP = Box.createVerticalBox();
      Box vBoxG = Box.createVerticalBox();
      Box hBox = Box.createHorizontalBox();
      pane.add(vBox);
      vBox.add(hBox);
      vBox.add(scrollM);
      hBox.add(vBoxC);
      hBox.add(vBoxP);
      hBox.add(vBoxG);
      vBoxC.add(buttonBarC);
      vBoxC.add(scrollC);
      vBoxP.add(buttonBarT);
      vBoxP.add(scrollT);
      vBoxG.add(buttonBarG);
      vBoxG.add(scrollG);
      scrollC.setPreferredSize(new Dimension(
         (int)(scrollCWidth*0.6), scrollCHeight));
      scrollT.setPreferredSize(new Dimension(
         (int)(scrollCWidth*0.5), scrollCHeight));
      scrollG.setPreferredSize(new Dimension(
         (int)(scrollCWidth*1.7), scrollCHeight));
      f.pack();
      f.setVisible(true);
    }
    else
      f.message("画面切り替えに異常。");
  }

  //■コンテナーに JMenu をレイアウト
  public void addA(Container cont, AbstractButton b)
  {
    cont.add(b);
  }
  //■コンテナーに JButton or JMenuItem をレイアウト
  public void addB(Container cont, AbstractButton b,
    ActionListener lis, String command)
  {
    cont.add(b);
    if(lis!=null)
      b.addActionListener(lis);
    if(command!=null)
      b.setActionCommand(command);
  }
  //■コンテナーに JButton or JMenuItem をレイアウト
  public void addC(Container cont, JTextField tf,
    ActionListener lis, String command)
  {
    cont.add(tf);
    if(lis!=null)
      tf.addActionListener(lis);
    if(command!=null)
      tf.setActionCommand(command);
  }

  //■システムメッセージの表示
  //Java仮想マシンが吐き出すエラー・メッセージまたは
  //GCreatorプログラム内から吐き出す警告文や通知文を表示
  public void message(String s)
  {  //●エラー通知、または、状況報告
    int len = mArea.getText().length();
    mArea.select(len, len); //自動スクロール
    mArea.append(s + "\n");
  }
} //EOF (GCreator.java)

◆GCreatorCanvasEngine.java

//■■GCreatorCanvasEngine.java
//Ver.4.1

//■■インポート
import java.awt.*;  //必須
import java.awt.geom.*;  //必須
import java.awt.image.*;  //必須
import java.util.List;  //必須（曖昧回避）
import java.util.*;  //必須
import javax.swing.*;  //必須
import java.io.*;  //必須
import javax.imageio.*;  //必須
import javax.imageio.stream.*;  //必須

//■■■描画機能の実現
class GCreatorCanvasEngine extends JComponent
{

  //■■変数宣言
  //■メンバー変数
  GCreator f; //JFlameの継承インスタンス
  Graphics2D g2;

  //●命令文関連の変数
  double imagePX_W = 0;  //指定画像サイズ幅（ピクセル単位）
  double imagePX_H = 0;  //指定画像サイズ丈（ピクセル単位）
  double printMM_W = 0;  //指定画像サイズ幅（ミリ単位）
  double printMM_H = 0;  //指定画像サイズ丈（ミリ単位）

  boolean markFlag          = true; //描画起点や曲線制御点などの目印線
  boolean commandInspection = false; //命令の記述エラー検査
  boolean canSaveMode       = false; //画像保存モード

  long randomSeed = //模様作成乱数初期値
    new GregorianCalendar().get(Calendar.MILLISECOND);
  Random ran = new Random(randomSeed);
  long randomSeed2 =  //間欠描画およびスプレーに用いる乱数初期値
    new GregorianCalendar().get(Calendar.MILLISECOND);
  Random ran2St = null;
  Random ran2Ex = null;
  Random ranSpray = new Random(new GregorianCalendar().get(Calendar.MILLISECOND));

  //画像倍率
  double affineScale = 1.0; //表示倍率
  double freeScale   = 1.0; //追加倍率

  //Shift命令
  int  shiftMode  = 0; //シフト区分（画像のシフト）
  double shiftX   = 0; //シフト量X
  double shiftY   = 0; //シフト量Y

  //Rotate命令
  boolean rotateFlag        = false; //90度回転モード
  double affineDegree       = 0.0;   //90度回転角度

  //RotateFree命令
  boolean rotateFreeFlag    = false; //指定角度回転モード
  double affineDegreeFree   = 0.0;   //指定角度回転角度
  int rotateFreeW           = 0;     //回転に伴って必要なx軸原点移動
  int rotateFreeH           = 0;     //回転に伴って必要なy軸原点移動

  //RoteteMulti命令（画像多段階回転重複描画）
  boolean rotateMultiFlag        = false;
  double rotateMultiStartDegree  = 0D;    //回転開始角度（ディグリー）
  double rotateMultiDegree       = 0D;    //回転角度（ディグリー）
  int rotateMultiTimes           = 0;    //回転回数
  String rotateMultiF            = null; //回転対象画像のファイル名（パス付き）
  BufferedImage rotateMultiImage = null; //完成画像の格納領域

  //SaveCommands命令
  String saveCmdFName = ""; //命令文書の保存ファイル名（パス付き）
  //SaveImage命令
  String saveImgFName = ""; //作成画像の保存ファイル名（パス付き）

  //CutAndSave命令
  int cutAndSaveImgX1 = 0; //作成画像の切り出し領域の左上ｘ座標
  int cutAndSaveImgY1 = 0; //作成画像の切り出し領域の左上ｙ座標
  int cutAndSaveImgX2 = 0; //作成画像の切り出し領域の右下ｘ座標
  int cutAndSaveImgY2 = 0; //作成画像の切り出し領域の右下ｙ座標
  String cutAndSaveImgFName = ""; //作成画像の切り取り保存ファイル名称（パス付き）

  //ChangeColor命令（単独色相変更）
  String colorChangeFile  = ""; //色変換処理対象画像のファイル名
  boolean colorChangeFlag = false; //色変換要求の有無
  int acceptableLimitC = 0;    //微妙な色の変動許容量
  int colorChangeMode  = 0;    //色相変更モード
  int colorChange1R    = 0;    //色変換の旧色
  int colorChange1G    = 0;
  int colorChange1B    = 0;
  int colorChange2R    = 0;    //色変換の新色
  int colorChange2G    = 0;
  int colorChange2B    = 0;
  BufferedImage colorChangeImage0 = null;
  BufferedImage colorChangeImage1 = null;

  //ReverseImage命令
  boolean reverseImageFlag    = false; //画像反転要求の有無
  String reverseImageFile     = "";    //画像反転の加工前対象画像ファイル名
  int reverseImageMode        = 0;     //反転方式の指定
  BufferedImage reverseImage0 = null;  //加工前画像
  BufferedImage reverseImage1 = null;  //加工後画像
  BufferedImage reverseImageX = null;  //90度または270度回転加工後画像

  //ColorGradient命令
  String gradientFName = ""; //線形階調加工の対象ファイル名
  int gradientY1 = 0;        //加工開始y軸位置
  int gradientY2 = 0;        //加工終了y軸位置
  double gradientR = 0.0;
  double gradientG = 0.0;
  double gradientB = 0.0;
  BufferedImage gradientImage0 = null;
  BufferedImage gradientImage1 = null;

  //MixImage命令
  String mixFName0        = ""; //二重像画像処理の対象ファイル名
  String mixFName1        = ""; //二重像画像処理の対象ファイル名
  int mixMode             = 1;  //通常のモード
  BufferedImage mixImage0 = null;
  BufferedImage mixImage1 = null;
  BufferedImage mixImage2 = null;

  //SoftFocus命令
  String softFocusFName = "";  //ソフト・フォーカス効果の対象画像ファイル名
  int softFocusDegree = 1;   //ソフト・フォーカス反復の度合い（0～100）
  BufferedImage softFocusImage0 = null;
  BufferedImage softFocusImage1 = null;

  //Convolve命令（画像の畳み込み処理：画像の鮮鋭化／画像の朦朧化）
  String convolveFName = "";   //畳み込み処理の元画像ファイル名
  float convolveV0 = 0.0f;     //ピクセルの中心点
  float convolveV1 = 0.0f;     //ピクセル中心点の上下左右隣接点
  float convolveV2 = 0.0f;     //ピクセル中心点の斜め方向隣接点
  float convolveV3 = 0.0f;     //5x5ピクセルの外周部
  float convolveV4 = 0.0f;     //5x5ピクセルの外周部
  float convolveV5 = 0.0f;     //5x5ピクセルの外周部
  int convolveKernelSize = 3;  //カーネル構成（3x3 or 5x5）
  int convolveDegree = 1;   //畳み込み反復の度合い（1～100）
  int convolveNoizeTolerance = 0; //ノイズ除去の可否
  int convolveColorDistance = 0;
  BufferedImage convolveImage0 = null; //元画像（写真画像を想定）
  BufferedImage convolveImage1 = null; //畳み込み画像
  BufferedImage convolveImage2 = null; //元画像の一時保存

  //GetOutline命令（輪郭線抽出）
  String outlineFName = "";  //元画像ファイル名
  int outlineColorDistance = 0;     //輪郭線（想定）に隣接するピクセル色との色差
  int outlineNoizeKernel = 3; //ノイズ除去で用いるカーネル・サイズ
  int outlineNoizeTolerance = 1; //ノイズ除去で用いるノイズ許容度
  BufferedImage outlineImage0 = null; //元画像（写真画像を想定）
  BufferedImage outlineImage1 = null; //輪郭線画像

  //マスク関連の用語定義
  //「マスク」は、「Stamp」や「CutAndPaste」や「ChangeColorMalti」などで用いる領域区分画像。
  //「Stamp」では、シングル・マスク（グレー・マスク）を用いる。
  //グレー・マスクは、透過部分をグレー色とし、それ以外の部分を表示したい図柄とする。
  //「CutAndPaste」や「ChangeColorMalti」では、マルチ・マスク（カラー・マスク）を用いる。
  //マルチ・マスクは、多色で色分けされた領域区分図であり、表示したい図柄が含まれない。

  //CutAndPaste命令
  boolean             cutAndPasteMaskFlag = false;
  boolean             cutAndPasteFlag     = false;
  String              capMaskF  = "";   //CutAndPaste用マルチ・マスク画像のファイル名
  BufferedImage       capImageM = null; //マルチ・マスク画像
  BufferedImage       capImage0 = null; //旧画像（切り貼り処理前画像）
  BufferedImage       capImage1 = null; //新画像（切り貼り処理完了画像）
  List<String>        capListF  = null; //前景画像（切り貼り元模様画像）リスト
  List<int[]>         capListI  = null; //指定色数値データリスト

  //ChangeColorMulti命令
  boolean             changeColorMultiBaseFlag = false;
  boolean             changeColorMultiFlag     = false;
  String              ccmMaskF  = "";   //ChangeColorMalti用　元画像のファイル名
  BufferedImage       ccmImage0 = null; //旧画像（連続色相変更処理前画像）
  BufferedImage       ccmImage1 = null; //新画像（連続色相変更処理完了画像）
  List<int[]>         ccmListI0 = null; //旧色指定リスト
  List<int[]>         ccmListI1 = null; //新色指定リスト

  //ChangeColorInner命令（図形内部単独彩色）
  //輪郭線で囲まれた閉じた図形領域を指定色で彩色。
  //彩色対象画像は、輪郭線で囲まれた図形内部に、
  //プログラムがスキャンしながら彩色位置を探し出し彩色し、輪郭線まで領域拡大を行なう。
  //輪郭線が予想外の理由により途切れることがあれば、正しく機能しない。
  boolean             changeColorInnerFlag = false;
  String              changeColorInnerF = ""; //彩色対象ファイル名（パス含む）
  int                 cciOutlineColorR = 0;   //輪郭線色
  int                 cciOutlineColorG = 0;
  int                 cciOutlineColorB = 0;
  int                 cciInnerColorR   = 0;   //彩色指定
  int                 cciInnerColorG   = 0;
  int                 cciInnerColorB   = 0;
  int                 cciInnerX        = 0;   //彩色領域の代表位置X
  int                 cciInnerY        = 0;   //彩色領域の代表位置Y
  int                 cciMode          = 0;   //輪郭線をどの色にするかの選択肢
  BufferedImage       cciImage         = null;//彩色対象画像のイメージ・バッファ

  //ChangeColorInnerMulti命令（図形内部連続彩色）
  //輪郭線で囲まれた閉じた複数の図形領域を指定色で連続的に彩色。
  //彩色対象画像は、輪郭線で囲まれた図形（白地図形式）の内部各所に、
  //プログラムがスキャンしながら彩色位置を探し出し彩色し、輪郭線まで彩色領域拡大を行なう。
  //ただし、輪郭線が予想外の理由により途切れることがあれば、正しく機能しない。
  //また、複雑に屈曲した輪郭線が入り交じる図形を内部連続彩色するとなると、相当な時間を要する。
  //これを便宜的手法によって高速化するとなると、点描画機能を用いるなどして、
  //図形内部の何箇所か（箇所数は多い方が高速）を部分的に指定色で予め彩色しておくと良い。
  boolean             changeColorInnerMultiFlag = false;
  String              changeColorInnerMultiF = ""; //彩色対象ファイル名（パス含む）
  int                 ccimOutlineColorR = 0;   //輪郭線色
  int                 ccimOutlineColorG = 0;
  int                 ccimOutlineColorB = 0;
  BufferedImage       ccimImage         = null;//彩色対象画像のイメージ・バッファ
  List<int[]>         ccimListI;               //数値データ（R,G,B,X,Y）のリスト

  //ChangeColorInnerAuto命令（図形内部連続自動彩色）
  //ChangeColorInnerおよびChangeColorInnerMultiを代替する高機能命令
  boolean             changeColorInnerAutoFlag = false;
  String              changeColorInnerAutoF = "";
  int                 cciaBaseColorR = 255; //地色r
  int                 cciaBaseColorG = 255; //地色g
  int                 cciaBaseColorB = 255; //地色b
  int                 cciaOutlineColorR = 0; //輪郭r
  int                 cciaOutlineColorG = 0; //輪郭g
  int                 cciaOutlineColorB = 0; //輪郭b
  BufferedImage       cciaImage    = null;//彩色対象画像のイメージ・バッファ

  //Spray命令（エアー・ブラシ）
  boolean             sprayFlag = false; //スプレー命令の有無
  double              sprayGaussianOp; //正規分布スプレーでの分散係数
  List<Integer>       sprayDiscStatus_List; //スプレー命令のステータス
  List<Integer>       sprayDiscX_List; //スプレイ円盤状飛沫集団（円盤）の中心ｘ座標
  List<Integer>       sprayDiscY_List; //スプレイ円盤状飛沫集団（円盤）の中心ｙ座標
  List<Integer>       sprayUnitTP_List; //スプレイ飛沫の分布タイプ
  List<Double>        sprayUnitSS_List; //スプレイ飛沫一個のサイズ（px相当）
  List<Integer>       sprayUnitSR_List; //スプレイ飛沫の円盤状拡散分布半径（px相当）
  List<Integer>       sprayUnitST_List; //スプレイ飛沫の分布個数
  List<Integer>       sprayUnitR_List; //スプレイ飛沫の赤成分
  List<Integer>       sprayUnitG_List; //スプレイ飛沫の緑成分
  List<Integer>       sprayUnitB_List; //スプレイ飛沫の青成分
  List<Integer>       sprayUnitA_List; //スプレイ飛沫の透明度（alpha）

  //LinkedLine命令（折れ線）
  boolean             linkedLineFlag = false; //折れ線命令の有無
  List<Integer>       linkedLineStatusList; //折れ線命令のステータス
  List<Double>        linkedLineXList; //折れ線ｘ座標
  List<Double>        linkedLineYList; //折れ線ｙ座標

  //Stamp命令
  boolean             stampFlag = false;
  List<String>        stampListF; //Stamp画像のファイル名リスト
  List<int[]>         stampListI; //Stampの数値データ（位置、サイズ）リスト
  List<BufferedImage> stampListB; //Stamp画像のリスト
  //（注）StampMulti命令は、途中で複数のStamp命令に変換されている。
  Color transparentColor = new Color(200,200,200);  //グレー・マスク作成用の色
  //（注）一部透明化対象画像（スタンプ元画像）の透過部分は、この色で作成する。

  //Image命令
  boolean             imageFlag = false;
  List<String>        imageListF; //背景画像のファイル名リスト
  List<int[]>         imageListI; //背景画像の数値データ（位置、サイズ）リスト
  List<BufferedImage> imageListB; //背景画像リスト

  //トーン・カーブ命令
  boolean             toneCurveFlag = false;

  //Antialias命令
  boolean antialiasFlag = false; //線（輪郭線含む）のギザギザ緩和
  float lineWidth;       //線幅（統一）

  //各種の線描画
  double[][] lineArr;    //直線
  double[][] line2Arr;   //仮直線
  double[][] curveArr;   //ベジェ曲線
  double[][] splineArr;  //スプライン曲線（命令文の単純羅列）
  double[][] splineArrX;  //スプライン曲線X座標（曲線毎に分解）
  double[][] splineArrY;  //スプライン曲線Y座標（曲線毎に分解）
  int splineOption = 1000;  //スプライン曲線精細度

  //ParallelLine…命令
  float parallelLineWidth;

  double parallelLineH_x = 0; //横平行線の始点ｘ
  double parallelLineH_y = 0; //横平行線の始点ｙ
  double parallelLineH_l = 0; //線の長さ
  double parallelLineH_w = 0; //線の幅
  int parallelLineH_t    = 0; //線の本数
  int parallelLineH_m    = 0; //線の種類
  int parallelLineH_h    = 0; //中間線の有無

  double parallelLineV_x = 0; //縦平行線
  double parallelLineV_y = 0;
  double parallelLineV_l = 0;
  double parallelLineV_w = 0;
  int parallelLineV_t    = 0;
  int parallelLineV_m    = 0;
  int parallelLineV_h    = 0;

  double parallelLineH2_x = 0; //横平行線の始点ｘ（補助用）
  double parallelLineH2_y = 0; //横平行線の始点ｙ
  double parallelLineH2_l = 0; //線の長さ
  double parallelLineH2_w = 0; //線の幅
  int parallelLineH2_t    = 0; //線の本数
  int parallelLineH2_m    = 0; //線の種類
  int parallelLineH2_h    = 0; //中間線の有無

  double parallelLineV2_x = 0; //縦平行線（補助用）
  double parallelLineV2_y = 0;
  double parallelLineV2_l = 0;
  double parallelLineV2_w = 0;
  int parallelLineV2_t    = 0;
  int parallelLineV2_m    = 0;
  int parallelLineV2_h    = 0;

  GeneralPath gp;          //自由図形の描画に必要
  double[][] shapeArr;     //自由図形のコマンド全行分のデータ

  double[][] stringHArrD;  //水平文字列（並字）表示でのdouble型データ
  String[][] stringHArrS;  //水平文字列（並字）表示でのString型データ
  double[][] stringBArrD;  //水平文字列（極太字）表示でのdouble型データ
  String[][] stringBArrS;  //水平文字列（極太字）表示でのString型データ
  double[][] stringVArrD;  //垂直文字列（並字）表示でのdouble型データ
  String[][] stringVArrS;  //垂直文字列（並字）表示でのString型データ

  boolean fontBold = false; //太字指定（並字）

  Color backgroundColor;  //背景色
  Color foregroundColorL; //前景色（線色）
  Color foregroundColorS; //前景色（文字色）
  Color foregroundColorB; //前景色（極太文字色）

  int stripePatternType = 0; //描画無視／横縞／縦縞
  int stripePatternW    = 0;  //ストライプ幅
  int stripePRedBase    = 0; //赤基調色
  int stripePGreenBase  = 0; //緑基調色
  int stripePBlueBase   = 0; //青基調色

  //matrixPatternでの用語定義
  //ユニット unit：柄紋一個をユニットと称する。
  //セル cell（コマ／小間）：柄紋一個が６ｘ６の構成なら、その構成単位１個。
  //ピクセル pixel ：セルは複数（例えば８ｘ８）のピクセルで構成される。
  //シフト shift：柄紋を縦横に反復された文様全体の起点を移動させるコマ数。
  //ドロップ drop：柄紋配列の行または列の奇数偶数で、起点位置をずらすコマ数。
  //スキップ skip：柄紋と柄紋との間隔を調整するプラスまたはマイナスのコマ数。
  //リピート repeat：柄紋の反復回数
  //インターミッティング intermitting：１で常時描画、２～１０で間欠描画。

  int matrixPatternNumSt   = 0; //柄紋番号（４桁）
  int matrixPatternWH_St   = 1; //柄紋の幅丈（幅丈兼用コマ数）最低数１
  double matrixShiftH_St   = 0; //横起点シフトのコマ数
  double matrixShiftV_St   = 0; //縦起点シフトのコマ数
  double matrixDropH_St    = 0; //柄紋横ドロップのコマ数
  double matrixDropV_St    = 0; //柄紋縦ドロップのコマ数
  double matrixSkipH_St    = 0; //柄紋横スキップのコマ数
  double matrixSkipV_St    = 0; //柄紋縦スキップのコマ数
  int matrixRepeatH_StX    = 0; //柄紋横リピートの回数
  int matrixRepeatV_StX    = 0; //柄紋縦リピートの回数
  int matrixPRedBaseSt     = 0; //赤基調色
  int matrixPGreenBaseSt   = 0; //緑基調色
  int matrixPBlueBaseSt    = 0; //青基調色
  int matrixColorLimitSt   = 10; //色成分の上限制限（1～10の値）
  int matrixRepeatH_St     = 100; //リピート横（数値は有効なダミー）
  int matrixRepeatV_St     = 100; //リピート縦（数値は有効なダミー）
  int matrixUnitSt         = 6; //コマ数（数値は有効なダミー）
  int matrixIntermittingSt = 10; //間欠描画指定。1～9が間欠描画、10が通常描画
  short[][] rgbSt;            //ランダム配色（統一配色）

  int matrixPatternNumEx   = 0; //柄紋番号（４桁）
  int matrixPatternWH_Ex   = 1; //柄紋の幅丈（幅丈兼用コマ数）最低数１
  double matrixShiftH_Ex   = 0; //横起点シフトのコマ数
  double matrixShiftV_Ex   = 0; //縦起点シフトのコマ数
  double matrixDropH_Ex    = 0; //柄紋横ドロップのコマ数
  double matrixDropV_Ex    = 0; //柄紋縦ドロップのコマ数
  double matrixSkipH_Ex    = 0; //柄紋横スキップのコマ数
  double matrixSkipV_Ex    = 0; //柄紋縦スキップのコマ数
  int matrixRepeatH_ExX    = 0; //柄紋横リピートの指定値の回数
  int matrixRepeatV_ExX    = 0; //柄紋縦リピートの指定値の回数
  int matrixPRedBaseEx     = 0; //赤基調色
  int matrixPGreenBaseEx   = 0; //緑基調色
  int matrixPBlueBaseEx    = 0; //青基調色
  int matrixColorLimitEx   = 10; //色成分の上限制限（1～10の値）
  int matrixRepeatH_Ex     = 100; //リピート横計算値（数値は有効なダミー）
  int matrixRepeatV_Ex     = 100; //リピート縦計算値（数値は有効なダミー）
  int matrixUnitEx         = 6; //コマ数（数値は有効なダミー）
  int matrixIntermittingEx = 10; //間欠描画指定。1～9が間欠描画、10が通常描画
  short[][][][][][] rgbEx;    //ランダム配色（個別配色）

  String[] manualArr;
  String[] patternArr;
  final int pages = 1;    //印刷で用いる形式的な総ページ数
  float quality   = -1.0f; //jpeg画質指定
    //（ただし、-1.0fは、デフォルト画質を意味し指定する有り得ない画質数値）
    //jpegでの画質は、０から１を指定できる（１が最高画質）
  double currentPointX;   //最新クリック位置（マウス入力モード時）
  double currentPointY;   //最新クリック位置（マウス入力モード時）

  List<double[]> lineList   ;   //直線
  List<double[]> line2List  ;   //一時補助線
  List<double[]> curveList  ;   //ベジェ曲線
  List<double[]> splineList ;   //スプライン曲線
  List<double[]> ellipseList  ; //真円、楕円
  List<double[]> rectList   ;   //長方形
  List<double[]> shapeList  ;   //自由図形
  List<double[]> stringHListD ; //水平文字関連でのdouble型データ
  List<String[]> stringHListS ; //水平文字関連でのString型データ
  List<double[]> stringBListD ; //極太文字関連でのdouble型データ
  List<String[]> stringBListS ; //極太文字関連でのString型データ
  List<double[]> stringVListD ; //垂直文字関連でのdouble型データ
  List<String[]> stringVListS ; //垂直文字関連でのString型データ

  //■コンストラクタ
  GCreatorCanvasEngine(GCreator flame)
  {
    f = flame;
    affineScale = 1.0; //拡大率初期設定
    freeScale   = 1.0; //拡大率初期設定
    f.scaleLabel.setText("  (a:x1.0)");  //表示拡大率設定
    f.scaleLabel2.setText("  (f:x1.0)"); //表示拡大率設定
    manualArr  = TextIO.loadStrArr(new File("./sys/GCreator_Manual.txt"));
    patternArr = TextIO.loadStrArr(new File("./sys/GCreator_Pattern.txt"));
    rgbSt = getRandom_rgbSt(); //ランダム色の要求（事前準備）
    rgbEx = getRandom_rgbEx(); //ランダム色の要求（事前準備）
    imageListB = new LinkedList<BufferedImage>();
    stampListB = new LinkedList<BufferedImage>();
  }

  //■■変数初期化
  void setInit()
  { //●内部プログラムから呼び出される
    g2.setPaint(new Color(255,255,255)); //残留画像の消去
    g2.fill(new Rectangle2D.Double(
      0,0,f.canvas.getPreferredSize().width,
      f.canvas.getPreferredSize().height));

    //●変数の初期化
    antialiasFlag = false;
    imagePX_W     = 720; //描画範囲初期設定
    imagePX_H     = 1008; //描画範囲初期設定
    printMM_W     = imagePX_W/3.0; //mmとpxとの換算比率（便宜的独自規格）
    printMM_H     = imagePX_H/3.0; //mmとpxとの換算比率（便宜的独自規格）
    freeScale     = 1.0; //印刷に反映される拡大倍率
    shiftMode     = 0;
    shiftX        = 0;
    shiftY        = 0;
    lineWidth     = 0.5f; //デフォルトの線幅
    parallelLineWidth = 0.5f;  //デフォルトの平行線線幅
    f.matrixStUnitLabel.setText("");
    f.matrixExUnitLabel.setText("");

    affineDegree     = 0.0; //90度回転角度
    affineDegreeFree = 0.0; //指定角度回転角度
    rotateFlag       = false;//90度回転モード
    rotateFreeFlag   = false;//指定角度回転モード
    rotateFreeW      = 0; //回転に伴って必要なx軸原点移動
    rotateFreeH      = 0; //回転に伴って必要なy軸原点移動

    rotateMultiFlag        = false;
    rotateMultiF           = null;
    rotateMultiStartDegree = 0;
    rotateMultiDegree      = 0;
    rotateMultiTimes       = 0;

    quality   = -1.0f; //JPEG画質指定（GCreator独自のデフォルト画質指定。）

    parallelLineH_x = 0; //横平行線
    parallelLineH_y = 0;
    parallelLineH_l = 0;
    parallelLineH_w = 0;
    parallelLineH_t = 0;
    parallelLineH_m = 0;
    parallelLineH_h = 0;
    parallelLineV_x = 0; //縦平行線
    parallelLineV_y = 0;
    parallelLineV_l = 0;
    parallelLineV_w = 0;
    parallelLineV_t = 0;
    parallelLineV_m = 0;
    parallelLineV_h = 0;

    parallelLineH2_x = 0; //横平行線（補助用）
    parallelLineH2_y = 0;
    parallelLineH2_l = 0;
    parallelLineH2_w = 0;
    parallelLineH2_t = 0;
    parallelLineH2_m = 0;
    parallelLineH2_h = 0;
    parallelLineV2_x = 0; //縦平行線
    parallelLineV2_y = 0;
    parallelLineV2_l = 0;
    parallelLineV2_w = 0;
    parallelLineV2_t = 0;
    parallelLineV2_m = 0;
    parallelLineV2_h = 0;

    splineArr  = null;   //スプライン曲線（命令文の単純羅列）
    splineArrX = null;   //スプライン曲線X座標（曲線毎に分解）
    splineArrY = null;   //スプライン曲線Y座標（曲線毎に分解）
    splineOption = 1000; //スプライン曲線の精細度のデフォルト

    commandInspection = true;
    backgroundColor   = Color.white; //背景色
    foregroundColorL  = Color.black; //線色
    foregroundColorS  = Color.black; //文字色
    foregroundColorB  = Color.red;   //極太字色（ダミー）

    fontBold = false;

    colorChangeImage0 = null;
//    colorChangeImage1 = null;//加工後の画像　画像を保持

    saveCmdFName = "";  //命令文書の保存ファイル名称（パス付き）
    saveImgFName = "";  //作成画像の保存ファイル名称（パス付き）

    changeColorInnerFlag = false;
    changeColorInnerF = ""; //図形内部彩色対象ファイル名（パス含む）
    cciOutlineColorR = 0;   //輪郭線色デフォルト黒色
    cciOutlineColorG = 0;
    cciOutlineColorB = 0;
    cciInnerColorR   = 255; //彩色デフォルト赤色
    cciInnerColorG   = 0;
    cciInnerColorB   = 0;
    cciInnerX        = 0;
    cciInnerY        = 0;
    cciMode          = 0;   //輪郭線をどの色にするかの選択肢
    //cciImage         = null;//彩色対象画像のイメージ・バッファ　画像を保持

    changeColorInnerMultiFlag = false;
    changeColorInnerMultiF = ""; //彩色対象ファイル名（パス含む）
    ccimOutlineColorR = 0;   //輪郭線色
    ccimOutlineColorG = 0;
    ccimOutlineColorB = 0;
    ccimListI         = new ArrayList<int[]>(); //数値データ（R,G,B,X,Y）のリスト
    //ccimImage         = null; //彩色対象画像（輪郭線画像）のイメージ・バッファ

    changeColorInnerAutoFlag = false;
    changeColorInnerAutoF = "";
    cciaBaseColorR = 255; //地色r
    cciaBaseColorG = 255; //地色g
    cciaBaseColorB = 255; //地色b
    cciaOutlineColorR = 0; //輪郭r
    cciaOutlineColorG = 0; //輪郭g
    cciaOutlineColorB = 0; //輪郭b
    //cciaImage         = null; //彩色対象画像（輪郭線画像）のイメージ・バッファ

    sprayFlag             = false; //スプレー
    sprayGaussianOp       = 0.45;
    sprayDiscStatus_List  = new LinkedList<Integer>();
    sprayDiscX_List       = new LinkedList<Integer>();
    sprayDiscY_List       = new LinkedList<Integer>();
    sprayUnitTP_List      = new LinkedList<Integer>();
    sprayUnitSS_List      = new LinkedList<Double>();
    sprayUnitSR_List      = new LinkedList<Integer>();
    sprayUnitST_List      = new LinkedList<Integer>();
    sprayUnitR_List       = new LinkedList<Integer>();
    sprayUnitG_List       = new LinkedList<Integer>();
    sprayUnitB_List       = new LinkedList<Integer>();
    sprayUnitA_List       = new LinkedList<Integer>();

    linkedLineFlag        = false; //折れ線
    linkedLineStatusList  = new LinkedList<Integer>();
    linkedLineXList       = new LinkedList<Double>();
    linkedLineYList       = new LinkedList<Double>();

    cutAndSaveImgFName = ""; //作成画像の切り取り保存ファイル名称（パス付き）
    cutAndSaveImgX1    = 0; //作成画像の切り出し領域の左上ｘ座標
    cutAndSaveImgY1    = 0; //作成画像の切り出し領域の左上ｙ座標
    cutAndSaveImgX2    = 0; //作成画像の切り出し領域の右下ｘ座標
    cutAndSaveImgY2    = 0; //作成画像の切り出し領域の右下ｙ座標

    reverseImageFile    = "";    //画像反転の対象画像ファイル名（加工前）
    reverseImageFlag    = false; //画像反転要求の有無
    reverseImageMode    = 0;     //反転方式の指定
    reverseImage0       = null;  //加工前画像
//    reverseImage1       = null;  //加工後画像（初期化しない）　画像を保持
//    reverseImageX       = null;  //90度、270度、回転加工後画像（初期化しない）　画像を保持

    mixFName0 = ""; //二重像画像処理のファイル名（パス付き）
    mixFName1 = ""; //二重像画像処理のファイル名（パス付き）
    mixMode   = 1; //通常のモード
    mixImage0 = null;
    mixImage1 = null;
//    mixImage2 = null; //加工後の画像　　repaint()のために画像を保持

    softFocusFName = "";  //ソフト・フォーカスのファイル名（パス付き）
    gradientFName  = "";  //階調加工処理のファイル名（パス付き）

    outlineFName = "";        //輪郭線抽出の元画像
    outlineColorDistance = 0; //輪郭線での色段差
    outlineNoizeKernel = 3;
    outlineNoizeTolerance = 1;

    convolveFName = "";    //畳み込み処理の元画像ファイル名
    convolveV0 = 0.0f;     //ピクセルの中心点
    convolveV1 = 0.0f;     //ピクセルの中心点の上下左右隣接点
    convolveV2 = 0.0f;     //ピクセルの中心点の斜め方向隣接点
    convolveV3 = 0.0f;     //5x5での外周部
    convolveV4 = 0.0f;     //5x5での外周部
    convolveV5 = 0.0f;     //5x5での外周部
    convolveKernelSize = 3;  //カーネル構成（3x3 or 5x5）
    convolveDegree = 1;   //畳み込み反復の度合い（1～100）
    convolveNoizeTolerance = 0; //ノイズ許容度
    convolveColorDistance = 0; //ノイズと見なす色段差
    //convolveImage0 = null; //元画像（写真画像を想定）
    //convolveImage1 = null; //畳み込み画像
    //convolveImage2 = null; //元画像の一時保存

    colorChangeFile  = "";    //単独色相変換処理のファイル名（パス付き）
    colorChangeFlag  = false; //単独色相変更要求の有無
    acceptableLimitC = 0;     //単独色相変動許容値
    colorChangeMode  = 0;     //単独色相変更モード
    colorChange1R    = 0;     //単独色相変更の旧色
    colorChange1G    = 0;
    colorChange1B    = 0;
    colorChange2R    = 0;     //単独色相変更の新色
    colorChange2G    = 0;
    colorChange2B    = 0;

    //toneCurveFlag = false;

    stripePatternType = 0;

    matrixPatternNumSt   = 0; //描画しない（空白）
    matrixRepeatH_St     = 100; //有効な初期値
    matrixRepeatV_St     = 100; //有効な初期値
    matrixShiftH_St      = 0; //全体横シフト
    matrixShiftV_St      = 0; //全体縦シフト
    matrixDropH_St       = 0; //図柄横ドロップ
    matrixDropV_St       = 0; //図柄縦ドロップ
    matrixSkipH_St       = 0; //図柄横スキップ
    matrixSkipV_St       = 0; //図柄縦スキップ
    matrixRepeatH_St     = 0; //図柄横リピート
    matrixRepeatV_St     = 0; //図柄縦リピート
    matrixIntermittingSt = 10; //間欠描画
    matrixColorLimitSt   = 10; //色成分の上限制限（1～10の値）
//      matrixUnitSt       = 6; 初期化不可

    matrixPatternNumEx   = 0; //描画しない（空白）
    matrixRepeatH_Ex     = 100; //有効な初期値
    matrixRepeatV_Ex     = 100; //有効な初期値
    matrixShiftH_Ex      = 0; //全体横シフト
    matrixShiftV_Ex      = 0; //全体縦シフト
    matrixDropH_Ex       = 0; //図柄横ドロップ
    matrixDropV_Ex       = 0; //図柄縦ドロップ
    matrixSkipH_Ex       = 0; //図柄横スキップ
    matrixSkipV_Ex       = 0; //図柄縦スキップ
    matrixRepeatH_Ex     = 0; //図柄横リピート
    matrixRepeatV_Ex     = 0; //図柄縦リピート
    matrixIntermittingEx = 10; //間欠描画
    matrixColorLimitEx   = 10; //色成分の上限制限（1～10の値）
//    matrixUnitEx         = 6; 初期化不可

    lineList   = new ArrayList<double[]>(); //直線
    line2List  = new ArrayList<double[]>(); //一時補助線
    curveList  = new ArrayList<double[]>(); //ベジェ曲線
    splineList  = new ArrayList<double[]>(); //スプライン曲線
    ellipseList  = new ArrayList<double[]>(); //真円、楕円
    rectList   = new ArrayList<double[]>(); //長方形
    shapeList  = new ArrayList<double[]>(); //自由図形
    stringHListD = new ArrayList<double[]>(); //水平文字
    stringHListS = new ArrayList<String[]>(); //
    stringBListD = new ArrayList<double[]>(); //極太文字
    stringBListS = new ArrayList<String[]>(); //
    stringVListD = new ArrayList<double[]>(); //垂直文字
    stringVListS = new ArrayList<String[]>(); //

//    imageFlag    = false; //setinit2() で初期化する
//    imageListI   = new LinkedList<int[]>(); //背景画像
//    imageListF   = new LinkedList<String>();
//    imageListB   = new LinkedList<BufferedImage>();

//    stampFlag  = false; 初期化不可 //setinit2() で初期化する
//    stampListI = new LinkedList<int[]>();
//    stampListF = new LinkedList<String>();
//    stampListB = new LinkedList<BufferedImage>();

//    cutAndPasteMaskFlag = false;
//    cutAndPasteFlag     = false;
//    capMaskF = "";     //切り貼り用マルチ・マスクのファイル名（パス付き）
//    capImageM = null;  //マルチ・マスクの画像
//    capImage0 = null;  //切り貼り元模様画像
//    capImage1 = null;  //加工後の画像　画像を保持
//    capListF  = new LinkedList<String>(); //切り貼り元画像
//    capListI  = new LinkedList<int[]>();  //色相指定リスト

//    changeColorMultiBaseFlag = false;
//    changeColorMultiFlag     = false;
//    ccmMaskF  = "";   //ChangeColorMalti用　元画像のファイル名
//    ccmImage0 = null; //旧画像（連続色相変更処理前画像）
//    ccmImage1 = null; //新画像（連続色相変更処理完了画像）　画像を保持
//    ccmListI0 = new LinkedList<int[]>(); //旧色指定リスト
//    ccmListI1 = new LinkedList<int[]>(); //新色指定リスト

    //------------------------------------------------------------

    //●命令文の全文を解析し、命令文で指定された内容を変数に格納
    String commandZ = f.cArea.getText();
    f.analyze.commandAnalyze(commandZ); //解析

    //------------------------------------------------------------

    //●直線 数値の取得
    Object[] lineArr0 = lineList.toArray();
    lineArr  = new double[lineArr0.length][4];
    for(int i=0; i<lineArr0.length; i++)
    {
      lineArr[i][0] = ((double[])(lineArr0[i]))[0];
      lineArr[i][1] = ((double[])(lineArr0[i]))[1];
      lineArr[i][2] = ((double[])(lineArr0[i]))[2];
      lineArr[i][3] = ((double[])(lineArr0[i]))[3];
    }
    //●仮直線Draw2 数値の取得
    Object[] line2Arr0 = line2List.toArray();
    line2Arr  = new double[line2Arr0.length][5];
    for(int i=0; i<line2Arr0.length; i++)
    {
      line2Arr[i][0] = ((double[])(line2Arr0[i]))[0];
      line2Arr[i][1] = ((double[])(line2Arr0[i]))[1];
      line2Arr[i][2] = ((double[])(line2Arr0[i]))[2];
      line2Arr[i][3] = ((double[])(line2Arr0[i]))[3];
      line2Arr[i][4] = ((double[])(line2Arr0[i]))[4];
    }
    //●ベジェ曲線 数値の取得
    Object[] curveArr0 = curveList.toArray();
    curveArr  = new double[curveArr0.length][8];
    for(int i=0; i<curveArr0.length; i++)
    {
      curveArr[i][0] = ((double[])(curveArr0[i]))[0];
      curveArr[i][1] = ((double[])(curveArr0[i]))[1];
      curveArr[i][2] = ((double[])(curveArr0[i]))[2];
      curveArr[i][3] = ((double[])(curveArr0[i]))[3];
      curveArr[i][4] = ((double[])(curveArr0[i]))[4];
      curveArr[i][5] = ((double[])(curveArr0[i]))[5];
      curveArr[i][6] = ((double[])(curveArr0[i]))[6];
      curveArr[i][7] = ((double[])(curveArr0[i]))[7];
    }

    //●スプライン曲線 数値の取得
    Object[] splineArr0 = splineList.toArray();
    splineArr  = new double[splineArr0.length][3];
    for(int i=0; i<splineArr0.length; i++)
    {
      splineArr[i][0] = ((double[])(splineArr0[i]))[0];
      splineArr[i][1] = ((double[])(splineArr0[i]))[1];
      splineArr[i][2] = ((double[])(splineArr0[i]))[2];
    }
    int arrCnt0 = 0; //スプライン曲線の本数をカウント
    for(int i=0; i<splineArr.length; i++)
    {
      if(splineArr[i][0]==0) //スプライン曲線の起点
        arrCnt0++;
    }
    if(arrCnt0>0) //スプライン曲線があれば
    {
      splineArrX = new double[arrCnt0][]; //スプライン曲線毎に分解
      splineArrY = new double[arrCnt0][]; //スプライン曲線毎に分解
    }

    int arrCnt1 = 0; //スプライン曲線の制御点を個別にカウント
    arrCnt0 = 0; //スプライン曲線の本数カウントを初期化
    int scale = 1;
    int k=0; //複数あるスプライン曲線の特定番号
    for(int i=0; i<splineArr.length; i++)
    {
      if(splineArr[i][0]==0) //或るスプライン曲線の起点
      {
        ;
      }
      else if(splineArr[i][0]==1) //或るスプライン曲線の制御点
      {
        arrCnt1++; //制御点のカウント
      }
      else if(splineArr[i][0]==2) //或るスプライン曲線の終点
      {
        //スプライン曲線における制御点の個数は、一個以上で、個数に上限なし。
        splineArrX[k] = new double[arrCnt1+2]; //起点＋制御点数個＋終点
        splineArrY[k] = new double[arrCnt1+2];
        for(int j=0; j<arrCnt1+2; j++)
        { //座標データをコピー
          splineArrX[k][j] = splineArr[i-(arrCnt1+1)+j][1];
          splineArrY[k][j] = splineArr[i-(arrCnt1+1)+j][2];
        }
        k++; //次のスプライン曲線へ移行
        arrCnt1 = 0; //制御点カウント
        arrCnt0++; //スプライン曲線の本数カウント
      }
    }

    //●色塗り自由図形 数値の取得
    Object[] shapeArr0 = shapeList.toArray();
    shapeArr  = new double[shapeArr0.length][9];
    for(int i=0; i<shapeArr0.length; i++)
    {
      shapeArr[i][0] = (((double[])(shapeArr0[i]))[0]);
      shapeArr[i][1] = (((double[])(shapeArr0[i]))[1]);
      shapeArr[i][2] = (((double[])(shapeArr0[i]))[2]);
      shapeArr[i][3] = (((double[])(shapeArr0[i]))[3]);
      shapeArr[i][4] = (((double[])(shapeArr0[i]))[4]);
      shapeArr[i][5] = (((double[])(shapeArr0[i]))[5]);
      shapeArr[i][6] = (((double[])(shapeArr0[i]))[6]);
      shapeArr[i][7] = (((double[])(shapeArr0[i]))[7]);
      shapeArr[i][8] = (((double[])(shapeArr0[i]))[8]);
    }

    //●文字列（並字）　データの取得
    Object[] stringHArrD0 = stringHListD.toArray();
    Object[] stringHArrS0 = stringHListS.toArray();
    stringHArrD = new double[stringHArrD0.length][3];
    stringHArrS = new String[stringHArrS0.length][2];
    for(int i=0; i<stringHArrD0.length; i++)
    {
      stringHArrD[i][0] = ((double[])(stringHArrD0[i]))[0];
      stringHArrD[i][1] = ((double[])(stringHArrD0[i]))[1];
      stringHArrD[i][2] = ((double[])(stringHArrD0[i]))[2];
    }
    for(int i=0; i<stringHArrD0.length; i++)
    {
      stringHArrS[i][0] = ((String[])(stringHArrS0[i]))[0];
      stringHArrS[i][1] = ((String[])(stringHArrS0[i]))[1];
    }

    //●文字列（極太字）　データの取得
    Object[] stringBArrD0 = stringBListD.toArray();
    Object[] stringBArrS0 = stringBListS.toArray();
    stringBArrD = new double[stringBArrD0.length][4];
    stringBArrS = new String[stringBArrS0.length][2];
    for(int i=0; i<stringBArrD0.length; i++)
    {
      stringBArrD[i][0] = ((double[])(stringBArrD0[i]))[0];
      stringBArrD[i][1] = ((double[])(stringBArrD0[i]))[1];
      stringBArrD[i][2] = ((double[])(stringBArrD0[i]))[2];
      stringBArrD[i][3] = ((double[])(stringBArrD0[i]))[3];
    }
    for(int i=0; i<stringBArrD0.length; i++)
    {
      stringBArrS[i][0] = ((String[])(stringBArrS0[i]))[0];
      stringBArrS[i][1] = ((String[])(stringBArrS0[i]))[1];
    }

    //●垂直文字列（疑似縦書き）　データの取得
    Object[] stringVArrD0 = stringVListD.toArray();
    Object[] stringVArrS0 = stringVListS.toArray();
    stringVArrD = new double[stringVArrD0.length][3];
    stringVArrS = new String[stringVArrS0.length][2];
    for(int i=0; i<stringVArrD0.length; i++)
    {
      stringVArrD[i][0] = ((double[])(stringVArrD0[i]))[0];
      stringVArrD[i][1] = ((double[])(stringVArrD0[i]))[1];
      stringVArrD[i][2] = ((double[])(stringVArrD0[i]))[2];
    }
    for(int i=0; i<stringVArrD0.length; i++)
    {
      stringVArrS[i][0] = ((String[])(stringVArrS0[i]))[0];
      stringVArrS[i][1] = ((String[])(stringVArrS0[i]))[1];
    }
  } //setInit()

  void setInit2()
  { //●内部プログラムから呼び出される特殊な初期化
    //メニュー・イベント発生またはボタン・イベント発生でのみ初期化される
    imageFlag   = false;
    imageListI  = new LinkedList<int[]>(); //背景画像
    imageListF  = new LinkedList<String>();
    imageListB  = new LinkedList<BufferedImage>();

    stampFlag  = false;
    stampListI = new LinkedList<int[]>();
    stampListF = new LinkedList<String>();
    stampListB = new LinkedList<BufferedImage>();
    transparentColor = new Color(200,200,200);

    cutAndPasteMaskFlag = false;
    cutAndPasteFlag     = false;
    capMaskF = "";     //切り貼り用マルチ・マスクのファイル名（パス付き）
    capImageM = null;  //マルチ・マスクの画像
    capImage0 = null;  //切り貼り元模様画像
    capImage1 = null;  //加工後の画像　画像を保持
    capListF  = new LinkedList<String>(); //切り貼り元画像
    capListI  = new LinkedList<int[]>();  //色相指定リスト

    changeColorMultiBaseFlag = false;
    changeColorMultiFlag     = false;
    ccmMaskF  = "";   //ChangeColorMalti用　元画像のファイル名
    ccmImage0 = null; //旧画像（連続色相変更処理前画像）
    ccmImage1 = null; //新画像（連続色相変更処理完了画像）　画像を保持
    ccmListI0 = new LinkedList<int[]>(); //旧色指定リスト
    ccmListI1 = new LinkedList<int[]>(); //新色指定リスト
  } //setInit2()

  void setInit3()
  { //●内部プログラムから呼び出される特殊な初期化の追加補足
    //メニュー・イベント発生またはボタン・イベント発生でのみ初期化される
      if(imageFlag==true)
        image(); //背景画像表示の下準備
      if(stampFlag==true)
        f.canvas.stamp(); //スタンプ押印の下準備
      if(cutAndPasteMaskFlag==true && cutAndPasteFlag==true)
        cutAndPaste(); //切り貼り処理の下準備
      if(changeColorMultiBaseFlag==true && changeColorMultiFlag==true)
        changeColorMulti(); //連続色相変更処理の下準備

      softFocus();  //ソフト・フォーカス処理の下準備
      getOutline(); //輪郭線抽出の下準備
        convolve();   //畳み込み処理（先鋭化／朦朧化）の下準備
      changeColorInner();      //図形内部単独彩色
      changeColorInnerMulti(); //図形内部連続彩色
      changeColorInnerAuto();  //図形内部連続自動彩色
      mixImage(); //二重画像処理の下準備
      reverseImage(); //画像反転処理の下準備
      rotateMulti(); //画像多段回転処理の下準備
      colorChange(f.canvas.colorChangeMode); //色相部分領域変更処理の下準備
      colorGradient(); //色相グラデーション加工の下準備
  } //setInit3()

  //■■描画処理
  public void paintComponent(Graphics g)
  {
    drawPage(g, false);
  }

  //■１ページ分の描画（現状では、１ページ分のみ）
  //drawPage()は、印刷時にも呼び出される。
  //このプログラムでは、改ページの概念を設定していないが、
  //改ページできる形にプログラムを改造することも可能。
  void drawPage(Graphics g, boolean printMode)
  {
    //●描画の初期対応
    g2 = (Graphics2D)g;

    setInit();  //変数初期化
    g2.scale(affineScale*freeScale, affineScale*freeScale); //拡大
    g2.setPaint(new Color(255,255,255)); //残留画像の消去
    g2.fill(new Rectangle2D.Double(
      0,0,f.canvas.getPreferredSize().width,
      f.canvas.getPreferredSize().height));
    g2.setColor(backgroundColor);  //画像サイズ指定領域の画像消去
    g2.fill(new Rectangle2D.Double(0,0,imagePX_W,imagePX_H));

    if(commandInspection == false)
    {  //命令記述に誤りがあれば
      return;
    }

    if(rotateFlag) //画像全体を90度回転させる
    {
      g2.translate(imagePX_H, 0); //移動
      affineDegree = 90; //90度回転指定
      g2.rotate(affineDegree*Math.PI/180.0);
      //座標原点を中心に回転（指定順注意）
    }
    if(rotateFreeFlag) //画像全体を指定角度回転させる
    {
      g2.translate(rotateFreeW, rotateFreeH); //指定数値で移動
      affineDegree = affineDegreeFree; //指定角度回転指定
      g2.rotate(affineDegreeFree*Math.PI/180.0);
      //座標原点を中心に回転（指定順注意）
    }

    if(antialiasFlag == true) //線のギザギザ緩和
      //細い線の色が、周囲との中間色化で、非常に薄くなる
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    else
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_OFF);

    //●シフト処理の計算
    double sX = shiftX;
    double sY = shiftY;
    if(shiftMode==1)
    {  //シフトあり
      ;
    }
    else
    {  //シフトなし
      shiftX = sX = 0;
      shiftY = sY = 0;
    }

    //●線の描画準備
    BasicStroke solidLine = new BasicStroke( //太さ可変の実線の定義
      lineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    BasicStroke solidLineX = new BasicStroke( //太さ固定の細実線の定義
      0.5f, BasicStroke.CAP_SQUARE,
      BasicStroke.JOIN_MITER);

    BasicStroke dashLine = new BasicStroke( //太さ固定の点線の定義
      2.0f, BasicStroke.CAP_SQUARE,
      BasicStroke.JOIN_MITER, 5f, new float[] {4f,6f,10f,6f,4f,6f}, 0f);

    BasicStroke dotLine = new BasicStroke( //太さ固定で密の点線の定義
      0.5f, BasicStroke.CAP_SQUARE,
      BasicStroke.JOIN_MITER, 5f, new float[] {4f,4f}, 0f);
    BasicStroke dotLine2 = new BasicStroke( //太さ固定で粗の点線の定義
      0.5f, BasicStroke.CAP_SQUARE,
      BasicStroke.JOIN_MITER, 5f, new float[] {4f,12f}, 0f);

    BasicStroke solidLineP = new BasicStroke( //太さ可変の実線平行線の定義
      parallelLineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    BasicStroke dotLineP = new BasicStroke( //太さ可変で密の点線平行線の定義
      parallelLineWidth, BasicStroke.CAP_SQUARE,
      BasicStroke.JOIN_MITER, 5f, new float[] {4f,4f}, 0f);
    BasicStroke dotLineP2 = new BasicStroke( //太さ可変で粗の点線平行線の定義
      parallelLineWidth, BasicStroke.CAP_SQUARE,
      BasicStroke.JOIN_MITER, 5f, new float[] {4f,12f}, 0f);

    g2.setStroke(solidLine); //太さ可変の実線に設定
    g2.setColor(foregroundColorL);

    //------------------------------------------------------------

    //●●以下は、各種の「描画処理」
    //一般描画処理とは、線描画、面描画、点描画、ストライブ模様描画、マトリックス模様描画。
    //特殊描画処理とは、背景画像描画、スタンプ描画、各種画像変形処理。
    //全種類の描画処理（一般描画処理＋特殊描画処理）の順序は、全面描画が先で部分描画が後の順序。
    //また、面描画、線描画、文字描画の順序で並べる。
    //具体的には、以下に始まる描画順序である。
    //この順序に不都合があれば、途中で画像保存し、その画像をImage命令で再表示して作業を継続する。
    //複雑な構成の画像は、部品画像を別途多数作成し保存し、最終的にそれらを寄せ合わせて仕上げる。

    //●Image 背景画像（特殊描画処理の一種）の描画。
    if(f.canvas.imageFlag==true && imageListB!=null && imageListI!=null)
    {
      for(int i=0; i<imageListB.size(); i++)
      {
        //画像サイズ計算
        int w = imageListB.get(i).getWidth(this);
        int h = imageListB.get(i).getHeight(this);
        int imageX = 0;
        int imageY = 0;
        int imageW = 0;
        int imageH = 0;
        boolean err = false;
        try
        {
          imageX = imageListI.get(i)[0];
          imageY = imageListI.get(i)[1];
          imageW = imageListI.get(i)[2];
          imageH = imageListI.get(i)[3];
        }
        catch (Exception e)
        {
          f.message(e.toString());
          err = true;
        }
        if(imageListB.get(i) != null && err == false)
        { //描画する
          g2.drawImage(imageListB.get(i), imageX, imageY, imageW, imageH, this);
        }
      }
    }

    //------------------------------------------------------------

    //以下は、各種メソッドで指定された画像をキャンバスに表示する。

    //●ランダム・ストライプ描画
    if(stripePatternType >= 1)
    {
      //  int stripePatternType; //無効／水平／垂直、0/1/2
      //  int stripePatternW //ストライプ幅
      //  int stripePRedBase  //赤基調色
      //  int stripePGreenBase //緑基調色
      //  int stripePBlueBase //青基調色
      int sizeW = (int)imagePX_W; //描画サイズ幅
      int sizeH = (int)imagePX_H; //描画サイズ幅
      int repeat; //ストライプ本数
      if(stripePatternType == 1) //水平
        repeat = (sizeH/stripePatternW)+1;
      else  //垂直
        repeat = (sizeW/stripePatternW)+1;
      if(stripePRedBase > 240)  stripePRedBase = 240;
      if(stripePGreenBase > 240)  stripePGreenBase = 240;
      if(stripePBlueBase > 240)  stripePBlueBase = 240;
      int r1,g1,b1;
      for(int i=0;i<repeat;i++)
      {
        r1 = stripePRedBase + ran.nextInt(255-stripePRedBase);
        g1 = stripePGreenBase + ran.nextInt(255-stripePGreenBase);
        b1 = stripePBlueBase + ran.nextInt(255-stripePBlueBase);
        g2.setColor(new Color(r1,g1,b1));
        if(stripePatternType==1) //水平
          g2.fillRect(0, i*stripePatternW , sizeW, stripePatternW);
        else if(stripePatternType==2)  //垂直
          g2.fillRect(i*stripePatternW ,0, stripePatternW, sizeH);
      }
      stripePatternType =0;
    }

    //●マトリックス・パターン描画
    if(matrixPatternNumSt >= 1 || matrixPatternNumEx >= 1)
    {
      int sizeW = (int)imagePX_W; //有効描画範囲幅
      int sizeH = (int)imagePX_H; //有効描画範囲丈
      int cSt = matrixPatternWH_St;  //１コマのピクセル数（横）
      int cEx = matrixPatternWH_Ex;  //１コマのピクセル数（横）
      matrixRepeatH_St = sizeW/(int)(cSt*matrixUnitSt+matrixSkipH_St)+2;  //横リピート回数
      matrixRepeatV_St = sizeH/(int)(cSt*matrixUnitSt+matrixSkipV_St)+2;  //縦リピート回数
      matrixRepeatH_Ex = sizeW/(int)(cEx*matrixUnitEx+matrixSkipH_Ex)+2;  //横リピート回数
      matrixRepeatV_Ex = sizeH/(int)(cEx*matrixUnitEx+matrixSkipV_Ex)+2;  //縦リピート回数
      int x1 = 0;  //Ｘ軸座標位置
      int y1 = 0;  //Ｙ軸座標位置
      int matrixPatternSt[][] = getPatternData(matrixPatternNumSt, "St");
      int matrixPatternEx[][] = getPatternData(matrixPatternNumEx, "Ex");
      if(matrixPatternNumSt>0)
        f.matrixStUnitLabel.setText("　　St:" + matrixUnitSt +"x"+ matrixUnitSt);
      else
        f.matrixStUnitLabel.setText("");
      if(matrixPatternNumEx>0)
        f.matrixExUnitLabel.setText("　　Ex:" + matrixUnitEx +"x"+ matrixUnitEx);
      else
        f.matrixExUnitLabel.setText("");

      //配色描画実施
      //標準メソッドStの使用（統一配色）
      try
      {
        if(matrixPatternNumSt>0)
        {
          //色指定は、１番色から９番色まで使用可能。
          boolean colorFlagSt = true; //描画の有無
          double matrixSkipH_StX = 0; //柄紋横スキップ累積の初期値
          double matrixSkipV_StY = 0; //柄紋縦スキップ累積の初期値
          double dropX =0; //偶数行で柄ずらし（ドロップ）の初期値
          double dropY =0; //偶数列で柄ずらし（ドロップ）の初期値
          int K2 =0;
          ran2St = new Random(randomSeed2);
          int randomSt = 0;

          //リピート計算およびリピート指定
          if(matrixSkipH_St < 0) //マイナス・スキップ対応のリピート追加
            matrixRepeatH_St = (int)((sizeW/(cSt*matrixUnitSt+matrixSkipH_St))*2.5);
            //ただし、大きな数値のマイナス・スキップには対応できない。
            //マイナス・スキップが大きい場合、リピート指定を行なう
          if(matrixSkipV_St < 0) //マイナス・スキップ対応のリピート追加
            matrixRepeatV_St = (int)((sizeH/(cSt*matrixUnitSt+matrixSkipV_St))*2.5);
            //ただし、大きな数値のマイナス・スキップには対応できない。
            //マイナス・スキップが大きい場合、リピート指定を行なう
          if(matrixRepeatH_StX >= 1) //リピート指定あれば、それに従う
            matrixRepeatH_St = matrixRepeatH_StX;
          if(matrixRepeatV_StX >= 1) //リピート指定あれば、それに従う
            matrixRepeatV_St = matrixRepeatV_StX;

          for( int i=0; i<matrixRepeatH_St; i++) //横リピート
          {
            matrixSkipH_StX = matrixSkipH_StX + matrixSkipH_St; //横スキップの累積
            for(int j=0; j<matrixRepeatV_St; j++) //縦リピート
            {
              if(j==0 && i==0) //縦スキップの準備
                matrixSkipV_StY = matrixSkipV_St;
              else if(j==0)
                matrixSkipV_StY = 0;
              if(K2==matrixUnitSt-1)
                matrixSkipV_StY = matrixSkipV_StY + matrixSkipV_St; //縦スキップの累積
              randomSt = ran2St.nextInt(10);
              for(int K=0; K<matrixUnitSt; K++) //横コマ数で反復
              {
                K2 = K;
                for(int L=0; L<matrixUnitSt; L++) //縦コマ数で反復
                {
                  if     (matrixPatternSt[K][L] == 1)
                    g2.setColor(new Color(rgbSt[0][0],rgbSt[0][1],rgbSt[0][2]));
                  else if(matrixPatternSt[K][L] == 2)
                    g2.setColor(new Color(rgbSt[1][0],rgbSt[1][1],rgbSt[1][2]));
                  else if(matrixPatternSt[K][L] == 3)
                    g2.setColor(new Color(rgbSt[2][0],rgbSt[2][1],rgbSt[2][2]));
                  else if(matrixPatternSt[K][L] == 4)
                    g2.setColor(new Color(rgbSt[3][0],rgbSt[3][1],rgbSt[3][2]));
                  else if(matrixPatternSt[K][L] == 5)
                    g2.setColor(new Color(rgbSt[4][0],rgbSt[4][1],rgbSt[4][2]));
                  else if(matrixPatternSt[K][L] == 6)
                    g2.setColor(new Color(rgbSt[5][0],rgbSt[5][1],rgbSt[5][2]));
                  else if(matrixPatternSt[K][L] == 7)
                    g2.setColor(new Color(rgbSt[6][0],rgbSt[6][1],rgbSt[6][2]));
                  else if(matrixPatternSt[K][L] == 8)
                    g2.setColor(new Color(rgbSt[7][0],rgbSt[7][1],rgbSt[7][2]));
                  else if(matrixPatternSt[K][L] == 9)
                    g2.setColor(new Color(rgbSt[8][0],rgbSt[8][1],rgbSt[8][2]));
                  else if(matrixPatternSt[K][L] == 0) //配色なし（描画せず）
                    colorFlagSt = false;
                  else
                    g2.setColor(Color.black);  //警告色
                  x1 = (int)(matrixShiftH_St*cSt);
                  y1 = (int)(matrixShiftV_St*cSt);
                  if(j%2 == 1) //柄紋の横ドロップ処理
                    dropX = matrixDropH_St;
                  else
                    dropX = 0;
                  if(i%2 == 1) //柄紋の縦ドロップ処理
                    dropY = (int)matrixDropV_St;
                  else
                    dropY  = 0;
                  if((colorFlagSt == true) &&
                    (randomSt < matrixIntermittingSt)) //間欠描画
                    g2.fillRect(x1+i*matrixUnitSt*cSt+L*cSt+
                      (int)(matrixSkipH_StX*cSt)+(int)(dropX*cSt),
                      y1+j*matrixUnitSt*cSt+K*cSt+
                      (int)(matrixSkipV_StY*cSt)+(int)(dropY*cSt),
                      cSt, cSt); //x, y, 幅, 高
                  else //色番号が０の場合、描画しない
                    colorFlagSt = true;
                }
              }
            }
          }
        }
      }
      catch(ArrayIndexOutOfBoundsException e)
      {
        if(matrixPatternNumSt>0)
          rgbSt = getRandom_rgbSt();
        repaint(); //表示エラー回復の試み。
      }

      //拡張メソッドExの使用（個別配色）
      try
      {
        if(matrixPatternNumEx>0)
        {
          //色指定は、１番色から９番色まで使用可能。
          boolean colorFlagEx = true; //描画の有無
          double matrixSkipH_ExX = 0; //柄紋横スキップ累積の初期値
          double matrixSkipV_ExY = 0; //柄紋縦スキップ累積の初期値
          double dropX =0; //偶数行で柄ずらし（ドロップ）の初期値
          double dropY =0; //偶数列で柄ずらし（ドロップ）の初期値
          int K2 =0;
          ran2Ex = new Random(randomSeed2+567);
          int randomEx = 0;

          //リピート計算およびリピート指定
          if(matrixSkipH_Ex < 0) //マイナス・スキップ対応のリピート追加
            matrixRepeatH_Ex = (int)((sizeW/(cEx*matrixUnitEx+matrixSkipH_Ex))*2.5);
            //ただし、異常な数値のスキップは想定していないので、リピート指定を行なう
          if(matrixSkipV_Ex < 0) //マイナス・スキップ対応のリピート追加
            matrixRepeatV_Ex = (int)((sizeH/(cEx*matrixUnitEx+matrixSkipH_Ex))*2.5);
            //ただし、異常な数値のスキップは想定していないので、リピート指定を行なう
          if(matrixRepeatH_ExX >= 1) //リピート指定あれば、それに従う
            matrixRepeatH_Ex = matrixRepeatH_ExX;
          if(matrixRepeatV_ExX >= 1) //リピート指定あれば、それに従う
            matrixRepeatV_Ex = matrixRepeatV_ExX;
          //特殊なマトリックス指定をする場合、プログラムでのリピート計算では対処不能と
          //なることもあるため、その場合、マトリックス命令文の中でリピート指定を行なう。
          //通常の使用なら、リピート数値指定は、０指定（リピート自動計算）で構わない。

          for( int i=0; i<matrixRepeatH_Ex; i++) //横リピート
          {
            matrixSkipH_ExX = matrixSkipH_ExX + matrixSkipH_Ex; //横スキップの累積
            for(int j=0; j<matrixRepeatV_Ex; j++) //縦リピート
            {
              if(j==0 && i==0) //縦スキップの準備
                matrixSkipV_ExY = matrixSkipV_Ex;
              else if(j==0)
                matrixSkipV_ExY = 0;
              if(K2==matrixUnitEx-1)
                matrixSkipV_ExY = matrixSkipV_ExY + matrixSkipV_Ex; //縦スキップの累積
              randomEx = ran2Ex.nextInt(10);
              for(int K=0; K<matrixUnitEx; K++) //横コマ数で反復
              {
              	K2 = K;
                for(int L=0; L<matrixUnitEx; L++) //縦コマ数で反復
                {
                  if     (matrixPatternEx[K][L] == 1) //色を設定
                    g2.setColor(new Color(rgbEx[i][j][K][L][0][0],
                      rgbEx[i][j][K][L][0][1],rgbEx[i][j][K][L][0][2]));
                  else if(matrixPatternEx[K][L] == 2)
                    g2.setColor(new Color(rgbEx[i][j][K][L][1][0],
                      rgbEx[i][j][K][L][1][1],rgbEx[i][j][K][L][1][2]));
                  else if(matrixPatternEx[K][L] == 3)
                    g2.setColor(new Color(rgbEx[i][j][K][L][2][0],
                      rgbEx[i][j][K][L][2][1],rgbEx[i][j][K][L][2][2]));
                  else if(matrixPatternEx[K][L] == 4)
                    g2.setColor(new Color(rgbEx[i][j][K][L][3][0],
                      rgbEx[i][j][K][L][3][1],rgbEx[i][j][K][L][3][2]));
                  else if(matrixPatternEx[K][L] == 5)
                    g2.setColor(new Color(rgbEx[i][j][K][L][4][0],
                      rgbEx[i][j][K][L][4][1],rgbEx[i][j][K][L][4][2]));
                  else if(matrixPatternEx[K][L] == 6)
                    g2.setColor(new Color(rgbEx[i][j][K][L][5][0],
                      rgbEx[i][j][K][L][5][1],rgbEx[i][j][K][L][5][2]));
                  else if(matrixPatternEx[K][L] == 7)
                    g2.setColor(new Color(rgbEx[i][j][K][L][6][0],
                      rgbEx[i][j][K][L][6][1],rgbEx[i][j][K][L][6][2]));
                  else if(matrixPatternEx[K][L] == 8)
                    g2.setColor(new Color(rgbEx[i][j][K][L][7][0],
                      rgbEx[i][j][K][L][7][1],rgbEx[i][j][K][L][7][2]));
                  else if(matrixPatternEx[K][L] == 9)
                    g2.setColor(new Color(rgbEx[i][j][K][L][8][0],
                      rgbEx[i][j][K][L][8][1],rgbEx[i][j][K][L][8][2]));
                  else if(matrixPatternEx[K][L] == 0) //配色なし（描画せず）
                    colorFlagEx = false;
                  else
                    g2.setColor(Color.black);  //警告色

                  x1 = (int)(matrixShiftH_Ex*cEx);
                  y1 = (int)(matrixShiftV_Ex*cEx);
                  if(j%2 == 1) //柄紋の横ドロップ処理
                    dropX = matrixDropH_Ex;
                  else
                    dropX = 0;
                  if(i%2 == 1) //柄紋の縦ドロップ処理
                    dropY = (int)matrixDropV_Ex;
                  else
                    dropY  = 0;

                  if((colorFlagEx == true) &&
                    (randomEx < matrixIntermittingEx)) //間欠描画
                    g2.fillRect(x1+i*matrixUnitEx*cEx+L*cEx+
                      (int)(matrixSkipH_ExX*cEx)+(int)(dropX*cEx),
                      y1+j*matrixUnitEx*cEx+K*cEx+
                      (int)(matrixSkipV_ExY*cEx)+(int)(dropY*cEx),
                      cEx, cEx); //x, y, 幅, 高
                  else //色番号が０の場合、描画しない
                    colorFlagEx = true;
                }
              }
            }
          }
        }
      }
      catch(ArrayIndexOutOfBoundsException e)
      {
        if(matrixPatternNumEx>0)
          rgbEx = getRandom_rgbEx();
        repaint(); //表示エラー回復の試み。
      }
    }

    //●●色塗り図形描画命令「実行」グループの始まり

    //●自由図形の色塗り描画（色塗りを先、輪郭線は後）
    int comCnt = 0; //命令カウンター
    int mS = 0; //自由図形描画モード（線描きか色塗りかのモード）
    Color shapeColor = Color.yellow; //不透明色（ダミー）
    Color shapeColorT = new Color(200,200,0,0); //透明色（ダミー）
    for(; comCnt<shapeArr.length;)
    {
      if(shapeArr[comCnt][0] == 0)
      { //▼DrawShapeStart()　（起点での処理）
        gp = new GeneralPath();
        mS = (int)shapeArr[comCnt][1]; //線描きか色塗りかのモード
        gp.moveTo(shapeArr[comCnt][2]+sX,shapeArr[comCnt][3]+sY);
        shapeColor = new Color((int)shapeArr[comCnt][4],
          (int)shapeArr[comCnt][5],(int)shapeArr[comCnt][6]);
        shapeColorT = new Color((int)shapeArr[comCnt][4],
          (int)shapeArr[comCnt][5],(int)shapeArr[comCnt][6],191);
          //「191」は、透明度で「(256/4)*3-1」の計算
        if(markFlag == true) //▼起点十字線および丸印の描画
        {
          drawStartMark(shapeArr[comCnt][2], shapeArr[comCnt][3]); //十字線
          drawPointMark(shapeArr[comCnt][2], shapeArr[comCnt][3]); //丸印
        }
        comCnt++;
      }
      else if(shapeArr[comCnt][0] == -1)
      { //▼DrawShapeLine()　（中間での直線部処理）
        gp.lineTo(shapeArr[comCnt][1]+sX,shapeArr[comCnt][2]+sY);
        if(markFlag == true)
        {
          drawPointMark(shapeArr[comCnt][1], shapeArr[comCnt][2]); //丸印
        }
        comCnt++;
      }
      else if(shapeArr[comCnt][0] == -2)
      { //▼DrawShapeCurve()　（中間での曲線処理）
        gp.curveTo(
          shapeArr[comCnt][1]+sX,shapeArr[comCnt][2]+sY,
          shapeArr[comCnt][3]+sX,shapeArr[comCnt][4]+sY,
          shapeArr[comCnt][5]+sX,shapeArr[comCnt][6]+sY);
        //曲線部補助線描画
        if(markFlag == true)
        {
          g2.setColor(new Color(200,0,0));
          g2.setStroke(solidLineX);
          g2.draw(new Line2D.Double(
            shapeArr[comCnt][1]+sX,shapeArr[comCnt][2]+sY,
            shapeArr[comCnt][3]+sX,shapeArr[comCnt][4]+sY));
          drawPointMarkX(shapeArr[comCnt][1], shapeArr[comCnt][2]); //二重丸印
          drawPointMarkX(shapeArr[comCnt][3], shapeArr[comCnt][4]);

          g2.setStroke(solidLineX);
          g2.setColor(new Color(200,0,0));
          g2.draw(new Line2D.Double(
            shapeArr[comCnt][3]+sX,shapeArr[comCnt][4]+sY,
            shapeArr[comCnt][5]+sX,shapeArr[comCnt][6]+sY));
          drawPointMark(shapeArr[comCnt][5], shapeArr[comCnt][6]); //丸印

          g2.setStroke(solidLineX);
          g2.setColor(new Color(200,0,0));
          if(shapeArr[comCnt-1][0] == 0)
          //DrawShapeCurveの直前がDrawShapeStartの場合
            g2.draw(new Line2D.Double(
              shapeArr[comCnt-1][2]+sX,shapeArr[comCnt-1][3]+sY,
              shapeArr[comCnt][1]+sX,shapeArr[comCnt][2]+sY));
          else if(shapeArr[comCnt-1][0] == -1)
          //DrawShapeCurveの直前がDrawShapeLineの場合
            g2.draw(new Line2D.Double(
              shapeArr[comCnt-1][1]+sX,shapeArr[comCnt-1][2]+sY,
              shapeArr[comCnt][1]+sX,shapeArr[comCnt][2]+sY));
          else if(shapeArr[comCnt-1][0] == -2)
          //DrawShapeCurveの直前がDrawShapeCurveの場合
            g2.draw(new Line2D.Double(
              shapeArr[comCnt-1][5]+sX,shapeArr[comCnt-1][6]+sY,
              shapeArr[comCnt][1]+sX,shapeArr[comCnt][2]+sY));
          else
            ; //命令文の記述ミス以外には有り得ないケース
          g2.setStroke(solidLine);
        }
        comCnt++;
      }
      else if(shapeArr[comCnt][0] == -3)
      { //▼DrawShapeEnd()　（終点での処理）
        gp.closePath();
        if(mS==2 || mS==3) //描画モード
        {
          g2.setColor(shapeColor);
          g2.fill(gp); //色塗り
        }
        if(mS==4 || mS == 5) //描画モード（透明色）
        {
          g2.setColor(shapeColorT);
          g2.fill(gp); //透明色塗り
        }
        if(mS==1 || mS==3 || mS==4)
        {
          g2.setColor(foregroundColorL);
          g2.draw(gp); //線描き（輪郭線）
        }
        comCnt++;
      }

    //●長方形の描画
      else if(shapeArr[comCnt][0] == -4)
      { //▼DrawRect()
        int mR   = (int)shapeArr[comCnt][1]; // 線描きか色塗りか
        double xR  = shapeArr[comCnt][2]; // x座標
        double yR  = shapeArr[comCnt][3]; // y座標
        double hrR = shapeArr[comCnt][4]; // 幅
        double vrR = shapeArr[comCnt][5]; // 高さ
        int crR  = (int)shapeArr[comCnt][6]; //color
        int cgR  = (int)shapeArr[comCnt][7]; //color
        int cbR  = (int)shapeArr[comCnt][8]; //color
        if(mR==2 || mR==3) //色塗り描画（不透明色）
        {
          g2.setColor(new Color(crR, cgR, cbR));
          g2.fill(new Rectangle2D.Double(xR+sX,yR+sY,hrR+sX,vrR+sY));
        }
        if(mR==4 || mR == 5) //色塗り描画（透明色）
        {
          g2.setColor(new Color(crR, cgR, cbR,191));
          g2.fill(new Rectangle2D.Double(xR+sX,yR+sY,hrR+sX,vrR+sY));
        }
        if(mR==1 || mR==3 || mR==4) //輪郭線描画
        {
          g2.setColor(foregroundColorL);
          g2.draw(new Rectangle2D.Double(xR+sX,yR+sY,hrR+sX,vrR+sY));
        }
        if(markFlag == true) //▼起点目印十字線の描画
        {
          drawPointMark(xR, yR);
          drawStartMark(xR, yR);
        }
        comCnt++;
      }

    //●円（楕円）の描画
      else if(shapeArr[comCnt][0] == -5)
      { //DrawEllipse()
        double mE  = shapeArr[comCnt][1]; // 線描か色塗りか
        double xE  = shapeArr[comCnt][2]; // x座標
        double yE  = shapeArr[comCnt][3]; // y座標
        double hrE = shapeArr[comCnt][4]; // 幅
        double vrE = shapeArr[comCnt][5]; // 高さ
        int crE  = (int)shapeArr[comCnt][6]; //color
        int cgE  = (int)shapeArr[comCnt][7]; //color
        int cbE  = (int)shapeArr[comCnt][8]; //color
        xE = xE-hrE;
        yE = yE-vrE;
        if(mE == 2 || mE == 3)
        {//▼円または楕円の色塗り
          g2.setColor(new Color(crE, cgE, cbE));
          g2.fill(new Ellipse2D.Double(
          xE+sX, yE+sY, hrE*2.0, vrE*2.0));
            //x座標, y座標, 幅, 高さ
        }
        if(mE == 4 || mE == 5)
        {//▼円または楕円の色塗り（透明色）
          g2.setColor(new Color(crE, cgE, cbE,191));
          g2.fill(new Ellipse2D.Double(
          xE+sX, yE+sY, hrE*2.0, vrE*2.0));
            //x座標, y座標, 幅, 高さ
        }
        if(mE == 1 || mE == 3 || mE==4)
        {//▼円または楕円の輪郭線
          g2.setColor(foregroundColorL);
          g2.draw(new Ellipse2D.Double(
          xE+sX, yE+sY, hrE*2.0, vrE*2.0));
          //x座標, y座標, 幅, 高さ
        }
        if(markFlag == true) //▼起点目印十字線の描画
          drawStartMark(xE+hrE, yE+vrE);
        comCnt++;
      }
    }

    //●スプレーの描画
    //sprayDiscStatus_List; //スプレー命令のステータス
    //sprayDiscX_List; //スプレイ円盤状飛沫集団（円盤）の中心ｘ座標
    //sprayDiscY_List; //スプレイ円盤状飛沫集団（円盤）の中心ｙ座標
    //sprayUnitTP_List; //スプレイ飛沫の分布タイプ
    //sprayUnitSS_List; //スプレイ飛沫一個のサイズ（px）
    //sprayUnitSR_List; //スプレイ飛沫の円盤状拡散分布半径（px）
    //sprayUnitST_List; //スプレイ飛沫の分布個数
    //sprayUnitR_List; //スプレイ飛沫の赤成分
    //sprayUnitG_List; //スプレイ飛沫の緑成分
    //sprayUnitB_List; //スプレイ飛沫の青成分
    //sprayUnitA_List; //スプレイ飛沫の透明度
    if(sprayFlag==true)
    {
      int unitCnt = 0;
      for(int i=0; i<sprayDiscStatus_List.size(); i++)
      {
        ranSpray = new Random(randomSeed2+i);
        double[][] sprayPoint = new double[0][0];
        if(sprayUnitTP_List.get(unitCnt) == 0) //円筒型飛沫タイプ（フラット）
        {
          sprayPoint = spray0(sprayUnitSR_List.get(unitCnt), sprayUnitST_List.get(unitCnt));
        }
        else if(sprayUnitTP_List.get(unitCnt) == 1) //ベル型飛沫タイプ（正規分布）
        {
          sprayPoint = spray1(sprayUnitSR_List.get(unitCnt), sprayUnitST_List.get(unitCnt));
        }
        else if(sprayUnitTP_List.get(unitCnt) == 2) //円錐型飛沫タイプ（中央集中）
        {
          sprayPoint = spray2(sprayUnitSR_List.get(unitCnt), sprayUnitST_List.get(unitCnt));
        }

        g2.setColor(new Color(sprayUnitR_List.get(unitCnt), sprayUnitG_List.get(unitCnt),
          sprayUnitB_List.get(unitCnt), sprayUnitA_List.get(unitCnt)));
        for(int j=0; j<sprayPoint.length; j++)
        {
          g2.fill(new Ellipse2D.Double(
            sprayDiscX_List.get(i) + sprayPoint[j][0]+sX,
            sprayDiscY_List.get(i) + sprayPoint[j][1]+sY,
            sprayUnitSS_List.get(unitCnt),
            sprayUnitSS_List.get(unitCnt)));
            //x座標, y座標, 楕円の幅, 楕円の高さ
        }
        if(sprayDiscStatus_List.get(i) == 2) //SprayEnd
        {
          unitCnt++;
        }
      }
      if(markFlag == true) //スプレー円盤中心の目印描画
      {
        //g2.setStroke(solidLineX);
        for(int i=0; i<sprayDiscStatus_List.size(); i++)
        {
          g2.setColor(Color.red);
          g2.draw(new Ellipse2D.Double(
            sprayDiscX_List.get(i) +sX -4,
            sprayDiscY_List.get(i) +sY -4,
            8, 8));
            //x座標, y座標, 楕円の幅, 楕円の高さ
          g2.setColor(Color.blue);
          g2.draw(new Line2D.Double(
            sprayDiscX_List.get(i)+sX+6, sprayDiscY_List.get(i)+sY,
            sprayDiscX_List.get(i)+sX-6, sprayDiscY_List.get(i)+sY));
          g2.draw(new Line2D.Double(
            sprayDiscX_List.get(i)+sX, sprayDiscY_List.get(i)+sY+6,
            sprayDiscX_List.get(i)+sX, sprayDiscY_List.get(i)+sY-6));
        }
      }
      g2.setColor(foregroundColorL);
    }

    //●●色塗り図形描画命令「実行」グループの終わり

    //●●特殊画像処理命令「実行」グループの始まり
    //●●各種「特殊描画命令」の実行位置は、この位置であることに意味あり。
    //●●Image命令（背景画像描画）の描画実行だけは、先行して実行済み

    //●ソフト・フォーカス処理済み画像の表示
    if(softFocusFName!=null && !softFocusFName.equals(""))
    {
      g2.drawImage(softFocusImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●f.toneCurve.bImageTC2処理済み画像の表示
    if(outlineFName!=null && !outlineFName.equals(""))
    {
      g2.drawImage(outlineImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●畳み込み処理済み画像（鮮鋭化画像／朦朧化画像）の表示
    if(!convolveFName.equals("") && convolveImage1!=null)
    {
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON); //描写を滑らかにする
      g2.setRenderingHint(RenderingHints.KEY_RENDERING,
        RenderingHints.VALUE_RENDER_QUALITY); //描写を滑らかにする

      g2.drawImage(convolveImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
      g2.drawImage(convolveImage0, (int)imagePX_W+10, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●ミックス・イメージ（二重像）処理済み画像の表示
    if(mixImage2!=null && !mixFName0.equals(""))
    { //描画する
      g2.drawImage(mixImage2, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●図形内部彩色処理済み画像の表示
    if(changeColorInnerFlag==true && cciImage != null)
    { //描画する
      g2.drawImage(cciImage, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●図形内部連続彩色処理済み画像の表示
    if(changeColorInnerMultiFlag==true && ccimImage != null)
    { //描画する
      g2.drawImage(ccimImage, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●図形内部連続自動彩色処理済み画像の表示
    if(changeColorInnerAutoFlag==true && cciaImage != null)
    { //描画する
      g2.drawImage(cciaImage, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●画像反転処理済み画像の表示
    if(reverseImage1!=null && !reverseImageFile.equals("") &&
      (reverseImageMode<=4 || reverseImageMode==6))
    { //描画する
      g2.drawImage(reverseImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    if(reverseImage1!=null && !reverseImageFile.equals("") &&
      (reverseImageMode==5 || reverseImageMode==7))
    { //90度、270度の回転処理画像を描画する（回転処理済みの画像保存を含む）
      g2.drawImage(reverseImage1, 0, 0, (int)imagePX_H, (int)imagePX_W, this);
    }
    //●画像多段回転処理済み画像の表示
    if(rotateMultiImage!=null && rotateMultiFlag==true)
    { //描画する
      g2.drawImage(rotateMultiImage, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●単独色相変更処理済み画像の表示
    if(colorChangeImage1!=null && !colorChangeFile.equals("") &&
      (colorChangeMode==1 ||colorChangeMode==2))
    { //描画する
      g2.drawImage(colorChangeImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●階調加工済み画像の表示
    if(gradientImage1!=null && !gradientFName.equals(""))
    {
      g2.drawImage(gradientImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●連続色相変更処理済み画像の表示
    if(changeColorMultiBaseFlag==true && changeColorMultiFlag==true)
    {
      g2.drawImage(ccmImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●カット・アンド・ペースト処理済み画像の表示
    if(f.canvas.cutAndPasteMaskFlag==true && f.canvas.cutAndPasteFlag==true)
    {
      g2.drawImage(capImage1, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●トーン・カーブ処理済み画像の表示
    if(f.canvas.toneCurveFlag==true && f.toneCurve.bImageTC2 != null)
    {
      g2.drawImage(f.toneCurve.bImageTC2, 0, 0, (int)imagePX_W, (int)imagePX_H, this);
    }
    //●スタンプ画像（透明化処理済み）の上書き描画。
    if(stampFlag==true && stampListB!=null && stampListI!=null)
    {
      for(int i=0; i<stampListB.size(); i++)
      {
        BufferedImage transparentImage = stampListB.get(i);
        //画像サイズ計算
        int w = stampListB.get(i).getWidth(this);
        int h = stampListB.get(i).getHeight(this);
        int stampX = 0;
        int stampY = 0;
        int stampW = 0;
        int stampH = 0;
        boolean err = false;
        try
        {
          stampX = stampListI.get(i)[0];
          stampY = stampListI.get(i)[1];
          stampW = stampListI.get(i)[2];
          stampH = stampListI.get(i)[3];
        }
        catch (Exception e)
        {
          f.message(e.toString());
          err = true;
        }
        if(transparentImage != null && err == false)
        { //描画する
          g2.drawImage(transparentImage, stampX, stampY, stampW, stampH, this);
        }
      }
    }

    //●●特殊画像処理命令「実行」グループの終わり

    //●●線および文字画像処理命令「実行」グループの始まり
    //●横平行線の描画（罫線または方眼線の描画に利用）
    if(parallelLineH_t > 0)
    {
      g2.setColor(foregroundColorL);
      if(parallelLineH_m == 0)
      	g2.setStroke(solidLineP); //実線に設定
      else if(parallelLineH_m == 1)
      	g2.setStroke(dotLineP); //密の点線に設定
      else
      	g2.setStroke(dotLineP2); //粗の点線に設定
      for(int i=0; i<parallelLineH_t; i++)
      { //描画実行（本来線）
        g2.draw(new Line2D.Double(
          parallelLineH_x+sX,
          parallelLineH_y+parallelLineH_w*i+sY,
          parallelLineH_x+parallelLineH_l+sX,
          parallelLineH_y+parallelLineH_w*i+sY));
      }
      for(int i=0; i<parallelLineH_t-1; i++)
      { //描画実行（中間線）
        g2.setStroke(dotLineP2); //粗の点線に設定
        if(parallelLineH_h == 1)
        {
        	g2.draw(new Line2D.Double(
          	parallelLineH_x+sX,
          	parallelLineH_y+parallelLineH_w*i+sY + (parallelLineH_w/2),
          	parallelLineH_x+parallelLineH_l+sX,
          	parallelLineH_y+parallelLineH_w*i+sY + (parallelLineH_w/2)));
        }
      }
      g2.setStroke(solidLine); //太さ可変の実線に戻す
    }
    //●縦平行線の描画（罫線または方眼線の描画に利用）
    if(parallelLineV_t > 0)
    {
      g2.setColor(foregroundColorL);
      if(parallelLineV_m == 0)
      	g2.setStroke(solidLineP); //実線に設定
      else if(parallelLineV_m == 1)
      	g2.setStroke(dotLineP); //密の点線に設定
      else
      	g2.setStroke(dotLineP2); //粗の点線に設定
      for(int i=0; i<parallelLineV_t; i++)
      { //描画実行（本来線）
        g2.draw(new Line2D.Double(
          parallelLineV_x+parallelLineV_w*i+sX,
          parallelLineV_y+sY,
          parallelLineV_x+parallelLineV_w*i+sX,
          parallelLineV_y+parallelLineV_l+sY));
      }
      for(int i=0; i<parallelLineV_t-1; i++)
      { //描画実行（中間線）
        g2.setStroke(dotLineP2); //粗の点線に設定
        if(parallelLineV_h == 1)
        {
        	g2.draw(new Line2D.Double(
          	parallelLineV_x+parallelLineV_w*i+sX + (parallelLineV_w/2),
          	parallelLineV_y+sY,
          	parallelLineV_x+parallelLineV_w*i+sX + (parallelLineV_w/2),
          	parallelLineV_y+parallelLineV_l+sY));
        }
      }
      g2.setStroke(solidLine); //太さ可変の実線に戻す
    }

    //●横平行線の描画（補助用）
    if(parallelLineH2_t > 0)
    {
      g2.setColor(foregroundColorL);
      if(parallelLineH2_m == 0)
      	g2.setStroke(solidLineP); //実線に設定
      else if(parallelLineH2_m == 1)
      	g2.setStroke(dotLineP); //密の点線に設定
      else
      	g2.setStroke(dotLineP2); //粗の点線に設定
      for(int i=0; i<parallelLineH2_t; i++)
      { //描画実行（本来線）
        g2.draw(new Line2D.Double(
          parallelLineH2_x+sX,
          parallelLineH2_y+parallelLineH2_w*i+sY,
          parallelLineH2_x+parallelLineH2_l+sX,
          parallelLineH2_y+parallelLineH2_w*i+sY));
      }
      for(int i=0; i<parallelLineH2_t-1; i++)
      { //描画実行（中間線）
        g2.setStroke(dotLineP2); //粗の点線に設定
        if(parallelLineH2_h == 1)
        {
        	g2.draw(new Line2D.Double(
          	parallelLineH2_x+sX,
          	parallelLineH2_y+parallelLineH2_w*i+sY + (parallelLineH2_w/2),
          	parallelLineH2_x+parallelLineH2_l+sX,
          	parallelLineH2_y+parallelLineH2_w*i+sY + (parallelLineH2_w/2)));
        }
      }
      g2.setStroke(solidLine); //太さ可変の実線に戻す
    }
    //●縦平行線の描画（補助用）
    if(parallelLineV2_t > 0)
    {
      g2.setColor(foregroundColorL);
      if(parallelLineV2_m == 0)
      	g2.setStroke(solidLineP); //実線に設定
      else if(parallelLineV2_m == 1)
      	g2.setStroke(dotLineP); //密の点線に設定
      else
      	g2.setStroke(dotLineP2); //粗の点線に設定
      for(int i=0; i<parallelLineV2_t; i++)
      { //描画実行（本来線）
        g2.draw(new Line2D.Double(
          parallelLineV2_x+parallelLineV2_w*i+sX,
          parallelLineV2_y+sY,
          parallelLineV2_x+parallelLineV2_w*i+sX,
          parallelLineV2_y+parallelLineV2_l+sY));
      }
      for(int i=0; i<parallelLineV2_t-1; i++)
      { //描画実行（中間線）
        g2.setStroke(dotLineP2); //粗の点線に設定
        if(parallelLineV2_h == 1)
        {
        	g2.draw(new Line2D.Double(
          	parallelLineV2_x+parallelLineV2_w*i+sX + (parallelLineV2_w/2),
          	parallelLineV2_y+sY,
          	parallelLineV2_x+parallelLineV2_w*i+sX + (parallelLineV2_w/2),
          	parallelLineV2_y+parallelLineV2_l+sY));
        }
      }
      g2.setStroke(solidLine); //太さ可変の実線に戻す
    }

    //●ベジェ曲線 Bezier Curve（ベジェは人名で自動車デザイナー）の描画
    for(int i=0; i<curveArr.length; i++)
    { //DrawCurve()
      g2.setColor(foregroundColorL);
      GeneralPath p = new GeneralPath();
      p.moveTo(curveArr[i][0]+sX,curveArr[i][1]+sY);
      p.curveTo(
        curveArr[i][2]+sX,curveArr[i][3]+sY,
        curveArr[i][4]+sX,curveArr[i][5]+sY,
        curveArr[i][6]+sX,curveArr[i][7]+sY);
      g2.draw(p);
      if(markFlag == true)
      { //▼補助線の描画
        g2.setColor(new Color(200,0,0));
      	g2.setStroke(solidLineX); //実線に設定
        g2.draw(new Line2D.Double(
          curveArr[i][0]+sX,curveArr[i][1]+sY,
          curveArr[i][2]+sX,curveArr[i][3]+sY));
        drawPointMark(curveArr[i][0], curveArr[i][1]); //丸印

        g2.setColor(new Color(200,0,0));
      	g2.setStroke(solidLineX); //実線に設定
        g2.draw(new Line2D.Double(
          curveArr[i][2]+sX,curveArr[i][3]+sY,
          curveArr[i][4]+sX,curveArr[i][5]+sY));
        drawPointMark(curveArr[i][2], curveArr[i][3]);
        drawPointMark(curveArr[i][4], curveArr[i][5]);

        g2.setColor(new Color(200,0,0));
      	g2.setStroke(solidLineX); //実線に設定
        g2.draw(new Line2D.Double(
          curveArr[i][4]+sX,curveArr[i][5]+sY,
          curveArr[i][6]+sX,curveArr[i][7]+sY));
        drawPointMark(curveArr[i][6], curveArr[i][7]);
        g2.setStroke(solidLine);
      }
      if(markFlag == true) //▼起点十字線の描画
        drawStartMark(curveArr[i][0], curveArr[i][1]);
    }
    //●スプライン曲線 Spline Curveの描画
    for(int i=0; splineArrX != null && i<splineArrX.length; i++)
    { //
      for(int j=1; splineArrX[i] != null && j<splineArrX[i].length; j++)
      {
        if(markFlag == true)
        { //▼補助線および目印の描画
          g2.setStroke(solidLineX); //太さ固定
          g2.setColor(new Color(200,0,0));
          g2.draw(new Line2D.Double(  //補助線
            splineArrX[i][j-1]+sX,splineArrY[i][j-1]+sY,
            splineArrX[i][j]+sX,splineArrY[i][j]+sY));
          if(j==1)
          {
            drawPointMark(splineArrX[i][j-1], splineArrY[i][j-1]);
            drawStartMark(splineArrX[i][j-1], splineArrY[i][j-1]);
          }
          drawPointMark(splineArrX[i][j], splineArrY[i][j]);
        }

        //（注）スプライン曲線は、短い直線を多数連結した「疑似曲線」として描画。
        //デフォルトは、1000本の直線に分割した「疑似曲線」。オプションで本数変更可能。
        //スプライン補間処理したデータによる「疑似曲線」描画
        double[][] interpolateXY =
          new Spline3(splineArrX[i], splineArrY[i], splineOption).getInterpolateXY();
        g2.setColor(foregroundColorL);
        g2.setStroke(solidLine); //太さ可変
        for(int k=1; k<interpolateXY.length; k++)
        { //▼スプライン曲線の描画
          g2.draw(new Line2D.Double(
            interpolateXY[k-1][0]+sX,interpolateXY[k-1][1]+sY,
            interpolateXY[k][0]+sX,interpolateXY[k][1]+sY));
        }
      }
    }

    //●直線の描画
    for(int i=0; i<lineArr.length; i++)
    { //DrawLine()
      g2.setColor(foregroundColorL);
      g2.setStroke(solidLine); //太さ可変
      g2.draw(new Line2D.Double(
        lineArr[i][0]+sX,lineArr[i][1]+sY,
        lineArr[i][2]+sX,lineArr[i][3]+sY));
      if(markFlag == true) //目印描画
      {
        drawStartMark(lineArr[i][0], lineArr[i][1]); //十字線
        drawPointMark(lineArr[i][0], lineArr[i][1]); //丸印
        drawPointMark(lineArr[i][2], lineArr[i][3]); //丸印
        g2.setColor(foregroundColorL);
      }
    }
    //●仮直線（補助線）の描画
    for(int i=0; i<line2Arr.length; i++)
    { //Draw2()
      if(line2Arr[i][0]==0)
      { //▼直線部補助線（自由図形の直線部）
        g2.setColor(new Color(0,200,0));
        g2.setStroke(solidLineX); //太さ固定
        g2.draw(new Line2D.Double(
          line2Arr[i][1]+sX,line2Arr[i][2]+sY,
          line2Arr[i][3]+sX,line2Arr[i][4]+sY));
         g2.setStroke(solidLine);
      }
      else
      { //▼曲線部補助線（曲線、自由図形の曲線部）
        if(line2Arr[i][0]==1)
          g2.setColor(new Color(200,0,0));
        else if(line2Arr[i][0] == 2)
          g2.setColor(Color.red);
        else if(line2Arr[i][0] == 3)
          g2.setColor(Color.red);
        if(line2Arr[i][0]>=1 && line2Arr[i][0]<=3)
        {
          g2.setStroke(solidLineX);
          g2.draw(new Line2D.Double(
            line2Arr[i][1]+sX,line2Arr[i][2]+sY,
            line2Arr[i][3]+sX,line2Arr[i][4]+sY));
          g2.setStroke(solidLine);
        }
      }
    }

    //●折れ線の描画
    if(linkedLineFlag==true)
    {
      int unitCnt = 0;
      for(int i=0; i<linkedLineStatusList.size(); i++)
      {
        if(linkedLineStatusList.get(i) == 1 || linkedLineStatusList.get(i) == 2)
        {
          g2.setColor(foregroundColorL);
          g2.draw(new Line2D.Double(
            linkedLineXList.get(i-1)+sX, linkedLineYList.get(i-1)+sY,
            linkedLineXList.get(i)+sX,   linkedLineYList.get(i)+sY));
        }
      }
      if(markFlag == true) //折れ線の目印描画
      {
        for(int i=0; i<linkedLineStatusList.size(); i++)
        {
          if(linkedLineStatusList.get(i) == 0)
            drawStartMark(linkedLineXList.get(i), linkedLineYList.get(i)); //十字線
          drawPointMark(linkedLineXList.get(i), linkedLineYList.get(i)); //丸印
        }
      }
      g2.setColor(foregroundColorL);
    }

    //●極太文字列の描画
    //極太字の太さ指定
    for(int i=0; i<stringBArrD.length; i++)
    { //WriteStringB()
      //字形は二種類あり（"SANS_SERIF" / "SERIF"）
      g2.setColor(foregroundColorB);
      Font fontT = new Font(stringBArrS[i][0],Font.PLAIN,
      (int)(stringBArrD[i][2]));
      g2.setFont(fontT);
      int z1 = 1; //移動量最小単位
      int z2 = (int)stringBArrD[i][3]; //移動量最大単位（文字太さ拡張指定）

      //中央部を確実に埋める処理（不必要だが、念のため）
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX),
        (float)(stringBArrD[i][1]+sY));

      //水平垂直線の末端角を埋める処理（基本処理）
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z2),
        (float)(stringBArrD[i][1]+sY+z2));
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z2),
        (float)(stringBArrD[i][1]+sY-z2));
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z2),
        (float)(stringBArrD[i][1]+sY-z2));
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z2),
        (float)(stringBArrD[i][1]+sY+z2));

      //斜め線の末端角中央欠落を埋める処理（基本補足処理）
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX),
        (float)(stringBArrD[i][1]+sY+z2));
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX),
        (float)(stringBArrD[i][1]+sY-z2));
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z2),
        (float)(stringBArrD[i][1]+sY));
      g2.drawString(
        stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z2),
        (float)(stringBArrD[i][1]+sY));

      for(int z=z1; z<z2; z++)
      {
        //斜め線の末端角欠落を微細に埋める処理（細部補足処理・上下方向）
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z),
          (float)(stringBArrD[i][1]+sY+z2));
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z),
          (float)(stringBArrD[i][1]+sY-z2));
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z),
          (float)(stringBArrD[i][1]+sY-z2));
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z),
          (float)(stringBArrD[i][1]+sY+z2));

        //斜め線の末端角欠落を微細に埋める処理（細部補足処理・左右方向）
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z2),
          (float)(stringBArrD[i][1]+sY+z));
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z2),
          (float)(stringBArrD[i][1]+sY-z));
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX+z2),
          (float)(stringBArrD[i][1]+sY-z));
        g2.drawString(
          stringBArrS[i][1],(float)(stringBArrD[i][0]+sX-z2),
          (float)(stringBArrD[i][1]+sY+z));
      }

      if(markFlag == true)
      { //▼起点目印十字線の描画
        drawStartMark(stringBArrD[i][0], stringBArrD[i][1]);
      }
    }

    //●水平文字列の描画（極太文字より後に描画）
    for(int i=0; i<stringHArrD.length; i++)
    { //WriteStringH()
      //字形は二種類あり（"SANS_SERIF" / "SERIF"）
      g2.setColor(foregroundColorS);
      Font fontT = new Font(stringHArrS[i][0],Font.PLAIN,
      (int)(stringHArrD[i][2]));
      if(fontBold==true)
      {
        fontT = new Font(stringHArrS[i][0],Font.BOLD,
        (int)(stringHArrD[i][2]));
      }
      g2.setFont(fontT);
      g2.drawString(
        stringHArrS[i][1],(float)(stringHArrD[i][0]+sX),
        (float)(stringHArrD[i][1]+sY));
      if(markFlag == true) //▼起点目印十字線の描画
        drawStartMark(stringHArrD[i][0], stringHArrD[i][1]);
    }

    //●垂直文字列の描画（90度回転式の疑似縦書き）
    //「疑似縦書き」を実行すると、画像全体の精細度が低下するため、
    //この命令（WriteStringV）を使用しないことが望ましい。
    for(int i=0; i<stringVArrD.length; i++)
    {  //WriteStringV()
      //文字列を垂直（90度回転）に描画する
      Dimension dim;  //縦横サイズを保持するインスタンス
      BufferedImage bImg;  //一時的描画空間
      dim = getSize(); //最終描画先のf.canvasのサイズを取得
      bImg = new BufferedImage(dim.width, dim.height,
        BufferedImage.TYPE_INT_ARGB);   //透明可に設定
      Graphics2D g2x = bImg.createGraphics();  //Graphics2Dを返却
      g2x.setColor(new Color(0,0,0,0));  //背景は無色透明で
      g2x.fillRect(0, 0, dim.width, dim.height);
      g2x.rotate(1.57,  //90度回転実施（ラディアン単位で角度指定）
        (float)(stringVArrD[i][0]+sX), (float)(stringVArrD[i][1]+sY));
      g2x.setColor(foregroundColorL);  //文字は不透明色
      Font fontT = new Font(stringVArrS[i][0],Font.PLAIN,
      (int)(stringVArrD[i][2]));
      g2x.setFont(fontT);
      g2x.drawString(  //文字列描画
        stringVArrS[i][1],(float)(stringVArrD[i][0]+sX),
        (float)(stringVArrD[i][1]+sY));
      //f.canvasにbImgを無色透明色の背景で転写描画する
      g2.drawImage(bImg, 0, 0, new Color(0,0,0,0), null);
      if(markFlag == true) //▼起点目印十字線の描画
        drawStartMark(stringVArrD[i][0], stringVArrD[i][1]);
    }

    //●プレビューの場合だけ描画有効範囲枠線を表示。
    //●二点鎖線十字線および三角形目印。
    //●印刷時や画像保存時には、これらを消す。
    if(printMode==false && canSaveMode==false)
    {
      g2.setColor(Color.red); //二点鎖線十字線
      g2.setStroke(dashLine);
      int z = (int)(imagePX_W/20);
      g2.draw(new Line2D.Double(5, imagePX_H,
        imagePX_W-5, imagePX_H));
      g2.draw(new Line2D.Double(imagePX_W, 5,
        imagePX_W, imagePX_H-5));
      g2.draw(new Line2D.Double(imagePX_W+5, imagePX_H,
        imagePX_W*2, imagePX_H));
      g2.draw(new Line2D.Double(imagePX_W, imagePX_H+5,
        imagePX_W, imagePX_H*2));

      g2.setColor(Color.black); //三角形目印
      g2.setStroke(solidLineX);
      int t = 20;
      GeneralPath gp1 = new GeneralPath();
      gp1.moveTo(imagePX_W,imagePX_H/2);
      gp1.lineTo(imagePX_W+t,imagePX_H/2-t);
      gp1.lineTo(imagePX_W+t,imagePX_H/2+t);
      gp1.closePath();
      g2.fill(gp1);
      GeneralPath gp2 = new GeneralPath();
      gp2.moveTo(imagePX_W/2,imagePX_H);
      gp2.lineTo(imagePX_W/2-t,imagePX_H+t);
      gp2.lineTo(imagePX_W/2+t,imagePX_H+t);
      gp2.closePath();
      g2.fill(gp2);
    }

    //●ピクセル数とミリ数とを、メニュー・バーに表示
    int pw = ((int)(imagePX_W*affineScale*freeScale));
      //pw : pixelを切り出す範囲の巾
    int ph = ((int)(imagePX_H*affineScale*freeScale));
      //ph : pixelを切り出す範囲の丈
    f.pixelLabel.setText("   (i:"+pw+"x"+ ph+"px)");
    f.mmLabel.setText("   (p:"+(int)(printMM_W*freeScale)+"x"+
      (int)(printMM_H*freeScale)+"mm)");

    //●現在点（最新クリック点）の現在点目印Ｘ字線の描画

    if(markFlag == true && currentPointX != 0 && currentPointY != 0 &&
      f.cMouseLis.canvasMouseMode != 0)
    {
      g2.setColor(Color.red);
      g2.draw(new Line2D.Double(
        currentPointX+sX+5, currentPointY+sY-5,
        currentPointX+sX-5, currentPointY+sY+5));
      g2.setColor(Color.blue);
      g2.draw(new Line2D.Double(
        currentPointX+sX+5, currentPointY+sY+5,
        currentPointX+sX-5, currentPointY+sY-5));
    }
    //●●線および文字画像処理命令「実行」グループの終わり
  } //drawPage()の終了

  //■■以下は各種メソッド

  //■背景画像表示の準備
  void image()
  {
    imageListB = new LinkedList<BufferedImage>(); //この位置が重要
    for(int i=0; i<imageListF.size(); i++)
    {
      int imageX = imageListI.get(i)[0];
      int imageY = imageListI.get(i)[1];
      int imageW = imageListI.get(i)[2];
      int imageH = imageListI.get(i)[3];
      //●画像ファイル指定のチェック
      String path = imageListF.get(i);

      if(checkImageFile(imageListF.get(i))==false)
        return;

      BufferedImage imageImage; //背景のピクセル画像
      try
      {
        imageImage = ImageIO.read(new File(path)); //背景のピクセル画像取得
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("背景画像ファイル指定が不適切："+path);
        return;
      }
      imageListB.add(imageImage); //背景画像をリストに追加
    }
  }

  //■スタンプ押印の準備
  void stamp()
  {
    stampListB = new LinkedList<BufferedImage>(); //この位置が重要
    for(int i=0; i<stampListF.size(); i++)
    {
      int stampX = stampListI.get(i)[0];
      int stampY = stampListI.get(i)[1];
      int stampW = stampListI.get(i)[2];
      int stampH = stampListI.get(i)[3];
      //●画像ファイル指定のチェック
      String path = stampListF.get(i);

      if(checkImageFile(stampListF.get(i))==false)
        return;

      BufferedImage stampImage; //ピクセル画像
      try
      {
        stampImage = ImageIO.read(new File(path)); //スタンプのピクセル画像取得
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("スタンプ画像ファイル指定が不適切："+path);
        return;
      }

      // 画像データのカラー・モデルを確認して表示（デバッグに使用）
/*
      int colorType = stampImage.getType();
      if(colorType == BufferedImage.TYPE_3BYTE_BGR)
        f.message("不透明タイプ：TYPE_3BYTE_BGR >> " + colorType);
      else if(colorType == BufferedImage.TYPE_4BYTE_ABGR)
        f.message("透明可タイプ：TYPE_4BYTE_ABGR >> " + colorType);
      else if(colorType == BufferedImage.TYPE_4BYTE_ABGR_PRE)
        f.message("透明可タイプ：TYPE_4BYTE_ABGR_PRE >> " + colorType);
      else if(colorType == BufferedImage.TYPE_BYTE_BINARY)
        f.message("不透明タイプ：TYPE_BYTE_BINARY >> " + colorType);
      else if(colorType == BufferedImage.TYPE_BYTE_GRAY)
        f.message("灰色タイプ：TYPE_BYTE_GRAY >> " + colorType);
      else if(colorType == BufferedImage.TYPE_BYTE_INDEXED)
        f.message("特殊タイプ：TYPE_BYTE_INDEXED >> " + colorType);
      else if(colorType == BufferedImage.TYPE_CUSTOM)
        f.message("特殊タイプ：TYPE_CUSTOM >> " + colorType);
      else if(colorType == BufferedImage.TYPE_INT_ARGB)
        f.message("透明可タイプ：TYPE_INT_ARGB >> " + colorType);
      else if(colorType == BufferedImage.TYPE_INT_ARGB_PRE)
        f.message("透明可タイプ：TYPE_INT_ARGB_PRE >> " + colorType);
      else if(colorType == BufferedImage.TYPE_INT_BGR)
        f.message("不透明タイプ：TYPE_INT_BGR >> " + colorType);
      else if(colorType == BufferedImage.TYPE_INT_RGB)
        f.message("不透明タイプ：TYPE_INT_RGB >> " + colorType);
      else if(colorType == BufferedImage.TYPE_USHORT_555_RGB)
        f.message("不透明タイプ：TYPE_USHORT_555_RGB >> " + colorType);
      else if(colorType == BufferedImage.TYPE_USHORT_565_RGB)
        f.message("不透明タイプ：TYPE_USHORT_565_RGB >> " + colorType);
      else if(colorType == BufferedImage.TYPE_USHORT_GRAY)
        f.message("灰色タイプ：TYPE_USHORT_GRAY >> " + colorType);
      else
        f.message("カラー・モデル：不明" );
*/
      //スタンプの背景色（灰色）を無色透明に変換
      int w = stampImage.getWidth(this);
      int h = stampImage.getHeight(this);
      BufferedImage transparentImage = new BufferedImage(
        w, h, BufferedImage.TYPE_INT_ARGB); //透明可に設定
      //f.message("transparentColor=" + Integer.toHexString(transparentColor.getRGB()));
      for(int y=0;y<h;y++){
        for(int x=0;x<w;x++){
          if (stampImage.getRGB(x,y) == transparentColor.getRGB())
          { //特定位置で灰色一致なら３２ビットの無色透明色に変換
            transparentImage.setRGB(x,y,0x00000000);
          }
          else
          { //それ以外なら無変換で転写
            transparentImage.setRGB(x, y, stampImage.getRGB(x, y));
          }
        }
      }
      //無色透明化処理は、大抵の場合成功するが、失敗する場合もある。
      //１．スタンプ画像作成での、アンチエイリアシングの有無。
      //２．画像保存ファイル形式（gif、jpeg、bmp、png）。
      //これらが原因で、無色透明化に失敗する場合もある。
      //スタンプ画像（グレー・マスク画像）をこのGCreatorで作成し保存した場合、
      //簡易実験では、読み込み時、次の３種類のカラー・モデルに分かれた。
      //TYPE_BYTE_INDEXED →  透明化に成功または失敗（結果が不安定）
      //TYPE_3BYTE_BGR  →  透明化に成功
      //TYPE_BYTE_BINARY  →  透明化に成功
      //１．アンチエイリアシング（なめらか処理）を行なった時、失敗しやすい。
      //２．ファイル形式としては、「gif」が透明化に失敗しやすく、
      //「jpeg」は、透明化できても画像の乱れが激しく適切でなく、
      //「png」や「bmp」は、成功しやすく適切であるように思われる。
      //不可逆性の画像圧縮（破壊的圧縮）を行なうファイル形式では、失敗すると思われる。
      //（結論）スタンプ画像は、png形式で保存すると、経験的に失敗が全くない。
      //スタンプ画像を作成し、それをファイル保存する時、png形式で保存すること。

      stampListB.add(transparentImage); //透明化したスタンプ画像をリストに追加
    }
  }

  //■図形の起点十字線の描画（赤線と青線の十字線）
  //直線、長方形、真円、楕円、自由図形などの起点表示に必要
  void drawStartMark(double x, double y)
  {
    BasicStroke solidLine = new BasicStroke( //太さ可変の実線
      lineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    BasicStroke solidLineX = new BasicStroke( //太さ固定の実線
      0.2f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    g2.setStroke(solidLineX);
    g2.setColor(Color.red);
    g2.draw(new Line2D.Double(
      x+shiftX+5, y+shiftY,x+shiftX-5, y+shiftY));
    g2.setColor(Color.blue);
    g2.draw(new Line2D.Double(
      x+shiftX, y+shiftY+5,x+shiftX, y+shiftY-5));
    g2.setStroke(solidLine); //線規格を元に戻す
  }

  //■線の起点中間点終点の描画（真円の目印）
  void drawPointMark(double x, double y) //丸印の目印
  {
    BasicStroke solidLine = new BasicStroke( //太さ可変の実線
      lineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    BasicStroke solidLineX = new BasicStroke( //太さ固定の実線
      0.2f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    g2.setStroke(solidLineX);
    g2.setColor(Color.red);
    g2.draw(new Ellipse2D.Double(
      x +shiftX -4, y +shiftY -4, 8, 8));
      //x座標, y座標, 楕円の幅, 楕円の高さ
    g2.setStroke(solidLine); //線規格を元に戻す
  }

  void drawPointMarkX(double x, double y) //二重丸の目印
  {  //自由図形の曲線部の制御点表示に必要
    BasicStroke solidLine = new BasicStroke( //太さ可変の実線
      lineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    BasicStroke solidLineX = new BasicStroke( //太さ固定の実線
      0.2f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    g2.setStroke(solidLineX);
    g2.setColor(Color.red);
    g2.draw(new Ellipse2D.Double(
      x +shiftX -3, y +shiftY -3, 6, 6));
    g2.draw(new Ellipse2D.Double(
      x +shiftX -5, y +shiftY -5, 10, 10));
      //x座標, y座標, 楕円の幅, 楕円の高さ
    g2.setStroke(solidLine); //線規格を元に戻す
  }

  //■マトリックス柄紋のランダム配色決定（統一配色）
  short[][] getRandom_rgbSt()
  {  //色番号は、０から９までで、０だけ無色透明扱い
      short[][] random_rgbSt = new short[9][3];
      if(matrixPRedBaseSt > 240) matrixPRedBaseSt = 240; //明度上限設定
      if(matrixPGreenBaseSt > 240) matrixPGreenBaseSt = 240;
      if(matrixPBlueBaseSt > 240) matrixPBlueBaseSt = 240;
      for(int i=0; i<9; i++) //ランダム配色
      {
        random_rgbSt[i][0] = (short)(matrixPRedBaseSt +
          (ran.nextInt(255-matrixPRedBaseSt))*matrixColorLimitSt/10);
        random_rgbSt[i][1] = (short)(matrixPGreenBaseSt +
          (ran.nextInt(255-matrixPGreenBaseSt))*matrixColorLimitSt/10);
        random_rgbSt[i][2] = (short)(matrixPBlueBaseSt +
          (ran.nextInt(255-matrixPBlueBaseSt))*matrixColorLimitSt/10);
      }
      return random_rgbSt;
  }

  //■マトリックス柄紋のランダム配色決定（個別配色）
  short[][][][][][] getRandom_rgbEx()
  {
    //このメソッドは、巨大配列を使うためヒープ領域不足になる可能性もあるので、
    //javaの実行時には、メモリー上のヒープ領域を増やすために、
    //以下の参考例を真似て数倍し、各自が最適値を考え、実行時オプションを加えること。
    //java -Xmx1024m GCreator
    //また、メモリーを多めに（Win11で8GB以上）、PCに搭載することが望ましい。
    //Win11で4GBの条件でも動作可能だが、常駐ソフトを最大限に無効化する必要があり、
    //仮想メモリーの設定も必要になる。
    //模様を複雑（ユニット巨大）かつ精細（コマ数微小）かつ巨大（全体サイズ巨大）
    //に指定すれば、ヒープ領域不足になる可能性がある。
    //メモリーが8GB以上あれば、問題は殆ど生じない。

    short[][][][][][] random_rgbEx =
      new short[matrixRepeatH_Ex][matrixRepeatV_Ex][matrixUnitEx][matrixUnitEx][9][3];
    if(matrixPRedBaseEx > 250) matrixPRedBaseEx = 250; //明度上限設定
    if(matrixPGreenBaseEx > 250) matrixPGreenBaseEx = 250;
    if(matrixPBlueBaseEx > 250) matrixPBlueBaseEx = 250;
    //ランダム配色
    short color[][]= new short [9][3]; //9色のランダム色を一時格納
    //返却配列に格納
    for(int repH=0; repH<matrixRepeatH_Ex; repH++) //リピート数、横
    {
      for(int repV=0; repV<matrixRepeatV_Ex; repV++) //リピート数、縦
      {
        for(int h=0; h<matrixUnitEx; h++) //横コマ数
        {
            if(h==0)
            {
              for(int a=0; a<9; a++) //９色
              {
                  color[a][0] = (short)(matrixPRedBaseEx +
                    (ran.nextInt(255-matrixPRedBaseEx))*matrixColorLimitEx/10);
                  color[a][1] = (short)(matrixPGreenBaseEx +
                    (ran.nextInt(255-matrixPGreenBaseEx))*matrixColorLimitEx/10);
                  color[a][2] = (short)(matrixPBlueBaseEx +
                    (ran.nextInt(255-matrixPBlueBaseEx))*matrixColorLimitEx/10);
              }
            }
          for(int v=0; v<matrixUnitEx; v++) //縦コマ数
          {
            for(int i=0; i<9; i++) //割り当てる配色決定（９色）
            {
              random_rgbEx[repH][repV][h][v][i][0] = (short)color[i][0];
              random_rgbEx[repH][repV][h][v][i][1] = (short)color[i][1];
              random_rgbEx[repH][repV][h][v][i][2] = (short)color[i][2];
            }
          }
        }
      }
    }
    return random_rgbEx;
  }

  //■マトリックス柄紋の柄紋番号での文様データ検索取得
  int[][] getPatternData(int patternNum, String colorType)
  {
    int patternUnit;
    int matrixPattern[][] = null;

    for(int i=0; i<patternArr.length; i++)
    {
      if((patternArr[i].startsWith("PTN")) &&
        (patternNum == Integer.parseInt(patternArr[i].substring(4,8))))
      {
        patternUnit = Integer.parseInt(patternArr[i].substring(9,11));
        if(colorType.equals("St"))
        {
          matrixUnitSt = patternUnit;
        }
        if(colorType.equals("Ex"))
        {
          matrixUnitEx = patternUnit;
        }
        matrixPattern = new int[patternUnit][patternUnit];
        for(int j=0; j<patternUnit; j++)
        {
          String[] s = Util.csv2Array(patternArr[i+j+1], patternUnit);
          for(int k=0; k<patternUnit; k++)
          {
            matrixPattern[j][k] = Integer.parseInt(s[k]);
          }
        }
        //if(patternNum != 0) f.message(""+patternArr[i]);
        break;
      }
      else
        continue;
    }
    if(matrixPattern == null) //柄紋検索エラー
    {
      matrixPattern = new int[][]{
        {0,1,1,1,1,0},
        {0,1,0,0,0,0},
        {0,1,1,1,1,0},
        {0,1,0,0,0,0},
        {0,1,1,1,1,0},
        {0,0,0,0,0,0}};
      if(colorType.equals("St"))
        matrixUnitSt = 6;
      if(colorType.equals("Ex"))
        matrixUnitEx = 6;
    }
    return matrixPattern;
  }

  //■フラット型スプレー
  //フラット型（円筒型分布）飛沫分散方式
  double[][] spray0(int sr, int st)
  { //srは飛沫群円盤の半径（最大斜辺）。
    //stは飛沫の個数。

    //●フラット型スプレー機能（円筒型飛沫集団形成）は、三平方の定理と乱数とで実現。
    //一回のスプレー機能の呼び出しで、飛沫群円盤が一個できる。
    //直角三角形⊿で、底辺をa、高さをb、斜辺をc、左下角度（ディグリー）をtとする。
    //ただし、左下角を円盤中心、右上角を飛沫位置と見なす。
    //底辺と高さとが乱数で決まれば、斜辺が算出できる。

    //●フラット型飛沫分散を実現する方法は、以下の通り。
    //飛沫円盤に外接する正方形は、一辺が sr*2 である。
    //この正方形内にフラット分散する飛沫位置は、
    //x軸もy軸も、sr*2 を最大値とする乱数で計算できる。
    //正方形の中心が円盤の中心であるから、その飛沫座標位置は、中心からの距離に調整。
    //さらに、飛沫円盤から飛び出す飛沫位置は、除外することになる。

    double[][] sprayXY = new double[st][2]; //stは飛沫の個数
    double aX; //⊿底辺a
    double bX; //⊿高さb

    for(int i=0; i<st; )
    {
      aX = ranSpray.nextDouble(sr*2) - sr;
      bX = ranSpray.nextDouble(sr*2) - sr;

      if(Math.sqrt(aX*aX + bX*bX) < sr) //⊿斜辺の計算と長さ判定
      {
        sprayXY[i][0] = aX;
        sprayXY[i][1] = bX;
        i++;
      }
    }
    return sprayXY;
  }

  //■正規分布型スプレー
  //正規分布型（ベル型分布、ガウス型分布）飛沫分散方式（なだらかな山形）
  double[][] spray1(int sr, int st)
  { //srは飛沫群円盤の半径（最大斜辺）。
    //stは飛沫の個数。

    //●ベル型スプレー機能（正規分布型飛沫集団形成）は、正規分布型乱数と通常乱数とで実現。
    //一回のスプレー機能の呼び出しで、飛沫群円盤が一個できる。
    //直角三角形⊿で、底辺をa、高さをb、斜辺をc、左下角度（ディグリー）をtとする。
    //ただし、左下角を円盤中心、右上角を飛沫位置と見なす。
    //底辺と高さとが乱数で決まれば、斜辺が算出できる。

    //●ベル型飛沫分散を実現する方法は、以下の通り。
    //飛沫円盤に外接する正方形は、一辺が sr*2 である。
    //この正方形内にフラット分散する飛沫位置は、
    //x軸もy軸も、sr*2 を最大値とする乱数で計算できる。
    //乱数は、ガウス分布（正規分布）を指定する。
    //正方形の中心が円盤の中心であるから、その飛沫座標位置は、中心からの距離に調整する。
    //さらに、飛沫円盤から飛び出す飛沫位置は、除外することになる。

    double[][] sprayXY = new double[st][2]; //stは飛沫の個数
    double aX; //⊿底辺a
    double bX; //⊿高さb

    for(int i=0; i<st; )
    {
      aX = (ranSpray.nextGaussian())*(sr)*sprayGaussianOp;
      bX = (ranSpray.nextGaussian())*(sr)*sprayGaussianOp;
      if(Math.sqrt(aX*aX + bX*bX) < sr) //⊿斜辺の計算と円盤範囲制限
      //実際の正規分布では、円盤の外にも飛沫が飛ぶが、これを円盤内に制限する。
      //そのため、円盤の外部が除去された正規分布である。
      {
        sprayXY[i][0] = aX;
        sprayXY[i][1] = bX;
        i++;
      }
    }
    return sprayXY;
  }

  //■円錐型スプレー
  //円錐型飛沫分散方式（尖った山形）
  double[][] spray2(int sr, int st)
  { //srは飛沫群円盤の半径（最大斜辺）。
    //stは飛沫の個数。

    //●円錐型スプレー機能（円錐型飛沫集団形成）は、三角関数と乱数とで実現する。
    //一回のスプレー機能の呼び出しで、飛沫群円盤が一個できる。
    //直角三角形⊿で、底辺をa、高さをb、斜辺をc、左下角度（ディグリー）をtとする。
    //円盤中心点から飛沫一個への距離cは、0から円盤半径までの整数乱数で決定し、
    //円盤中心点から飛沫一個への角度tは、0から360までの整数乱数で決定する。
    //関係する計算式は、以下の通り。
    //sin(t) = b/c　これを変形すれば、b = c*sin(t) または c = b/sin(t)
    //cos(t) = a/c　これを変形すれば、a = c*cos(t) または c = a/cos(t)
    //tan(t) = b/a　これを変形すれば、b = a*tan(t) または a = b/tan(t)
    //ただし、左下角を円盤中心、右上角を飛沫位置と見なす。

    //●円錐型スプレーは、円盤領域の中央に飛沫が集中する仕様であって、
    //円錐型の飛沫分布になるので、やや中央に集中し過ぎの感もある。
    //この仕様にした意図は、飛沫個数を少なくして、飛沫円盤をランダム・ウォーク方式で
    //多数描画して、全体として朦朧とした画像を形成する使用法を想定している。
    //また、中央に集中した飛沫集団で、朦朧としつつも芯のある画像の形成を想定する。

    Random ranS = new Random(new GregorianCalendar().get(Calendar.MILLISECOND));
    double aX; //⊿底辺a
    double bX; //⊿高さb
    double cX; //⊿斜辺c
    double tX; //⊿左下角度t
    double[][] sprayXY = new double[st][2]; //stは飛沫の個数
    for(int i=0; i<st; i++)
    {
      cX = ranSpray.nextDouble(sr); //飛沫一個への距離（斜辺）
      tX = ranSpray.nextDouble(360); //飛沫一個への角度（ディグリー）
      //斜辺と角度とが乱数で決まれば、底辺aと高さbとが三角関数で算出できる。
      aX = cX*Math.cos(Math.toRadians(tX)); //飛沫一個への底辺（x軸）
      bX = aX*Math.tan(Math.toRadians(tX)); //飛沫一個への高さ（y軸）
      sprayXY[i][0] = aX;
      sprayXY[i][1] = bX;
    }
    return sprayXY;
  }

  //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  //■ソフト・フォーカス効果
  void softFocus()
  {
    //画像ファイル指定のチェック
    if(!softFocusFName.equals("") && softFocusFName != null)
    {
      if(checkImageFile(softFocusFName)==false)
        return;

      softFocusImage0 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      softFocusImage1 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      try
      {
        softFocusImage0 = ImageIO.read(new File(softFocusFName)); //画像読み取り
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("ソフト・フォーカス対象ファイルのリード・エラー："+softFocusFName);
        softFocusImage0 = null;
        return;
      }
      //ソフト・フォーカス加工
      int w = softFocusImage0.getWidth(this);
      int h = softFocusImage0.getHeight(this);

      //ソフト・フォーカス中心位置をm0とし、それを取り巻くピクセル位置（kernel）は、以下の通り。
      //kernelとは、画像（写像）での数学的意味は、全体を構成する小集団（小粒）を意味する。
      //m5, m2, m6
      //m1, m0, m3
      //m8, m4, m7

      int m0,m1,m2,m3,m4,m5,m6,m7,m8;
      int m0R,m0G,m0B;
      int m1R,m1G,m1B,m2R,m2G,m2B,m3R,m3G,m3B,m4R,m4G,m4B;
      int m5R,m5G,m5B,m6R,m6G,m6B,m7R,m7G,m7B,m8R,m8G,m8B;
      for(int y=0; y<h; y++)
      {
        for(int x=0; x<w; x++)
        {
            m0 = softFocusImage0.getRGB(x,y);
            m0R = (m0 & 0x00ff0000)>>>16;
            m0G = (m0 & 0x0000ff00)>>> 8;
            m0B = (m0 & 0x000000ff);
            int color =  (m0R<<16) | (m0G<<8) | m0B;
            softFocusImage1.setRGB(x, y, color);
        }
      }
      for(int z=0; z<softFocusDegree; z++) //ソフト度合いの累積処理
      {
        softFocusImage0 = softFocusImage1;
        for(int y=1; y<h-2; y++)
        {
          for(int x=1; x<w-2; x++)
          {
              m0 = softFocusImage0.getRGB(x,y);
              m0R = (m0 & 0x00ff0000)>>>16;
              m0G = (m0 & 0x0000ff00)>>> 8;
              m0B = (m0 & 0x000000ff);

              m1 = softFocusImage0.getRGB(x-1,y);
              m1R = (m1 & 0x00ff0000)>>>16;
              m1G = (m1 & 0x0000ff00)>>> 8;
              m1B = (m1 & 0x000000ff);
              m2 = softFocusImage0.getRGB(x,y-1);
              m2R = (m2 & 0x00ff0000)>>>16;
              m2G = (m2 & 0x0000ff00)>>> 8;
              m2B = (m2 & 0x000000ff);
              m3 = softFocusImage0.getRGB(x+1,y);
              m3R = (m3 & 0x00ff0000)>>>16;
              m3G = (m3 & 0x0000ff00)>>> 8;
              m3B = (m3 & 0x000000ff);
              m4 = softFocusImage0.getRGB(x,y+1);
              m4R = (m4 & 0x00ff0000)>>>16;
              m4G = (m4 & 0x0000ff00)>>> 8;
              m4B = (m4 & 0x000000ff);

              m5 = softFocusImage0.getRGB(x-1,y-1);
              m5R = (m5 & 0x00ff0000)>>>16;
              m5G = (m5 & 0x0000ff00)>>> 8;
              m5B = (m5 & 0x000000ff);
              m6 = softFocusImage0.getRGB(x+1,y-1);
              m6R = (m6 & 0x00ff0000)>>>16;
              m6G = (m6 & 0x0000ff00)>>> 8;
              m6B = (m6 & 0x000000ff);
              m7 = softFocusImage0.getRGB(x+1,y+1);
              m7R = (m7 & 0x00ff0000)>>>16;
              m7G = (m7 & 0x0000ff00)>>> 8;
              m7B = (m7 & 0x000000ff);
              m8 = softFocusImage0.getRGB(x-1,y+1);
              m8R = (m8 & 0x00ff0000)>>>16;
              m8G = (m8 & 0x0000ff00)>>> 8;
              m8B = (m8 & 0x000000ff);

              double mRd = (m0R+m1R+m2R+m3R+m4R+m5R+m6R+m7R+m8R)/9.0D;
              double mGd = (m0G+m1G+m2G+m3G+m4G+m5G+m6G+m7G+m8G)/9.0D;
              double mBd = (m0B+m1B+m2B+m3B+m4B+m5B+m6B+m7B+m8B)/9.0D;
              int mRx = (int)(mRd+0.5); //計算端数誤差を調整して整数化し、
              int mGx = (int)(mGd+0.5); //ソフト・フォーカス処理を正常化させる。
              int mBx = (int)(mBd+0.5); //
              //この疑似ソフト・フォーカス処理は、各ピクセルの隣接八方向の色相しか
              //計算に入れないので、全体的にぼやけた八角形の形状に、ぼかされる。
              //ただし、肉眼では、このぼやけた八角形は認識できない。
              //レンズによる全方向の真円形ソフト・フォーカスとは、微妙に違う。

              int color = (mRx<<16) | (mGx<<8) | mBx;
              softFocusImage1.setRGB(x, y, color);
          }
        }
      }
    }
    //ソフト・フォーカス画像の描画自体は、drawPage()の中で行なう。
  }

  //■畳み込み画像（画像の鮮鋭化／画像の朦朧化）の処理
  //画像の濃淡を山谷の連続的波動に例えれば、
  //鮮鋭化は、周囲のピクセルとの比較で、相対的に山を高くし谷を深くする操作であり、
  //朦朧化は、周囲のピクセルとの比較で、相対的に山を低くし谷を浅くする操作である。
  //畳み込みでは、輪郭線を鮮明にしたり不鮮明にしたりの副次的効果が生じるが、
  //輪郭線の連続形状を認識しているわけではないため、全面に及ぶノイズの発生もある。
  //画像の鮮鋭化は、他に適当な方法がないため、効果は限定的ながら、貴重な機能である。
  //画像の朦朧化は、ソフト・フォーカス処理での計算の仕方とかなり違う。
  void convolve()
  {
    //画像ファイル指定のチェック
    if(convolveFName.equals(""))
      return;
    else
    {
      if(checkImageFile(convolveFName)==false)
        return;

      convolveImage0 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      convolveImage1 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      convolveImage2 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      try
      {
        convolveImage0 = ImageIO.read(new File(convolveFName)); //画像読み取り
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("畳み込み処理対象ファイルのリード・エラー："+convolveFName);
        convolveImage0 = null;
        return;
      }

      //畳み込み処理の実施
      //ピクセル位置v0を中心に、それを取り巻くピクセルv1,v2の配置（kernel）は、以下の通り。
      //kernelとは、画像（写像）での数学的意味は、全体を構成する小集団（小粒）を意味する。
      float[] kernelDataX;
      Kernel kernel;

      if(convolveKernelSize==3) //3x3 Kernel
      {
        float[] kernelData =
        {
          convolveV2,convolveV1,convolveV2,
          convolveV1,convolveV0,convolveV1,
          convolveV2,convolveV1,convolveV2
        };
        kernel = new Kernel(3, 3, kernelData);
      }
      else if(convolveKernelSize==5) //5x5 Kernel
      {
        float[] kernelData =
        {
          convolveV5,convolveV4,convolveV3,convolveV4,convolveV5,
          convolveV4,convolveV2,convolveV1,convolveV2,convolveV4,
          convolveV3,convolveV1,convolveV0,convolveV1,convolveV3,
          convolveV4,convolveV2,convolveV1,convolveV2,convolveV4,
          convolveV5,convolveV4,convolveV3,convolveV4,convolveV5
        };
        kernel = new Kernel(5, 5, kernelData);
      }
      else
      {
        f.message("カーネルの指定エラー");
        convolveImage0 = null;
        return;
      }

      ConvolveOp conv = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);

      for(int z=0; z<convolveDegree; z++) //畳み込みの累積処理
      {
        if(z == 0)
          convolveImage2 = convolveImage0; //元画像を一時保存
        convolveImage1 = conv.filter(convolveImage0, null); //畳み込み画像変換
        convolveImage0 = convolveImage1;
        if(z == (convolveDegree-1))
          convolveImage0 = convolveImage2; //一時保存の元画像を本来の位置に戻す。
      }
    }
    convolveImage1 = removeColorNoize(convolveImage1, convolveKernelSize,
      convolveNoizeTolerance, convolveColorDistance);
    //畳み込み画像の描画自体は、drawPage()の中で行なう。
  }

  //■輪郭線抽出
  //無階調のベタ塗りの画像であれば、完璧な輪郭線が抽出される。
  //連続階調の写真画像を元にして、写っている物体の輪郭線を取り出す場合、
  //完全な輪郭線は得られず、ノイズも多少混じり、途切れがちな輪郭線が抽出されるだけである。
  //途切れた輪郭線は、画像保存した後で、必要ならマウス操作でスプライン曲線を描き加える。
  //元画像は、輪郭部でピクセル単位の大きな色段差があり、輪郭以外は、緩やかな階調のものが適する。
  void getOutline()
  {
    //画像ファイル指定のチェック
    if(!outlineFName.equals("") && outlineFName != null)
    {
      if(checkImageFile(outlineFName)==false)
        return;

      outlineImage0 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      outlineImage1 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      try
      {
        outlineImage0 = ImageIO.read(new File(outlineFName)); //画像読み取り
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("輪郭線抽出対象画像ファイルのリード・エラー："+outlineFName);
        outlineImage0 = null;
        outlineImage1 = null;
        return;
      }
    }
    else
      return;

    int w = outlineImage0.getWidth(this);
    int h = outlineImage0.getHeight(this);

    int oCD = outlineColorDistance; //色段差
    int outlineColor; //輪郭線を描画する色

    for(int y=0; y<h; y++)
    {
      for(int x=0; x<w; x++)
      {
          outlineImage1.setRGB(x, y, 0x00ffffff);
      }
    }

    //輪郭線想定位置k22を中心に、それを取り巻くピクセル位置の集合（kernel）は、以下の通り。
    //kernelとは、画像（写像）での数学的意味は、全体を構成する小集団（小粒）を意味する。
    //輪郭線の判定は、基本的に3x3のカーネルを用いて行なう。

    //k11, k21, k31
    //k12, k22, k32
    //k13, k23, k33
    int k11, k21, k31, k12, k22, k32, k13, k23, k33;
    int k11R, k11G, k11B, k21R, k21G, k21B, k31R, k31G, k31B;
    int k12R, k12G, k12B, k22R, k22G, k22B, k32R, k32G, k32B;
    int k13R, k13G, k13B, k23R, k23G, k23B, k33R, k33G, k33B;

    for(int y=1; y<h-2; y++)
    {
      for(int x=1; x<w-2; x++)
      {
        k11 = outlineImage0.getRGB(x-1,y-1);
        k11R = (k11 & 0x00ff0000)>>>16;
        k11G = (k11 & 0x0000ff00)>>> 8;
        k11B = (k11 & 0x000000ff);
        k21 = outlineImage0.getRGB(x,y-1);
        k21R = (k21 & 0x00ff0000)>>>16;
        k21G = (k21 & 0x0000ff00)>>> 8;
        k21B = (k21 & 0x000000ff);
        k31 = outlineImage0.getRGB(x+1,y-1);
        k31R = (k31 & 0x00ff0000)>>>16;
        k31G = (k31 & 0x0000ff00)>>> 8;
        k31B = (k31 & 0x000000ff);

        k12 = outlineImage0.getRGB(x-1,y);
        k12R = (k12 & 0x00ff0000)>>>16;
        k12G = (k12 & 0x0000ff00)>>> 8;
        k12B = (k12 & 0x000000ff);
        k22 = outlineImage0.getRGB(x,y);
        k22R = (k22 & 0x00ff0000)>>>16;
        k22G = (k22 & 0x0000ff00)>>> 8;
        k22B = (k22 & 0x000000ff);
        k32 = outlineImage0.getRGB(x,y+1);
        k32R = (k32 & 0x00ff0000)>>>16;
        k32G = (k32 & 0x0000ff00)>>> 8;
        k32B = (k32 & 0x000000ff);

        k13 = outlineImage0.getRGB(x-1,y+1);
        k13R = (k13 & 0x00ff0000)>>>16;
        k13G = (k13 & 0x0000ff00)>>> 8;
        k13B = (k13 & 0x000000ff);
        k23 = outlineImage0.getRGB(x+1,y);
        k23R = (k23 & 0x00ff0000)>>>16;
        k23G = (k23 & 0x0000ff00)>>> 8;
        k23B = (k23 & 0x000000ff);
        k33 = outlineImage0.getRGB(x+1,y+1);
        k33R = (k33 & 0x00ff0000)>>>16;
        k33G = (k33 & 0x0000ff00)>>> 8;
        k33B = (k33 & 0x000000ff);

        //k11, k21, k31
        //k12, k22, k32
        //k13, k23, k33
        //輪郭線の検出は、中核的要素のみを検査対象とするので、
        //多少の検出漏れ（欠損）や偽解像（過剰）の発生もあるが、それを許容する。
        if(
          //R成分
          ((k12R > k32R+oCD && Math.abs(k22R-k12R)>Math.abs(k22R-k32R)) || //垂直線R
          (k12R+oCD < k32R && Math.abs(k22R-k12R)<Math.abs(k22R-k32R)) || //同、　反転R
          (k21R > k23R+oCD && Math.abs(k22R-k21R)>Math.abs(k22R-k23R)) || //水平線R
          (k21R+oCD < k23R && Math.abs(k22R-k21R)<Math.abs(k22R-k23R)) || //同、　反転R
          (k11R > k33R+oCD && Math.abs(k22R-k11R)>Math.abs(k22R-k33R)) || //右下がり傾斜線R
          (k11R+oCD < k33R && Math.abs(k22R-k11R)<Math.abs(k22R-k33R)) || //同、　反転R
          (k31R > k13R+oCD && Math.abs(k22R-k31R)>Math.abs(k22R-k13R)) || //右上がり傾斜線R
          (k31R+oCD < k13R && Math.abs(k22R-k31R)<Math.abs(k22R-k13R)) || //同、　反転R
          //G成分
          (k12G > k32G+oCD && Math.abs(k22G-k12G)>Math.abs(k22G-k32G)) ||
          (k12G+oCD < k32G && Math.abs(k22G-k12G)<Math.abs(k22G-k32G)) ||
          (k21G > k23G+oCD && Math.abs(k22G-k21G)>Math.abs(k22G-k23G)) ||
          (k21G+oCD < k23G && Math.abs(k22G-k21G)<Math.abs(k22G-k23G)) ||
          (k11G > k33G+oCD && Math.abs(k22G-k11G)>Math.abs(k22G-k33G)) ||
          (k11G+oCD < k33G && Math.abs(k22G-k11G)<Math.abs(k22G-k33G)) ||
          (k31G > k13G+oCD && Math.abs(k22G-k31G)>Math.abs(k22G-k13G)) ||
          (k31G+oCD < k13G && Math.abs(k22G-k31G)<Math.abs(k22G-k13G)) ||
          //B成分
          (k12B > k32B+oCD && Math.abs(k22B-k12B)>Math.abs(k22B-k32B)) ||
          (k12B+oCD < k32B && Math.abs(k22B-k12B)<Math.abs(k22B-k32B)) ||
          (k21B > k23B+oCD && Math.abs(k22B-k21B)>Math.abs(k22B-k23B)) ||
          (k21B+oCD < k23B && Math.abs(k22B-k21B)<Math.abs(k22B-k23B)) ||
          (k11B > k33B+oCD && Math.abs(k22B-k11B)>Math.abs(k22B-k33B)) ||
          (k11B+oCD < k33B && Math.abs(k22B-k11B)<Math.abs(k22B-k33B)) ||
          (k31B > k13B+oCD && Math.abs(k22B-k31B)>Math.abs(k22B-k13B)) ||
          (k31B+oCD < k13B && Math.abs(k22B-k31B)<Math.abs(k22B-k13B)) )
          )
        {
          outlineColor = 0x00000000;
        }
        else
        {
          outlineColor = 0x00ffffff;
        }
        outlineImage1.setRGB(x, y, outlineColor);
      }
    }
    outlineImage1 = removeBlackNoize(outlineImage1, outlineNoizeKernel, outlineNoizeTolerance);
    //砂目ノイズ除去に限っては、カーネルのサイズを可変とし、3x3, 5x5, 7x7 を選べる。
    //輪郭線画像の描画自体は、drawPage()の中で行なう。
  }

  //■切り貼り画像処理
  void cutAndPaste()
  {
    //●切り貼り画像（外部からの読み込み画像）の上書き描画
    if(capMaskF != null && !capMaskF.equals("")) //マルチ・マスク・ファイル
    {
      //画像ファイル指定のチェック
      if(checkImageFile(capMaskF)==false)
        return;

      int w = (int)imagePX_W;
      int h = (int)imagePX_H;
      try
      {
        capImageM = ImageIO.read(new File(capMaskF)); //画像の読み込み
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("マルチ・マスク・ファイルのリード・エラー："+capMaskF);
        capImageM = null;
        return;
      }
    }

    capImage0 = new BufferedImage( //切り貼り元模様画像（不透明）
      (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB);
    capImage1 = new BufferedImage( //切り貼り後の画像（透明可）
      (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_ARGB);
    for(int i=0; i<capListF.size(); i++) //
    {
      //画像ファイル指定のチェック
      String path1 = capListF.get(i).toLowerCase();
      int maskR = capListI.get(i)[0];
      int maskG = capListI.get(i)[1];
      int maskB = capListI.get(i)[2];
      int maskRGB = (maskR<<16) | (maskG<<8) | maskB;

      if(path1.endsWith(".jpeg") ||path1.endsWith(".jpg") ||
        path1.endsWith(".gif") ||path1.endsWith(".png") ||
        path1.endsWith(".bmp"))
        ; //OK
      else
      {
        f.message("切り貼り元画像ファイル指定が不適切："+capListF.get(i));
        return;
      }
      if(! new File(path1).exists())
      {
        f.message("切り貼り元画像ファイルが存在しません："+capListF.get(i));
        return;
      }

      try
      {
        capImage0 = ImageIO.read(new File(path1));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("切り貼り元画像ファイルのリード・エラー："+path1);
        return;
      }

      for(int y=0;y<imagePX_H;y++)
      {
        for(int x=0;x<imagePX_W;x++)
        {
          if ((0x00ffffff & capImageM.getRGB(x,y)) == maskRGB)
          { //
            capImage1.setRGB(x, y, capImage0.getRGB(x, y));
          }
        }
      }
    }
    //切り貼り完成画像の描画自体は、drawPage()の中で行なう。
  }

  //■連続色相変更処理
  void changeColorMulti()
  {
    //●元画像（外部からの読み込み画像）の上書き描画
    //主に、マルチ・マスク・ファイルの色相修正に用いる画像加工。
    //String         ccmMaskF  //ChangeColorMalti用　元画像のファイル名
    //BufferedImage  ccmImage0 //元画像（連続色相変更処理前画像）
    //BufferedImage  ccmImage1 //新画像（連続色相変更処理完了画像）
    //List<int[]>    ccmListI0 //旧色指定リスト
    //List<int[]>    ccmListI1 //新色指定リスト

    if(ccmMaskF != null && !ccmMaskF.equals("")) //主にマルチ・マスク・ファイル
    {
      //画像ファイル指定のチェック
      if(checkImageFile(ccmMaskF)==false)
        return;

      try
      {
        ccmImage0 = ImageIO.read(new File(ccmMaskF)); //元画像の読み込み
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("マルチ・マスク・ファイルのリード・エラー："+ccmMaskF);
        ccmImage0 = null;
        return;
      }
    }

    int ccmW = ccmImage0.getWidth();
    int ccmH = ccmImage0.getHeight();

    if(ccmImage0 == null)
      return;
    ccmImage1 = new BufferedImage( //連続色相変更後の画像
      ccmW, ccmH, BufferedImage.TYPE_INT_RGB);
    for(int y=0; y<imagePX_H; y++) //初期状態として画像コピー
    {
      for(int x=0; x<imagePX_W; x++)
      {
        ccmImage1.setRGB(x, y, ccmImage0.getRGB(x, y));
      }
    }

    int rgb0 = 0, rgb1 = 0;
    for(int i=0; i<ccmListI0.size(); i++) //色相変更命令の回数だけループ
    {
      for(int y=0; y<imagePX_H; y++)
      {
        for(int x=0; x<imagePX_W; x++)
        {
          rgb0 = (ccmListI0.get(i)[0] << 16 | ccmListI0.get(i)[1] << 8 | ccmListI0.get(i)[2]);
          rgb1 = (ccmListI1.get(i)[0] << 16 | ccmListI1.get(i)[1] << 8 | ccmListI1.get(i)[2]);
          if ((ccmImage0.getRGB(x,y) & 0x00ffffff) == rgb0)
          {
            ccmImage1.setRGB(x, y, rgb1);
          }
        }
      }
    }
    //連続色相変更完成画像の描画自体は、drawPage()の中で行なう。
  }

  //■図形内部単独彩色
  void changeColorInner()
  {
    //●輪郭線で囲まれた図形内部を、指定色でベタ塗り彩色。

    //輪郭線で囲まれた図形の内外を自動的に判定する方法はある。
    //それは、輪郭線の色を手掛かりにするもので、図形を含む全体領域（Size命令で指定の領域）を
    //端から順にスキャンし、そのピクセルの色が輪郭線の色かどうかを判別し、
    //輪郭線を超えて色が変わるたびにカウントし、カウントが奇数であれば
    //図形の外側と判断し、偶数であれば内側と判断して、
    //内側判定したピクセルを指定色で彩色するアルゴリズムである。
    //ただし、針状に細く尖った部分を持つ図形では、輪郭線がピクセル単位で重なり、
    //偶数が奇数になる部分も生じるため、x軸とy軸とでの双方向検査が必要になる。
    //また、全体領域内に複数の図形がある場合、その区別が難しくなる。
    //いずれにせよ、このプログラムでは、上に述べた内外自動判定のテクニックを使わない。

    if(changeColorInnerFlag==false)
      return;
    if(changeColorInnerFlag==true && !changeColorInnerF.equals(""))
    {
      if(checkImageFile(changeColorInnerF)==false)
        return;

      try
      {
         cciImage = ImageIO.read(new File(changeColorInnerF));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("図形内部彩色用画像ファイルのリード・エラー："+changeColorInnerF);
        cciImage = null;
        return;
      }
    }
    else
    {
      f.message("図形内部彩色元画像ファイル指定に問題あり。");
      return;
    }

    int w = cciImage.getWidth(this);
    int h = cciImage.getHeight(this);
    int outlineColor = 0xff<<24 | cciOutlineColorR<<16 | cciOutlineColorG<<8 | cciOutlineColorB;
    int innerColor   = 0xff<<24 | cciInnerColorR<<16 | cciInnerColorG<<8 | cciInnerColorB;
    if(cciInnerX == 0  && cciInnerY == 0)
      ; //何もしない。（図形内で事前にスポット彩色されている場合）
    else
      cciImage.setRGB(cciInnerX, cciInnerY, innerColor); //図形内部代表位置の１ピクセルを彩色。
    int nextPositionColor = 0;
    for(;;) //スキャンの反復
    {
      boolean scanFlag = false;
      for(int j=0; j<h-1; j++) //右向き彩色拡張
      {
        for(int k=0; k<w-1; k++)
        {
          nextPositionColor = cciImage.getRGB(k+1,j);
          if(cciImage.getRGB(k,j)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciImage.setRGB(k+1,j,innerColor);
            scanFlag = true;
          }
        }
      }
      for(int j=0; j<h-1; j++) //左向き彩色拡張
      {
        for(int k=w-1; k>0; k--)
        {
          nextPositionColor = cciImage.getRGB(k-1,j);
          if(cciImage.getRGB(k,j)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciImage.setRGB(k-1,j,innerColor);
            scanFlag = true;
          }
        }
      }
      for(int j=0; j<w-1; j++) //下向き彩色拡張
      {
        for(int k=0; k<h-1; k++)
        {
          nextPositionColor = cciImage.getRGB(j,k+1);
          if(cciImage.getRGB(j,k)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciImage.setRGB(j,k+1,innerColor);
            scanFlag = true;
          }
        }
      }
      for(int j=0; j<w-1; j++) //上向き彩色拡張
      {
        for(int k=h-1; k>0; k--)
        {
          nextPositionColor = cciImage.getRGB(j,k-1);
          if(cciImage.getRGB(j,k)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciImage.setRGB(j,k-1,innerColor);
            scanFlag = true;
          }
        }
      }
      if(scanFlag == false) //新たに色彩変更することがなかった場合
        break;
    }

    if(cciMode==0)
    { //何もしないで、輪郭線の色はそのまま
      ;
    }
    else if(cciMode==1)
    { //輪郭線を内部彩色と同一色に変換
      int currentPositionColor = 0;
      for(int i=0; i<h; i++)
      {
        for(int j=0; j<w; j++)
        {
          currentPositionColor = cciImage.getRGB(j,i);
          if(cciImage.getRGB(j,i)==outlineColor)
          {
            cciImage.setRGB(j,i,innerColor);
          }
        }
      }
    }
    else if(cciMode==2)
    { //輪郭線を黒色(0,0,0)に変換
      int currentPositionColor = 0;
      for(int i=0; i<h; i++)
      {
        for(int j=0; j<w; j++)
        {
          currentPositionColor = cciImage.getRGB(j,i);
          if(cciImage.getRGB(j,i)==outlineColor)
          {
            cciImage.setRGB(j,i,0xff000000);
          }
        }
      }
    }
    else if(cciMode==3)
    { //輪郭線を灰色(200,200,200)に変換
      int currentPositionColor = 0;
      for(int i=0; i<h; i++)
      {
        for(int j=0; j<w; j++)
        {
          currentPositionColor = cciImage.getRGB(j,i);
          if(cciImage.getRGB(j,i)==outlineColor)
          {
            cciImage.setRGB(j,i,0xff<<24 | 200<<16 | 200<<8 | 200);
          }
        }
      }
    }
    else if(cciMode==4)
    { //輪郭線を白色(255,255,255)に変換
      int currentPositionColor = 0;
      for(int i=0; i<h; i++)
      {
        for(int j=0; j<w; j++)
        {
          currentPositionColor = cciImage.getRGB(j,i);
          if(cciImage.getRGB(j,i)==outlineColor)
          {
            cciImage.setRGB(j,i,0xff<<24 | 0xff<<16 | 0xff<<8 | 0xff);
          }
        }
      }
    }
  }

  //■図形内部連続彩色
  void changeColorInnerMulti()
  {
    //●複雑に交叉した輪郭線で構成された図形内部区画を指定色で連続彩色。
    //輪郭線で囲まれた図形がジグザク状や渦巻き状に屈曲している場合、彩色完了までに、
    //長時間（巨大で複雑で多色の図形なら数分）を要する。
    //これを高速化するには、点描画機能を用い、輪郭線図形の彩色部の何箇所かに
    //予め指定色を部分的に塗っておく。
    //ただし、特殊な事情がない限り、changeColorInnerAuto()を使用することを推奨。

    if(changeColorInnerMultiFlag==false)
      return;
    if(changeColorInnerMultiFlag==true && !changeColorInnerMultiF.equals(""))
    {
      if(checkImageFile(changeColorInnerMultiF)==false)
        return;

      try
      {
         ccimImage = ImageIO.read(new File(changeColorInnerMultiF));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("図形内部連続彩色用画像ファイルのリード・エラー："+changeColorInnerMultiF);
        ccimImage = null;
        return;
      }
    }
    else
    {
      f.message("図形内部連続彩色元画像ファイル指定に問題あり。");
      return;
    }

    int w = ccimImage.getWidth(this);
    int h = ccimImage.getHeight(this);
    int outlineColor = 0xff<<24 | ccimOutlineColorR<<16 | ccimOutlineColorG<<8 |
      ccimOutlineColorB;

    //連続彩色
    for(int i=0; i<ccimListI.size(); i++)
    {
      int rgb = (ccimListI.get(i)[0] << 16 | ccimListI.get(i)[1] << 8 | ccimListI.get(i)[2]);
      int innerColor = 0xff<<24 | ccimListI.get(i)[0]<<16 | ccimListI.get(i)[1]<<8 |
        ccimListI.get(i)[2];
      int ccimInnerX = ccimListI.get(i)[3];
      int ccimInnerY = ccimListI.get(i)[4];
      if(ccimInnerX == 0  && ccimInnerY == 0)
        ; //何もしない。（図形内で事前にスポット彩色されている場合）
      else //図形内部代表位置の１ピクセルを彩色。
        ccimImage.setRGB(ccimInnerX, ccimInnerY, innerColor);
      int nextPositionColor = 0;
      for(;;) //スキャンの反復
      {
        boolean scanFlag = false;
        for(int j=0; j<h-1; j++) //右向き彩色拡張
        {
          for(int k=0; k<w-1; k++)
          {
            nextPositionColor = ccimImage.getRGB(k+1,j);
            if(ccimImage.getRGB(k,j)==innerColor && nextPositionColor!=outlineColor &&
              nextPositionColor!=innerColor)
            {
              ccimImage.setRGB(k+1,j,innerColor);
              scanFlag = true;
            }
          }
        }
        for(int j=0; j<h-1; j++) //左向き彩色拡張
        {
          for(int k=w-1; k>0; k--)
          {
            nextPositionColor = ccimImage.getRGB(k-1,j);
            if(ccimImage.getRGB(k,j)==innerColor && nextPositionColor!=outlineColor &&
              nextPositionColor!=innerColor)
            {
              ccimImage.setRGB(k-1,j,innerColor);
              scanFlag = true;
            }
          }
        }
        for(int j=0; j<w-1; j++) //下向き彩色拡張
        {
          for(int k=0; k<h-1; k++)
          {
            nextPositionColor = ccimImage.getRGB(j,k+1);
            if(ccimImage.getRGB(j,k)==innerColor && nextPositionColor!=outlineColor &&
              nextPositionColor!=innerColor)
            {
              ccimImage.setRGB(j,k+1,innerColor);
              scanFlag = true;
            }
          }
        }
        for(int j=0; j<w-1; j++) //上向き彩色拡張
        {
          for(int k=h-1; k>0; k--)
          {
            nextPositionColor = ccimImage.getRGB(j,k-1);
            if(ccimImage.getRGB(j,k)==innerColor && nextPositionColor!=outlineColor &&
              nextPositionColor!=innerColor)
            {
              ccimImage.setRGB(j,k-1,innerColor);
              scanFlag = true;
            }
          }
        }
        if(scanFlag == false) //新たに色彩変更することがなかった場合
          break;
      }
    }
  }

  //■図形内部連続自動彩色
  void changeColorInnerAuto()
  {
    //●複雑に交叉した輪郭線で構成された図形内部区画を指定色で連続自動彩色。
    //ChangeColorInner命令およびChangeColorInnerMulti命令を代替し高速化し自動化する機能を実現。
    //ただし、輪郭線画像（白地図形式画像）は、指定色がスポット彩色（点描画方式）されていること。
    //このメソッドでは、背景色の「地色」でも「輪郭線色」でも「彩色指定色」でもない「無関係色」が
    //塗り替え対象画像（輪郭線画像にスポット彩色された画像）に含まれてはならない。
    //「地色」でも「輪郭線色」でもない色があれば、「彩色指定色」と見なされる。
    //使い方は、メニューの「見本」を参照のこと。

    if(changeColorInnerAutoFlag==false)
    {
      return;
    }
    if(changeColorInnerAutoFlag==true && !changeColorInnerAutoF.equals(""))
    {
      if(checkImageFile(changeColorInnerAutoF)==false)
        return;

      try
      {
         cciaImage = ImageIO.read(new File(changeColorInnerAutoF));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("図形内部連続自動彩色用画像ファイルのリード・エラー："+changeColorInnerAutoF);
        cciaImage = null;
        return;
      }
    }
    else
    {
      f.message("図形内部連続彩色元画像ファイル指定に問題あり。");
      return;
    }

    int w = cciaImage.getWidth(this);
    int h = cciaImage.getHeight(this);
    int baseColor = 0xff<<24 | cciaBaseColorR<<16 | cciaBaseColorG<<8 | cciaBaseColorB; //地色
    int outlineColor =
      0xff<<24 | cciaOutlineColorR<<16 | cciaOutlineColorG<<8 | cciaOutlineColorB; //輪郭線色
    int innerColor = 0xffffffff; //内部着色する指定色（ダミーを初期設定）

    //連続自動彩色

    int nextPositionColor = 0;
    for(;;) //スキャンの反復
    {
      boolean scanFlag = false;
      for(int j=0; j<h-1; j++) //右向き彩色拡張
      {
        for(int k=0; k<w-1; k++)
        {
          nextPositionColor = cciaImage.getRGB(k+1,j);
          if(nextPositionColor != baseColor && nextPositionColor != outlineColor)
            innerColor = nextPositionColor;
          else if(nextPositionColor == outlineColor)
            innerColor = baseColor;
          if(cciaImage.getRGB(k,j)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciaImage.setRGB(k+1,j,innerColor);
            scanFlag = true;
          }
        }
      }
      for(int j=0; j<h-1; j++) //左向き彩色拡張
      {
        for(int k=w-1; k>0; k--)
        {
          nextPositionColor = cciaImage.getRGB(k-1,j);
          if(nextPositionColor != baseColor && nextPositionColor != outlineColor)
            innerColor = nextPositionColor;
          else if(nextPositionColor == outlineColor)
            innerColor = baseColor;
          if(cciaImage.getRGB(k,j)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciaImage.setRGB(k-1,j,innerColor);
            scanFlag = true;
          }
        }
      }
      for(int j=0; j<w-1; j++) //下向き彩色拡張
      {
        for(int k=0; k<h-1; k++)
        {
          nextPositionColor = cciaImage.getRGB(j,k+1);
          if(nextPositionColor != baseColor && nextPositionColor != outlineColor)
            innerColor = nextPositionColor;
          else if(nextPositionColor == outlineColor)
            innerColor = baseColor;
          if(cciaImage.getRGB(j,k)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciaImage.setRGB(j,k+1,innerColor);
            scanFlag = true;
          }
        }
      }
      for(int j=0; j<w-1; j++) //上向き彩色拡張
      {
        for(int k=h-1; k>0; k--)
        {
          nextPositionColor = cciaImage.getRGB(j,k-1);
          if(nextPositionColor != baseColor && nextPositionColor != outlineColor)
            innerColor = nextPositionColor;
          else if(nextPositionColor == outlineColor)
            innerColor = baseColor;
          if(cciaImage.getRGB(j,k)==innerColor && nextPositionColor!=outlineColor &&
            nextPositionColor!=innerColor)
          {
            cciaImage.setRGB(j,k-1,innerColor);
            scanFlag = true;
          }
        }
      }
      if(scanFlag == false) //新たに色彩変更することがなかった場合
        break;
    }
  }

  //■二重像画像処理
  void mixImage()
  {
    //●ミックス用画像（外部からの読み込み画像）を用いた二重像合成描画
    //●写真の二重露光と同様の画像合成
    //●画像ファイル指定のチェック
    if(!mixFName0.equals(""))
    {
      if(checkImageFile(mixFName0)==false)
        return;

      try
      {
        mixImage0 = ImageIO.read(new File(mixFName0));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("ミックス用画像ファイル0のリード・エラー："+mixFName0);
        mixImage0 = null;
        return;
      }

      if(checkImageFile(mixFName1)==false)
        return;

      try
      {
        mixImage1 = ImageIO.read(new File(mixFName1));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("ミックス用画像ファイル1のリード・エラー："+mixFName1);
        mixImage1 = null;
        return;
      }

      //●画像ミックス
      //●画像サイズを全て統一しておくこと
      int w = mixImage0.getWidth(this);
      int h = mixImage0.getHeight(this);
      int R,G,B;
      mixImage2 = new BufferedImage(
        w, h, BufferedImage.TYPE_INT_RGB); //不透明

      if(mixMode == 1) //通常の二重像モード
      {
        for(int y=0;y<h;y++)
        {
          for(int x=0;x<w;x++)
          {
            int m = mixImage0.getRGB(x,y); //元画像
            int t = mixImage1.getRGB(x,y); //追加画像

            if( //追加画像の背景部分が灰色（200,200,200）の場合、
                //混色せずに、元画像の色相を維持
              (((t & 0x00ff0000)>>>16) == 200) &&
            	(((t & 0x0000ff00)>>> 8) == 200) &&
              (( t & 0x000000ff)      == 200) )
            {
            	R = (m & 0x00ff0000)>>>16;
            	G = (m & 0x0000ff00)>>> 8;
            	B = (m & 0x000000ff);
              int color = (R<<16) | (G<<8) | B;
              mixImage2.setRGB(x, y, color);
            }
            else //元画像と追加画像とを、有色半透明で混色合成
            {
            	R = ((m & 0x00ff0000)>>>16)/2 + ((t & 0x00ff0000)>>>16)/2;
            	G = ((m & 0x0000ff00)>>> 8)/2 + ((t & 0x0000ff00)>>> 8)/2;
            	B = (m & 0x000000ff)/2       + ( t & 0x000000ff)/2;
              int color = (R<<16) | (G<<8) | B;
              mixImage2.setRGB(x, y, color);
            }
          }
        }
      }
      else if(mixMode == 0) //拡大縮小を伴わない画像全体の「簡易Stamp命令」として機能
      {
        for(int y=0;y<h;y++)
        {
          for(int x=0;x<w;x++)
          {
            int m = mixImage0.getRGB(x,y); //元画像
            int t = mixImage1.getRGB(x,y); //追加画像

            if( //追加画像の背景部分が灰色（200,200,200）の場合、
                //元画像の色相を維持
              (((t & 0x00ff0000)>>>16) == 200) &&
            	(((t & 0x0000ff00)>>> 8) == 200) &&
              (( t & 0x000000ff)      == 200) )
            {
            	R = (m & 0x00ff0000)>>>16;
            	G = (m & 0x0000ff00)>>> 8;
            	B = (m & 0x000000ff);
              int color = (R<<16) | (G<<8) | B ;
              mixImage2.setRGB(x, y, color);
            }
            else //追加画像の色相をコピー（簡易Stamp押印）
            {
            	R = (t & 0x00ff0000)>>>16;
            	G = (t & 0x0000ff00)>>> 8;
            	B = (t & 0x000000ff);
              int color = (R<<16) | (G<<8) | B;
              mixImage2.setRGB(x, y, color);
            }
          }
        }
      }
    }
    //二重像画像の描画自体は、drawPage()の中で行なう。
  }

  //■鏡像への画像反転処理（回転処理も一部含む）
  void reverseImage()
  {
    //●画像の鏡像反転（回転処理も一部含む）
    if(reverseImageFlag == true)
    {
      if(checkImageFile(reverseImageFile)==false)
        return;

      try
      { //反転対象既存画像の読み込み
        reverseImage0 = ImageIO.read(new File(reverseImageFile));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("反転対象既存画像のリード・エラー");
        return;
      }

      int ww = reverseImage0.getWidth(this);
      int hh = reverseImage0.getHeight(this);

      reverseImage1 = new BufferedImage(
        ww, hh, BufferedImage.TYPE_INT_RGB); //不透明に設定
      reverseImageX = new BufferedImage( //回転
        hh, ww, BufferedImage.TYPE_INT_RGB); //不透明に設定

      if(reverseImageMode==1) //左右鏡像反転
      {
        for(int y=0; y<hh; y++)
        {
          for(int x=0, w1=ww; x<ww; x++, w1--)
          {
            reverseImage1.setRGB(w1-1, y, reverseImage0.getRGB(x,y));
          }
        }
      }
      else if(reverseImageMode==2) //上下鏡像反転
      {
        for(int y=0, h1=hh; y<hh; y++, h1--)
        {
          for(int x=0; x<ww; x++)
          {
            reverseImage1.setRGB(x, h1-1, reverseImage0.getRGB(x,y));
          }
        }
      }
      else if(reverseImageMode==3) //左半分を右半分に対称型に転写して左右対称にする。
      {
        int half;
        if(ww%2 == 0)
          half=ww/2;
        else
          half=ww/2+1;
        for(int y=0; y<hh; y++)
        {
          for(int x=0, w1=half; x<half; x++, w1--)
          {
            reverseImage1.setRGB(x, y, reverseImage0.getRGB(x,y));
            reverseImage1.setRGB(half+w1-1, y, reverseImage0.getRGB(x,y));
          }
        }
      }
      else if(reverseImageMode==4) //上半分を下半分に対称型に転写して上下対称にする。
      {
        int half;
        if(hh%2 == 0)
          half=hh/2;
        else
          half=hh/2+1;
        for(int y=0, h1=half; y<half; y++, h1--)
        {
          for(int x=0; x<ww; x++)
          {
            reverseImage1.setRGB(x, y, reverseImage0.getRGB(x,y));
            reverseImage1.setRGB(x, half+h1-1, reverseImage0.getRGB(x,y));
          }
        }
      }
      else if(reverseImageMode==6) //時計回りで、180度回転（半回転）させる。
      {
        for(int y=0, y1=hh-1; y<hh; y++, y1--)
        {
          for(int x=0, x1=ww-1; x<ww; x++, x1--)
          {
            reverseImage1.setRGB(x1,y1, reverseImage0.getRGB(x,y));
          }
        }
      }

      //これ以降のreverseImageMode（5 or 7）は、画像の幅と丈とが入れ替わるので、
      //通常の方法（メニューやボタンの操作）では、Size命令が邪魔をして、
      //正常に画像保存できないため、このメソッドの内部で、画像保存を強制的に行なう。

      else if(reverseImageMode==5) //時計回りで、90度回転させる。
      {
        for(int y=0, y1=hh-1; y<hh; y++, y1--)
        {
          for(int x=0; x<ww; x++)
          {
            reverseImageX.setRGB(y1,x, reverseImage0.getRGB(x,y)); //*********
          }
        }
        reverseImage1=reverseImageX;
        try
        {
          ImageIO.write(reverseImage1, "png", new File("./image/reverseImageTemp.png"));
        }
        catch (Exception e)
        {
          e.printStackTrace();
          return;
        }
        f.message("./image/reverseImageTemp.pngに画像保存しました。");
      }
      else if(reverseImageMode==7) //時計回りで、270度回転させる。
      {
        for(int y=0; y<hh; y++)
        {
          for(int x=0, x1=ww-1; x<ww; x++,x1--)
          {
            reverseImageX.setRGB(y,x1, reverseImage0.getRGB(x,y));
          }
        }
        reverseImage1=reverseImageX;
        try
        {
          ImageIO.write(reverseImage1, "png", new File("./image/reverseImageTemp.png"));
        }
        catch (Exception e)
        {
          e.printStackTrace();
          return;
        }
        f.message("./image/reverseImageTemp.pngに画像保存しました。");
      }
      else
      {
        reverseImage1 = reverseImage0;
      }
    }
  }

  //■単独色相変更処理
  void colorChange(int mode)
  {
    //●単独色相変更機能の実現。
    //単独色相変更要求があれば、指定の旧色に対して指定の新色に変換する。
    //処理対象の画像が、既に画像ファイルとして存在するものとする。
    //階調画像からグレー・マスクを生成する機能を追加的に含む。
    if(mode==0)
    {
      return; //何もしない（単独色相変更要求がない）
    }

    if(checkImageFile(colorChangeFile)==false)
      return;

    if(colorChangeFlag == true)
    {
      try
      {
        colorChangeImage0 = ImageIO.read(new File(colorChangeFile));
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("カラー・チェンジ既存画像のリード・エラー");
        colorChangeImage0 = null;
        return;
      }

      Color oldColor  = new Color(colorChange1R, colorChange1G, colorChange1B);
      Color newColor  = new Color(colorChange2R, colorChange2G, colorChange2B);
      int grayColor = (200<<16 | 200<<8 | 200);
      //単独色相変更実施
      int w_ = colorChangeImage0.getWidth(this);
      int h_ = colorChangeImage0.getHeight(this);
      colorChangeImage1 = new BufferedImage(
        w_, h_, BufferedImage.TYPE_INT_RGB); //不透明に設定
      for(int y=0;y<h_;y++)
      {
        for(int x=0;x<w_;x++)
        {
          int rgbX = colorChangeImage0.getRGB(x,y);
          int redX   = (rgbX & 0x00ff0000) >>> 16;
          int greenX = (rgbX & 0x0000ff00) >>> 8;
          int blueX  = (rgbX & 0x000000ff);
          if (  //近似色をも許容する
            (redX >= (oldColor.getRed() - acceptableLimitC) &&
             redX <= (oldColor.getRed() + acceptableLimitC))
              &&
            (greenX >= (oldColor.getGreen() - acceptableLimitC) &&
             greenX <= (oldColor.getGreen() + acceptableLimitC))
              &&
            (blueX >= (oldColor.getBlue() - acceptableLimitC) &&
             blueX <= (oldColor.getBlue() + acceptableLimitC))    )
          { //各種条件一致なら３２ビットの新色に変換
            colorChangeImage1.setRGB(x, y, newColor.getRGB());
          }
          else
          {
            if(mode==1)
            { //旧色のまま転写
              colorChangeImage1.setRGB(x, y, colorChangeImage0.getRGB(x,y));
            }
            else if(mode==2)
            { //グレー色（200,200,200）を転写
              //階調画像からグレー・マスクを生成
              colorChangeImage1.setRGB(x, y, grayColor);
            }
            else if(mode>2)
            {
              f.message("colorChange命令のモード指定が異常。");
              return;
            }
          }
        }
      }
    }
    //単独色相変更の描画自体は、drawPage()の中で行なう。
  }

  //■色相濃淡階調効果（垂直線形グラデーション）
  void colorGradient()
  {
    //●画像ファイル指定のチェック
    if(!gradientFName.equals("") && gradientFName != null)
    {
      if(checkImageFile(gradientFName)==false)
        return;

      gradientImage0 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      gradientImage1 = new BufferedImage(
        (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明に設定
      try
      {
        gradientImage0 = ImageIO.read(new File(gradientFName)); //画像読み取り
      }
      catch (Exception e)
      {
        e.printStackTrace();
        f.message("色相濃淡階調加工対象ファイルのリード・エラー："+gradientFName);
        gradientImage0 = null;
        return;
      }
      //色調濃淡階調加工（グラデーション）
      int w = gradientImage0.getWidth(this);
      int h = gradientImage0.getHeight(this);
      int cR,cG,cB; //元の色相
      int cR1,cG1,cB1; //濃淡階調加工後の色相
      for(int y=0; y<h; y++)
      { //全体を単純にコピー
        for(int x=0; x<w; x++)
        {
            int m = gradientImage0.getRGB(x,y);
            gradientImage1.setRGB(x, y, m);
        }
      }
      for(int y=gradientY1; y<gradientY2; y++)
      { //非対称グラデーションの上書き
        for(int x=0; x<w; x++)
        {
            int m = gradientImage0.getRGB(x,y);
            cR = (m & 0x00ff0000) >>> 16;
            cG = (m & 0x0000ff00) >>> 8;
            cB = (m & 0x000000ff) >>> 0;

            cR1 = cR + (int)(gradientR*(y-gradientY1));
            if(cR1>255)
              cR1=255;
            else if(cR1<0)
              cR1=0;

            cG1 = cG + (int)(gradientG*(y-gradientY1));
            if(cG1>255)
              cG1=255;
            else if(cG1<0)
              cG1=0;

            cB1 = cB + (int)(gradientB*(y-gradientY1));
            if(cB1>255)
              cB1=255;
            else if(cB1<0)
              cB1=0;

            int color = (cR1<<16) | (cG1<<8) | cB1 ;
            gradientImage1.setRGB(x, y, color);
        }
      }
      //対称グラデーションの追加上書き
      int gY =gradientY2-gradientY1;
      for(int y=gradientY2; y<(gradientY1+(gradientY2-gradientY1)*2) && (y<h); y++)
      {
        gY--;
        for(int x=0; x<w; x++)
        {
            int m = gradientImage0.getRGB(x,y);
            cR = (m & 0x00ff0000) >>> 16;
            cG = (m & 0x0000ff00) >>> 8;
            cB = (m & 0x000000ff) >>> 0;

            cR1 = cR + (int)(gradientR*(gY));
            if(cR1>255)
              cR1=255;
            else if(cR1<0)
              cR1=0;

            cG1 = cG + (int)(gradientG*(gY));
            if(cG1>255)
              cG1=255;
            else if(cG1<0)
              cG1=0;

            cB1 = cB + (int)(gradientB*(gY));
            if(cB1>255)
              cB1=255;
            else if(cB1<0)
              cB1=0;

            int color = (cR1<<16) | (cG1<<8) | cB1 ;
            gradientImage1.setRGB(x, y, color);
        }
      }
    }
    //色相濃淡階調加工の描画自体は、drawPage()の中で行なう。
  }

  //■画像多段階回転重複描画
  void rotateMulti()
  {
    //●Size命令で設定された座標範囲の内側にある回転対象領域のみを
    //多段階に回転させ上書きする。
    //画像多段階回転は、中心点を同じくする二重の正方形の枠組みの中で、
    //回転させつつ多段階に描画する。例えば、一枚の花弁を事前に描き、
    //これを３０度づつ回転させ、花弁が１２枚の花を自動描画する用途に使用。
    //外枠の正方形（Size命令で指定）の中に内枠の正方形が入る形だが、
    //一辺の比率は、３対２の比率にする。
    //内枠の中に、回転させる元画像が、はみ出さずに収まらねばならない。
    //外枠と内枠との中間領域は、回転する余裕を与える空間である。
    //回転対象画像は、グレー・マスク形式（背景がグレー）とし、完成画像も、
    //グレー・マスク形式になる。

    if(rotateMultiFlag == false)
      return;

    if(checkImageFile(rotateMultiF)==false)
      return;

    BufferedImage rotateMultiImage1 = new BufferedImage(
      (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明
    BufferedImage rotateMultiImage2 = new BufferedImage(
      (int)imagePX_W, (int)imagePX_H, BufferedImage.TYPE_INT_RGB); //不透明

    try
    {
      rotateMultiImage1 = ImageIO.read(new File(rotateMultiF)); //画像読み取り
    }
    catch (Exception e)
    {
      e.printStackTrace();
      f.message("回転対象ファイルのリード・エラー："+rotateMultiF);
      rotateMultiImage = null;
      return;
    }

    int gray = (0xff<<24) | (200<<16) | (200<<8) | 200;
    for(int i=0; i<imagePX_W; i++) //グレーで初期化
    {
      for(int j=0; j<imagePX_H; j++)
      {
        rotateMultiImage2.setRGB(i,j,gray);
      }
    }

    int color1 = 0;
    int color2 = 0;
    int x2 = 0;
    int y2 = 0;

    int x1min = (int)(imagePX_W/6);
    int x1max = (int)((imagePX_W/6)*5);
    int y1min = (int)(imagePX_H/6);
    int y1max = (int)((imagePX_H/6)*5);
    int centerX = (int)(imagePX_W/2); //画像中心点
    int centerY = (int)(imagePX_H/2);
    double radian = 0;
    double startRadian = Math.toRadians(rotateMultiStartDegree);
    for( int k=0; k<rotateMultiTimes; k++) //回転回数分のループ
    {
      radian = startRadian + Math.toRadians(rotateMultiDegree*k);
      for(int j=x1min; j<x1max; j++) //回転させる位置変換
      {
        for(int i=y1min; i<y1max; i++)
        {
          x2 = (int)(((i-centerX)*Math.cos(radian) -
            (j-centerY)*Math.sin(radian))+centerX);
          y2 = (int)(((i-centerX)*Math.sin(radian) +
            (j-centerY)*Math.cos(radian))+centerY);
          color1 = rotateMultiImage1.getRGB(i,j);
          if(color1 != gray)
          {
            try
            {
              rotateMultiImage2.setRGB(x2,y2,color1);
            }
            catch (Exception e)
            {
              e.printStackTrace();
              return;
            }
          }
        }
      }
    }

    //●画像補正（多段階回転させた画像のピクセル欠けを埋める処理）
    //これから行なう画像補正は、三角関数による座標変換計算で生じた
    //実数座標を整数座標に変換する際に生じる画像のピクセル欠けを補正する。
    //ただし、多段階回転に適するのは、単色無階調画像（ベタ塗り画像）に限られ、
    //多色無階調画像（マトリックス模様など）や階調画像（ボカシ画像）は、
    //画像の重なりがある場合、一段階回転しか適さない。
    //多色画像を無条件に多段階回転多重描画すると、モアレ模様が現われ、精細さが失われる。
    //多色が入り乱れる複雑な画像を、回転させながら多重描画する用途は、殆どない。
    //一回分の回転のたびに画像補正して多重上書きすれば、
    //階調画像でもモアレ回避が可能のはずだが、そこまでする必要がないので、そうしない。
    //なお、回転加工した画像は、三角関数計算値の整数化および画像補正により、
    //輪郭線が多少乱れるので、予め巨大画像で作成しておいて、
    //スタンプ機能で利用する際に、画像縮小で目立たないようにする。
    //なお、回転させる画像は、「細い線」での線画を想定しておらず、
    //「細い線」を無理に回転させると、「細い線」が途切れて、補正も上手く行かない可能性がある。
    //千差万別の全ての画像に対して、補正が上手くいく保証はなく、高確率の成功を保証するのみ。

    for(int p=1; p<imagePX_H-1; p++)
    {
      for(int q=1; q<imagePX_W-1; q++)
      {
        int col0 = rotateMultiImage2.getRGB(q,p);   //当該ピクセル

        int col1 = rotateMultiImage2.getRGB(q-1,p); //上下左右ピクセル
        int col2 = rotateMultiImage2.getRGB(q+1,p);
        int col3 = rotateMultiImage2.getRGB(q,p-1);
        int col4 = rotateMultiImage2.getRGB(q,p+1);

        int col5 = rotateMultiImage2.getRGB(q-1,p-1); //斜め上下左右
        int col6 = rotateMultiImage2.getRGB(q-1,p+1);
        int col7 = rotateMultiImage2.getRGB(q+1,p-1);
        int col8 = rotateMultiImage2.getRGB(q+1,p+1);

        int col1R = (col1 & 0x00ff0000)>>>16;
        int col1G = (col1 & 0x0000ff00)>>>8;
        int col1B = (col1 & 0x000000ff);
        int col2R = (col1 & 0x00ff0000)>>>16;
        int col2G = (col1 & 0x0000ff00)>>>8;
        int col2B = (col1 & 0x000000ff);
        int col3R = (col1 & 0x00ff0000)>>>16;
        int col3G = (col1 & 0x0000ff00)>>>8;
        int col3B = (col1 & 0x000000ff);
        int col4R = (col1 & 0x00ff0000)>>>16;
        int col4G = (col1 & 0x0000ff00)>>>8;
        int col4B = (col1 & 0x000000ff);

        if(col0==gray)
        {
          if(col1!=gray && col1==col2) //単色無階調画像を基本に想定。
            rotateMultiImage2.setRGB(q,p,col1);
          else if(col1!=gray && col3==col4)
            rotateMultiImage2.setRGB(q,p,col3);
          else if(col5!=gray && col5==col6 && col6==col7 && col7==col8)
            rotateMultiImage2.setRGB(q,p,col5);
          else if(col1!=gray && col2!=gray && col3!=gray && col4!=gray)
          { //多色無階調画像や階調画像の場合は、モアレ回避のため、一段階回転を想定。
            //ただし、多段階回転させても、画像の重なりがない場合、その限りではない。
            //else if条件に合致する場合、階調画像と見なして、目立たない中間色を設定。
            int colXR = (int)((col1R + col2R + col3R + col4R)/4);
            int colXG = (int)((col1G + col2G + col3G + col4G)/4);
            int colXB = (int)((col1B + col2B + col3B + col4B)/4);
            int colX  = 0xff<<24 | colXR<<16 | colXG<<8 | colXB;
            rotateMultiImage2.setRGB(q,p,colX);
          }
        }
      }
    }
    rotateMultiImage = rotateMultiImage2;
    //多段階回転加工処理した画像描画自体は、drawPage()の中で行なう。
  }

  //■ブラック・ノイズ除去フィルター
  //画像から砂粒状（孤立したピクセル異常値）のブラック・ノイズを除去する。
  //白背景に黒線描があり、これに黒ノイズが砂粒状に混じる場合、そのノイズを除去。
  //ただし、ノイズを完全には除去できず、多少のノイズは残る。
  //ノイズ除去で用いるカーネルのサイズは可変であり、3x3, 5x5, 7x7 このどれかを選ぶ。
  //このメソッドは、getOutlineメソッドの内部で利用する。
  BufferedImage removeBlackNoize(BufferedImage img0, int kernelSize, int noizeTolerance)
  {
    if(kernelSize !=3 && kernelSize !=5 && kernelSize !=7)
    {
      f.message("カーネル・サイズの指定が間違っています。");
      return null; //カーネル・サイズは、3か、5か、7でなければならない。
    }
    if(noizeTolerance == 1 )
    {
      f.message("ブラック・ノイズ除去を回避しました。");
      return img0; //ノイズ除去回避。
    }
    if(noizeTolerance >= kernelSize*kernelSize ||
        noizeTolerance <= 0)
    {
      f.message("ノイズ許容値の指定が間違っています。");
      return null; //ノイズ許容値は、1以上で、カーネル・サイズの自乗未満でなければならない。
    }
    int width = img0.getWidth();
    int height = img0.getHeight();
    BufferedImage img1 = new BufferedImage(width, height, img0.getType());
    for(int y=0; y<height; y++)
      for(int x=0; x<width; x++)
        img1.setRGB(x, y, 0x00ffffff); //空白に初期化

    int radius = outlineNoizeKernel / 2; //カーネルの半径（整数化）

    for (int y = radius; y < height-radius; y++)
    {
      for (int x = radius; x < width-radius; x++)
      {

        int nCnt = 0; //ノイズ判定の周辺ピクセルのカウント
        // 近傍のピクセルの色彩データを収集（3x3か5x5か7x7のカーネルを想定）

        for (int ky = -radius; ky < radius; ky++) //カーネル内部をスキャン
        {
          for (int kx = -radius; kx < radius; kx++)  //カーネル内部をスキャン
          {
            if((img0.getRGB(x+kx, y+ky) & 0x00ffffff)==0x0)
              nCnt++;
          }
        }

        int centerRGB = img0.getRGB(x, y) & 0x00ffffff; //カーネルの中心RGB
        int newRGB;

        if(centerRGB==0x00000000 && nCnt>=outlineNoizeTolerance)
          newRGB = 0x00000000;  //ノイズ除去
        else
          newRGB = 0x00ffffff;

        if(centerRGB==0x00ffffff &&  //カーネル中央白
            (img0.getRGB(x-1, y) & 0x00ffffff)==0x00000000 &&   //左隣黒
            (img0.getRGB(x+1, y) & 0x00ffffff)==0x00000000 &&   //右隣黒
            (img0.getRGB(x, y-1) & 0x00ffffff)==0x00000000 &&   //上隣黒
            (img0.getRGB(x, y+1) & 0x00ffffff)==0x00000000 )    //下隣黒
          newRGB = 0x00000000; //中抜け補正 （十文字想定補正）

        if(centerRGB==0x00000000 &&  //カーネル中央黒
            (img0.getRGB(x-1, y)   & 0x00ffffff)==0x00ffffff && //左隣白
            (img0.getRGB(x+1, y)   & 0x00ffffff)==0x00ffffff && //右隣白
            (img0.getRGB(x, y-1)   & 0x00ffffff)==0x00ffffff && //上隣白
            (img0.getRGB(x, y+1)   & 0x00ffffff)==0x00ffffff && //下隣白
            (img0.getRGB(x-1, y-1) & 0x00ffffff)==0x00ffffff && //左上白
            (img0.getRGB(x+1, y+1) & 0x00ffffff)==0x00ffffff && //右下白
            (img0.getRGB(x-1, y+1) & 0x00ffffff)==0x00ffffff && //左下白
            (img0.getRGB(x+1, y-1) & 0x00ffffff)==0x00ffffff )  //右上白
          newRGB = 0x00ffffff; //単独黒点補正（黒点除去補正）

        img1.setRGB(x, y, newRGB);
      }
    }
    f.message("ブラック・ノイズ除去を実施しました。");
    return img1; //ブラック・ノイズ除去済み画像
  }

  //■カラー・ノイズ除去フィルター
  //画像から砂粒状（孤立したピクセル異常値）のカラー・ノイズを除去する。
  //また、輪郭部（色段差巨大部）での砂粒状は、ノイズと見なさない。
  //ただし、ノイズを完全には除去できず、多少のノイズは残る。
  //このメソッドは、convolveメソッドの内部で利用する。
  BufferedImage removeColorNoize(BufferedImage img0, int kernelSize,
    int noizeTolerance, int colorDistance)
  { //カーネル・サイズは、3x3, 5x5 のどれかを想定する。
    if(noizeTolerance==0 || colorDistance==0)
    {
      f.message("カラー・ノイズ除去を回避しました。");
      return img0;
    }
    if(img0==null)
    {
      f.message("処理対象の画像がありません。");
      return null;
    }
    int width = img0.getWidth();
    int height = img0.getHeight();
    BufferedImage img1 = new BufferedImage(width, height, img0.getType());

    int radius = kernelSize / 2; //カーネルの半径

    for (int y = 0; y < height; y++)
    {
      for (int x = 0; x < width; x++)
      {
        int[] r = new int[kernelSize * kernelSize];
        int[] g = new int[kernelSize * kernelSize];
        int[] b = new int[kernelSize * kernelSize];
        int kCnt = 0; //カーネル内のスキャン・カウンター

        //近傍のピクセル色彩データを収集
        //2次元のカーネルを、1次元化して扱う
        for (int ky = -radius; ky <= radius; ky++)
        {
          for (int kx = -radius; kx <= radius; kx++)
          {
            int rgb = img0.getRGB(
              Math.max(0, Math.min((width - 1), (x + kx))),
              Math.max(0, Math.min((height - 1), (y + ky))));
            r[kCnt] = (rgb >>> 16) & 0x000000ff;
            g[kCnt] = (rgb >>> 8) & 0x000000ff;
            b[kCnt] = rgb & 0x000000ff;
            kCnt++;
          }
        }

        Arrays.sort(r); //昇順整列
        Arrays.sort(g);
        Arrays.sort(b);

        int medianR = r[r.length / 2]; //ソートされた配列の中央値を得る
        int medianG = g[g.length / 2];
        int medianB = b[b.length / 2];
        int darkR   = r[0]; //暗色部（輪郭線を想定）での赤成分
        int darkG   = g[0]; //暗色部（輪郭線を想定）での緑成分
        int darkB   = b[0]; //暗色部（輪郭線を想定）での青成分
        int brightR   = r[r.length-1]; //明色部（輪郭線を想定）での赤成分
        int brightG   = g[g.length-1]; //明色部（輪郭線を想定）での緑成分
        int brightB   = b[b.length-1]; //明色部（輪郭線を想定）での青成分

        int currentRGB = img0.getRGB(x, y) & 0x00ffffff; //カーネル中央の色
        int currentR   = (currentRGB >>> 16) & 0x000000ff;
        int currentG   = (currentRGB >>> 8) & 0x000000ff;
        int currentB   = (currentRGB) & 0x000000ff;
        int newRGB;
        int medianRGB = (medianR << 16) | (medianG << 8) | medianB;
        int darkRGB = (darkR << 16) | (darkG << 8) | darkB;
        newRGB = currentRGB; //ベース色を確定

        if(
            (r[noizeTolerance]-darkR >= colorDistance) &&
            (g[noizeTolerance]-darkG >= colorDistance) &&
            (b[noizeTolerance]-darkB >= colorDistance) &&
            (currentR <= darkR+colorDistance) &&
            (currentG <= darkG+colorDistance) &&
            (currentB <= darkB+colorDistance) )  //輪郭線が想定される暗色部
          newRGB = medianRGB; //ベース色に対する部分補正

        if(
            (brightR-r[r.length-noizeTolerance] >= colorDistance) &&
            (brightG-r[g.length-noizeTolerance] >= colorDistance) &&
            (brightB-r[b.length-noizeTolerance] >= colorDistance) &&
            (currentR >= brightR-colorDistance) &&
            (currentG >= brightG-colorDistance) &&
            (currentB >= brightB-colorDistance) )  //輪郭線が想定される暗色部
          newRGB = medianRGB; //ベース色に対する部分補正

        img1.setRGB(x, y, newRGB);
      }
    }
    f.message("カラー・ノイズ除去を実施しました。");
    return img1;
  }

  //画像ファイル指定の正常性チェック
  boolean checkImageFile(String fileName) //fileNameは、パス付き
  {
    String fileNameX = fileName.toLowerCase();
    if(fileNameX.endsWith(".jpeg") || fileNameX.endsWith(".jpg") ||
      fileNameX.endsWith(".gif") || fileNameX.endsWith(".png") ||
      fileNameX.endsWith(".bmp"))
      ; //OK
    else
    {
      f.message("画像ファイル指定が不適切です："+fileName);
      return false;
    }
    if(! new File(fileName).exists())
    {
      f.message("指定の画像ファイルが存在しません："+fileName);
      return false;
    }
    return true;
  }
} //EOF (GCreatorCanvasEngine.java)

◆GCreatorAnalyzeEngine.java

//■■GCreatorAnalyzeEngine.java
//Ver.4.1

//■■インポート
import java.awt.*;   //必須
import java.util.*;  //必須
import java.io.*;    //必須
import java.util.List;  //必須（曖昧回避）

//■■描画機能の実現
class GCreatorAnalyzeEngine
{
  //■メンバー変数
  GCreator f; //JFlameの継承インスタンス
  Graphics2D g2;
  GCreatorCanvasEngine can;
  double[] shape; //色塗り系命令文を解析して全部格納
  String command1; //命令文１行分
  int tcCnt1 = 0;
  int tcCnt2 = 0;

  //■コンストラクタ
  GCreatorAnalyzeEngine(GCreator flame)
  {
    f = flame;
    can = f.canvas;
  }

  void commandAnalyze(String commandZ)
  {
    //●命令文の全文解析
    //命令の引数が多いものや紛らわしいものだけ、数のチェックを行なう。

    //●コメント文がどうかの判定用
    boolean commentFlag = false;

    //●Import命令の処理
    //Import命令が命令文書の先頭にあれば、指定された既存命令文書を、この命令文書の先頭に挿入する。
    //Import命令が対象とする命令文書は、レイアウト・スケール命令文書などを想定している。
    //レイアウト・スケール命令文書（方眼用紙作成用）は、メニューにその実例がある。
    //Import命令は、命令文書の先頭にだけ許され、一行だけが許される。
    //導入される既存命令文書にImport命令が含まれていても、そのImport命令は無効である。
    //混乱防止のため、既存命令文書にSaveCommands命令やSaveImage命令が含まれないこと。
    //新旧の命令文書が連結されるので、同じ命令による干渉（命令上書き）に注意すること。
    StringTokenizer stI1 = new StringTokenizer(commandZ,";\n");
    if(stI1.hasMoreTokens())
    {
      String commandIa = stI1.nextToken().trim();
      StringTokenizer stI2 = new StringTokenizer(commandIa,"(,)");
      if(commandIa.startsWith("Import"))
      {
        String commandIb = stI2.nextToken().trim();
        commandIb = stI2.nextToken().trim();
        String fName;
        fName = Util.trimAffix(commandIb,'\"','\"');//file path
        String strI = TextIO.loadStr(new File(fName));
        if(strI != null)
          commandZ = strI + commandZ;
      }
    }

    //●以下は、一般的な命令文解析
    StringTokenizer st1 = new StringTokenizer(commandZ,";\n");
      //命令全文に対して、セミコロンと改行コードで切り分ける準備
    String commandS = ""; //命令1件の命令本体（引数含まず）
    f.scaleLabel2.setText("　(f:x1.0)"); //フリー・スケールの初期化
    f.canvas.freeScale = 1.0;//フリー・スケールの初期化

    f.toneCurve.toneCurveArrX = new double[3][5];  //トーン・カーブX座標（RGB曲線毎のｙ座標点列に分解）
    f.toneCurve.toneCurveArrY = new double[3][5];  //トーン・カーブY座標（RGB曲線毎のｙ座標点列に分解）

    try
    {
      for(int i=0; st1.hasMoreTokens(); i++)
      { //●命令文の全文読み込み
        command1 = st1.nextToken().trim(); //一行分の命令文

        if(command1.equals("")) //空行
          continue;

        if(command1.substring(0,1).equals("　") ) //全角スペース
          continue;

        if(command1.substring(0,2).equals("//")) //◆一行コメント文
          continue;

        if(command1.substring(0,2).equals("/@")) //◆多行コメント文
        {  //「/@」は、単独で書かねばならず、同じ行の直後に命令文を書いてはならない。
          commentFlag = true;
          continue;
        }
        if(command1.substring(0,2).equals("@/"))
        { //「@/」は、単独で書かねばならず、同じ行の直後に命令文を書いてはならない。
          commentFlag = false;
          continue;
        }
        if(commentFlag == true)
        { //「/@」と「@/」とで挟まれた中間行
          continue;
        }

        if(command1.substring(0,5).equals("Break")) //◆これ以降の命令文全部を無視。
          break;

        StringTokenizer st2 = new StringTokenizer(command1,"(,)");
          //引数区切を「括弧」および「コンマ」に設定。
        commandS = st2.nextToken().trim(); //命令1件の命令本体（引数含まず）
          //これ以降のst2は、命令本体が取り除かれた状態（引数群）を維持する。
          //そのため、st2.countTokens()の返却値に注意。
          //st2.countTokens()の返却値は、
          //st2.nextToken()された後に残されているトークンの数。

        //●命令文の逐次解析実施
        if(commandS.equals("Import"))
        { //●既存命令文書の先頭部への導入
          ; //既に処理済み
        }
        else if(commandS.equals("SaveCommands"))
        { //●命令文書の保存ファイル名の指定
          //ボタン操作による文書半自動保存に対応
          can.saveCmdFName =
            Util.trimAffix(st2.nextToken().trim(),'\"','\"');
        }
        else if(commandS.equals("SaveImage"))
        { //●作成画像の保存ファイル名の指定
          //ボタン操作による画像半自動保存に対応
          can.saveImgFName =
            Util.trimAffix(st2.nextToken().trim(),'\"','\"');
        }
        else if(commandS.equals("SetJPEG_Op"))
        { //●作成画像のJPEG保存での画質指定オプション（JPEG保存にのみ有効）
          //「0」から「1.0」を指定可能。最高画質は、「1.0」
        //SetJPEG_Op(float q)
          can.quality = Float.parseFloat(st2.nextToken().trim());
        }
        else if(commandS.equals("CutAndSaveImage"))
        { //●作成画像の切り取り保存する領域およびファイル名の指定
          //「切取」ボタン操作による画像の「一部切取保存」に対応
          can.cutAndSaveImgX1 = Integer.parseInt(st2.nextToken().trim());
          can.cutAndSaveImgY1 = Integer.parseInt(st2.nextToken().trim());
          can.cutAndSaveImgX2 = Integer.parseInt(st2.nextToken().trim());
          can.cutAndSaveImgY2 = Integer.parseInt(st2.nextToken().trim());
          can.cutAndSaveImgFName =
            Util.trimAffix(st2.nextToken().trim(),'\"','\"');
        }
        else if(commandS.equals("Antialias"))
        { //●線（輪郭線を含む）のギザギザ緩和
          //この処理で、細い線の色が薄くなる
          String s1 = st2.nextToken().trim();
          if(s1.equals("true"))
            can.antialiasFlag = true;
          else
            can.antialiasFlag = false;
        }
        else if(commandS.equals("Size"))
        { //●画像の大きさ
        //Size(double w, double h)
        //w:    巾(px)
        //h:    丈(px)
          String s1 = st2.nextToken().trim();
          if(Util.countDelimiter(command1, ',') == 0)
          { //文字列１個を指定の場合
            if(s1.equals("\"A4\""))
            {  //常用判型は簡易指定可能
              can.printMM_W = 210; //mm
              can.printMM_H = 297;
              can.imagePX_W = 210*3; //mm→px変換（便宜的独自規格）
              can.imagePX_H = 297*3; //印刷時には、サイズ調整を行なう
            }
            else if(s1.equals("\"B5\""))
            {
              can.printMM_W = 182; //mm
              can.printMM_H = 257;
              can.imagePX_W = 182*3; //mm→px変換（便宜的独自規格）
              can.imagePX_H = 257*3; //印刷時には、サイズ調整を行なう
            }
          }
          else if(Util.countDelimiter(command1, ',') == 1)
          { //数値２個を指定の場合（数値はピクセル単位）
            String s2 = st2.nextToken().trim();
            can.imagePX_W = Double.parseDouble(s1);
            can.imagePX_H = Double.parseDouble(s2);
            can.printMM_W = Double.parseDouble(s1)/3.0;
            can.printMM_H = Double.parseDouble(s2)/3.0;
          }
          else if(Util.countDelimiter(command1, ',') == 2)
          {  //数値２個と単位とを指定の場合
            String s2 = st2.nextToken().trim();
            String s3 = st2.nextToken().trim();
            if(s3.equals("\"px\"")) //ピクセル単位
            {
              can.printMM_W = Double.parseDouble(s1)/3.0;
              can.printMM_H = Double.parseDouble(s2)/3.0;
              can.imagePX_W = Double.parseDouble(s1);
              can.imagePX_H = Double.parseDouble(s2);
            }
            else if(s3.equals("\"mm\"")) //ミリ単位
            { //ミリ単位は、印刷での紙サイズをミリ単位で表わすだけである。
              //その他の描画時の各種サイズ指定は、文字サイズを除き、全てピクセル。
              can.printMM_W = Double.parseDouble(s1);
              can.printMM_H = Double.parseDouble(s2);
              can.imagePX_W = Double.parseDouble(s1)*3.0;
              can.imagePX_H = Double.parseDouble(s2)*3.0;
            }
          }
          else
          {
            f.message(command1 + " >>引数に異常");
            return;
          }
        }
        else if(commandS.equals("BackgroundColor"))
        { //●背景色の指定
        //BackgroundColor(int r, int g, int b)
        //r:     赤色成分　0-255
        //g:     緑色成分　0-255
        //b:     青色成分　0-255
          int red   = Integer.parseInt(st2.nextToken().trim());
          int green = Integer.parseInt(st2.nextToken().trim());
          int blue  = Integer.parseInt(st2.nextToken().trim());
          if(red>255)
          {
            red = 255;
            f.message("色指定の上限は255です。");
          }
          if(green>255)
          {
            green = 255;
            f.message("色指定の上限は255です。");
          }
          if(blue>255)
          {
            blue = 255;
            f.message("色指定の上限は255です。");
          }
          can.backgroundColor = new Color(red, green, blue);
        }
        else if(commandS.equals("Image"))
        { //●背景画像の表示指定
        //Image(int x, int y, int w, int h, String fileName)
        //x:     表示ｘ座標位置
        //y:     表示ｙ座標位置
        //w:     画像の表示幅
        //h:     画像の表示丈
        //fileName:画像ファイル・ネーム（パス含む）
          can.imageFlag = true;
          int[]  imgI = new int[4]; //複数画像を別位置に表示可能
          imgI[0] = Integer.parseInt(st2.nextToken().trim()); //x
          imgI[1] = Integer.parseInt(st2.nextToken().trim()); //y
          imgI[2] = Integer.parseInt(st2.nextToken().trim()); //w
          imgI[3] = Integer.parseInt(st2.nextToken().trim()); //h
          can.imageListI.add(imgI);
          String imgF;
          imgF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path
          can.imageListF.add(imgF);
        }
        else if(commandS.equals("Stamp"))
        { //●スタンプ画像の表示指定
        //Stamp(int x, int y, int w, int h, String f)
        //x:     表示ｘ座標位置
        //y:     表示ｙ座標位置
        //w:     画像の表示幅
        //h:     画像の表示丈
        //f:     画像ファイル（パス含む）
          int[]  stmI = new int[4]; //複数画像を別位置に表示可能
          stmI[0] = Integer.parseInt(st2.nextToken().trim()); //x
          stmI[1] = Integer.parseInt(st2.nextToken().trim()); //y
          stmI[2] = Integer.parseInt(st2.nextToken().trim()); //w
          stmI[3] = Integer.parseInt(st2.nextToken().trim()); //h
          can.stampListI.add(stmI);
          String stmF;
          stmF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path
          can.stampListF.add(stmF);
          can.stampFlag = true;
        }
        else if(commandS.equals("StampOp"))
        { //●スタンプ機能におけるグレー・マスクの灰色を指定色に変更するオプション
        //StampOp(int r, int g, int b)
        //r:     グレー・マスク代替色の赤成分
        //g:     グレー・マスク代替色の緑成分
        //b:     グレー・マスク代替色の青成分
          int r = Integer.parseInt(st2.nextToken().trim());
          int g = Integer.parseInt(st2.nextToken().trim());
          int b = Integer.parseInt(st2.nextToken().trim());
          can.transparentColor = new Color(r, g, b);
        }
        else if(commandS.equals("StampMulti"))
        { //●スタンプ画像の表示指定の連続処理
        //StampMulti(int x, int y, int w, int h, int sx, int sy, int tx, int ty, String f)
        //x:     当初表示ｘ座標位置
        //y:     当初表示ｙ座標位置
        //w:     画像の表示幅
        //h:     画像の表示丈
        //sx:    画像の横方向スキップのピクセル数
        //sy:    画像の縦方向スキップのピクセル数
        //tx:    画像の横方向表示反復回数
        //ty:    画像の縦方向表示反復回数
        //f:     画像ファイル（パス含む）
          int x    = Integer.parseInt(st2.nextToken().trim());
          int y    = Integer.parseInt(st2.nextToken().trim());
          int w    = Integer.parseInt(st2.nextToken().trim());
          int h    = Integer.parseInt(st2.nextToken().trim());
          int sx   = Integer.parseInt(st2.nextToken().trim());
          int sy   = Integer.parseInt(st2.nextToken().trim());
          int tx   = Integer.parseInt(st2.nextToken().trim());
          int ty   = Integer.parseInt(st2.nextToken().trim());
          String f = Util.trimAffix(st2.nextToken().trim(),'\"','\"');

          //Stamp命令の反復に変換する
          for(int p=0; p<ty; p++)
          {
            for(int q=0; q<tx; q++)
            {
              int[]  stmI = new int[4];
              stmI[0] = x + sx*q; //x位置
              stmI[1] = y + sy*p; //y位置
              stmI[2] = w; //w
              stmI[3] = h; //h
              can.stampListI.add(stmI);
              can.stampListF.add(f);
            }
          }
          can.stampFlag = true;
        }

        else if(commandS.equals("SprayStart"))
        { //●スプレー１回（円盤状飛沫集団）の反復作業での共通条件設定。
        //スプレー機能（円盤状飛沫集団形成）は、三角関数と乱数とで実現する。
        //円盤中心点から飛沫一個への距離cは、0から円盤半径までの整数乱数で決定し、
        //円盤中心点から飛沫一個への角度tは、0から360までの整数乱数で決定する。
        //直角三角形⊿で、底辺をa、高さをb、斜辺をc、左下角度（ディグリー）をtとすれば、
        //ただし、左下角を円盤中心、右上角を飛沫位置と見なす。
        //関係する計算式は、以下の通り。

        //SprayStart(int x, int y, int tp, double ss, int sr, int st, int r, int g, int b, int a)
        //x:     スプレイ円盤状飛沫集団（円盤）の中心ｘ座標
        //y:     スプレイ円盤状飛沫集団（円盤）の中心ｙ座標
        //tp:    スプレイ飛沫の分散タイプ
        //ss:    スプレイ飛沫一個のサイズ（px相当）
        //sr:    スプレイ飛沫の円盤状拡散分布半径（px相当）
        //st:    スプレイ飛沫の分布個数
        //r:     スプレイ飛沫の色相、赤成分
        //g:     スプレイ飛沫の色相、緑成分
        //b:     スプレイ飛沫の色相、青成分
        //a:     スプレイ飛沫の色相、透明度
          can.sprayFlag = true;
          can.sprayDiscStatus_List.add(0);
          can.sprayDiscX_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayDiscY_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitTP_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitSS_List.add(Double.parseDouble(st2.nextToken().trim()));
          can.sprayUnitSR_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitST_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitR_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitG_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitB_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayUnitA_List.add(Integer.parseInt(st2.nextToken().trim()));
        }
        else if(commandS.equals("SprayNext"))
        { //●スプレーの反復作業での個別座標設定
        //SprayNext(int x, int y)
        //x:     スプレイ円盤状飛沫集団の中心ｘ座標
        //y:     スプレイ円盤状飛沫集団の中心ｙ座標
          can.sprayDiscStatus_List.add(1);
          can.sprayDiscX_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayDiscY_List.add(Integer.parseInt(st2.nextToken().trim()));
        }
        else if(commandS.equals("SprayEnd"))
        { //●//スプレーのユニット終了
        //SprayEnd(int x, int y)
          can.sprayDiscStatus_List.add(2);
          can.sprayDiscX_List.add(Integer.parseInt(st2.nextToken().trim()));
          can.sprayDiscY_List.add(Integer.parseInt(st2.nextToken().trim()));
        }
        else if(commandS.equals("SprayGaussianOp"))
        { //●//スプレーでの正規分布オプション
        //SprayGaussianOp(double g)
        //g:      正規分布スプレーでの分布操作係数
          can.sprayGaussianOp = Double.parseDouble(st2.nextToken().trim());
        }

        else if(commandS.equals("LinkedLineStart"))
        { //●折れ線ユニット開始（「折れ線ユニット」とは、連続した折れ線のこと）
        //LinkedLineStart(double x, double y)
        //x:      始点のｘ座標
        //x:      始点のｙ座標
          can.linkedLineFlag = true;
          can.linkedLineStatusList.add(0);
          can.linkedLineXList.add(Double.parseDouble(st2.nextToken().trim()));
          can.linkedLineYList.add(Double.parseDouble(st2.nextToken().trim()));
        }
        else if(commandS.equals("LinkedLineNext"))
        { //●折れ線ユニット継続
        //LinkedLineNext(double x, double y)
        //x:      継続点のｘ座標
        //x:      継続点のｙ座標
          can.linkedLineStatusList.add(1);
          can.linkedLineXList.add(Double.parseDouble(st2.nextToken().trim()));
          can.linkedLineYList.add(Double.parseDouble(st2.nextToken().trim()));
        }
        else if(commandS.equals("LinkedLineEnd"))
        { //●折れ線ユニット終了
        //LinkedLineEnd(double x, double y)
        //x:      終点のｘ座標
        //x:      終点のｙ座標
          can.linkedLineStatusList.add(2);
          can.linkedLineXList.add(Double.parseDouble(st2.nextToken().trim()));
          can.linkedLineYList.add(Double.parseDouble(st2.nextToken().trim()));
        }

        else if(commandS.equals("CutAndPasteMask"))
        { //●切り貼り画像合成でのマルチ・マスク指定
        //CutAndPasteMask(String f)
        //f:      マルチ・マスク画像ファイル（パス含む）
          can.cutAndPasteMaskFlag = true;
          can.capMaskF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path;
        }
        else if(commandS.equals("CutAndPaste"))
        { //●切り貼り画像合成の実行
        //CutAndPaste(String fileName, int r, int g, int b)
        //fileName:模様画像ファイル（パス含む）
        //r:      マスク画像切り貼り部分の色相赤成分
        //g:
        //b:
          can.cutAndPasteFlag = true;
          can.capListF.add(Util.trimAffix(st2.nextToken().trim(),'\"','\"'));
          int[]  capI = new int[3]; //マルチ・マスクの色分け指定色
          capI[0] = Integer.parseInt(st2.nextToken().trim()); //r
          capI[1] = Integer.parseInt(st2.nextToken().trim()); //g
          capI[2] = Integer.parseInt(st2.nextToken().trim()); //b
          can.capListI.add(capI);
        }
        else if(commandS.equals("ChangeColorMultiBase"))
        { //●連続色相変更でのベース画像指定
        //ChangeColorMultiBase(String fileName)
        //fileName:連続色相変更ベース画像ファイル（パス含む）
          can.changeColorMultiBaseFlag = true;
          can.ccmMaskF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path;
        }
        else if(commandS.equals("ChangeColorMulti"))
        { //●連続色相変更の実行
        //ChangeColorMulti(int r0, int g0, int b0, int r1, int g1, int b1)
        //r0:      旧色の色相赤成分
        //g0:
        //b0:
        //r1:      新色の色相赤成分
        //g1:
        //b1:
          can.changeColorMultiFlag = true;
          int[]  ccmI0 = new int[3]; //旧画像　指定色　数値データ
          ccmI0[0] = Integer.parseInt(st2.nextToken().trim()); //r
          ccmI0[1] = Integer.parseInt(st2.nextToken().trim()); //g
          ccmI0[2] = Integer.parseInt(st2.nextToken().trim()); //b
          can.ccmListI0.add(ccmI0);
          int[]  ccmI1 = new int[3]; //新画像　指定色　数値データ
          ccmI1[0] = Integer.parseInt(st2.nextToken().trim()); //r
          ccmI1[1] = Integer.parseInt(st2.nextToken().trim()); //g
          ccmI1[2] = Integer.parseInt(st2.nextToken().trim()); //b
          can.ccmListI1.add(ccmI1);
        }
        else if(commandS.equals("ChangeColorInner"))
        { //●輪郭線で囲まれた図形の内部を指定色で塗り直す。
          //塗り直し対象領域は、輪郭線で囲まれた図形の内部の代表位置を、
          //xy座標位置で指定しなければならない。
          //その座標位置（１ピクセル分）を初期設定として指定色で彩色した後、
          //プログラムが全体をスキャンしながら指定色のありかを探し出し、その領域拡大を行なう。
        //ChangeColorInner(String f. int r0, int g0, int b0, int r1, int g1, int b1, int x, int y, int mode)
        //f:       塗り直し対象輪郭線画像ファイル名（パス含む）
        //r0:      輪郭線色
        //g0:
        //b0:
        //r1:      彩色指定色
        //g1:
        //b1:
        //x:       図形内側代表位置のx座標
        //y:       図形内側代表位置のy座標
        //mode     輪郭線も塗り直すかの可否（０は否、１は可）
          can.changeColorInnerFlag = true;
          can.changeColorInnerF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.cciOutlineColorR  = Integer.parseInt(st2.nextToken().trim());
          can.cciOutlineColorG  = Integer.parseInt(st2.nextToken().trim());
          can.cciOutlineColorB  = Integer.parseInt(st2.nextToken().trim());
          can.cciInnerColorR    = Integer.parseInt(st2.nextToken().trim());
          can.cciInnerColorG    = Integer.parseInt(st2.nextToken().trim());
          can.cciInnerColorB    = Integer.parseInt(st2.nextToken().trim());
          can.cciInnerX         = Integer.parseInt(st2.nextToken().trim());
          can.cciInnerY         = Integer.parseInt(st2.nextToken().trim());
          can.cciMode           = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("ChangeColorInnerMultiMask"))
        { //●輪郭線で囲まれた図形の特定領域を指定色で連続的に塗り直すための統一指定。
          //輪郭線画像は、白地図形式であり、必要に応じてスポット彩色（部分点描）された状態にあるものとする。
          //ただし、スポット彩色は、必須の条件ではない。
          //輪郭線（共用輪郭線）は、塗り直し対象外であって、そのままの色で残る。
          //輪郭線を隠すには、最終段階でソフト・フォーカスおよびスタンプで対処する。
          //複雑に屈曲した輪郭線図形で、その内部彩色処理を高速化するには、点描画機能などを用い、
          //彩色部の数箇所に指定色を予め塗っておくこと。
        //ChangeColorInnerMultiMask(String f. int r, int g, int b)
        //f:       塗り直し対象輪郭線画像ファイル名（パス含む）
        //r:       輪郭線色
        //g:
        //b:
          can.changeColorInnerMultiFlag = true;
          can.changeColorInnerMultiF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.ccimOutlineColorR  = Integer.parseInt(st2.nextToken().trim());
          can.ccimOutlineColorG  = Integer.parseInt(st2.nextToken().trim());
          can.ccimOutlineColorB  = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("ChangeColorInnerMulti"))
        { //●輪郭線で囲まれた図形の内部を指定色で連続的に塗り直すための個別指定。
        //ChangeColorInnerMulti(int r, int g, int b, int x, int y,)
        //r:       彩色指定色
        //g:
        //b:
        //x:       図形内側彩色領域代表位置のx座標
        //y:       図形内側彩色領域代表位置のy座標
          int[]  intArr = new int[5]; //
          intArr[0] = Integer.parseInt(st2.nextToken().trim()); //r
          intArr[1] = Integer.parseInt(st2.nextToken().trim()); //g
          intArr[2] = Integer.parseInt(st2.nextToken().trim()); //b
          intArr[3] = Integer.parseInt(st2.nextToken().trim()); //x
          intArr[4] = Integer.parseInt(st2.nextToken().trim()); //y
          can.ccimListI.add(intArr);
        }

        else if(commandS.equals("ChangeColorInnerAuto"))
        { //●輪郭線で囲まれた図形の特定領域を指定色で連続的かつ自動的かつ高速に塗り直す指定。
          //ChangeColorInnerMultiの機能を高速化し代替する新機能。
          //輪郭線画像は、白地図形式を基礎にしつつ、スポット彩色（部分点描）された状態にあるものとする。
          //ただし、スポット彩色は、必須の条件である。
          //輪郭線（共用輪郭線）は、塗り直し対象外であって、そのままの色で残る。
          //なお、地色（変換しない色）および輪郭線色の事前決定が、理論上必要である。
          //地色のデフォルト値は、白色(255,255,255)とし、輪郭線色のデフォルト値は、黒色(0,0,0)とする。
          //輪郭線画像のスキャン中に、地色でも輪郭線色でもないスポット彩色を発見すれば、
          //その色をその輪郭線内でピクセル単位でコピーする。
          //輪郭線を隠すには、最終段階でソフト・フォーカス命令およびスタンプ命令で対処する。
          //複雑に屈曲した輪郭線図形で、その内部彩色処理を高速化するには、点描画機能などを用い、
          //彩色部の多数箇所に指定色をスポット彩色で予め塗っておくこと。
        //ChangeColorInnerAuto(String f)
        //f:       塗り直し対象輪郭線画像ファイル名（パス含む）
          can.changeColorInnerAutoFlag = true;
          can.changeColorInnerAutoF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
        }
        else if(commandS.equals("ChangeColorInnerAutoOp"))
        { //●ChangeColorInnerAutoに対するオプション指定。
          //地色既定値および輪郭線色規定値を変更する。
        //ChangeColorInnerAutoOp(int r1,int g1, int b1, int r2, int g2, int b2)
          can.cciaBaseColorR = Integer.parseInt(st2.nextToken().trim()); //地色r
          can.cciaBaseColorG = Integer.parseInt(st2.nextToken().trim()); //地色g
          can.cciaBaseColorB = Integer.parseInt(st2.nextToken().trim()); //地色b
          can.cciaOutlineColorR = Integer.parseInt(st2.nextToken().trim()); //輪郭r
          can.cciaOutlineColorG = Integer.parseInt(st2.nextToken().trim()); //輪郭g
          can.cciaOutlineColorB = Integer.parseInt(st2.nextToken().trim()); //輪郭b
        }

        else if(commandS.equals("MixImage"))
        { //●ミックス画像（二重像画像）の合成指定
          if(st2.countTokens() == 2 && Util.countDelimiter(command1, ',') == 1)
          {
          //MixImage(String fileName1, String fileName2)
          //fileName1:元画像ファイル（パス含む）
          //fileName2:追加画像ファイル名（パス含む）
            can.mixFName0 = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path
            can.mixFName1 = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path
          }
          else if(st2.countTokens() == 3 && Util.countDelimiter(command1, ',') == 2)
          {
          //MixImage(int mixMode, String fileName1, String fileName2)
          //mixMode:画像の拡大縮小を伴わないStamp押印として機能するモードの指定（０を指定）
          //fileName1:元画像ファイル名（パス含む）
          //fileName2:追加画像ファイル名（パス含む）
            can.mixMode = Integer.parseInt(st2.nextToken().trim());
            can.mixFName0 = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path
            can.mixFName1 = Util.trimAffix(st2.nextToken().trim(),'\"','\"');//file path
            if(can.mixMode!=0 && can.mixMode!=1)
            {
              can.mixMode = 1;
              f.message(command1 + " >>モード指定が異常のため、通常モードにしました。");
            }
          }
          else
          {
            f.message(command1 + " >>引数が異常。");
            return;
          }
        }
        else if(commandS.equals("SoftFocus"))
        { //●ソフト・フォーカス効果要求
        //SoftFocus(String f, int d)
        //f:     元画像ファイル（パス含む）
        //d:     ソフト・フォーカスの反復回数（０～１００）
          can.softFocusFName = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.softFocusDegree = Integer.parseInt(st2.nextToken().trim());
          if(can.softFocusDegree > 100)
            can.softFocusDegree = 100;
          if(can.softFocusDegree < 0)
            can.softFocusDegree = 0;
        }
        else if(commandS.equals("Convolve"))
        { //●畳み込み処理要求（鮮鋭化／朦朧化）
        //Convolve(String f, float v0, float v1, float v2, int d, int k、 int t, int c)
        //Convolve(String f, float v0, float v1, float v2, float v3, float v4, float v5, int d, int k, int t, int c)
        //f:     元画像ファイル（パス含む）
        //v0:    畳み込みフィルター値（カーネル中心値）
        //v1:    畳み込みフィルター値（中心より上下左右隣接値）
        //v2:    畳み込みフィルター値（中心より斜め方向隣接値）
        //v3:    畳み込みフィルター値（5x5での周辺部）
        //v4:    畳み込みフィルター値（5x5での周辺部）
        //v5:    畳み込みフィルター値（5x5での周辺部）
        //d:     畳み込みの反復回数（鮮鋭化や朦朧化の度合い）1～10
        //k:     カーネル・サイズ（3 / 5）
        //t:     ノイズ許容度（1以上で、カーネル・サイズの自乗未満）
        //c:     ノイズ識別色段差（1～254）

        //3x3のピクセル・ブロック（カーネル）におけるフィルター値の配置は、
        //v2, v1, v2
        //v1, v0, v1
        //v2, v1, v2
        //5x5のピクセル・ブロック（カーネル）におけるフィルター値の配置は、
        //v5, v4, v3, v4, v5
        //v4, v2, v1, v2, v4
        //v3, v1, v0, v1, v3
        //v4, v2, v1, v2, v4
        //v5, v4, v3, v4, v5

        //「鮮鋭化」の場合、フィルター値の標準は、3x3の場合、v0が5, v1が-1, v2が0。
        // 「鮮鋭化」の数値を調整するなら、0.1単位や0.01単位の微調整とする。
        //「鮮鋭化」での反復回数は、1を推奨する。2以上では、偽解像やノイズが生じる。

        //「朦朧化」の場合、フィルター値の標準は、3x3の場合、v0が-0.14, v1が0.14, v2が0.14。
        // 「朦朧化」の数値を調整するなら、0.1単位や0.01単位の微調整とする。
        //「朦朧化」での反復回数は、100を一応の上限とする。

        //畳み込み処理は、色の明暗にも多大な影響を与えるため、
        //フィルター値は、個別に繊細な微調整を要する。
        //なお、「Convolve」すなわち「畳み込み」は、画像処理等での数学用語である。
          if(st2.countTokens() == 7 && Util.countDelimiter(command1, ',') == 6)
          { //3x3 kernel
            can.convolveFName = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            can.convolveV0 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV1 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV2 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV3 = 0.0f;
            can.convolveV4 = 0.0f;
            can.convolveV5 = 0.0f;
            can.convolveKernelSize = 3; //3x3
            can.convolveDegree = Integer.parseInt(st2.nextToken().trim());
            if(can.convolveDegree > 100)
              can.convolveDegree = 100;
            else if(can.convolveDegree < 1)
              can.convolveDegree = 1;
            can.convolveNoizeTolerance = Integer.parseInt(st2.nextToken().trim());
            can.convolveColorDistance = Integer.parseInt(st2.nextToken().trim());
          }
          else if(st2.countTokens() == 10 && Util.countDelimiter(command1, ',') == 9)
          { //5x5 kernel
            can.convolveFName = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            can.convolveV0 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV1 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV2 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV3 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV4 = Float.parseFloat(st2.nextToken().trim());
            can.convolveV5 = Float.parseFloat(st2.nextToken().trim());
            can.convolveKernelSize = 5; //5x5
            can.convolveDegree = Integer.parseInt(st2.nextToken().trim());
            if(can.convolveDegree > 100)
              can.convolveDegree = 100;
            else if(can.convolveDegree < 1)
              can.convolveDegree = 1;
            can.convolveNoizeTolerance = Integer.parseInt(st2.nextToken().trim());
            can.convolveColorDistance = Integer.parseInt(st2.nextToken().trim());
          }
        }
        else if(commandS.equals("GetOutline"))
        { //●輪郭線抽出処理
        //GetOutline(String f, int d, int k, int t)
        //f:     元画像ファイル名（パス含む）
        //d:     輪郭線での色段差（1～254）
        //k:     ノイズ除去でのカーネル・サイズ（3 / 5 / 7）
        //t:     ノイズ許容度（1以上で、カーネル・サイズの自乗未満）
          can.outlineFName = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.outlineColorDistance = Integer.parseInt(st2.nextToken().trim());
          can.outlineNoizeKernel = Integer.parseInt(st2.nextToken().trim());
          can.outlineNoizeTolerance = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("ColorGradient"))
        { //●色彩階調効果の追加
        //ColorGradient(String fName, int m, int y1, int y2,
        //  double r, double g, double b)
        //fName:  元画像ファイル名（パス含む）
        //y1:     加工開始y軸位置
        //y2:     加工反転y軸位置
        //r:      赤成分の追加数値
        //g:      緑成分の追加数値
        //b:      青成分の追加数値
          if(st2.countTokens() != 6 || Util.countDelimiter(command1, ',') != 5)
          { //引数の個数が多いので、個数をチェック（以下同様）
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.gradientFName = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.gradientY1 = Integer.parseInt(st2.nextToken().trim());
          can.gradientY2 = Integer.parseInt(st2.nextToken().trim());
          can.gradientR = Double.parseDouble(st2.nextToken().trim());
          can.gradientG = Double.parseDouble(st2.nextToken().trim());
          can.gradientB = Double.parseDouble(st2.nextToken().trim());
        }
        else if(commandS.equals("ChangeColor"))
        { //●単独色相変更（近似色をも含めた単独色相変更）
        //ChangeColor(String fName,int c, int mode,
        //  int r1, int g1, int b1, int r2, int g2, int b2 )
        //ChangeColor(String fName,int c,
        //  int r1, int g1, int b1, int r2, int g2, int b2 )
        //fName:  元画像ファイル名（パス含む）
        //c:      指定色許容値
        //mode:   1が単純な色相変更で、2がグレー・マスクを生成
        //r1:     旧色
        //g1:
        //b1:
        //r2:     新色
        //g2:
        //b2:
          if(st2.countTokens() == 9 && Util.countDelimiter(command1, ',') == 8)
          {
            can.colorChangeFlag = true;
            can.colorChangeFile  = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            can.acceptableLimitC = Integer.parseInt(st2.nextToken().trim());
            can.colorChangeMode  = Integer.parseInt(st2.nextToken().trim());
            can.colorChange1R    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange1G    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange1B    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange2R    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange2G    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange2B    = Integer.parseInt(st2.nextToken().trim());
          }
          else if(st2.countTokens() == 8 && Util.countDelimiter(command1, ',') == 7)
          {
            can.colorChangeFlag = true;
            can.colorChangeFile  = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            can.acceptableLimitC = Integer.parseInt(st2.nextToken().trim());
            can.colorChangeMode  = 1;
            can.colorChange1R    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange1G    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange1B    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange2R    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange2G    = Integer.parseInt(st2.nextToken().trim());
            can.colorChange2B    = Integer.parseInt(st2.nextToken().trim());
          }
          else
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
        }

        else if(commandS.equals("ReverseImage"))
        { //●画像反転（鏡像反転または直角系回転）
        //ReverseImage(String fName,int m)
        //fName:  元画像ファイル名（パス含む）
        //c:      反転モード（１～７）
          can.reverseImageFlag = true;
          can.reverseImageFile = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.reverseImageMode = Integer.parseInt(st2.nextToken().trim());
        }

        else if(commandS.equals("ForegroundColorL") || commandS.equals("ForegroundColor"))
        { //●前景色（線の色）の指定（ForegroundColorは、省略名称）
        //ForegroundColorL(int r, int g, int b)
        //ForegroundColor(int r, int g, int b)
        //r:     赤色成分　0-255
        //g:     緑色成分　0-255
        //b:     青色成分　0-255
          int red   = Integer.parseInt(st2.nextToken().trim());
          int green = Integer.parseInt(st2.nextToken().trim());
          int blue  = Integer.parseInt(st2.nextToken().trim());
          if(red>255)
          {
            red = 255;
            f.message("色指定の上限は255です。");
          }
          if(green>255)
          {
            green = 255;
            f.message("色指定の上限は255です。");
          }
          if(blue>255)
          {
            blue = 255;
            f.message("色指定の上限は255です。");
          }
          can.foregroundColorL = new Color(red, green, blue);
        }
        else if(commandS.equals("ForegroundColorS"))
        { //●前景色（文字の色）の指定
        //ForegroundColorS(int r, int g, int b)
        //r:     赤色成分　0-255
        //g:     緑色成分　0-255
        //b:     青色成分　0-255
          int red   = Integer.parseInt(st2.nextToken().trim());
          int green = Integer.parseInt(st2.nextToken().trim());
          int blue  = Integer.parseInt(st2.nextToken().trim());
          if(red>255)
          {
            red = 255;
            f.message("色指定の上限は255です。");
          }
          if(green>255)
          {
            green = 255;
            f.message("色指定の上限は255です。");
          }
          if(blue>255)
          {
            blue = 255;
            f.message("色指定の上限は255です。");
          }
          can.foregroundColorS = new Color(red, green, blue);
        }
        else if(commandS.equals("ForegroundColorB"))
        { //●前景色（極太文字の色）の指定
        //ForegroundColorB(int r, int g, int b)
        //r:     赤色成分　0-255
        //g:     緑色成分　0-255
        //b:     青色成分　0-255
          int red   = Integer.parseInt(st2.nextToken().trim());
          int green = Integer.parseInt(st2.nextToken().trim());
          int blue  = Integer.parseInt(st2.nextToken().trim());
          if(red>255)
          {
            red = 255;
            f.message("色指定の上限は255です。");
          }
          if(green>255)
          {
            green = 255;
            f.message("色指定の上限は255です。");
          }
          if(blue>255)
          {
            blue = 255;
            f.message("色指定の上限は255です。");
          }
          can.foregroundColorB = new Color(red, green, blue);
        }
        else if(commandS.equals("AffineScale") || commandS.equals("DisplayScale"))
        { //●標準の拡大率の指定（印刷に反映されない）
        //「AffineScale」の別名として、「DisplayScale」を定義する。
        //AffineScale(double scale)
        //DisplayScale(double scale)
        //scale:  表示、画像保存に有効な拡大倍率
          can.affineScale = Double.parseDouble(st2.nextToken().trim());
          f.scaleLabel.setText("　(a:x" + can.affineScale + ")");
        }
        else if(commandS.equals("FreeScale") || commandS.equals("PrintScale"))
        { //●任意の拡大率の指定（印刷にも反映される）
        //「FreeScale」の別名として、「PrintScale」を定義する。
        //FreeScale(double scale)
        //PrintScale(double scale)
        //scale:  表示、画像保存、印刷に有効な拡大倍率
          can.freeScale = Double.parseDouble(st2.nextToken().trim());
          f.scaleLabel2.setText("　(f:x" + can.freeScale + ")");
        }
        else if(commandS.equals("Shift"))
        { //●全体の画像をずらす指定
        //Shift(int mode, double x, double y)
        //mode:   0がシフトなし、1がシフトあり
        //x:    X軸のシフト量
        //y:    Y軸のシフト量
          can.shiftMode = Integer.parseInt(st2.nextToken().trim());
          can.shiftX = Double.parseDouble(st2.nextToken().trim());
          can.shiftY = Double.parseDouble(st2.nextToken().trim());
        }
        else if(commandS.equals("LineWidth"))
        { //●線の太さ指定
        //LineWidth(float width)
        //width:  線の太さ
          can.lineWidth = Float.parseFloat(st2.nextToken().trim());
        }
        else if(commandS.equals("ParallelLineWidth"))
        { //●平行線の太さ指定
        //ParallelLineWidth(float width)
        //width:  平行線の太さ
          can.parallelLineWidth = Float.parseFloat(st2.nextToken().trim());
        }
        else if(commandS.equals("DrawLine"))
        { //●直線の描画指定
        //DrawLine(double x1, double y1, double x2, double y2)
        //x1:  起点座標X
        //y1:  起点座標Y
        //x2:  終点座標X
        //y2:  終点座標Y
          double[] d = new double[4];
          d[0] = Double.parseDouble(st2.nextToken().trim());
          d[1] = Double.parseDouble(st2.nextToken().trim());
          d[2] = Double.parseDouble(st2.nextToken().trim());
          d[3] = Double.parseDouble(st2.nextToken().trim());
          can.lineList.add(d);
        }
        else if(commandS.equals("DrawLine2"))  //マウス操作時に一時的使用
        { //●仮直線の描画指定
        //Draw2(int m; double x1, double y1, double x2, double y2)
        // m:  モード
        //x1:  起点座標X
        //y1:  起点座標Y
        //x2:  終点座標X
        //y2:  終点座標Y
          double[] d = new double[5];
          d[0] = Double.parseDouble(st2.nextToken().trim());
          d[1] = Double.parseDouble(st2.nextToken().trim());
          d[2] = Double.parseDouble(st2.nextToken().trim());
          d[3] = Double.parseDouble(st2.nextToken().trim());
          d[4] = Double.parseDouble(st2.nextToken().trim());
          can.line2List.add(d);
        }
        else if(commandS.equals("DrawParallelLineH"))
        { //●横平行線の描画指定
        //DrawParallelLineH(double x, double y, double l, double w, int t, int m)
        //x:  起点座標X
        //y:  起点座標Y
        //l:  線の長さ
        //w:  線の間隔
        //t:  線の本数
        //m:  線の種類（０：実線、１：密点線、２：粗点線）
        //h:  中間線の有無（０：無し、１：有り）
          if(st2.countTokens() != 7 || Util.countDelimiter(command1, ',') != 6)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.parallelLineH_x = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH_y = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH_l = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH_w = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH_t = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineH_m = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineH_h = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("DrawParallelLineV"))
        { //●縦平行線の描画指定
        //DrawParallelLineV(double x, double y, double l, double w, int t, int m)
        //x:  起点座標X
        //y:  起点座標Y
        //l:  線の長さ
        //w:  線の間隔
        //t:  線の本数
        //m:  線の種類（０：実線、１：密点線、２：粗点線）
        //h:  中間線の有無（０：無し、１：有り）
          if(st2.countTokens() != 7 || Util.countDelimiter(command1, ',') != 6)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.parallelLineV_x = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV_y = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV_l = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV_w = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV_t = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineV_m = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineV_h = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("DrawParallelLineH2"))
        { //●横平行線の描画指定（補助用）
        //DrawParallelLineH2(double x, double y, double l, double w, int t, int m)
        //x:  起点座標X
        //y:  起点座標Y
        //l:  線の長さ
        //w:  線の間隔
        //t:  線の本数
        //m:  線の種類（０：実線、１：密点線、２：粗点線）
        //h:  中間線の有無（０：無し、１：有り）
          if(st2.countTokens() != 7 || Util.countDelimiter(command1, ',') != 6)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.parallelLineH2_x = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH2_y = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH2_l = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH2_w = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineH2_t = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineH2_m = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineH2_h = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("DrawParallelLineV2"))
        { //●縦平行線の描画指定（補助用）
        //DrawParallelLineV2(double x, double y, double l, double w, int t, int m)
        //x:  起点座標X
        //y:  起点座標Y
        //l:  線の長さ
        //w:  線の間隔
        //t:  線の本数
        //m:  線の種類（０：実線、１：密点線、２：粗点線）
        //h:  中間線の有無（０：無し、１：有り）
          if(st2.countTokens() != 7 || Util.countDelimiter(command1, ',') != 6)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.parallelLineV2_x = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV2_y = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV2_l = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV2_w = Double.parseDouble(st2.nextToken().trim());
          can.parallelLineV2_t = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineV2_m = Integer.parseInt(st2.nextToken().trim());
          can.parallelLineV2_h = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("DrawCurve"))
        { //●ベジェ曲線の描画指定
        //DrawCurve(double x1, double y1, double x2, double y2,
        //  double x3, double y3, double x4, double y4)
        //x1:  起点座標X
        //y1:  起点座標Y
        //x2:  第一制御点座標X
        //y2:  第一制御点座標Y
        //x3:  第二制御点座標X
        //y3:  第二制御点座標Y
        //x4:  終点座標X
        //y4:  終点座標Y
          if(st2.countTokens() != 8 || Util.countDelimiter(command1, ',') != 7)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          double[] d = new double[8];
          d[0] = Double.parseDouble(st2.nextToken().trim());
          d[1] = Double.parseDouble(st2.nextToken().trim());
          d[2] = Double.parseDouble(st2.nextToken().trim());
          d[3] = Double.parseDouble(st2.nextToken().trim());
          d[4] = Double.parseDouble(st2.nextToken().trim());
          d[5] = Double.parseDouble(st2.nextToken().trim());
          d[6] = Double.parseDouble(st2.nextToken().trim());
          d[7] = Double.parseDouble(st2.nextToken().trim());
          can.curveList.add(d);
        }
        else if(commandS.equals("DrawSplineStart"))
        { //●スプライン曲線の描画指定（起点）
        //DrawSplineStart(double cmd, double x, double y)
        //cmd: 命令識別番号（定数0）
        //x1:  起点座標X
        //y1:  起点座標Y
          double[] d = new double[3];
          d[0] = 0;
          d[1] = Double.parseDouble(st2.nextToken().trim());
          d[2] = Double.parseDouble(st2.nextToken().trim());
          can.splineList.add(d);
        }
        else if(commandS.equals("DrawSplineControl"))
        { //●スプライン曲線の描画指定（制御点）
        //DrawSplineControl(double cmd, double x, double y)
        //cmd: 命令識別番号（定数1）
        //x1:  制御点座標X
        //y1:  制御点座標Y
          double[] d = new double[3];
          d[0] = 1;
          d[1] = Double.parseDouble(st2.nextToken().trim());
          d[2] = Double.parseDouble(st2.nextToken().trim());
          can.splineList.add(d);
        }
        else if(commandS.equals("DrawSplineEnd"))
        { //●スプライン曲線の描画指定（終点）
        //DrawSplineEnd(double cmd, double x, double y)
        //cmd: 命令識別番号（定数2）
        //x1:  終点座標X
        //y1:  終点座標Y
          double[] d = new double[3];
          d[0] = 2;
          d[1] = Double.parseDouble(st2.nextToken().trim());
          d[2] = Double.parseDouble(st2.nextToken().trim());
          can.splineList.add(d);
        }
        else if(commandS.equals("DrawSplineOp"))
        { //●スプライン曲線の描画指定（曲線精細度オプション）
        //DrawSplineOp(int op)
        //op: 曲線を構成する短い直線の本数
          can.splineOption = Integer.parseInt(st2.nextToken().trim());
        }

        else if(commandS.equals("ToneCurveStart"))
        { //●トーン・カーブ曲線の描画指定（起点）
        //トーン・カーブ曲線のデータは、複数の曲線を一本のリストに詰め込み、
        //後に、複数の曲線に分解する。分解の手掛かりとして、命令識別番号を使用。
        //ToneCurveStart(double x, double y)
        //x:   起点座標X
        //y:   起点座標Y
          f.toneCurve.toneCurveArrX[tcCnt1][tcCnt2] = Double.parseDouble(st2.nextToken().trim());
          f.toneCurve.toneCurveArrY[tcCnt1][tcCnt2] = Double.parseDouble(st2.nextToken().trim());
          tcCnt2++;
        }
        else if(commandS.equals("ToneCurveControl"))
        { //●トーン・カーブ曲線の描画指定（制御点）
        //ToneCurveControl(double x, double y)
        //x:   制御点座標X
        //y:   制御点座標Y
          f.toneCurve.toneCurveArrX[tcCnt1][tcCnt2] = Double.parseDouble(st2.nextToken().trim());
          f.toneCurve.toneCurveArrY[tcCnt1][tcCnt2] = Double.parseDouble(st2.nextToken().trim());
          tcCnt2++;
        }
        else if(commandS.equals("ToneCurveEnd"))
        { //●トーン・カーブ曲線の描画指定（終点）
        //ToneCurveEnd(double x, double y)
        //x:   終点座標X
        //y:   終点座標Y
          f.toneCurve.toneCurveArrX[tcCnt1][tcCnt2] = Double.parseDouble(st2.nextToken().trim());
          f.toneCurve.toneCurveArrY[tcCnt1][tcCnt2] = Double.parseDouble(st2.nextToken().trim());
          tcCnt1++;
          tcCnt2 = 0;
          if(tcCnt1 == 3)
            tcCnt1=0;
        }

        //●●色塗り図形描画命令「解読」グループの始まり（命令識別を添加）

        //●自由図形の描画指定
        else if(commandS.equals("DrawShapeStart"))
        //DrawShapeStart(int m, double x,double y, int r, int g, int b)
        //m:  描画モード指定
        //x:  自由図形の起点座標X
        //y:  自由図形の起点座標Y
        //r:  赤色成分　0-255
        //g:  緑色成分　0-255
        //b:  青色成分　0-255
        {
          if(st2.countTokens() != 6 || Util.countDelimiter(command1, ',') != 5)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          shape = new double[9];
          shape[0] = 0; //命令識別（DrawShapeStart）
          shape[1] = Double.parseDouble(
            st2.nextToken().trim()); //m
          shape[2] = Double.parseDouble(
            st2.nextToken().trim()); //x
          shape[3] = Double.parseDouble(
            st2.nextToken().trim()); //y
          shape[4] = Integer.parseInt(
            st2.nextToken().trim()); //r
          shape[5] = Integer.parseInt(
            st2.nextToken().trim()); //g
          shape[6] = Integer.parseInt(
            st2.nextToken().trim()); //b
          shape[7] = 0; //dummy
          shape[8] = 0; //dummy
          can.shapeList.add(shape);
        }
        else if(commandS.equals("DrawShapeLine"))
        //DrawShapeLine(double x,double y)
        //x:  直線終点座標X
        //y:  直線終点座標Y
        {
          shape = new double[9];
          shape[0] = -1; //命令識別（DrawShapeLine）
          shape[1] = Double.parseDouble(
            st2.nextToken().trim()); //x
          shape[2] = Double.parseDouble(
            st2.nextToken().trim()); //y
          shape[3] = 0; //dummy
          shape[4] = 0; //dummy
          shape[5] = 0; //dummy
          shape[6] = 0; //dummy
          shape[7] = 0; //dummy
          shape[8] = 0; //dummy
          can.shapeList.add(shape);
        }
        else if(commandS.equals("DrawShapeCurve"))
        //DrawShapeCurve(double x1,double y1,double x2,double y2,
        //  double x3,double y3)
        //x1:  曲線部第一制御点座標X
        //y1:  曲線部第一制御点座標Y
        //x2:  曲線部第二制御点座標X
        //y2:  曲線部第二制御点座標Y
        //x3:  曲線部終点座標X
        //y3:  曲線部終点座標Y
        {
          if(st2.countTokens() != 6 || Util.countDelimiter(command1, ',') != 5)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          shape = new double[9];
          shape[0] = -2; //命令識別（DrawShapeCurve）
          shape[1] = Double.parseDouble(
            st2.nextToken().trim()); //x1
          shape[2] = Double.parseDouble(
            st2.nextToken().trim()); //y1
          shape[3] = Double.parseDouble(
            st2.nextToken().trim()); //x2
          shape[4] = Double.parseDouble(
            st2.nextToken().trim()); //y2
          shape[5] = Double.parseDouble(
            st2.nextToken().trim()); //x3
          shape[6] = Double.parseDouble(
            st2.nextToken().trim()); //y3
          shape[7] = 0; //dummy
          shape[8] = 0; //dummy
          can.shapeList.add(shape);
        }
        else if(commandS.equals("DrawShapeEnd"))
        //DrawShapeEnd()
        //  引数なし。自由図形の終結宣言
        {
          shape = new double[9];
          shape[0] = -3; //命令識別（DrawShapeEnd）
          shape[1] = 0; //dummy
          shape[2] = 0; //dummy
          shape[3] = 0; //dummy
          shape[4] = 0; //dummy
          shape[5] = 0; //dummy
          shape[6] = 0; //dummy
          shape[7] = 0; //dummy
          shape[8] = 0; //dummy
          can.shapeList.add(shape);
        }
        else if(commandS.equals("DrawRect"))
        { //●長方形
        //DrawRect(int m, int x, int y, int w, int h, int r, int g, int b)
        //m:  描画モード、0は描画せず、1は線、2は色塗り、3は線と色
        //    4は線描と透明色塗り
        //x:  ｘ座標
        //y:  ｙ座標
        //w:  幅
        //h:  丈
        //r:  R
        //g:  G
        //b:  B
          if(st2.countTokens() != 8 || Util.countDelimiter(command1, ',') != 7)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          double[] d = new double[9];
           d[0] = -4; //命令識別（DrawRect）
           d[1] = Double.parseDouble(st2.nextToken().trim()); //m
           d[2] = Double.parseDouble(st2.nextToken().trim()); //x
           d[3] = Double.parseDouble(st2.nextToken().trim()); //y
           d[4] = Double.parseDouble(st2.nextToken().trim()); //w
           d[5] = Double.parseDouble(st2.nextToken().trim()); //h
           d[6] = Double.parseDouble(st2.nextToken().trim()); //r
           d[7] = Double.parseDouble(st2.nextToken().trim()); //g
           d[8] = Double.parseDouble(st2.nextToken().trim()); //b
           can.shapeList.add(d);
        }
        else if(commandS.equals("DrawEllipse"))
        { //●楕円の描画指定
        //DrawEllipse(double m, double x, double y,
        //  double hr, double vr, double r, double g, double b)
        //m:  描画モード、0は描画せず、1は線、2は色塗り、3は線と色
        //    4は線描と透明色塗り
        //x:  楕円の中心のｘ座標
        //y:  楕円の中心のｙ座標
        //hr: 横半径
        //vr: 縦半径
        //r:  赤色
        //g:  緑色
        //b:  青色
          if(st2.countTokens() != 8 || Util.countDelimiter(command1, ',') != 7)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          double[] d = new double[9];
          d[0] = -5; //命令識別（DrawEllipse）
          d[1] = Double.parseDouble(st2.nextToken().trim()); //m
          d[2] = Double.parseDouble(st2.nextToken().trim()); //x
          d[3] = Double.parseDouble(st2.nextToken().trim()); //y
          d[4] = Double.parseDouble(st2.nextToken().trim()); //hr
          d[5] = Double.parseDouble(st2.nextToken().trim()); //vr
          d[6] = Double.parseDouble(st2.nextToken().trim()); //r
          d[7] = Double.parseDouble(st2.nextToken().trim()); //g
          d[8] = Double.parseDouble(st2.nextToken().trim()); //b
          can.shapeList.add(d);
        }
        else if(commandS.equals("DrawCircle"))
        { //●真円の描画指定
        //DrawCircle(double m, double x, double y,
        //  double rr, double r, double g, double b)
        //m:  描画モード、0は描画せず、1は線、2は色塗り、3は線と色
        //    4は線描と透明色塗り
        //x:  円の中心のｘ座標
        //y:  円の中心のｙ座標
        //rr: 半径
        //r:  赤色
        //g:  緑色
        //b:  青色
          if(st2.countTokens() != 7 || Util.countDelimiter(command1, ',') != 6)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          double[] d = new double[9];
          d[0] = -5; //命令識別（DrawEllipse）
          d[1] = Double.parseDouble(st2.nextToken().trim()); //m
          d[2] = Double.parseDouble(st2.nextToken().trim()); //x
          d[3] = Double.parseDouble(st2.nextToken().trim()); //y
          d[4] = Double.parseDouble(st2.nextToken().trim()); //rr
          d[5] = d[4];
          d[6] = Double.parseDouble(st2.nextToken().trim()); //r
          d[7] = Double.parseDouble(st2.nextToken().trim()); //g
          d[8] = Double.parseDouble(st2.nextToken().trim()); //b
          can.shapeList.add(d);
        }
        //●●色塗り図形描画命令「解読」グループの終わり

        else if(commandS.equals("FontBold"))
        { //●太字指定
        //FontBold(bool b)
        //b:        太字指定ならtrue
          String value = st2.nextToken().trim();
          if(value.equals("true"))
          {
            can.fontBold = true;
          }
          else
          {
            can.fontBold = false;
          }
        }
        else if(commandS.equals("WriteStringH") || commandS.equals("WriteString"))
        { //●文字列の描画指定（省略形の「WriteString」も許容）
        //WriteStringH(double x,double y,int size, string style, string s)
        //x:   ｘ座標
        //y:   ｙ座標
        //size:  フォント・サイズ
        //style: 字形（"sansserif" / "serif"）
        //s:   表示する文字列
          double[] d = new double[3];
          String[] s = new String[2];
          d[0] = Double.parseDouble(st2.nextToken().trim()); //x
          d[1] = Double.parseDouble(st2.nextToken().trim()); //y
          d[2] = Double.parseDouble(st2.nextToken().trim()); //size
          s[0] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          s[1] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.stringHListD.add(d);
          can.stringHListS.add(s);
        }
        else if(commandS.equals("WriteStringB"))
        { //●文字列の描画指定（極太字）補助的用途
        //WriteStringB(double x,double y,int size, string style, string s)
        //WriteStringB(double x,double y,int size, int weight, string style, string s)
        //x:   ｘ座標
        //y:   ｙ座標
        //size:  フォント・サイズ
        //weight:  太さ
        //style: 字形（sansserif / serif）
        //s:    表示する文字列
          double[] d = new double[4];
          String[] s = new String[2];
          if(st2.countTokens() == 5 && Util.countDelimiter(command1, ',') == 4)
          { //
            d[0] = Double.parseDouble(st2.nextToken().trim()); //x
            d[1] = Double.parseDouble(st2.nextToken().trim()); //y
            d[2] = Double.parseDouble(st2.nextToken().trim()); //size
            d[3] = 4; //weight デフォルトの極太文字の太さ拡張
            s[0] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            s[1] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            can.stringBListD.add(d);
            can.stringBListS.add(s);
          }
          else if(st2.countTokens() == 6 && Util.countDelimiter(command1, ',') == 5)
          {
            d[0] = Double.parseDouble(st2.nextToken().trim()); //x
            d[1] = Double.parseDouble(st2.nextToken().trim()); //y
            d[2] = Double.parseDouble(st2.nextToken().trim()); //size
            d[3] = Double.parseDouble(st2.nextToken().trim()); //weight
            //weight 極太文字の太さ拡張指定（１～１０程度を推奨）
            s[0] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            s[1] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
            can.stringBListD.add(d);
            can.stringBListS.add(s);
          }
        }
        else if(commandS.equals("WriteStringV"))
        { //●文字列の垂直描画指定（疑似縦書き）
        //「疑似縦書き」を実行すると、画像の精細度が低下するため、
        //この命令（WriteStringV）を使用しないことが望ましい。
        //WriteStringV(double x,double y,int size,
        //     string style, string s)
        //x:   ｘ座標
        //y:   ｙ座標
        //size:  フォント・サイズ
        //style: 字形（"sansserif" / "serif"）
        //s:   表示する文字列
          double[] d = new double[3];
          String[] s = new String[2];
          d[0] = Double.parseDouble(st2.nextToken().trim()); //x
          d[1] = Double.parseDouble(st2.nextToken().trim()); //y
          d[2] = Double.parseDouble(st2.nextToken().trim()); //size
          s[0] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          s[1] = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
          can.stringVListD.add(d);
          can.stringVListS.add(s);
        }
        else if(commandS.equals("Rotate"))
        { //●画像全体の90度回転指定
          //Rotate命令は、正方形の画像に対して行なうこと。
          //長方形画像なら、Size命令で指定した正方形の中にこれを収納し、
          //回転処理し保存した上で、事後的に必要部分を切り取り保存する。
          //そうしないと、画像保存が意図通りにならない。
        //Rotate(bool b)
        //b:  trueの時だけ90度回転
          String value = st2.nextToken().trim();
          if(value.equals("true"))
            can.rotateFlag = true;
          else
            can.rotateFlag = false;
        }
        else if(commandS.equals("RotateFree"))
        { //●画像全体の指定角度回転指定
          //マトリックス・パターンの傾斜を想定した命令で、
          //巨大画像を作成し回転させて、事後的に必要部分を切り取る。
          //メニューの「見本」を参照。
        //RotateFree(int degree, int w, int h)
            can.rotateFreeFlag = true;
            can.affineDegreeFree = Integer.parseInt(st2.nextToken().trim());
            can.rotateFreeW = Integer.parseInt(st2.nextToken().trim());
            can.rotateFreeH = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("RotateMulti"))
        { //●画像多段階回転重複描画
          //メニューの「見本」を参照。
        //RotateMulti(double startDegree, double degree, int times, String fName)
        //startDegree:      回転開始角度
        //degree:           回転角度
        //times:            回転回数
        //fName:            回転対象画像ファイル名
            can.rotateMultiFlag = true;
            can.rotateMultiStartDegree = Double.parseDouble(st2.nextToken().trim());
            can.rotateMultiDegree = Double.parseDouble(st2.nextToken().trim());
            can.rotateMultiTimes = Integer.parseInt(st2.nextToken().trim());
            can.rotateMultiF = Util.trimAffix(st2.nextToken().trim(),'\"','\"');
        }
        else if(commandS.equals("StripePattern"))
        { //●背景画像にランダム色のストライプ模様を表示
        //StripePattern(int stripePatternType,int stripeW,
        //  int stripePRedBase, int stripePGreenBase,int stripePBlueBase)
        //stripePatternType: ストライプ無効または水平または垂直、0/1/2
        //stripePatternW:    ストライプ幅
        //stripePRedBase:    赤基調色
        //stripePGreenBase:  緑基調色
        //stripePBlueBase:   青基調色
          if(st2.countTokens() != 5 || Util.countDelimiter(command1, ',') != 4)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.stripePatternType  = Integer.parseInt(st2.nextToken().trim());
          can.stripePatternW   = Integer.parseInt(st2.nextToken().trim());
          can.stripePRedBase   = Integer.parseInt(st2.nextToken().trim());
          can.stripePGreenBase = Integer.parseInt(st2.nextToken().trim());
          can.stripePBlueBase  = Integer.parseInt(st2.nextToken().trim());
        }
        else if(commandS.equals("MatrixPatternSt"))
        { //●背景画像にマトリックス模様を表示（統一配色の基本設定）
        //MatrixPattern(int matrixPatternNumSt, int matrixPatternWH_St
        //  int matrixPRedBaseSt, int matrixPGreenBaseSt, int matrixPBlueBaseSt
        //  int matrixColorLimitSt)
        //matrixPatternNumSt: 描画無効または柄紋番号
        //matrixPatternWH_St: 柄紋の幅丈
        //matrixPRedBaseSt:   赤基調色
        //matrixPGreenBaseSt: 緑基調色
        //matrixPBlueBaseSt:  青基調色
        //matrixColorLimitSt: 色成分上限設定（1～10）
          if(st2.countTokens() != 6 || Util.countDelimiter(command1, ',') != 5)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.matrixPatternNumSt = Integer.parseInt(st2.nextToken().trim());
          can.matrixPatternWH_St = Integer.parseInt(st2.nextToken().trim());
          can.matrixPRedBaseSt   = Integer.parseInt(st2.nextToken().trim());
          can.matrixPGreenBaseSt = Integer.parseInt(st2.nextToken().trim());
          can.matrixPBlueBaseSt  = Integer.parseInt(st2.nextToken().trim());
          can.matrixColorLimitSt = Integer.parseInt(st2.nextToken().trim());
          if(can.matrixColorLimitSt<1)
            can.matrixColorLimitSt = 1;
          else if(can.matrixColorLimitSt>10)
            can.matrixColorLimitSt = 10;
        }
        else if(commandS.equals("MatrixPatternStOp"))
        { //●背景画像にマトリックス模様を表示（統一配色のオプション）
        //MatrixPattern(
        //  double matrixShiftH_St, double matrixShiftV_St,
        //  double matrixDropH_St, double matrixDropV_St,
        //  double matrixSkipH_St, double matrixSkipV_St,
        //  int matrixRepeatH_StX, int matrixRepeatV_StX,
        //  matrixIntermittingSt)
        //matrixShiftH_St: 全体横シフト（コマ数）コマ＝小間
        //matrixShiftV_St: 全体縦シフト（コマ数）
        //matrixDropH_St:  柄紋横ドロップ（コマ数）
        //matrixDropV_St:  柄紋縦ドロップ（コマ数）
        //matrixSkipH_St:  柄紋横スキップ（コマ数）
        //matrixSkipV_St:  柄紋縦スキップ（コマ数）
        //matrixRepeatH_StX:  柄紋横リピート指定（回数）
        //matrixRepeatV_StX:  柄紋縦リピート指定（回数）
        //matrixIntermittingSt:  間欠描画（1～10）
          if(st2.countTokens() != 9 || Util.countDelimiter(command1, ',') != 8)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.matrixShiftH_St    = Double.parseDouble(st2.nextToken().trim());
          can.matrixShiftV_St    = Double.parseDouble(st2.nextToken().trim());
          can.matrixDropH_St     = Double.parseDouble(st2.nextToken().trim());
          can.matrixDropV_St     = Double.parseDouble(st2.nextToken().trim());
          can.matrixSkipH_St     = Double.parseDouble(st2.nextToken().trim());
          can.matrixSkipV_St     = Double.parseDouble(st2.nextToken().trim());
          can.matrixRepeatH_StX  = Integer.parseInt(st2.nextToken().trim());
          can.matrixRepeatV_StX  = Integer.parseInt(st2.nextToken().trim());
          can.matrixIntermittingSt = Integer.parseInt(st2.nextToken().trim());
          if(can.matrixIntermittingSt > 10)
            can.matrixIntermittingSt = 10;
          if(can.matrixIntermittingSt <= 0)
            can.matrixIntermittingSt = 1;
        }
        else if(commandS.equals("MatrixPatternEx"))
        { //●背景画像にマトリックス模様を表示（個別配色の基本設定）
        //MatrixPatternEx(int matrixPatternNumEx, int matrixPatternWH_Ex,
        //  int matrixPRedBase, int matrixPGreenBase, int matrixPBlueBase,
        //  int matrixColorLimitEx)
        //matrixPatternNumEx:  描画無効または柄紋種類
        //matrixPatternWH_Ex:  柄紋の幅丈
        //matrixShiftH_Ex:     全体横シフト（コマ数）
        //matrixShiftV_Ex:     全体縦シフト（コマ数）
        //matrixPRedBaseEx:    赤基調色
        //matrixPGreenBaseEx:  緑基調色
        //matrixPBlueBaseEx:   青基調色
        //matrixColorLimitEx:  色成分上限設定（1～10）
          if(st2.countTokens() != 6 || Util.countDelimiter(command1, ',') != 5)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.matrixPatternNumEx = Integer.parseInt(st2.nextToken().trim());
          can.matrixPatternWH_Ex = Integer.parseInt(st2.nextToken().trim());
          can.matrixPRedBaseEx   = Integer.parseInt(st2.nextToken().trim());
          can.matrixPGreenBaseEx = Integer.parseInt(st2.nextToken().trim());
          can.matrixPBlueBaseEx  = Integer.parseInt(st2.nextToken().trim());
          can.matrixColorLimitEx = Integer.parseInt(st2.nextToken().trim());
          if(can.matrixColorLimitEx<1)
            can.matrixColorLimitEx = 1;
          else if(can.matrixColorLimitEx>10)
            can.matrixColorLimitEx = 10;
        }
        else if(commandS.equals("MatrixPatternExOp"))
        { //●背景画像にマトリックス模様を表示（個別配色のオプション）
        //MatrixPatternExOp(
        //  double matrixShiftH_Ex, double matrixShiftV_Ex,
        //  double matrixDropH_Ex, double matrixDropV_Ex,
        //  double matrixSkipH_Ex, double matrixSkipV_Ex,
        //  int matrixRepeatH_ExX, int matrixRepeatV_ExX,
        //  matrixIntermittingEx)
        //matrixShiftH_Ex: 全体横シフト（コマ数）コマ＝小間
        //matrixShiftV_Ex: 全体縦シフト（コマ数）
        //matrixDropH_Ex:  柄紋横ドロップ（コマ数）
        //matrixDropV_Ex:  柄紋縦ドロップ（コマ数）
        //matrixSkipH_Ex:  柄紋横スキップ（コマ数）
        //matrixSkipV_Ex:  柄紋縦スキップ（コマ数）
        //matrixRepeatH_ExX:  柄紋横リピート指定（回数）
        //matrixRepeatV_ExX:  柄紋縦リピート指定（回数）
        //matrixIntermittingEx:  間欠描画（1～10）
          if(st2.countTokens() != 9 || Util.countDelimiter(command1, ',') != 8)
          {
            f.message(command1 + " >>引数の個数に異常");
            return;
          }
          can.matrixShiftH_Ex    = Double.parseDouble(st2.nextToken().trim());
          can.matrixShiftV_Ex    = Double.parseDouble(st2.nextToken().trim());
          can.matrixDropH_Ex     = Double.parseDouble(st2.nextToken().trim());
          can.matrixDropV_Ex     = Double.parseDouble(st2.nextToken().trim());
          can.matrixSkipH_Ex     = Double.parseDouble(st2.nextToken().trim());
          can.matrixSkipV_Ex     = Double.parseDouble(st2.nextToken().trim());
          can.matrixRepeatH_ExX  = Integer.parseInt(st2.nextToken().trim());
          can.matrixRepeatV_ExX  = Integer.parseInt(st2.nextToken().trim());
          can.matrixIntermittingEx = Integer.parseInt(st2.nextToken().trim());
          if(can.matrixIntermittingEx > 10)
            can.matrixIntermittingEx = 10;
          if(can.matrixIntermittingEx <= 0)
            can.matrixIntermittingEx = 1;
        }

        else
        { //●命令文が異常
          f.message(command1 + " >>命令スペル・エラー");
          can.commandInspection = false;
          return;
        }
      } // for文の終結
    }
    catch(NumberFormatException e)
    {
      f.message(command1 + " >>引数の数値表現エラー");
      can.commandInspection = false;
      return;
    }
    catch(Exception e)
    {
      f.message(command1 + " >>各種エラー");
      f.message(e.toString());
      can.commandInspection = false;
      return;
    }
  }
} //EOF (GCreatorAnalyzeEngine.java)

◆GCreatorPaletteEngine.java

//■■GCreatorPaletteEngine.java
//Ver.4.1

//■■インポート
import java.awt.*;  //必須
import java.awt.event.*;  //
import java.awt.geom.*;  //必須
import javax.swing.*;  //必須
import javax.swing.event.*;  //

class GCreatorPaletteEngine extends JLabel
{
  //■メンバー変数
  GCreator f;
  Graphics2D g2;
  final int x=5; //margin
  final int y=5;
  int choiceN = 0;
  Color choiceC1 = Color.black;
  Color choiceC2 = Color.black;
  Color choiceC3 = Color.black;
  Color choiceC4 = Color.black;
  Color mixColor1 = Color.black;
  Color mixColor2 = Color.black;
  int numberInputMode = 0;
  int tfR = 0;
  int tfG = 0;
  int tfB = 0;

  //■コンストラクタ
  GCreatorPaletteEngine(GCreator flame)
  {
    f = flame;
  }

  //■描画処理
  public void paintComponent(Graphics g)
  {
    drawPage(g);
  }

  //■パレット描画
  //パレットで混色または数値指定した色相は、
  //メニューの「図形彩色指定変更」または「点描画筆」の機能を選んだ時に利用され、
  //それ以外の時は、利用されない。
  //パレットを非表示にしても、指定した色相データは温存される。
  //また、パレットで何も指定しなければ、「黒色」がデフォルトになる。
  //「取消」ボタンが押されれば、パレットはデフォルトの初期設定に戻る。
  void drawPage(Graphics g)
  {
    g2 = (Graphics2D)g;

    //●描画の初期対応
    g2.setColor(new Color(127,255,255)); //（淡青緑）
    g2.fillRect(0,0,f.palette.getPreferredSize().width,
      f.palette.getPreferredSize().height);
    makePalette();
  }

  //■パレット基本色表示
  void makePalette()
  {
    g2.setFont(new Font("Serif", Font.PLAIN, 12));
    g2.setColor(new Color(0xff, 0x00, 0x00)); //red
    g2.fill(new Rectangle2D.Double(x+0,y+0,50,50));
    g2.setColor(Color.black);
    g2.drawString("ff0000",x+0,y+65);
    g2.drawString("Red",   x+0,y+80);
    g2.setColor(new Color(0x80, 0x00, 0x00)); //maroon
    g2.fill(new Rectangle2D.Double(x+50,y+0,50,50));
    g2.setColor(Color.black);
    g2.drawString("800000",x+50,y+65);
    g2.drawString("Maroon",x+50,y+80);
    g2.setColor(new Color(0xff, 0x00, 0xff)); //magenta
    g2.fill(new Rectangle2D.Double(x+100,y+0,50,50));
    g2.setColor(Color.black);
    g2.drawString("ff00ff", x+100,y+65);
    g2.drawString("Magenta",x+100,y+80);
    g2.setColor(new Color(0xa0, 0x00, 0xa0)); //purple
    g2.fill(new Rectangle2D.Double(x+150,y+0,50,50));
    g2.setColor(Color.black);
    g2.drawString("800080",x+150,y+65);
    g2.drawString("Purple",x+150,y+80);
    //------
    g2.setColor(new Color(0x00, 0xff, 0x00)); //green
    g2.fill(new Rectangle2D.Double(x+0,y+95,50,50));
    g2.setColor(Color.black);
    g2.drawString("00ff00",x+0,y+160);
    g2.drawString("Green",  x+0,y+175);
    g2.setColor(new Color(0x00, 0x80, 0x00)); //dark green
    g2.fill(new Rectangle2D.Double(x+50,y+95,50,50));
    g2.setColor(Color.black);
    g2.drawString("008000",x+50,y+160);
    g2.drawString("D.Green", x+50,y+175);
    g2.setColor(new Color(0xff, 0xff, 0x00)); //yellow
    g2.fill(new Rectangle2D.Double(x+100,y+95,50,50));
    g2.setColor(Color.black);
    g2.drawString("ffff00",x+100,y+160);
    g2.drawString("Yellow",x+100,y+175);
    g2.setColor(new Color(0x80, 0x80, 0x00)); //olive
    g2.fill(new Rectangle2D.Double(x+150,y+95,50,50));
    g2.setColor(Color.black);
    g2.drawString("808000",x+150,y+160);
    g2.drawString("Olive", x+150,y+175);
    //------
    g2.setColor(new Color(0x00, 0x00, 0xff)); //blue
    g2.fill(new Rectangle2D.Double(x+0,y+190,50,50));
    g2.setColor(Color.black);
    g2.drawString("0000ff",x+0,y+255);
    g2.drawString("Blue",  x+0,y+270);
    g2.setColor(new Color(0x00, 0x00, 0x80)); //navy
    g2.fill(new Rectangle2D.Double(x+50,y+190,50,50));
    g2.setColor(Color.black);
    g2.drawString("000080",x+50,y+255);
    g2.drawString("Navy",  x+50,y+270);
    g2.setColor(new Color(0x00, 0xff, 0xff)); //cyan
    g2.fill(new Rectangle2D.Double(x+100,y+190,50,50));
    g2.setColor(Color.black);
    g2.drawString("00ffff",x+100,y+255);
    g2.drawString("Cyan",  x+100,y+270);
    g2.setColor(new Color(0x00, 0x80, 0x80)); //teal
    g2.fill(new Rectangle2D.Double(x+150,y+190,50,50));
    g2.setColor(Color.black);
    g2.drawString("008080",x+150,y+255);
    g2.drawString("Teal",  x+150,y+270);
    //------
    g2.setColor(new Color(0xff, 0xff, 0xff)); //white
    g2.fill(new Rectangle2D.Double(x+0,y+285,50,50));
    g2.setColor(Color.black);
    g2.drawString("ffffff",x+0,y+350);
    g2.drawString("White", x+0,y+365);
    g2.setColor(new Color(0xc0, 0xc0, 0xc0)); //silver
    g2.fill(new Rectangle2D.Double(x+50,y+285,50,50));
    g2.setColor(Color.black);
    g2.drawString("c0c0c0",x+50,y+350);
    g2.drawString("Silver",x+50,y+365);
    g2.setColor(new Color(0x80, 0x80, 0x80)); //gray
    g2.fill(new Rectangle2D.Double(x+100,y+285,50,50));
    g2.setColor(Color.black);
    g2.drawString("808080",x+100,y+350);
    g2.drawString("Gray",  x+100,y+365);
    g2.setColor(new Color(0x00, 0x00, 0x00)); //black
    g2.fill(new Rectangle2D.Double(x+150,y+285,50,50));
    g2.setColor(Color.black);
    g2.drawString("000000",x+150,y+350);
    g2.drawString("Black", x+150,y+365);
    //------
    colorMix() ;
    //------
  }

  //■パレット混色表示
  void colorMix()
  {
    if(numberInputMode == 1) //パレット色の直接数値指定
    {
      colorModifyX(tfR, tfG, tfB);
      return;
    }

    int r01 =0;
    int g01 =0;
    int b01 =0;
    int r02 =0;
    int g02 =0;
    int b02 =0;
    int r03 =0;
    int g03 =0;
    int b03 =0;
    int r04 =0;
    int g04 =0;
    int b04 =0;
    int r0X =0;
    int g0X =0;
    int b0X =0;

    if(numberInputMode == 1) //パレット色の直接数値指定
    {
      colorModifyX(tfR, tfG, tfB);
      return;
    }

    if(choiceN==1) //第一選択色
    {
      r01 = choiceC1.getRed();
      g01 = choiceC1.getGreen();
      b01 = choiceC1.getBlue();
      g2.setColor(choiceC1);
      g2.fill(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+380,50,50));

      mixColor1 = choiceC1;
      g2.setColor(mixColor1);
      g2.fill(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.drawString(getColorCode(mixColor1), x+0, y+505);
      colorModify(r01,g01,b01);
    }
    else if(choiceN==2) //第二選択色
    {
      r01 = choiceC1.getRed();
      g01 = choiceC1.getGreen();
      b01 = choiceC1.getBlue();
      r02 = choiceC2.getRed();
      g02 = choiceC2.getGreen();
      b02 = choiceC2.getBlue();
      g2.setColor(choiceC1);
      g2.fill(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(choiceC2);
      g2.fill(new Rectangle2D.Double(x+50,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+50,y+380,50,50));

      r0X = (r01 + r02)/2;
      g0X = (g01 + g02)/2;
      b0X = (b01 + b02)/2;
      mixColor1 = new Color(r0X, g0X, b0X);
      g2.setColor(mixColor1);
      g2.fill(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setFont(new Font("Serif", Font.PLAIN, 12));
      g2.setColor(Color.black);
      g2.drawString(getColorCode(mixColor1), x+0, y+505);
      colorModify(r0X,g0X,b0X);
    }
    else if(choiceN==3) //第三選択色
    {
      r01 = choiceC1.getRed();
      g01 = choiceC1.getGreen();
      b01 = choiceC1.getBlue();
      r02 = choiceC2.getRed();
      g02 = choiceC2.getGreen();
      b02 = choiceC2.getBlue();
      r03 = choiceC3.getRed();
      g03 = choiceC3.getGreen();
      b03 = choiceC3.getBlue();
      g2.setColor(choiceC1);
      g2.fill(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(choiceC2);
      g2.fill(new Rectangle2D.Double(x+50,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+50,y+380,50,50));
      g2.setColor(choiceC3);
      g2.fill(new Rectangle2D.Double(x+100,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+100,y+380,50,50));

      r0X = (int)((r01 + r02 + r03)/3);
      g0X = (int)((g01 + g02 + g03)/3);
      b0X = (int)((b01 + b02 + b03)/3);
      mixColor1 = new Color(r0X, g0X, b0X);
      g2.setColor(mixColor1);
      g2.fill(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setFont(new Font("Serif", Font.PLAIN, 12));
      g2.setColor(Color.black);
      g2.drawString(getColorCode(mixColor1), x+0, y+505);
      colorModify(r0X,g0X,b0X);
    }
    else if(choiceN==4) //第四選択色
    {
      r01 = choiceC1.getRed();
      g01 = choiceC1.getGreen();
      b01 = choiceC1.getBlue();
      r02 = choiceC2.getRed();
      g02 = choiceC2.getGreen();
      b02 = choiceC2.getBlue();
      r03 = choiceC3.getRed();
      g03 = choiceC3.getGreen();
      b03 = choiceC3.getBlue();
      r04 = choiceC4.getRed();
      g04 = choiceC4.getGreen();
      b04 = choiceC4.getBlue();
      g2.setColor(choiceC1);
      g2.fill(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+380,50,50));
      g2.setColor(choiceC2);
      g2.fill(new Rectangle2D.Double(x+50,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+50,y+380,50,50));
      g2.setColor(choiceC3);
      g2.fill(new Rectangle2D.Double(x+100,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+100,y+380,50,50));
      g2.setColor(choiceC4);
      g2.fill(new Rectangle2D.Double(x+150,y+380,50,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+150,y+380,50,50));
      r0X = (int)((r01 + r02 + r03 +r04)/4);
      g0X = (int)((g01 + g02 + g03 +g04)/4);
      b0X = (int)((b01 + b02 + b03 +b04)/4);
      mixColor1 = new Color(r0X, g0X, b0X);
      g2.setColor(mixColor1);
      g2.fill(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setColor(Color.black);
      g2.draw(new Rectangle2D.Double(x+0,y+440,100,50));
      g2.setFont(new Font("Serif", Font.PLAIN, 12));
      g2.setColor(Color.black);
      g2.drawString(getColorCode(mixColor1), x+0, y+505);
      colorModify(r0X,g0X,b0X);
    }
    f.palette.repaint();
  }

  //■混色補正と色表示
  void colorModify(int r, int g, int b)
  {
    int r01 = r+f.sliderLis.adjustR;
    if(r01 > 255) r01=255;
    else if(r01 < 0)   r01=0;

    int g01 = g+f.sliderLis.adjustG;
    if(g01 > 255) g01=255;
    else if(g01 < 0)   g01=0;

    int b01 = b+f.sliderLis.adjustB;
    if(b01 > 255) b01=255;
    else if(b01 < 0)   b01=0;

    mixColor2 = new Color(r01,g01,b01); //修正色
    g2.setColor(mixColor2);
    g2.fill(new Rectangle2D.Double(x+100,y+440,100,50));
    g2.setColor(Color.black);
    g2.draw(new Rectangle2D.Double(x+100,y+440,100,50));
    g2.setFont(new Font("Serif", Font.PLAIN, 12));
    g2.setColor(Color.black);
    g2.drawString(getColorCode(mixColor2) +
      " / " + mixColor2.getRed() + "," +
      mixColor2.getGreen() + "," + mixColor2.getBlue(),
      x+100, y+505);
  }

  //■混色なし混色補正なしで数値指定色表示
  void colorModifyX(int r, int g, int b)
  {
    mixColor2 = mixColor1 = new Color(r,g,b); //数値指定色
    g2.setColor(mixColor2);
    g2.fill(new Rectangle2D.Double(x+100,y+440,100,50));
    g2.setColor(Color.black);
    g2.draw(new Rectangle2D.Double(x+100,y+440,100,50));
    g2.setFont(new Font("Serif", Font.PLAIN, 12));
    g2.setColor(Color.black);
    g2.drawString(getColorCode(mixColor2) +
      " / " + mixColor2.getRed() + "," +
      mixColor2.getGreen() + "," + mixColor2.getBlue(),
      x+100, y+505);
    f.palette.repaint();
  }

  //■3バイトカラー・コードの取得
  String getColorCode(Color clr)
  {
    String hexR = Integer.toHexString(clr.getRed());
    String hexG = Integer.toHexString(clr.getGreen());
    String hexB = Integer.toHexString(clr.getBlue());
    if(hexR.length() == 1) hexR = "0"+ hexR;
    if(hexG.length() == 1) hexG = "0"+ hexG;
    if(hexB.length() == 1) hexB = "0"+ hexB;
    return (hexR+hexG+hexB);
  }
} //EOF (GCreatorPaletteEngine.java)

◆GCreatorToneCurveEngine.java

//■■GCreatorToneCurveEngine.java
//Ver.4.1

//■■インポート
import java.awt.*;  //必須
import java.awt.geom.*;  //必須
import java.awt.image.*;  //必須
import javax.swing.*;  //必須

//■■■描画機能の実現
class GCreatorToneCurveEngine extends JComponent
{

  //■■変数宣言
  //■メンバー変数
  GCreator f; //JFlameの継承インスタンス
  Graphics2D g2;
  BufferedImage bImageTC1; //「原画」ボタンの押下によって、先に確定済み。
  BufferedImage bImageTC2; //調色済み画像の一時保存場所。

  static int toneCurveConstant = 256;  //トーン・カーブ曲線精細度
  double[][]  interpolateXY  = new double[toneCurveConstant][2];
    //調色済みの色彩セット（３本を１本に連結、曲線描画用double型）

  //●曲線描画用変数
  //トーン・カーブ曲線のデータは、複数の曲線を一本のデータに詰め込み、
  //後に、複数の曲線に分解する。分解の手掛かりとして、命令識別番号を使用。
  //曲線の制御点は３箇所とし、制御点の増減は出来ない。
  //座標枠から曲線が食み出す指定（クリック）を行なうと、自動補正される。
  //調色作業に異常を来たした場合、「原画」のボタン押下から、やり直すこと。

  double[][] toneCurveArrX; //曲線X座標（RGB曲線毎のｘ座標点列に分解）
  double[][] toneCurveArrY; //曲線Y座標（RGB曲線毎のｙ座標点列に分解）

  BasicStroke solidLine1 = new BasicStroke(
    1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
  BasicStroke solidLine2 = new BasicStroke(
    1.5f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);

  //■コンストラクタ
  GCreatorToneCurveEngine(GCreator flame)
  {
    f = flame;
  }

  //■■変数初期化
  void setInit()
  { //●内部プログラムから呼び出される
    g2.setColor(new Color(255,255,255)); //残留画像の消去
    g2.fill(new Rectangle2D.Double(
      0,0,300,600 ));

    //トーン・カーブ相対座標枠の描画
    g2.setStroke(solidLine2);
    g2.setColor(new Color(180, 180, 180));

    g2.draw(new Rectangle2D.Double(30, 30.5, 127.5, 127.5)); //red座標枠
    g2.draw(new Line2D.Double(30, 158, 157.5, 30.5)); //基準斜線
    g2.drawString("red", 165, 50);

    g2.draw(new Rectangle2D.Double(30, 195, 127.5, 127.5)); //green座標枠
    g2.draw(new Line2D.Double(30, 323, 157.5, 195)); //基準斜線
    g2.drawString("green", 165, 225);

    g2.draw(new Rectangle2D.Double(30, 359.5, 127.5, 127.5)); //blue座標枠
    g2.draw(new Line2D.Double(30, 488, 157.5, 360.5)); //基準斜線
    g2.drawString("blue", 165, 400);

    g2.setStroke(solidLine1);
  } //setInit()

  //■■描画処理
  public void paintComponent(Graphics g)
  {
    drawPage(g);
  }

  //■１ページ分の描画（現状では、１ページ分のみ）
  void drawPage(Graphics g)
  {
    //●描画の初期対応
    g2 = (Graphics2D)g;
    setInit();  //変数初期化

    //● ヒストグラムの描画
    int[][] histogramData = getHistogramData();
    double hgX = 0;
    double hgY = 0;
    double hgW = 0;
    double hgH = 0;
    double maxValue = 0;

    if(bImageTC1 != null && histogramData != null)
    {
      for(int i=0; i<3; i++) //RGB
      {
        for(int j=0; j<32; j++) //32 blocks (256/8)
        {
           maxValue = Math.max(maxValue, histogramData[i][j]);
        }
      }

      g2.setColor(new Color(180, 180, 180));
      for(int i=0; i<32; i++) //red
      {
        hgX = 30 + i*4;
        hgY = 158 - (double)histogramData[0][i]/maxValue*127.5D;
        hgW = 3;
        hgH = (double)histogramData[0][i]/maxValue*127.5D;
        g2.fill(new Rectangle2D.Double(hgX, hgY, hgW, hgH));
      }
      for(int i=0; i<32; i++) //green
      {
        hgX = 30 + i*4;
        hgY = 323 - (double)histogramData[1][i]/maxValue*127.5D;
        hgW = 3;
        hgH = (double)histogramData[1][i]/maxValue*127.5D;
        g2.fill(new Rectangle2D.Double(hgX, hgY, hgW, hgH));
      }
      for(int i=0; i<32; i++) //blue
      {
        hgX = 30 + i*4;
        hgY = 488 - (double)histogramData[2][i]/maxValue*127.5D;
        hgW = 3;
        hgH = (double)histogramData[2][i]/maxValue*127.5D;
        g2.fill(new Rectangle2D.Double(hgX, hgY, hgW, hgH));
      }
    }
    repaint();

    //● トーン・カーブの描画

    for(int i=0; toneCurveArrX != null && i<toneCurveArrX.length; i++) //RGB３本
    { //● 目印を先行描画
      interpolateXY =
        new Spline3(toneCurveArrX[i], toneCurveArrY[i], toneCurveConstant).getInterpolateXY();
      for(int j=1; toneCurveArrX[i] != null && j<toneCurveArrX[i].length; j++)
      {
        for(int k=1; k<interpolateXY.length; k++)
        { //▼トーン・カーブ曲線の描画
          if(i==0) //red
          {
            drawPointMark(toneCurveArrX[i][j-1]+30, 158-toneCurveArrY[i][j-1]); //目印
            drawPointMark(toneCurveArrX[i][j]+30,   158-toneCurveArrY[i][j]);
          }
          else if(i==1) //green
          {
            drawPointMark(toneCurveArrX[i][j-1]+30, 323-toneCurveArrY[i][j-1]);
            drawPointMark(toneCurveArrX[i][j]+30,   323-toneCurveArrY[i][j]);
          }
          else if(i==2) //blue
          {
            drawPointMark(toneCurveArrX[i][j-1]+30, 488-toneCurveArrY[i][j-1]);
            drawPointMark(toneCurveArrX[i][j]+30,   488-toneCurveArrY[i][j]);
          }
        }
      }
    }

    for(int i=0; toneCurveArrX != null && i<toneCurveArrX.length; i++) //RGB３本
    { //● 曲線を後続描画
      interpolateXY =
        new Spline3(toneCurveArrX[i], toneCurveArrY[i], toneCurveConstant).getInterpolateXY();
      for(int j=1; toneCurveArrX[i] != null && j<toneCurveArrX[i].length; j++)
      {
        //（注）トーン・カーブ曲線は、短い直線を多数連結した「疑似曲線」として描画。
        //スプライン補間処理したデータによる「疑似曲線」描画。
        for(int k=1; k<interpolateXY.length; k++)
        { //▼トーン・カーブ曲線の描画
          if(i==0) //red
          {
            if(interpolateXY[k][1] > 127.5)
              interpolateXY[k][1] = 127.5; //補正
            else if(interpolateXY[k][1] < 0)
              interpolateXY[k][1] = 0; //補正

            if(interpolateXY[0][1] < 0)
              interpolateXY[0][1] = 0; //補正
            if(interpolateXY[255][1] > 127.5)
              interpolateXY[255][1] = 127.5; //補正

            g2.setColor(new Color(255,0,0));
            g2.draw(new Line2D.Double(
              interpolateXY[k-1][0]+30, 158-interpolateXY[k-1][1],
              interpolateXY[k][0]+30, 158-interpolateXY[k][1]));
          }
          else if(i==1) //green
          {
            if(interpolateXY[k][1] > 127.5)
              interpolateXY[k][1] = 127.5; //補正
            else if(interpolateXY[k][1] < 0)
              interpolateXY[k][1] = 0; //補正

            if(interpolateXY[0][1] < 0)
              interpolateXY[0][1] = 0; //補正
            if(interpolateXY[255][1] > 127.5)
              interpolateXY[255][1] = 127.5; //補正

            g2.setColor(new Color(0,255,0));
            g2.draw(new Line2D.Double(
              interpolateXY[k-1][0]+30, 323-interpolateXY[k-1][1],
              interpolateXY[k][0]+30, 323-interpolateXY[k][1]));
          }
          else if(i==2) //blue
          {
            if(interpolateXY[k][1] > 127.5)
              interpolateXY[k][1] = 127.5; //補正
            else if(interpolateXY[k][1] < 0)
              interpolateXY[k][1] = 0; //補正

            if(interpolateXY[255][1] > 127.5)
              interpolateXY[255][1] = 127.5; //補正
            if(interpolateXY[0][1] < 0)
              interpolateXY[0][1] = 0; //補正

            g2.setColor(new Color(0,0,255));
            g2.draw(new Line2D.Double(
              interpolateXY[k-1][0]+30,488-interpolateXY[k-1][1],
              interpolateXY[k][0]+30,488-interpolateXY[k][1]));
          }
        }
      }
    }
  } //drawPage()の終了

  //■曲線の起点、中間点、終点の目印描画
  void drawPointMark(double x, double y) //
  {
    g2.setColor(new Color(0,0,0));
    g2.setStroke(solidLine2);

    g2.draw(new Ellipse2D.Double(x-3, y-3, 6, 6));
    g2.setStroke(solidLine1);
  }

  //■標準コマンドの自動入力
  void setStandardCommands()
  {
    f.cArea.setText("");
    f.cArea.append( //red
      "ToneCurveStart(0,0); //red\n" +
      "ToneCurveControl(31.875,31.875); //red\n" +
      "ToneCurveControl(63.75,63.75); //red\n" +
      "ToneCurveControl(95.625,95.625); //red\n" +
      "ToneCurveEnd(127.5,127.5); //red\n"   +
      "//\n" );

    f.cArea.append( //green
      "ToneCurveStart(0,0); //green\n" +
      "ToneCurveControl(31.875,31.875); //green\n" +
      "ToneCurveControl(63.75,63.75); //green\n" +
      "ToneCurveControl(95.625,95.625); //green\n" +
      "ToneCurveEnd(127.5,127.5); //green\n"   +
      "//\n" );

    f.cArea.append( //blue
      "ToneCurveStart(0,0); //blue\n" +
      "ToneCurveControl(31.875,31.875); //blue\n" +
      "ToneCurveControl(63.75,63.75); //blue\n" +
      "ToneCurveControl(95.625,95.625); //blue\n" +
      "ToneCurveEnd(127.5,127.5); //blue\n"   +
      "//\n" );
  }

  //■色彩変更
  BufferedImage changeColorTC()
  { //bImageTC1は、「原画」ボタンの押下で、既に画像がロードされ確定している。

    //操作では、「メニュー」で「トーン・カーブ表示」の画面に切り替える。
    //「原画」ボタン押下、マウスで「曲線変更」、「調色」ボタン押下、の順で操作。
    //好み通りに調色が完了すれば、「終了」ボタン押下。

    if(bImageTC1 == null)
    {
      return null;
    }
    int w = bImageTC1.getWidth(); //原画のサイズ
    int h = bImageTC1.getHeight();
    bImageTC2 = new BufferedImage( //調色済み新画像
      w, h, BufferedImage.TYPE_INT_RGB); //不透明に設定

    //トーン・カーブ画像全体をスキャンしながら、トーン・カーブに従って色彩変換を行なう。

    int[] redNewValue   = new int[256];//色彩変換表の準備
    int[] greenNewValue = new int[256];
    int[] blueNewValue  = new int[256];
    BufferedImage imageTC = f.io.compImage2BufferedImage(this, 0, 0, 300, 600);
    if(imageTC == null)
    { //トーン・カーブの表示領域全体のピクセル画像
      f.message("トーン・カーブの取得に失敗しました。");
      return null;
    }

    for(int x=30,c=0; x<30+128; x++,c++) //cは、色彩成分の値
    { //色彩変換表の作成
      for(int y=0; y<600; y++)
      {
        int rgbTC   = imageTC.getRGB(x, y); //トーン・カーブ図のピクセル色
        if(rgbTC == 0xffff0000) //赤線部を発見 （最上位部はffになっている）
        {
          redNewValue[c*2]   = (158 - y)*2; //２倍で等倍に復元
          redNewValue[c*2+1] = (158 - y)*2;

          if(redNewValue[c*2] < 0) //曲線座標位置計測誤差の修正（y軸）
          {
            redNewValue[c*2]   = 0;
            redNewValue[c*2+1] = 0;
          }
          if(redNewValue[c*2] > 255)
          {
            redNewValue[c*2]   = 255;
            redNewValue[c*2+1] = 255;
          }
        }
        if(rgbTC == 0xff00ff00) //緑線部を発見（最上位部はffになっている）
        {
          greenNewValue[c*2]   = (323 - y)*2;
          greenNewValue[c*2+1] = (323 - y)*2;

          if(greenNewValue[c*2] < 0) //曲線座標位置計測誤差の修正（y軸）
          {
            greenNewValue[c*2]   = 0;
            greenNewValue[c*2+1] = 0;
          }
          if(greenNewValue[c*2] > 255)
          {
            greenNewValue[c*2]   = 255;
            greenNewValue[c*2+1] = 255;
          }
        }
        if(rgbTC == 0xff0000ff) //青線部を発見（最上位部はffになっている）
        {
          blueNewValue[c*2]   = (488 - y)*2;
          blueNewValue[c*2+1] = (488 - y)*2;

          if(blueNewValue[c*2] < 0) //曲線座標位置計測誤差の修正（y軸）
          {
            blueNewValue[c*2]   = 0;
            blueNewValue[c*2+1] = 0;
          }
          if(blueNewValue[c*2] > 255)
          {
            blueNewValue[c*2]   = 255;
            blueNewValue[c*2+1] = 255;
          }
        }
      }
    }

    int rgbOldValue   = 0;
    int redOldValue   = 0;
    int greenOldValue = 0;
    int blueOldValue  = 0;
    for(int y=0; y<h; y++)
    { //色彩変換作業（色彩変換表を利用）
      for(int x=0; x<w; x++)
      {
        rgbOldValue    = bImageTC1.getRGB(x, y);
        redOldValue    = (0x00ff0000 & rgbOldValue) >>> 16;
        greenOldValue  = (0x0000ff00 & rgbOldValue) >>> 8;
        blueOldValue   = (0x000000ff & rgbOldValue);

        bImageTC2.setRGB(x, y, 0xff000000 | redNewValue[redOldValue]<<16 |
          greenNewValue[greenOldValue]<<8 | blueNewValue[blueOldValue]);
      }
    }
    f.canvas.toneCurveFlag = true;
    return bImageTC2;
  }

  //■ヒストグラム・データの取得
  int[][] getHistogramData()
  { //bImageTC1は、「原画」ボタンの押下で、既に画像がロードされ確定している。
    if(bImageTC1 == null)
    {
      return null;
    }
    int w = bImageTC1.getWidth(); //元画像のサイズ
    int h = bImageTC1.getHeight();
    int rgbValue   = 0;
    int redValue   = 0;
    int greenValue = 0;
    int blueValue  = 0;

    int[][] histogramData = new int[3][256/8];

    for(int y=0; y<h; y++)
    { //原画からピクセル単位でRGB成分を抽出し、RGB別かつ濃度階級別に分類し集計する。
      //RGB成分における近似した数値を１ブロックとし、３２階級（256/8）に分ける。
      //これによって、光の濃度別の分布統計表が得られる。
      //ヒストグラムは、RGB別の棒グラフ形式になっていて、棒が右側であるほど、
      //光の強いピクセルであることを意味し、棒が上に高く伸びていれば、
      //その明るさのピクセル数が多いことを意味する。
      //ただし、RGB別に分解されているため、棒と色彩とが直ちに対応するわけではない。
      //ヒストグラムは、調色曲線を調整するための目安に過ぎず、
      //出来上がる色彩を予想しての曲線調整は困難で、あれこれと試行錯誤が必要になる
      //ヒストグラムの棒が長い濃度位置の調色曲線を集中的に操作すれば、効果が大きい。

      for(int x=0; x<w; x++)
      {
        rgbValue    = bImageTC1.getRGB(x, y);
        redValue    = (0x00ff0000 & rgbValue) >>> 16;
        greenValue  = (0x0000ff00 & rgbValue) >>> 8;
        blueValue   = (0x000000ff & rgbValue);

        histogramData[0][redValue/8]   = histogramData[0][redValue/8] +1; //カウント
        histogramData[1][greenValue/8] = histogramData[1][greenValue/8] +1;
        histogramData[2][blueValue/8]  = histogramData[2][blueValue/8] +1;
      }
    }
    return histogramData;
  }
} //EOF (GCreatorToneCurveEngine.java)

◆GCreatorPrintEngine.java

//■■GCreatorPrintEngine.java
//Ver.4.1

//■■インポート
import java.awt.*;  //必須
import java.awt.print.*;  //必須
import javax.print.attribute.*;  //必須
import javax.print.attribute.standard.*;  //必須

//■■印刷実行処理
class GCreatorPrintEngine
{
  //■メンバー変数
  GCreator f;
  double printerMarginX = 3.0; //プリンター機種依存のマージン調整(mm単位)
  double printerMarginY = 3.0; //プリンター機種依存のマージン調整

  //■コンストラクタ
  GCreatorPrintEngine(GCreator flame)
  {
    f = flame;
  }

  //■印刷開始要求の受付け
  void start()
  {
    //●ディスプレイ表示倍率の保存
    double scale = f.canvas.affineScale; //元の数値を保存

    //●画像サイズ倍率調整
    float bt = 0.949f;//倍率調整
    f.canvas.affineScale = bt; //一時的に変更
    //1mm=2.8457point
    //画面表示倍率=3 (1mm=3pxに設定)
    //2.8457÷3 ≒ 0.949

    //●印刷制御オブジェクト
    PrinterJob pj = PrinterJob.getPrinterJob();

    //●用紙書式設定オブジェクト
    PageFormat fmt = new PageFormat();

    //●用紙情報格納オブジェクト
    Paper paper = new Paper();

    //●印刷制御オブジェクトに要件設定
    PrintOnePage printable = new PrintOnePage();

    if(f.canvas.rotateFlag == false)
    { //●90度回転なし
      paper.setImageableArea(0,0,
        f.canvas.printMM_W *bt, f.canvas.printMM_H *bt);
    }
    else
    { //●90度回転あり
      paper.setImageableArea(0,0,
        (int)(f.canvas.printMM_H *bt), (int)(f.canvas.printMM_W *bt));
    }
    fmt.setPaper(paper);

    //●余白設定
    PrintRequestAttributeSet reqAtt =
      new HashPrintRequestAttributeSet();
    float topMgn    = 0.0f;  //余白なしを設定
    float bottomMgn = 0.0f;
    float leftMgn   = 0.0f;
    float rightMgn  = 0.0f;
    if(f.canvas.rotateFlag == false) //●回転なし
    {
      reqAtt.add(new MediaPrintableArea(leftMgn, topMgn,
      ((float)f.canvas.printMM_W *bt - leftMgn - rightMgn),
      ((float)f.canvas.printMM_H *bt - topMgn - bottomMgn),
      MediaPrintableArea.MM));
    }
    else //●90度回転あり
    {
      reqAtt.add(new MediaPrintableArea(leftMgn, topMgn,
      ((float)f.canvas.printMM_H *bt - topMgn - bottomMgn),
      ((float)f.canvas.printMM_W *bt - leftMgn - rightMgn),
      MediaPrintableArea.MM));
    }
    reqAtt.add(OrientationRequested.PORTRAIT);
    pj.setPrintable(new PrintOnePage());

    //●印刷開始
    try
    {  //Printable.print(...)にページ毎に描画要求（複数ページには非対応）
      if (pj.printDialog()) //印刷開始のダイアログ・ボックス
        pj.print(reqAtt); //印刷開始
    }
    catch(Exception e)
    {
      f.message("印刷実行エラー："+e);
    }

    //●倍率をディスプレイ表示用に戻す
    f.canvas.affineScale = scale;
  }

  //■残ページ判定（複数ページには非対応）
  boolean hasMorePages(int page)
  {
    if(f.canvas.pages <= page)
      return false;
    else
      return true;
  }

  //■印刷イメージの描画（
  //PrinterJobの管理下で機能するPrintableの実装
  class PrintOnePage implements Printable
  {
    public int print(Graphics g, PageFormat fmt,
      int pageIndex) //指定ページ描画（複数ページには非対応）
    { //指定ページ描画
      if(hasMorePages(pageIndex))
      { //未処理ページがあれば（複数ページには非対応）
        Graphics2D g2 = (Graphics2D)g;
        g2.translate(fmt.getImageableX()-printerMarginX,
          fmt.getImageableY()-printerMarginY);
        //描画は外部委託
        f.canvas.drawPage(g,true);
        //該当ページ印刷実行合図返却
        return Printable.PAGE_EXISTS;
      }
      else
      { //印刷完了による停止合図返却
        return Printable.NO_SUCH_PAGE;
      }
    }
  }
} //EOF (GCreatorPrintEngine.java)

◆GCreatorFileIO.java

//■■GCreatorFileIO.java
//Ver.4.1

//■■インポート
import javax.swing.*;  //必須
import javax.swing.text.*;  //必須
import java.io.*;  //必須
import java.awt.*;  //必須
import java.awt.image.*;  //必須
import java.util.*;  //必須
import javax.imageio.*;  //必須
import javax.imageio.stream.ImageOutputStream;  //必須
import javax.swing.filechooser.FileNameExtensionFilter; //必須

//■■テキストおよび画像入出力
class GCreatorFileIO
{
  //■メンバー変数
  GCreator f;
  GCreatorCanvasEngine can;

  //■コンストラクタ
  GCreatorFileIO(GCreator flame)
  {
    f = flame;
    can = f.canvas;
  }

  //■テキスト・ファイルからJTextAreaに読み込む
  void load(JTextArea tArea, String dir, String ext)
  {
    File file = TextIO.callFileChooser("open", f.pane, dir, ext);
    if(file == null)
    { //ファイルがない場合
      return;
    }
    try
    {
      FileReader reader = new FileReader(file);
      try
      {
        tArea.read(reader,new PlainDocument());
      }
      catch(IOException e)
      {
        f.message("リードエラー："+e);
      }
      reader.close();
    }
    catch(FileNotFoundException e)
    {
      f.message("オープンエラー："+e);
    }
    catch(IOException e)
    {
      f.message("クローズエラー："+e);
    }
  }

  //■JTextAreaからテキスト・ファイルに書き込む
  void save(JTextArea tArea, String dir, String ext)
  {
    File file = TextIO.callFileChooser("save", f.pane, dir, ext);
    if(file == null)
    { //ファイルがない場合
      return;
    }
    try
    {
      FileWriter writer = new FileWriter(file);
      try
      {
        String str = tArea.getText().trim();
        if(str.equals(""))
          f.message("データなし。書き込み回避");
        else
          writer.write(str);
      }
      catch(IOException e)
      {
        f.message("ライトエラー："+e);
      }
      writer.close();
      f.message(file.getName()+" を書き込みました。");
    }
    catch(FileNotFoundException e)
    {
      f.message("オープンエラー："+e);
    }
    catch(IOException e)
    {
      f.message("クローズエラー："+e);
    }
  }

  //■JTextAreaからテキスト・ファイルに書き込む（ファイル名事前指定）
  void save(JTextArea tArea, String fName)
  { //fNameは、パス付き
    try
    {
      FileWriter writer = new FileWriter(fName);
      try
      {
        String str = tArea.getText().trim();
        if(str.equals(""))
          f.message("データなし。書き込み回避。");
        else
          writer.write(str);
      }
      catch(IOException e)
      {
        f.message("ライトエラー："+e);
      }
      writer.close();
      f.message(fName + " を書き込みました。");
    }
    catch(FileNotFoundException e)
    {
      f.message("オープンエラー："+e);
    }
    catch(IOException e)
    {
      f.message("クローズエラー："+e);
    }
  }

  //■画像ファイル入力（jpeg,gif,png,bmp 使用可能）
  //Image命令またはStamp命令として画像を導入する。
  BufferedImage loadGraphics(int mode)
  {
    BufferedImage bImage = null;
    JFileChooser fileChooser = new JFileChooser("./");
    FileNameExtensionFilter filter = new FileNameExtensionFilter(
        "Images:png,jpeg,gif,bmp", "png","jpeg","jpg", "gif","bmp");
    fileChooser.setFileFilter(filter);
    int ret = fileChooser.showOpenDialog(f.pane);
    File file = fileChooser.getSelectedFile();
    if(ret != JFileChooser.APPROVE_OPTION || file == null)
    { //OKボタンが押されなかったか、ファイルがない場合
      return null;
    }
    String path = file.getPath();
    String fileName = file.getName();
    String extension = fileName.substring(
      fileName.indexOf(".")+1,fileName.length());
    extension = extension.toLowerCase();
    if(!(extension.equals("jpeg") || extension.equals("jpg") ||
       extension.equals("gif")  || extension.equals("png") ||
       extension.equals("bmp")))
    {
      path = path.replace('\\', '/');
      f.message(path + ":画像ファイルではありません。");
      return null;
    }
    try
    {
      bImage = ImageIO.read(file);
    }
    catch (Exception e)
    {
      e.printStackTrace();
      f.message("画像ファイル読み込みエラー：" +fileName);
      return null;
    }
    int w = bImage.getWidth(can);
    int h = bImage.getHeight(can);
    String pathX = path.toLowerCase();
    if(pathX.indexOf("c:\\user\\java\\gcreator") != -1)
    { //絶対パスを相対パスに変換する。
      //バッチ・ファイルで、事前にカレント・ディレクトリーを設定しておく。
      path = "." + path.substring(21,path.length());
      path = path.replace('\\', '/');
    }
    if(mode ==0) //背景画像
    { //位置やサイズは、標準の設定
      f.cArea.append("Image(0,0," + w + "," + h + ",\"" +
        path + "\");\n");
      path = path.replace('\\', '/');
      f.mArea.append(path + ": " +w +" x " +h +" pixcels\n");
    }
    else if(mode ==1) //前景画像（スタンプ画像）
    { //位置やサイズは、標準の設定
      f.cArea.append("Stamp(0,0," + w + "," + h + ",\"" +
        path + "\");\n");
      path = path.replace('\\', '/');
      f.mArea.append(path + ": " +w +" x " +h +" pixcels\n");
    }
    else if(mode ==2) //トーン・カーブ調色の元画像
    { //
      f.cArea.append("Size(" + w + "," + h + ");\n");
      path = path.replace('\\', '/');
      f.cArea.append("Image(" + 0 + ",0," + w + "," + h + ",\"" +
        path + "\");\n");  //色彩変換後の画像
      f.cArea.append("Image(" + (w+10) + ",0," + w + "," + h + ",\"" +
        path + "\");\n"); //色彩変換前の画像
      String ext = ".png"; //出力画像ファイルの拡張子は、強制的に「png」にする。
      String[] baseName; //パス付きベース・ネーム
      if(path.endsWith(".png"))
        baseName = path.split(".png", 2);
      else if(path.endsWith(".jpeg"))
        baseName = path.split(".jpeg", 2);
      else if(path.endsWith(".jpg"))
        baseName = path.split(".jpg", 2);
      else if(path.endsWith(".gif"))
        baseName = path.split(".gif", 2);
      else if(path.endsWith(".bmp"))
        baseName = path.split(".bmp", 2);
      else
        baseName = null;
      f.cArea.append("SaveImage(" + "\"" + baseName[0] + "TC" + ext + "\"" + ");\n"); //png画像保存
      f.mArea.append(path + ": " +w +" x " +h +" pixcels\n");
      f.canvas.repaint();
      return bImage;
    }
    return bImage;
  }

  //■画像ファイル出力（png,gif,jpeg,bmp が使用可能）
  //GCreatorでは、「png」や「gif」での保存を推奨し、「jpeg」や「bmp」での保存を推奨しない。
  //キャンバスの全体画像（一般用）または部分画像（特殊用）のファイル保存を行なう。
  void saveGraphics(File _file, int imageX, int imageY, int imageW, int imageH)
  {
    //●キャンバス画像のBufferedImageに変換する準備
    //画像を部分的に切り取る場合にも対応するための準備
    can.canSaveMode = true; //グラフィック保存モードにする。
    can.repaint(); //十字線などの余分な目印表示を再描画により消去。

    BufferedImage bImage1 = null; //（全体画像または部分画像）

    bImage1 = compImage2BufferedImage(can, imageX, imageY, imageW, imageH);
    if(bImage1 == null)
      f.message("キャンバス画像の取得に失敗。");

    //●画像ファイル出力の準備（出力ファイル名の取得）
    String path;
    String fileName;
    String extension;
    if(_file==null)//●一般使用（ファイル名が不明の場合）
    {
      JFileChooser fileChooser = new JFileChooser("./");
      FileNameExtensionFilter filter = new FileNameExtensionFilter(
        "Images:png,jpeg,gif,bmp", "png","jpeg","jpg", "gif","bmp");
      fileChooser.setFileFilter(filter);
      int ret = fileChooser.showSaveDialog(f.pane);
      File file = fileChooser.getSelectedFile();
      if(ret != JFileChooser.APPROVE_OPTION || file == null)
      { //OKボタンが押されなかったか、ファイルがない場合
        return;
      }
      path = file.getPath();
      fileName = file.getName();
      extension = fileName.substring(
        fileName.indexOf(".")+1,fileName.length());
    }
    else //●特殊使用（ファイル名が既知の場合）
    {
      path = _file.getPath();
      fileName = _file.getName();
      extension = fileName.substring(
        fileName.indexOf(".")+1,fileName.length());
    }

    //●jpeg 画質指定した（標準画質指定の「-1.0f」以外）の画像ファイル出力。
    //jpeg画質指定は、必要な時だけのオプションである。
    //標準画質指定の「-1.0f」は、GCreatorでの独自ルール。
    //jpegで画質指定する時は、「0」から「1.0」の範囲でなければならない。
    //写真などのグラデーションのある画像の場合に使用。
    Iterator writers = ImageIO.getImageWritersBySuffix(extension);
    extension = extension.toLowerCase();
    if(writers.hasNext() && (can.quality != -1.0f) &&
       (extension.equals("jpeg") || extension.equals("jpg")))
    {
      ImageWriter writer = (ImageWriter)writers.next();
      try
      {
        ImageOutputStream stream
          = ImageIO.createImageOutputStream(new File(path));
        writer.setOutput(stream);
        ImageWriteParam param = writer.getDefaultWriteParam();
        if (param.canWriteCompressed()) //圧縮できるか
        {
          param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
          param.setCompressionQuality(can.quality); //画質の指定
        }
        else
        {
          path = path.replace('\\', '/');
          f.message(path+ "：圧縮できない");
        }
        writer.write(null, new IIOImage(bImage1, null, null), param);
        writer.dispose();
        stream.close();
        path = path.replace('\\', '/');
        f.message(path+ "：画像ファイル出力  画質=" + can.quality);
      }
      catch (IOException e)
      {
        e.printStackTrace();
        path = path.replace('\\', '/');
        f.message(path+ "：画像保存失敗");
      }
      finally
      {
        can.canSaveMode = false;
      }
    }
    else
    { //●標準画質での画像ファイル出力（png,gif,標準画質jpeg,bmp）。
      //画質指定のない標準画質のjpegも、ここで処理する。
      //jpegの標準画質は、Javaによって事前設定されている。
      //GCreatorでの画像ファイル出力では、一般的に、「png」を推奨。
      //色数少ない単純な画像であり、特別に有利になる場合に限り、「gif」を推奨。
      //「jpeg」は、不可逆の画像圧縮の結果、最高画質でも画質が荒れるため、非推奨。
      //「bmp」は、ファイル・サイズが巨大になるため、非推奨。
      try
      {
        if(f.buttonLis.cutAndSaveFlag == false)
        {
          ImageIO.write(bImage1, extension, new File(path));
          path = path.replace('\\', '/');
          f.message(path+ "：全体画像ファイル出力");
        }
        else
        {
          ImageIO.write(bImage1, extension, new File(path));
          path = path.replace('\\', '/');
          f.message(path+ "：部分画像ファイル出力");
        }
      }
      catch (Exception e)
      {
        e.printStackTrace();
        path = path.replace('\\', '/');
        f.message(path+ "：画像保存失敗");
      }
      finally
      {
        can.canSaveMode = false;
      }
    }
  }

  //■JComponent画像（ベクター画像）をBufferedImage画像（ラスター画像）に変換
  BufferedImage compImage2BufferedImage(
    Component comp, int imageX, int imageY, int imageW, int imageH)
  {
    if(comp == can)
      can.canSaveMode = true; //グラフィック保存モード
    comp.repaint();
    //●イメージの取得
    //JComponentのImage を取得して、 BufferedImage に転換する準備
    Image image1  = comp.createImage(imageX+imageW, imageY+imageH); //イメージ・オブジェクト生成
    //image1は、既存画像の全域（切り取り部分画像ではない）。

    MediaTracker tracker = new MediaTracker(new Component(){});
    //trackerは、メディア・オブジェクトのステータスを追跡。
    tracker.addImage(image1, 1); //1は、識別ID番号（この場合、後で使用しない）
    try
    {
      tracker.waitForAll(); //イメージのロードを開始
    }
    catch(InterruptedException e)
    {
      System.err.println("イメージのロードに失敗");
      if(comp == can)
        can.canSaveMode = false;
      return null;
    }
    //●オフスクリーン・バッファを取得し、これに描画する。
    //オフスクリーン・バッファとは、画面に描画される前の
    //背後にある隠れた画像記憶領域のこと。
    comp.update(image1.getGraphics());

    PixelGrabber pixelGrabber =
      new PixelGrabber(image1, imageX, imageY, imageW, imageH, false);
      //new PixelGrabber(image1, 0, 0, -1, -1, false); これで画像全体を範囲指定できる。
      //new PixelGrabber(image1, 0, 0, w, h, false); としても可。
      //ここでは、部分切り取り画像の処理もできるようにしている。
      //PixelGrabber は、矩形の領域を部分的に切り出すクラス。
      //PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB)の形式。
      //画像の幅丈の指定に-1を用いれば、デフォルトの数値を用いる指定。
      //forceRGBは、trueにすればRGB形式の強制（この場合、不適切）になり、
      //falseにすればイメージ・プロデューサー（OS依存）のカラーモデルに委ねる。
    if(pixelGrabber == null)
      System.err.println("PixelGrabberの取得に失敗。");
    try
    {
      pixelGrabber.grabPixels(); //ピクセル取得
    }
    catch(InterruptedException e)
    {
      System.err.println("ピクセル取得エラー");
      if(comp == can)
        can.canSaveMode = false;
      return null;
    }
    if((pixelGrabber.status() & ImageObserver.ABORT) != 0)
    {
      System.err.println("ピクセル取得エラー");
      if(comp == can)
        can.canSaveMode = false;
      return null;
    }
    //●ColorModel, WritableRaster を取得
    ColorModel cModel = pixelGrabber.getColorModel();//カラー・モデル取得
    if(cModel == null)
      System.err.println("ColorModelの取得に失敗。");
    int pgW = pixelGrabber.getWidth();  //切り出し領域の幅
    int pgH = pixelGrabber.getHeight(); //切り出し領域の丈
    if(pgW==0 || pgH==0)
      System.err.println("画像の幅または丈が、ゼロ");
    WritableRaster wRaster =
      cModel.createCompatibleWritableRaster(pgW, pgH);
    BufferedImage bImage1 = new BufferedImage( //新規のBufferedImageを作成
      cModel, wRaster, cModel.isAlphaPremultiplied(), new Hashtable());

    //●ピクセル・データをＯＳのカラー・モデルに合うように加工
    if(pixelGrabber.getPixels() instanceof int[])
    {
      int[] intPixels = (int[])pixelGrabber.getPixels();
      try
      {
        bImage1.getRaster().setDataElements(0, 0, imageW, imageH, intPixels); //******要注意
        //ラスターとは、整数単位での二次元座標空間（画像データ格納）での
        //ピクセル画像のこと
      }
      catch (Exception e)
      {
        System.err.println("ピクセル画像の取得に失敗しました。");
        return null;
      }
    }
    else
    {
      System.err.println("エラー: pixelGrabber.getPixels()において");
      if(comp == can)
        can.canSaveMode = false;
      return null;
    }
    if(comp == can)
      can.canSaveMode = false;
    return bImage1;
  }

} //EOF (GCreatorFileIO.java)

◆GCreatorMenuLis.java

//■■GCreatorMenuLis.java
//Ver.4.1

//■■インポート
import java.awt.event.*;  //必須
import javax.swing.*;  //必須
import java.io.*;  //必須

//■■JMenuItemのイベントリスナー
class GCreatorMenuLis implements ActionListener
{
  //■メンバー変数
  GCreator f;

  //■コンストラクタ
  GCreatorMenuLis(GCreator flame)
  {
    f = flame;
  }

  //■JMenuItemのイベントハンドラ
  public void actionPerformed(ActionEvent event)
  {
    String com = event.getActionCommand();

    if(com.equals("LoD"))
    {  //●命令文の読み込み
      f.io.load(f.cArea, "./", "gcc");
      init(); //完全初期化
    }
    else if(com.equals("SaD"))
    {  //●命令文の保存
      f.canvas.setInit();  //一般初期化のみ
      f.io.save(f.cArea, "./", "gcc");
    }
    else if(com.equals("LoI"))
    {  //●背景画像読み込み
      f.io.loadGraphics(0);
      init();
    }
    else if(com.equals("Stm"))
    {  //●スタンプ画像読み込み
      f.io.loadGraphics(1);
      init();
    }
    else if(com.equals("Sa2"))
    {  //●画像保存
      f.canvas.markFlag = false; //目印線消去
      f.canvas.setInit();  //一般初期化のみ
      f.io.saveGraphics(null, 0, 0,  //画像全体を指定
        (int)(f.canvas.imagePX_W*f.canvas.affineScale*f.canvas.freeScale),
        (int)(f.canvas.imagePX_H*f.canvas.affineScale*f.canvas.freeScale));
    }
    else if(com.equals("Pri"))
    {  //●画像印刷
      f.canvas.setInit();  //一般初期化のみ
      f.canvas.markFlag = false; //目印線消去
      f.printer.start();
    }
    else if(com.equals("Cl2"))
    {  //●命令文消去
      f.cArea.setText("");
      init();  //完全初期化
    }
    else if(com.equals("Cl3"))
    {  //●警告文消去
      f.mArea.setText("");
    }
    else if(com.equals("Cl4"))
    {  //●全消去
      f.cArea.setText("");
      f.mArea.setText("");
      init();  //完全初期化
    }

    else if(com.equals("FrS"))
    {  //●各種図形描画
      String cmd =
        """
        //各種図形描画
        Size(\"A4\");
        LineWidth(1.5);
        WriteStringH(40,30,20,"sansserif","各種図形描画");
        DrawLine(43,126,292,46);
        WriteStringH(113,82,16,"sansserif","直線");
        DrawCircle(3,64,193,40,214,214,230);
        WriteStringH(110,216,16,"sansserif","真円");
        DrawEllipse(3,225,146,70,34,248,224,237);
        WriteStringH(263,193,16,"sansserif","楕円");
        DrawRect(3,87,256,153,73,214,231,216);
        WriteStringH(253,304,16,"sansserif","長方形");
        DrawShapeStart(4,61,406,223,218,234);
        DrawShapeLine(134,369);
        DrawShapeCurve(214,359,247,379,255,467);
        DrawShapeLine(202,479);
        DrawShapeCurve(110,406,113,499,30,449);
        DrawShapeEnd();
        WriteStringH(264,449,16,"sansserif","自由図形");
        WriteStringH(325,71,16,"sansserif","ベジェ曲線");
        DrawCurve(404,100,449,24,555,28,598,79);
        WriteStringH(342,90,15,"sansserif","Ｕ字型");
        DrawCurve(400,155,453,85,543,186,583,104);
        WriteStringH(323,135,15,"sansserif","ベジェ曲線");
        WriteStringH(339,155,15,"sansserif","Ｓ字型");
        DrawCurve(432,290,602,210,400,184,501,294);
        WriteStringH(334,243,15,"sansserif","ベジェ曲線");
        WriteStringH(357,261,15,"sansserif","ループ型");
        DrawSplineStart(367,347);
        DrawSplineControl(419,316);
        DrawSplineControl(466,334);
        DrawSplineControl(529,391);
        DrawSplineControl(572,390);
        DrawSplineControl(602,360);
        DrawSplineControl(526,331);
        DrawSplineEnd(458,371);
        WriteStringH(373,394,15,"sansserif","スプライン曲線");
        LinkedLineStart(372,445);
        LinkedLineNext(422,427);
        LinkedLineNext(471,452);
        LinkedLineNext(519,494);
        LinkedLineNext(562,495);
        LinkedLineNext(596,459);
        LinkedLineNext(519,441);
        LinkedLineEnd(459,494);
        WriteStringH(379,477,15,"sansserif","折れ線");
        """;
      f.cArea.setText(cmd);
      f.canvas.markFlag = true;
      init();
    }
    else if(com.equals("SpD"))
    {  //●スプレー描画
      String cmd =
        """
        //スプレー描画
        //以下は、円筒型分布：均等分布
        Size(500,500);
        SprayStart(100, 100, 0, 1.0, 25, 1000, 220, 110, 60, 255);
        SprayNext(150,100);
        SprayNext(200,100);
        SprayNext(250,100);
        SprayNext(270,100);
        SprayEnd(290,100);
        //以下は、ベル型分布：正規分布
        SprayStart(100, 200, 1, 1.0, 25, 1000, 20, 110, 60, 255);
        SprayNext(150,200);
        SprayNext(200,200);
        SprayNext(250,200);
        SprayNext(270,200);
        SprayEnd(290,200);
        SprayGaussianOp(0.5);
        //以下は、円錐型分布：集中分布
        SprayStart(100, 300, 2, 1.0, 25,1000, 20, 110, 160, 255);
        SprayNext(150,300);
        SprayNext(200,300);
        SprayNext(250,300);
        SprayNext(270,300);
        SprayEnd(290,300);
        """;
      f.cArea.setText(cmd);
      init();
    }

    else if(com.equals("BG1"))
    {  //●模様画像生成（統一配色）
      String cmd =
        """
        //模様画像生成（統一配色）
        SaveImage("./image/image1.png");
        Size(720,1008);
        MatrixPatternSt(0001,8,150,100,170,7);
        //画像上部の「乱数」ボタンを押して下さい。
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG2"))
    {  //●模様画像生成（個別配色）
      String cmd =
        """
        //模様画像生成（個別配色）
        SaveImage("./image/image2.png");
        Size(720,1008);
        MatrixPatternEx(0001,8,170,140,170,10);
        //画像上部の「乱数」ボタンを押して下さい。
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG3"))
    {  //●模様画像生成（二重混用）
      String cmd =
        """
        //模様画像生成（二重混用）
        SaveImage("./image/image3.png");
        Size(720,1008);
        MatrixPatternSt(0010,8,80,50,220,7);
        MatrixPatternEx(0114,8,100,100,150,10);
        //画像上部の「乱数」ボタンを押して下さい。
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG4"))
    {  //●模様画像生成（シフト）
      String cmd =
        """
        //模様画像生成（シフト）
        Size(720,1008);
        MatrixPatternEx(0011,8,70,120,170,10);
        MatrixPatternExOp(2,4,0,0,0,0,0,0,10);
        //画像上部の「乱数」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG5"))
    {  //●模様画像生成（ドロップ）
      String cmd =
        """
        //模様画像生成（ドロップ）
        Size(720,1008);
        MatrixPatternSt(1001,8,70,170,70,10);
        MatrixPatternStOp(0,0,-4.5,0,0,0,0,0,10);
        //画像上部の「乱数」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG6"))
    {  //●模様画像生成（スキップ）
      String cmd =
        """
        //模様画像生成（スキップ）
        Size(720,1008);
        MatrixPatternEx(1002,8,170,150,70,10);
        MatrixPatternExOp(0,0,0,0,-3,-3,0,0,10);
        //画像上部の「乱数」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG7"))
    {  //●模様画像生成（間欠描画）
      String cmd =
        """
        //模様画像生成（間欠描画）
        Size(720,1008);
        MatrixPatternSt(1001,8,170,150,70,10);
        MatrixPatternStOp(0,0,0,0,0,0,0,0,5);
        //画像上部の「乱数」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG8a"))
    {  //●傾斜元画像（画像傾斜する前の元画像の準備）
      String cmd =
        """
        //傾斜元画像生成
        SaveImage("./image/imageRa.png");
        AffineScale(1);
        Size(2000,2000);
        MatrixPatternSt(0003,8,100,110,180,10);
        //画像上部の「乱数」ボタンを押して下さい。
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG8b"))
    {  //●画像傾斜加工
      String cmd =
        """
        //模様画像生成（画像傾斜）
        SaveImage("./image/imageRb.png");
        AffineScale(1);
        Size(2000,2000);
        Image(0,0,2000,2000,"./image/imageRa.png");
        RotateFree(45,300,-750);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG8c"))
    {  //●傾斜画像サイズ調整
      String cmd =
        """
        //傾斜画像サイズ調整
        SaveImage("./image/imageRc.png");
        Size(720,1008);
        Image(0,0,2000,2000,"./image/imageRb.png");
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG9"))
    {  //●模様画像生成（複雑指定１）
      String cmd =
        """
        //模様画像生成（複雑指定１）
        Size(720,1008);
        BackgroundColor(200,100,220);
        MatrixPatternEx(1005,8,100,110,80,10);
        MatrixPatternExOp(-0.5,-1,-5,0,1,-4,10,27,10);
        //画像上部の「乱数」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("BG10"))
    {  //●模様画像生成（複雑指定２）
      String cmd =
        """
        //模様画像生成（複雑指定２）
        Size(720,1008);
        BackgroundColor(200,200,120);
        MatrixPatternSt(1003,4,70,50,70,10);
        MatrixPatternStOp(-3.5,-8.5,0,-21,-11,17,0,0,10);
        MatrixPatternEx(1004,4,50,50,70,10);
        MatrixPatternExOp(-3.5,-8.5,0,-21,-11,17,0,0,5);
        //画像上部の「乱数」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }

    //●これ以降、画像の特殊加工を行なうが、画像保存を１倍に固定する命令が含まれる。
    //●標準拡大率指定の「AffineScale(1);」が、それである。
    //●画像サイズが所定通りでないと、実行時エラーが発生する処理が一部含まれるため。

    else if(com.equals("Log"))
    {  //●ロゴ画像生成
      String cmd =
        """
        //ロゴ画像生成
        SaveImage("./image/ZLogo.png");
        AffineScale(1);
        Size(500,500);
        ForegroundColorL(200,0,0);
        BackgroundColor(200,200,200);
        Antialias(true);
        DrawCircle(2,250,250,250,200,0,0);
        DrawCircle(2,250,250,220,200,200,255);
        DrawCircle(2,250,250,210,200,0,0);
        DrawCircle(2,250,250,195,200,200,255);
        DrawShapeStart(2,118,159,200,0,0);
        DrawShapeCurve(201,47,306,197,384,138);
        DrawShapeCurve(303,261,198,111,118,159);
        DrawShapeEnd();
        DrawShapeStart(2,107,344,200,0,0);
        DrawShapeCurve(190,233,298,382,398,330);
        DrawShapeCurve(298,453,198,297,107,344);
        DrawShapeEnd();
        DrawShapeStart(2,138,320,200,0,0);
        DrawShapeLine(339,162,);
        DrawShapeLine(349,174,);
        DrawShapeLine(150,330,);
        DrawShapeEnd();
        DrawShapeStart(2,172,255,200,0,0);
        DrawShapeCurve(228,191,274,275,313,237);
        DrawShapeCurve(260,304,221,228,172,255);
        DrawShapeEnd();
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("LBG"))
    {  //●ロゴ入り画像（スタンプ押印）
      String cmd =
        """
        //スタンプ押印
        SaveImage("./image/BirdwatchingZClub.png");
        AffineScale(1);
        Size(720,1008);
        Image(0,0,720,1008,"./image/image1.png");
        Antialias(true);
        ForegroundColorB(240,240,240);
        ForegroundColorS(0,0,0);
        Stamp(314,601,100,100,"./image/ZLogo.png");
        WriteStringB(110,220,80,3,"sansserif","野鳥観察の栞");
        WriteStringH(110,220,80,"sansserif","野鳥観察の栞");
        WriteStringB(168,910,53,3,"sansserif","野鳥観察Ｚ会編");
        WriteStringH(168,910,53,"sansserif","野鳥観察Ｚ会編");
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("REV"))
    {  //●画像鏡像反転
      String cmd =
        """
        //画像鏡像反転
        Size(720,1008);
        ReverseImage("./image/BirdwatchingZClub.png",1);
        //モードが５または７の場合、回転処理済み画像保存を伴う。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("CAS"))
    {  //●画像切取り保存
      String cmd =
        """
        //画像切取り保存
        AffineScale(1);
        Size(720,1008);
        Image(0,0,720,1008,"./image/BirdwatchingZClub.png");
        CutAndSaveImage(100,140,600,240,"./image/BirdwatchingZClubCut.png");
        //「切取」ボタンを押すことで、画像切取りと画像保存とが実行される。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("MSK"))
    {  //●切り貼り用マルチ・マスク作成
      String cmd =
        """
        //切り貼り用マルチ・マスク作成
        SaveImage("./image/multiMask.png");
        AffineScale(1);
        Size(720,1008);
        BackgroundColor(0,0,200);
        DrawShapeStart(2,360,96,200,0,0);
        DrawShapeLine(120,336);
        DrawShapeLine(360,574);
        DrawShapeLine(600,336);
        DrawShapeEnd();
        DrawShapeStart(2,360,432,0,200,0);
        DrawShapeLine(120,672);
        DrawShapeLine(360,912);
        DrawShapeLine(360,912);
        DrawShapeLine(600,672);
        DrawShapeEnd();
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("CAP"))
    {  //●切り貼り画像処理
      String cmd =
        """
        //切り貼り画像処理
        Size(720,1008);
        CutAndPasteMask("./image/multiMask.png");
        CutAndPaste("./image/image1.png", 0,0,200);
        CutAndPaste("./image/image2.png", 200,0,0);
        CutAndPaste("./image/image3.png", 0,200,0);
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("CCM"))
    {  //●連続色相変更処理
      String cmd =
        """
        //連続色相変更処理
        Size(720,1008);
        ChangeColorMultiBase("./image/MultiMask.png");
        ChangeColorMulti(200,0,0,200,0,200);
        ChangeColorMulti(0,200,0,200,200,50);
        ChangeColorMulti(0,0,200,250,150,50);
        Image(750,0,720,1008,"./image/MultiMask.png");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("MiM"))
    {  //●二重画像用グレー・マスク作成
      String cmd =
        """
        //二重画像用グレー・マスク作成
        SaveImage(\"./image/image4.png\");
        AffineScale(1);
        Size(720,1008);
        BackgroundColor(200,200,200);
        DrawCircle(2,360,340,260,200,0,0);
        DrawCircle(2,360,680,260,0,0,200);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Mix"))
    {  //●二重像画像処理
      String cmd =
        """
        //二重像画像処理
        Size(720,1008);
        MixImage("./image/image1.png", "./image/image4.png");
        Image(200,200,720,1008,"./image/image1.png");
        Image(400,400,720,1008,"./image/image4.png");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SFx"))
    {  //●ソフト・フォーカス処理準備
      String cmd =
        """
        //ソフト・フォーカス処理準備（着色同心円描画）
        SaveImage("./image/circles.png");
        AffineScale(1);
        Size(720,1008);
        BackgroundColor(200,200,200);
        DrawCircle(2,240,240,200,50,100,200);
        DrawCircle(2,240,240,150,100,150,250);
        DrawCircle(2,240,240,100,100,200,250);
        DrawCircle(2,240,240,50,150,250,250);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SFo"))
    {  //●ソフト・フォーカス処理
      String cmd =
        """
        //ソフト・フォーカス処理
        SaveImage("./image/circlesSf.png");
        AffineScale(1);
        Size(720,1008);
        SoftFocus("./image/circles.png", 4);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Con"))
    {  //●畳み込み処理（コンボリューション：鮮鋭化／朦朧化）
      String cmd =
        """
        //畳み込み処理（コンボリューション：鮮鋭化／朦朧化）
        Size(720,1008);
        Convolve(\"./image/circles.png\", 5, -1, 0, 1, 0, 0); //3x3鮮鋭化
        //Convolve(\"./image/circles.png\", 8.3, -2.37, 0.235, 0.1, 0.08, 0.06, 1, 0, 0); //5x5鮮鋭化
        //Convolve(\"./image/circles.png\", -0.143, 0.143, 0.143, 8, 0, 0); //3x3朦朧化
        //仕方なく無階調画像を用いたが、自然な階調画像（写真画像）でないと、鮮鋭化効果は確認できない。
        //以下は、自然な階調画像による効果テスト用の命令サンプル。
        //Size(1440,2016);
        //Convolve(\"./project/java_K10/ajisai.png\", 4.98, -1.1, 0.15, 1, 2, 10); //3x3鮮鋭化
        //Convolve(\"./project/java_K10/ajisai.png\", 8.3, -2.35, 0.25, 0.1, 0.08, 0.06, 1, 5, 30); //5x5鮮鋭化
        //Convolve(\"./project/java_K10/ajisai.png\", -0.143, 0.143, 0.143, 8, 0, 0); //3x3朦朧化
        //鮮鋭化処理は、激しいピンボケ画像（輪郭不鮮明画像）に対しては、効果がない。
        //鮮鋭化処理は、ピクセル単位で濃淡（濃度の山谷）を強調するため、その副作用でノイズが発生する。
        //鮮鋭化処理では、反復処理の実引数を、「1」にしなければならない。
        //カーネルを3x3から5x5にすると、より鮮鋭化はするが、その副作用でノイズが激しくなる。3x3を推奨する。
        //ノイズ除去処理もできるが、効果は繊細である。画像拡大（4倍）で、ノイズ除去効果を精密に確かめられる。
        //ノイズ除去のための実引数は、元画像の個性や特徴に合わせて、あれこれと試行錯誤する必要がある。
        //朦朧化処理は、類似効果のソフト・フォーカス命令と比べ、色調が変化しやすい難点がある。
        //なお、ajisai.png の画像は、添付していない。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("GOL"))
    {  //●輪郭線抽出処理
      String cmd =
        """
        //輪郭線抽出処理
        Size(720,1008);
        Image(730,0,720,1008,"./image/circles.png");
        GetOutline("./image/circles.png", 30, 5, 2);
        //
        //色段差の大きい無階調画像（ベタ塗り画像）を用いれば、完璧な輪郭線が抽出できる。
        //自然な階調画像（写真画像）を用いれば、抽出された輪郭線は、低コントラスト部で途切れる。
        //また、元画像の輪郭部分でピントが甘い状態（輪郭不鮮明）だと、輪郭線が不規則に太くなる。
        //結局、元画像は、輪郭部が高コントラストで、パンフォーカスのシャープなピントが望まれる。
        //以下は、階調画像を用いた効果テスト用の命令サンプル。
        //
        //Size(1440,2016);
        //Image(1450,0,1440,2016,"./project/java_K10/ajisai.png");
        //GetOutline("./project/java_K10/ajisai.png", 40, 7, 2);
        //なお、ajisai.jpg に関連する画像は、添付していない。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("RoI"))
    {  //●画像多段階回転描画用の元画像の準備
      String cmd =
        """
        //画像多段階回転描画用の元画像の準備
        SaveImage("./image/rotateMaltiImage.png");
        Size(600,600); //外枠
        DrawRect(1,98,98,402,402,0,0,0); //内枠
        DrawCircle(1,300,300,284,0,0,0); //回転範囲
        BackgroundColor(200,200,200);
        //
        DrawShapeStart(2,300,100,50,50,250);
        DrawShapeLine(270,330);
        DrawShapeLine(330,330);
        DrawShapeEnd();
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("RoM"))
    {  //●画像多段階回転描画
      String cmd =
        """
        //画像多段階回転描画
        Size(600,600);
        RotateMulti(0,30, 12, "./image/rotateMaltiImage.png");
        Image(610,0,600,600,"./image/rotateMaltiImage.png");
        //RotateMulti(30,30, 1, "./image/circlesSf.png");
        //Image(610,0,720,1008,"./image/circlesSf.png");
        //階調画像は、多段階回転に適さず、一段階回転に限定される。
        //画像周囲に回転余裕がないと、画像の一部だけの回転になる。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("ChC"))
    {  //●単独色相変更処理
      String cmd =
        """
        //単独色相変更処理
        Size(720,1008);
        ChangeColor("./image/circlesSf.png", 5,100,200,250,255,0,0);
        Image(730,0,720,1008,"./image/circlesSf.png");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Grd"))
    {  //●色相階調加工
      String cmd =
        """
        //色相階調加工
        Size(720,1008);
        ColorGradient("./image/image3.png", 100, 504, 0.1, -0.2, -0.1);
        //ColorGradient("./image/image3.png", 0, 1008, 0.1, -0.2, -0.1);
        Image(100,100,720,1008,"./image/image3.png");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Sp1"))
    {  //●スプライン曲線図形１
      String cmd =
        """
        //スプライン曲線図形１
        SaveImage("./image/splineOutline.png");
        Size(500,500);
        ForegroundColorL(0,0,0);
        BackgroundColor(200,200,200);
        DrawSplineStart(235,155);
        DrawSplineControl(348,77);
        DrawSplineControl(418,156);
        DrawSplineControl(391,305);
        DrawSplineControl(234,441);
        DrawSplineControl(97,314);
        DrawSplineControl(61,159);
        DrawSplineControl(130,77);
        DrawSplineEnd(235,155);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SpP"))
    {  //●輪郭線図形内部単独彩色
       //スプライン曲線で作画された輪郭線内部を彩色する場合で、
       //針のように細い先端部を持ち、その先端部が屈曲していると、ピクセルが不連続となり、
       //先端部が彩色されず白色（地色）で残ることがあるが、その場合、彩色行為の最終段階で、
       //その微細な塗り残し部分を輪郭線色に色彩変換する必要がある。
      String cmd =
        """
        //輪郭線図形内部単独彩色
        Size(500,500);
        ChangeColorInner("./image/splineOutline.png", 0, 0, 0, 200, 40, 150, 250,250,1);
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Sp2"))
    {  //●スプライン曲線図形２
      String cmd =
        """
        //スプライン曲線図形２
        SaveImage("./image/splineOutline2.png");
        Size(500,500);
        ForegroundColorL(200,200,200);
        BackgroundColor(60,100,220);
        DrawSplineStart(235,155);
        DrawSplineControl(348,77);
        DrawSplineControl(418,156);
        DrawSplineControl(391,305);
        DrawSplineControl(234,441);
        DrawSplineControl(97,314);
        DrawSplineControl(61,159);
        DrawSplineControl(130,77);
        DrawSplineEnd(235,155);
        //
        DrawSplineStart(58,222);
        DrawSplineControl(122,207);
        DrawSplineControl(186,267);
        DrawSplineControl(270,198);
        DrawSplineControl(313,275);
        DrawSplineControl(383,183);
        DrawSplineEnd(418,245);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SpM"))
    {  //●輪郭線図形内部連続彩色
       //スプライン曲線で作画された輪郭線内部を彩色する場合で、
       //針のように細い先端部を持ち、その先端部が屈曲していると、ピクセルが不連続となり、
       //先端部が彩色されず白色（地色）で残ることがあるが、その場合、彩色行為の最終段階で、
       //その微細な塗り残し部分を輪郭線色に色彩変換する必要がある。
      String cmd =
        """
        //輪郭線図形内部連続彩色
        SaveImage("./image/splineOutline2A.png");
        Size(500,500);
        ChangeColorInnerMultiMask("./image/splineOutline2.png", 200, 200, 200);
        ChangeColorInnerMulti(20, 40, 150, 250,190);
        ChangeColorInnerMulti(220, 40, 50, 250,340);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SpS"))
    {  //●輪郭線図形内部連続彩色ソフト・フォーカス
      String cmd =
        """
        //輪郭線図形内部連続彩色ソフト・フォーカス
        SaveImage("./image/splineOutline2B.png");
        Size(500,500);
        SoftFocus("./image/splineOutline2A.png", 5);
        //画像上部の「保存」ボタンを押して下さい。
        //ソフト・フォーカスは、画像加工の仕上げ段階で行う。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SpF"))
    {  //●輪郭線図形内部連続彩色仕上げ
      String cmd =
        """
        //輪郭線図形内部連続彩色仕上げ
        Size(500,500);
        Image(0,0,500,500,"./image/splineOutline2B.png");
        Stamp(0,0,500,500,"./image/splineOutline2A.png");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Sp3"))
    {  //●スプライン曲線図形３
       //内部彩色処理を高速化するには、点描画機能などを用い、彩色部の数箇所に指定色を塗っておく。
      String cmd =
        """
        //スプライン曲線図形３／高速内部彩色用
        SaveImage("./image/splineOutline3.png");
        Size(500,500);
        ForegroundColorL(0,0,0);
        BackgroundColor(255,255,255);
        DrawRect(1,70,70,340,350,43,65,162);
        //
        DrawSplineStart(154,70);
        DrawSplineControl(108,152);
        DrawSplineControl(200,102);
        DrawSplineControl(124,232);
        DrawSplineControl(277,140);
        DrawSplineControl(257,215);
        DrawSplineControl(362,153);
        DrawSplineControl(286,306);
        DrawSplineControl(374,291);
        DrawSplineControl(351,375);
        DrawSplineEnd(410,322);
        //
        DrawSplineStart(131,70);
        DrawSplineControl(84,171);
        DrawSplineControl(162,139);
        DrawSplineControl(100,249);
        DrawSplineControl(222,204);
        DrawSplineControl(143,349);
        DrawSplineControl(284,239);
        DrawSplineControl(206,393);
        DrawSplineControl(323,315);
        DrawSplineControl(330,399);
        DrawSplineEnd(410,393);
        //
        DrawCircle(2,81,81,4.0,255,0,0);
        DrawCircle(2,143,157,4.0,255,0,0);
        DrawCircle(2,205,223,4.0,255,0,0);
        DrawCircle(2,84,405,4.0,255,0,0);
        DrawCircle(2,260,265,4.0,255,0,0);
        DrawCircle(2,311,327,4.0,255,0,0);
        DrawCircle(2,398,409,4.0,255,0,0);
        DrawCircle(2,137,80,4.0,0,128,0);
        DrawCircle(2,92,157,4.0,0,128,0);
        DrawCircle(2,183,120,4.0,0,128,0);
        DrawCircle(2,111,239,4.0,0,128,0);
        DrawCircle(2,261,152,4.0,0,128,0);
        DrawCircle(2,169,318,4.0,0,128,0);
        DrawCircle(2,340,176,4.0,0,128,0);
        DrawCircle(2,253,231,4.0,0,128,0);
        DrawCircle(2,267,312,4.0,0,128,0);
        DrawCircle(2,227,366,4.0,0,128,0);
        DrawCircle(2,362,303,4.0,0,128,0);
        DrawCircle(2,397,381,4.0,0,128,0);
        DrawCircle(2,128,129,4.0,0,0,255);
        DrawCircle(2,394,83,4.0,0,0,255);
        DrawCircle(2,158,195,4.0,0,0,255);
        DrawCircle(2,277,192,4.0,0,0,255);
        DrawCircle(2,300,287,4.0,0,0,255);
        DrawCircle(2,366,351,4.0,0,0,255);
        //
        DrawCircle(2,238,34,4.0,200,150,0);
        DrawCircle(2,258,461,4.0,200,150,0);
        //画像上部の「保存」ボタンを押して下さい。
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("SpA"))
    {  //●輪郭線図形内部連続自動彩色
      String cmd =
        """
        //輪郭線図形内部高速連続自動彩色
        Size(500,500);
        ChangeColorInnerAuto("./image/splineOutline3.png");
        Image(510,0,500,500,"./image/splineOutline3.png");
        """;
      f.cArea.setText(cmd);
      init();
    }

    //●画像の特殊加工は、以上で終了。

    else if(com.equals("NCP"))
    {  //●カード印刷
      String cmd =
        """
        //無地はがき用紙にカードを二枚印刷
        //はがきサイズ： 100 x 148 mm　（300 x 444 px）
        //名刺サイズ：    90 x  55 mm　（270 x 165 px）
        //カード・サイズ：85 x  54 mm　（255 x 162 px）
        //
        Size(100,148,\"mm\"); //はがきサイズ
        Antialias(true);
        DrawRect(1,15,43,255,162,255,255,255); //カード・サイズ
        DrawRect(1,15,243,255,162,255,255,255); //カード・サイズ
        //
        WriteStringH(33,70,12,"BIZ UDゴシック","『思考方法概論』");
        WriteStringH(33,90,12,"BIZ UDゴシック","『Java実例プログラミング』描画処理編");
        WriteStringH(33,110,12,"BIZ UDゴシック","『Java実例プログラミング』事務処理編");
        WriteStringH(33,130,12,"Consolas","https://rakue.ganriki.net/");
        WriteStringH(33,150,12,"Consolas","https://dl.ndl.go.jp/pid/13727096");
        WriteStringH(33,170,12,"Consolas","https://dl.ndl.go.jp/pid/13307204");
        WriteStringH(33,190,12,"Consolas","https://dl.ndl.go.jp/pid/13719801");
        //
        WriteStringH(33,270,12,"BIZ UDゴシック","『思考方法概論』");
        WriteStringH(33,290,12,"BIZ UDゴシック","『Java実例プログラミング』描画処理編");
        WriteStringH(33,310,12,"BIZ UDゴシック","『Java実例プログラミング』事務処理編");
        WriteStringH(33,330,12,"Consolas","https://rakue.ganriki.net/");
        WriteStringH(33,350,12,"Consolas","https://dl.ndl.go.jp/pid/13727096");
        WriteStringH(33,370,12,"Consolas","https://dl.ndl.go.jp/pid/13307204");
        WriteStringH(33,390,12,"Consolas","https://dl.ndl.go.jp/pid/13719801");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Lay"))
    {  //●全体レイアウト・スケール
      //レイアウト・スケールは、Import命令で活用するか、紙に印刷して活用する。
      String cmd =
        """
        //全体レイアウト・スケール
        Size(1440,2016);
        LineWidth(2.0); //標準の線幅指定
        ParallelLineWidth(1.0); //平行線の線幅指定        //
        //B5規格は、182x257mm
        //Size(1660,2340); //B5判印刷用に描画枠拡大
        //FreeScale(0.325); //B5判に画像縮小
        //Shift(1,110,200); //B5判印刷用に余白調整
        //
        //A4規格は、210x297mm
        //Size(1916,2708); //A4判印刷用に描画枠拡大
        //FreeScale(0.325); //A4判に画像縮小
        //Shift(1,220,300); //A4判印刷用に余白調整
        //
        DrawLine(64,64,1376,64); //枠線
        DrawLine(64,64,1376,64);
        DrawLine(64,1952,1376,1952);
        DrawLine(64,64,64,1952);
        DrawLine(1376,64,1376,1952);
        DrawLine(288,288,1152,288);
        DrawLine(288,672,1152,672);
        DrawLine(288,288,288,672);
        DrawLine(1152,288,1152,672);
        DrawCircle(1,720,1488,96,250,200,200); //ロゴ
        DrawLine(624,1392,816,1392);
        DrawLine(816,1392,816,1584);
        DrawLine(816,1584,624,1584);
        DrawLine(624,1584,624,1392);
        //
        DrawParallelLineH(0,0,1440,96,22,1,1); //縦平行線
        DrawParallelLineV(0,0,2016,96,16,1,1); //横平行線
        DrawLine(720,0,720,2016); //横中央線
        DrawLine(0,1008,1440,1008); //縦中央線
        //横目盛り（px）
        WriteStringH(64,36,22,"sansserif","96");
        WriteStringH(148,36,22,"sansserif","192");
        WriteStringH(242,36,22,"sansserif","288");
        WriteStringH(338,36,22,"sansserif","386");
        WriteStringH(434,36,22,"sansserif","480");
        WriteStringH(530,36,22,"sansserif","576");
        WriteStringH(626,36,22,"sansserif","672");
        WriteStringH(724,36,22,"sansserif","768");
        WriteStringH(818,36,22,"sansserif","864");
        WriteStringH(914,36,22,"sansserif","960");
        WriteStringH(994,36,22,"sansserif","1056");
        WriteStringH(1090,36,22,"sansserif","1152");
        WriteStringH(1186,36,22,"sansserif","1248");
        WriteStringH(1282,36,22,"sansserif","1344");
        WriteStringH(1378,36,22,"sansserif","1440");
        //
        WriteStringH(64,1988,22,"sansserif","96");
        WriteStringH(148,1988,22,"sansserif","192");
        WriteStringH(242,1988,22,"sansserif","288");
        WriteStringH(338,1988,22,"sansserif","386");
        WriteStringH(434,1988,22,"sansserif","480");
        WriteStringH(530,1988,22,"sansserif","576");
        WriteStringH(626,1988,22,"sansserif","672");
        WriteStringH(724,1988,22,"sansserif","768");
        WriteStringH(818,1988,22,"sansserif","864");
        WriteStringH(914,1988,22,"sansserif","960");
        WriteStringH(994,1988,22,"sansserif","1056");
        WriteStringH(1090,1988,22,"sansserif","1152");
        WriteStringH(1186,1988,22,"sansserif","1248");
        WriteStringH(1282,1988,22,"sansserif","1344");
        WriteStringH(1378,1988,22,"sansserif","1440");
        //縦目盛り（px）
        WriteStringH(34,92,22,"sansserif","96");
        WriteStringH(22,188,22,"sansserif","192");
        WriteStringH(22,284,22,"sansserif","288");
        WriteStringH(22,380,22,"sansserif","384");
        WriteStringH(22,476,22,"sansserif","480");
        WriteStringH(22,572,22,"sansserif","576");
        WriteStringH(22,668,22,"sansserif","672");
        WriteStringH(22,764,22,"sansserif","768");
        WriteStringH(22,860,22,"sansserif","864");
        WriteStringH(22,956,22,"sansserif","960");
        WriteStringH(6,1052,22,"sansserif","1056");
        WriteStringH(6,1148,22,"sansserif","1152");
        WriteStringH(6,1244,22,"sansserif","1248");
        WriteStringH(6,1340,22,"sansserif","1344");
        WriteStringH(6,1436,22,"sansserif","1440");
        WriteStringH(6,1532,22,"sansserif","1536");
        WriteStringH(6,1628,22,"sansserif","1632");
        WriteStringH(6,1724,22,"sansserif","1728");
        WriteStringH(6,1820,22,"sansserif","1824");
        WriteStringH(6,1916,22,"sansserif","1920");
        WriteStringH(6,2008,22,"sansserif","2016");
        //
        WriteStringH(1398,92,22,"sansserif","96");
        WriteStringH(1386,188,22,"sansserif","192");
        WriteStringH(1386,284,22,"sansserif","288");
        WriteStringH(1386,380,22,"sansserif","384");
        WriteStringH(1386,476,22,"sansserif","480");
        WriteStringH(1386,572,22,"sansserif","576");
        WriteStringH(1386,668,22,"sansserif","672");
        WriteStringH(1386,764,22,"sansserif","768");
        WriteStringH(1386,860,22,"sansserif","864");
        WriteStringH(1386,956,22,"sansserif","960");
        WriteStringH(1374,1052,22,"sansserif","1056");
        WriteStringH(1374,1148,22,"sansserif","1152");
        WriteStringH(1374,1244,22,"sansserif","1248");
        WriteStringH(1374,1340,22,"sansserif","1344");
        WriteStringH(1374,1436,22,"sansserif","1440");
        WriteStringH(1374,1532,22,"sansserif","1536");
        WriteStringH(1374,1628,22,"sansserif","1632");
        WriteStringH(1374,1724,22,"sansserif","1728");
        WriteStringH(1374,1820,22,"sansserif","1824");
        WriteStringH(1374,1916,22,"sansserif","1920");
        WriteStringH(1374,2008,22,"sansserif","2016");
        """;
      f.cArea.setText(cmd);
      init();
    }

    else if(com.equals("La2"))
    {  //●部品レイアウト・スケール
      //レイアウト・スケールは、Import命令で活用するか、紙に印刷して活用する。
      String cmd =
        """
        //部品レイアウト・スケール
        //Size(720,1008);
        //
        //B5規格は、182x257mm
        Size(830,1170); //B5判印刷用に描画枠拡大
        FreeScale(0.65); //B5判に画像縮小
        Shift(1,55,210); //B5判印刷用に余白調整
        //
        //A4規格は、210x297mm
        //Size(958,1354); //A4判印刷用に描画枠拡大
        //FreeScale(0.65); //A4判に画像縮小
        //Shift(1,100,250); //A4判印刷用に余白調整
        //
        ParallelLineWidth(1.5); //平行線の線幅指定
        DrawParallelLineH(0,0,720,12,61,1,0);
        DrawParallelLineV(0,0,720,12,61,1,0);
        DrawParallelLineH2(0,0,720,72,11,0,0);
        DrawParallelLineV2(0,0,720,72,11,0,0);
        WriteStringH(90,780,12,"sansserif","1 unit = 6 cell × 6 cell");
        WriteStringH(90,800,12,"sansserif","1 side = 6 cell × 10 unit = 60 cell");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("RLS"))
    {  //●多段階回転画像作成用レイアウト・スケール
      //レイアウト・スケールは、Import命令で活用する。
      String cmd =
        """
        //多段階回転画像作成用レイアウト・スケール
        Size(600,600); //外枠
        BackgroundColor(200,200,200); //グレー背景色
        //以下は補助線（完成画像保存時にコメント・アウトすること）
        DrawCircle(1,300,300,283,0,0,0); //回転範囲
        DrawParallelLineH(100,100,400,10,41,1,0); //方眼線
        DrawParallelLineV(100,100,400,10,41,1,0);
        DrawParallelLineH2(0,0,600,50,13,0,0);
        DrawParallelLineV2(0,0,600,50,13,0,0);
        DrawLine(100,100,500,500);
        DrawLine(500,100,100,500);
        """;
      f.cArea.setText(cmd);
      init();
    }

    else if(com.equals("TA4"))
    {  //●A4印刷テスト図形Ａ４
      String cmd =
        """
        //印刷テスト図形Ａ４（印刷不能マージン確認）
        Size(\"A4\");
        FontBold(true);
        DrawLine(0,0,630,891);
        DrawLine(630,0,0,891);
        DrawLine(0,445.5,630,445.5);
        DrawLine(315,0,315,891);
        DrawLine(315,0,0,445.5);
        DrawLine(157.5,222.5,315,222.5);
        DrawLine(157.5,222.5,157.5,445.5);
        DrawLine(0,445.5,315,891);
        DrawLine(630,445.5,315,891);
        DrawLine(315,0,630,445.5);
        WriteStringH(90,60,24,"sansserif","GCreator A4");
        WriteStringH(90,90,15,"sansserif","210x297mm");
        WriteStringH(216,240,15,"sansserif","52.5mm");
        WriteStringH(162,330,15,"sansserif","74.25mm");
        WriteStringH(315,445.5,48,"sansserif","活字48pt");
        """;
      f.cArea.setText(cmd);
      init();
    }
    else if(com.equals("Pht"))
    {  //●フォント表示テスト１
      f.cArea.setText("");
      f.cArea.append("//フォント表示テスト１\n");
      f.cArea.append("Size(\"A4\");\n");
      f.cArea.append("Antialias(true);\n");
      f.cArea.append("FontBold(false);\n");

      f.cArea.append("WriteString(30,60,15,\"sansserif\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [sansserif]\");\n");
      f.cArea.append("WriteString(30,90,15,\"serif\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [serif]\");\n");
      f.cArea.append("WriteString(30,120,15,\"monospaced\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [monospaced]\");\n");
      f.cArea.append("WriteString(30,150,15,\"dialog\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [dialog]\");\n");
      f.cArea.append("WriteString(30,180,15,\"dialoginput\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [dialoginput]\");\n");
      f.cArea.append("//以上は、仮想的な論理フォントで、以下は、実体的な物理フォント。\n");
      f.cArea.append("//論理フォント名は、大文字小文字の区別をしない。\n");
      f.cArea.append("//論理フォントは、以下に示す五種類の物理フォント全角半角の組み合わせである。\n");

      f.cArea.append("//\n");
      f.cArea.append("WriteString(30,210,15,\"Arial\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Arial]\");\n");
      f.cArea.append("WriteString(30,240,15,\"Times New Roman\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Times New Roman]\");\n");
      f.cArea.append("WriteString(30,270,15,\"Courier New\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Courier New]\");\n");
      f.cArea.append("WriteString(30,300,15,\"ＭＳ ゴシック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [ＭＳ ゴシック]\");\n");
      f.cArea.append("WriteString(30,330,15,\"ＭＳ 明朝\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [ＭＳ 明朝]\");\n");
      f.cArea.append("//\n");

      f.cArea.append("WriteString(30,360,15,\"ＭＳ Ｐゴシック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [ＭＳ Ｐゴシック]\");\n");
      f.cArea.append("WriteString(30,390,15,\"ＭＳ Ｐ明朝\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [ＭＳ Ｐ明朝]\");\n");
      f.cArea.append("WriteString(30,420,15,\"MS UI Gothic\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [MS UI Gothic]\");\n");

      f.cArea.append("WriteString(30,450,15,\"游ゴシック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游ゴシック]\");\n");
      f.cArea.append("WriteString(30,480,15,\"游明朝\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游明朝]\");\n");

      f.cArea.append("WriteString(30,510,15,\"BIZ UDPゴシック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDPゴシック]\");\n");
      f.cArea.append("WriteString(30,540,15,\"BIZ UDP明朝 Medium\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDP明朝 Medium]\");\n");
      f.cArea.append("WriteString(30,570,15,\"BIZ UDゴシック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDゴシック]\");\n");
      f.cArea.append("WriteString(30,600,15,\"BIZ UD明朝 Medium\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UD明朝 Medium]\");\n");

      f.cArea.append("WriteString(30,630,15,\"Meiryo UI\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Meiryo UI]\");\n");
      f.cArea.append("WriteString(30,660,15,\"メイリオ\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [メイリオ]\");\n");

      f.cArea.append("WriteString(30,690,15,\"UD デジタル 教科書体 N\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [UD デジタル 教科書体 N]\");\n");
      f.cArea.append("WriteString(30,720,15,\"UD デジタル 教科書体 NK\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [UD デジタル 教科書体 NK]\");\n");
      f.cArea.append("WriteString(30,750,15,\"UD デジタル 教科書体 NP\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [UD デジタル 教科書体 NP]\");\n");

      f.cArea.append("//Windows11 に搭載されているフォントの表示。\n");
      f.cArea.append("//物理フォント名は、空白の個数、全角と半角、これらの違いに注意。\n");
      f.cArea.append("//フォント名を間違うと、「sansserif」での表示になる。\n");
      init();
    }
    else if(com.equals("Ph2"))
    {  //●フォント表示テスト２
      f.cArea.setText("");
      f.cArea.append("//フォント表示テスト（詳細拡張版）\n");
      f.cArea.append("Size(\"A4\");\n");
      f.cArea.append("Antialias(true);\n");
      f.cArea.append("FontBold(false);\n");

      f.cArea.append("WriteString(30,60,15,\"BIZ UDPゴシック Regular\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDPゴシック Regular]\");\n");
      f.cArea.append("WriteString(30,90,15,\"BIZ UDPゴシック Bold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDPゴシック Bold]\");\n");

      f.cArea.append("WriteString(30,120,15,\"BIZ UDゴシック Regular\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDゴシック Regular]\");\n");
      f.cArea.append("WriteString(30,150,15,\"BIZ UDゴシック Bold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [BIZ UDゴシック Bold]\");\n");

      f.cArea.append("WriteString(30,180,15,\"Meiryo UI Regular\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Meiryo UI Regular]\");\n");
      f.cArea.append("WriteString(30,210,15,\"Meiryo UI Bold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Meiryo UI Bold]\");\n");
      f.cArea.append("WriteString(30,240,15,\"Meiryo UI Italic\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Meiryo UI Italic]\");\n");
      f.cArea.append("WriteString(30,270,15,\"Meiryo Bold Italic\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Meiryo UI Bold Italic]\");\n");
      f.cArea.append("WriteString(30,300,15,\"メイリオ レギュラー\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [メイリオ レギュラー]\");\n");
      f.cArea.append("WriteString(30,330,15,\"メイリオ ボールド\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [メイリオ ボールド]\");\n");
      f.cArea.append("WriteString(30,360,15,\"メイリオ イタリック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [メイリオ イタリック]\");\n");
      f.cArea.append("WriteString(30,390,15,\"メイリオ ボールド イタリック\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [メイリオ ボールド イタリック]\");\n");

      f.cArea.append("WriteString(30,420,15,\"Yu Gothic UI Light\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Yu Gothic UI Light]\");\n");
      f.cArea.append("WriteString(30,450,15,\"Yu Gothic UI Semilight\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Yu Gothic UI Semilight]\");\n");
      f.cArea.append("WriteString(30,480,15,\"Yu Gothic UI Regular\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Yu Gothic UI Regular]\");\n");
      f.cArea.append("WriteString(30,510,15,\"Yu Gothic UI Semibold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Yu Gothic UI Semibold]\");\n");
      f.cArea.append("WriteString(30,540,15,\"Yu Gothic UI Bold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Yu Gothic UI Bold]\");\n");

      f.cArea.append("WriteString(30,570,15,\"游ゴシック Light\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游ゴシック Light]\");\n");
      f.cArea.append("WriteString(30,600,15,\"游ゴシック Regular\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游ゴシック Regular]\");\n");
      f.cArea.append("WriteString(30,630,15,\"游ゴシック Medium\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游ゴシック Medium]\");\n");
      f.cArea.append("WriteString(30,660,15,\"游ゴシック Bold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游ゴシック Bold]\");\n");

      f.cArea.append("WriteString(30,690,15,\"游明朝 Light\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游明朝 Light]\");\n");
      f.cArea.append("WriteString(30,720,15,\"游明朝 Regular\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游明朝 Regular]\");\n");
      f.cArea.append("WriteString(30,750,15,\"游明朝 Demibold\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [游明朝 Demibold]\");\n");

      f.cArea.append("WriteString(30,810,15,\"sansserif\","+
          "\"以下は、コンピューター関連用途に便利な英文等幅フォント\");\n");
      f.cArea.append("WriteString(30,840,15,\"Consolas\","+
          "\"漢字かなカナＡＢａｂ■●ABab01.2*+-=#$@!? [Consolas]\");\n");

      f.cArea.append("//Windows11 に搭載されているフォントの表示。\n");
      f.cArea.append("//物理フォント名は、空白の個数、全角と半角、これらの違いに注意。\n");
      f.cArea.append("//フォント名を間違うと、「sansserif」での表示になる。\n");
      init();
    }

    else if(com.equals("XL4"))
    {  //●拡大率：４倍
      f.canvas.affineScale = f.xL4;
      f.scaleLabel.setText("  (a:x4.0)");
      init();
    }
    else if(com.equals("XL3"))
    {  //●拡大率：３倍
      f.canvas.affineScale = f.xL3;
      f.scaleLabel.setText("  (a:x3.0)");
      init();
    }
    else if(com.equals("XL2"))
    {  //●拡大率：２倍
      f.canvas.affineScale = f.xL2;
      f.scaleLabel.setText("  (a:x2.0)");
      init();
    }
    else if(com.equals("XML"))
    {  //●拡大率：１．５倍
      f.canvas.affineScale = f.xML;
      f.scaleLabel.setText("  (a:x1.5)");
      init();
    }
    else if(com.equals("XM1"))
    {  //●拡大率：１倍
      f.canvas.affineScale = f.xM1;
      f.scaleLabel.setText("  (a:x1.0)");
      init();
    }
    else if(com.equals("XMS"))
    {  //●拡大率：１／１．５倍
      f.canvas.affineScale = f.xMS;
      f.scaleLabel.setText("  (a:x1/1.5)");
      init();
    }
    else if(com.equals("XS2"))
    {  //●拡大率：１／２倍
      f.canvas.affineScale = f.xS2;
      f.scaleLabel.setText("  (a:x1/2)");
      init();
    }
    else if(com.equals("XS3"))
    {  //●拡大率：１／３倍
      f.canvas.affineScale = f.xS3;
      f.scaleLabel.setText("  (a:x1/3)");
      init();
    }
    else if(com.equals("XS4"))
    {  //●拡大率：１／４倍
      f.canvas.affineScale = f.xS4;
      f.scaleLabel.setText("  (a:x1/4)");
      init();
    }

    else if(com.equals("Of1"))
    {  //●マウス描画有効モード（根本モード）
       //マウスによる位置や色相の問い合わせ機能などを含む
      f.cMouseLis.canvasMouseFlag = true;
      f.cMouseLis.canvasMouseMode = 0;
      f.canvas.currentPointX =  0;
      f.canvas.currentPointY =  0;
      f.canvas.markFlag = true;
      f.mouseModeLabel.setText("マウス描画有効モード");
      f.cMouseLis.clear();
    }
    else if(com.equals("Of2"))
    {  //●マウス描画無効モード（根本モード）
      f.cMouseLis.canvasMouseFlag = false;
      f.cMouseLis.canvasMouseMode = 0;
      f.canvas.currentPointX = 0;
      f.canvas.currentPointY = 0;
      f.canvas.markFlag = false;
      f.mouseModeLabel.setText("マウス描画無効モード");
      f.cMouseLis.clear();
    }

    //これ以降は、「マウス描画有効モード」の下で、具体的な「派生モード」が機能する
    else if(com.equals("Lin"))
    {  //●直線、マウス描画モード
      f.cMouseLis.canvasMouseMode = 1;
      f.cMouseLis.clear();
    }
    else if(com.equals("Eli"))
    {  //●直線、マウス消去モード
      f.cMouseLis.canvasMouseMode = 6;
      f.cMouseLis.clear();
    }
    else if(com.equals("LLi"))
    {  //●折れ線、マウス描画モード
      f.cMouseLis.canvasMouseMode = 30;
      f.cMouseLis.clear();
    }
    else if(com.equals("Cur"))
    {  //●ベジェ曲線、マウス描画モード
      f.cMouseLis.canvasMouseMode = 9;
      f.cMouseLis.clear();
    }
    else if(com.equals("Spl"))
    {  //●スプライン曲線、マウス描画モード
      f.cMouseLis.canvasMouseMode = 22;
      f.cMouseLis.clear();
    }
    else if(com.equals("SpE"))
    {  //●スプライン曲線制御点、マウス消去モード
      f.cMouseLis.canvasMouseMode = 33;
      f.cMouseLis.clear();
    }
    else if(com.equals("SpZ"))
    {  //●スプライン曲線制御点、マウス増殖モード
      f.cMouseLis.canvasMouseMode = 34;
      f.cMouseLis.clear();
    }
    else if(com.equals("AC3"))
    {  //●座標点、マウス修正モード
      f.cMouseLis.canvasMouseMode = 10;
      f.cMouseLis.clear();
    }
    else if(com.equals("ECu"))
    {  //●描画目印線の消去
      f.canvas.markFlag = false; //canvasMouseModeに関係なし
      f.cMouseLis.clear();
    }
    else if(com.equals("DCu"))
    {  //●描画目印線の復活
      f.canvas.markFlag = true; //canvasMouseModeに関係なし
      f.cMouseLis.clear();
    }
    else if(com.equals("Cir"))
    {  //●真円の描画モード
      f.cMouseLis.canvasMouseMode = 2;
      f.cMouseLis.clear();
    }
    else if(com.equals("CiE"))
    {  //●真円消去の描画モード（点描画の修正消去が主な用途）
      f.cMouseLis.canvasMouseMode = 32;
      f.cMouseLis.clear();
    }
    else if(com.equals("Ell"))
    {  //●楕円の描画モード
      f.cMouseLis.canvasMouseMode = 8;
      f.cMouseLis.clear();
    }
    else if(com.equals("Rec"))
    {  //●四角形の描画モード
      f.cMouseLis.canvasMouseMode = 20;
      f.cMouseLis.clear();
    }
    else if(com.equals("Fre"))
    {  //●自由図形の描画モード
      f.cMouseLis.canvasMouseMode = 14;
      f.cMouseLis.clear();
    }
    else if(com.equals("Str"))
    {  //●文字の記入モード
      f.cMouseLis.canvasMouseMode = 3;
      f.cMouseLis.clear();
    }
    else if(com.equals("St2"))
    {  //●表題の記入モード
      f.cMouseLis.canvasMouseMode = 13;
      f.cMouseLis.clear();
    }
    else if(com.equals("Pos"))
    {  //●位置確認モード
      f.cMouseLis.canvasMouseMode = 4;
      f.cMouseLis.clear();
    }
    else if(com.equals("Ref"))
    {  //●命令文検索モード
      f.cMouseLis.canvasMouseMode = 15;
      f.cMouseLis.clear();
    }
    else if(com.equals("Clx"))
    {  //●色相確認モード
      f.cMouseLis.canvasMouseMode = 21;
      f.cMouseLis.clear();
    }
    else if(com.equals("CoP"))
    {  //●塗り色変更モード（混色パレット使用）
      f.cMouseLis.canvasMouseMode = 19;
      f.cMouseLis.clear();
    }

    else if(com.equals("Sc1"))
    {  //●標準表示
      f.changeLayout(1);
      f.canvas.currentPointX = 0;
      f.canvas.currentPointY = 0;
      f.canvas.toneCurveFlag = false;
    }
    else if(com.equals("Sc2"))
    {  //●パレット表示
      f.changeLayout(2);
      f.canvas.currentPointX = 0;
      f.canvas.currentPointY = 0;
      f.canvas.toneCurveFlag = false;
    }
    else if(com.equals("Sc3"))
    {  //●トーン・カーブ表示
      f.changeLayout(3);
      f.canvas.currentPointX = 0;
      f.canvas.currentPointY = 0;
      f.canvas.toneCurveFlag = true;
    }

    else if(com.equals("BrL"))
    {  //●点描画筆（大）
      f.cMouseLis.canvasMouseMode = 101;
      f.cMouseLis.brushSize = 4;
    }
    else if(com.equals("BrM"))
    {  //●点描画筆（中）
      f.cMouseLis.canvasMouseMode = 101;
      f.cMouseLis.brushSize = 2;
    }
    else if(com.equals("BrS"))
    {  //●点描画筆（小）
      f.cMouseLis.canvasMouseMode = 101;
      f.cMouseLis.brushSize = 1;
    }
    else if(com.equals("Spr"))
    {  //●スプレー描画
      f.cMouseLis.canvasMouseMode = 102;
      f.cMouseLis.sprayCnt = 1;
    }
    else if(com.equals("SpX"))
    {  //●スプレー飛沫円盤中間点消去
      f.cMouseLis.canvasMouseMode = 103;
      f.cMouseLis.clear();
    }

    else if(com.equals("Usa"))
    {  //●命令仕様書
      Util.textBrowseCCP(f, new File(
        "./sys/GCreator_Manual.txt"));
    }
    else if(com.equals("Ptn"))
    {  //●模様データ
      Util.textBrowseCCP(f, new File(
        "./sys/GCreator_Pattern.txt"));
    }
    else
    {
      f.message("メニューに該当なし");
    }
  }
  void init()
  {
    f.canvas.setInit2(); //特殊初期化（先行実施）
    f.canvas.setInit();  //一般初期化（後続実施）
    f.canvas.setInit3(); //追加特殊初期化（最終実施）
    f.canvas.repaint();  //描画実行
  }
} //EOF (GCreatorMenuLis.java)

◆GCreatorButtonLis.java

//■■GCreatorButtonLis.java
//Ver.4.1

//■■インポート
import java.awt.event.*;  //必須
import java.util.*;  //必須
import java.io.*;  //必須
import java.awt.image.*;  //必須

//■■JButtonのイベントリスナー
class GCreatorButtonLis implements ActionListener
{
  //■メンバー変数
  GCreator f;
  boolean cutAndSaveFlag = false;

  //■コンストラクタ
  GCreatorButtonLis(GCreator flame)
  {
    f = flame;
  }

  //■JButtonのイベントハンドラ
  public void actionPerformed(ActionEvent event)
  {
    String com = event.getActionCommand();
    if(com.equals("Rep"))
    {   //●グラフィックの再描画（「描画」ボタン）
        //命令文書を書き換えた場合、「描画」ボタンを押すこと。

    //各種特殊コマンドの下準備
      f.canvas.setInit2(); //特殊初期化（先行実施）
      f.canvas.setInit();  //一般初期化（後続実施）
      f.canvas.setInit3(); //追加特殊初期化（最終実施）
      f.canvas.repaint();  //再描画（多用途対応）
    }
    else if(com.equals("Rp2"))
    {  //●グラフィックのマトリックス模様更新（「乱数」ボタン）
      if(f.canvas.matrixPatternNumSt>0)
        f.canvas.rgbSt = f.canvas.getRandom_rgbSt();
      if(f.canvas.matrixPatternNumEx>0)
        f.canvas.rgbEx = f.canvas.getRandom_rgbEx();
      f.canvas.randomSeed2 = f.canvas.ran.nextInt();
      f.canvas.repaint();  //乱数効果の画像を表示
    }
    else if(com.equals("Can"))
    {  //●パレット混色取消（「取消」ボタン）
      f.sldR.setValue(0);
      f.sldG.setValue(0);
      f.sldB.setValue(0);
      f.palette.tfR = 0;
      f.palette.tfG = 0;
      f.palette.tfB = 0;
      f.palette.colorModifyX(0,0,0);
      f.palette.numberInputMode = 0;
      f.pMouseLis.clear();
      f.paletteRGB.setText("");
      f.palette.colorMix();
    }
    else if(com.equals("TFP")) //パレットを数値入力に切り替え
    {
      f.pMouseLis.clear();
      String rgb = f.paletteRGB.getText();
      StringTokenizer st = new StringTokenizer(rgb,", ");
      try
      {
        int r = Integer.parseInt(st.nextToken().trim());
        int g = Integer.parseInt(st.nextToken().trim());
        int b = Integer.parseInt(st.nextToken().trim());
        if(r<0 || r>255 || g<0 || g>255 || b<0 || b>255)
        {
          f.message("パレットでの色指定数値範囲エラー");
          return;
        }
        f.palette.tfR = r;
        f.palette.tfG = g;
        f.palette.tfB = b;
      }
      catch(Exception e)
      {
        f.message("パレットでの色指定数値入力エラー");
        return;
      }
      f.sldR.setValue(0);
      f.sldG.setValue(0);
      f.sldB.setValue(0);
      f.palette.numberInputMode = 1;
    }
    else if(com.equals("Adj"))
    {  //●スライダー修正値のゼロ・クリア（「復元」ボタン）
      f.sldR.setValue(0);
      f.sldG.setValue(0);
      f.sldB.setValue(0);
    }

    else if(com.equals("SvC"))
    {  //●命令文書の保存
      if(!f.canvas.saveCmdFName.equals("") || f.canvas.saveCmdFName != null)
      {
        f.canvas.setInit();  //一般初期化のみ
        f.io.save(f.cArea, f.canvas.saveCmdFName);
      }
      else
        f.message("ファイル名の指定がなく、命令文書を保存できません。");
    }
    else if(com.equals("SvI"))
    {  //●作成画像の全体保存
      f.canvas.canSaveMode = true;
      f.canvas.markFlag = false;
      f.canvas.setInit();  //一般初期化のみ
      f.canvas.repaint();
      cutAndSaveFlag = false;

      if(!f.canvas.saveImgFName.equals(""))
      {
        f.io.saveGraphics(new File(f.canvas.saveImgFName), 0, 0,
          (int)(f.canvas.imagePX_W*f.canvas.affineScale*f.canvas.freeScale),
          (int)(f.canvas.imagePX_H*f.canvas.affineScale*f.canvas.freeScale));
      }
      else
        f.message("ファイル名の指定がなく、全体画像を保存できません。");
      f.canvas.canSaveMode = false;
    }
    else if(com.equals("SvP"))
    {  //●作成画像の部分切り取り保存
      f.canvas.setInit();  //一般初期化のみ
      f.canvas.canSaveMode = true;
      f.canvas.markFlag = false;
      f.canvas.repaint();
      cutAndSaveFlag = true;

      if(cutAndSaveFlag = true && !f.canvas.cutAndSaveImgFName.equals(""))
      {
        f.io.saveGraphics(new File(f.canvas.cutAndSaveImgFName),
          f.canvas.cutAndSaveImgX1, f.canvas.cutAndSaveImgY1,
          f.canvas.cutAndSaveImgX2 - f.canvas.cutAndSaveImgX1,
          f.canvas.cutAndSaveImgY2 - f.canvas.cutAndSaveImgY1);
      }
      else
      {
        f.message("ファイル名の指定がなく、切り取り画像を保存できません。");
      }
      cutAndSaveFlag = false;
      f.canvas.canSaveMode = false;
    }
    else if(com.equals("TC1"))
    {  //●第一段階／トーン・カーブ調色の元画像指定
      f.toneCurve.bImageTC1 = null; //元画像
      f.toneCurve.bImageTC2 = null; //新画像
      f.cArea.setText(""); //古い命令文を全て消す
      f.canvas.setInit2(); //特殊初期化（先行実施）
      f.canvas.setInit();  //一般初期化（後続実施）
      f.canvas.setInit3(); //追加特殊初期化（最終実施）
      f.canvas.repaint();  //描画（古い画像を消す）
      f.toneCurve.setStandardCommands(); //標準命令がコマンド・エリアに書き込まれる。
      f.toneCurve.bImageTC1 = f.io.loadGraphics(2); //元画像がここで確定する。
      f.canvas.setInit2(); //特殊初期化（先行実施）
      f.canvas.setInit();  //一般初期化（後続実施）
      f.canvas.setInit3(); //追加特殊初期化（最終実施）
      f.canvas.repaint();  //描画（新しく選んだ画像を表示）
    }
    else if(com.equals("TC2"))
    {  //●第二段階／トーン・カーブによる調色処理（先に元画像の確定が必要）
      f.toneCurve.changeColorTC(); //元画像は既に確定済み。
      f.canvas.setInit2(); //特殊初期化（先行実施）
      f.canvas.setInit();  //一般初期化（後続実施）
      f.canvas.setInit3(); //追加特殊初期化（最終実施）
      f.canvas.repaint();  //描画（調色処理した画像の表示）
    }
    else if(com.equals("TC3"))
    {  //●第三段階／トーン・カーブ調色の終了
      f.toneCurve.bImageTC1 = null; //元画像
      f.toneCurve.bImageTC2 = null; //新画像
      f.cArea.setText(""); //古い命令文を全て消す
      f.canvas.setInit2(); //特殊初期化（先行実施）
      f.canvas.setInit();  //一般初期化（後続実施）
      f.canvas.setInit3(); //追加特殊初期化（最終実施）
      f.canvas.repaint();  //描画（古い画像を消す）
    }
    else
      f.message("ボタン機能に該当なし");
  }
} //EOF (GCreatorButtonLis.java)

◆GCreatorCanMouseLis.java

//■■GCreatorCanMouseLis.java
//Ver.4.1

//■■インポート
import java.awt.*;  //必須
import java.awt.event.*;  //必須
import java.awt.image.*;  //必須
import java.util.*;  //必須
import javax.swing.*;  //必須

//■■キャンバス上のマウスのクリックで呼び出されるリスナー。
//描画命令を自動生成して、cAreaに順次書き込む。
class GCreatorCanMouseLis implements MouseListener
{
  //■メンバー変数
  GCreator f;
  int x1 = 0;
  int y1 = 0;
  int x2 = 0;
  int y2 = 0;
  int x3 = 0;
  int y3 = 0;
  int x4 = 0;
  int y4 = 0;
  double brushSize = 4; //点描画用の筆のデフォルト・サイズ
  int strCnt = 1;  //文字列描画命令における文字列番号
  int curveCnt = 1;  //ベジェ曲線ポイント番号（始点が1、終点が4）
  int linkedLineCnt = 1;  //折れ線ポイント番号（始点が1、継続点が2以上、終点で1に戻される）
  int sprayCnt = 1;  //スプレーのポイント番号（始点が1、それ以外が2以上）
  int splineCnt = 1;  //スプライン曲線ポイント番号（始点が1、制御点が2以上）
  int splineX0;
  int splineY0;
  int canvasMouseMode = 0;  //0が無効、1以上が線描画マウス入力機能種別
  boolean canvasMouseFlag = false;
  boolean startFlag = true;  //線の始点か否かの判定
  boolean horizontFlag = true; //楕円の横半径指定クリックか否かの判定
  String commandX = ""; //自由図形での右クリック曲線制御点での命令文

  //■コンストラクタ
  GCreatorCanMouseLis(GCreator flame)
  {
    f = flame;
  }

  //■イベントハンドラ
  public void mousePressed(MouseEvent eve)
  {
    //●マウス入力モードが解除状態なら
    if(canvasMouseFlag == false)
    {
      clear();
      return;
    }
    //●特殊モードには非対応
    if(f.canvas.rotateFlag  || f.canvas.rotateFreeFlag ||
      f.canvas.rotateMultiFlag || f.canvas.shiftMode!=0)
    {
      f.message("Rotate、RotateFree、RotateMulti、Shift がある命令文書は、" +
        "マウス操作に非対応。該当命令文をコメント・アウトして下さい。");
      return;
    }
    int x = eve.getX(); //マウスのクリック位置を取得
    int y = eve.getY();
    double scaleAF = f.canvas.affineScale * f.canvas.freeScale; //合成倍率
    f.canvas.currentPointX = x/scaleAF;
    f.canvas.currentPointY = y/scaleAF;

    //●テキスト・エリアの命令文書の末尾に改行コードがなければ、改行コードを付加する。
    //命令文書の末尾には、常に改行コードがある準備状態にしておく。
    String commandsX = f.cArea.getText();
    if(commandsX.length() > 0 && commandsX.charAt(commandsX.length()-1) != '\n')
      f.cArea.append("\n");

    //●線描画モードで、左ボタンがクリックされた場合の動作
    if((canvasMouseFlag == true)  &&
      (eve.getButton() == MouseEvent.BUTTON1) )
    {
      if(canvasMouseMode == 1 && startFlag)
      { //●直線の第一段階
        //マウスクリック位置の端数を四捨五入
        x1 = (int)(x/scaleAF +0.5); //端数四捨五入
        y1 = (int)(y/scaleAF +0.5);
        startFlag = false;
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
      }
      else if(canvasMouseMode == 1 && !startFlag)
      { //●直線の第二段階
        x2 = (int)(x/scaleAF +0.5); //端数四捨五入
        y2 = (int)(y/scaleAF +0.5);
        String method = "DrawLine(" +
          x1 + "," + y1 + "," +
          x2 + "," + y2 + ");";
        f.cArea.append(method + "\n");
        startFlag = true;
        f.canvas.currentPointX = x2;
        f.canvas.currentPointY = y2;
        clear();
      }

      else if(canvasMouseMode == 20 && startFlag)
      { //●長方形の第一段階
        //マウスクリック位置の端数を四捨五入
        x1 = (int)(x/scaleAF +0.5); //端数四捨五入
        y1 = (int)(y/scaleAF +0.5);
        startFlag = false;
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
      }
      else if(canvasMouseMode == 20 && !startFlag)
      { //●長方形の第二段階
        x2 = (int)(x/scaleAF +0.5); //端数四捨五入
        y2 = (int)(y/scaleAF +0.5);
        //m: 描画モード、0は描画せず、1は線、2は色塗り、3は線と色
        //x: ｘ座標
        //y: ｙ座標
        //w: 幅
        //h: 丈
        //r: R
        //g: G
        //b: B
        int rc = colorRanNum();
        int gc = colorRanNum();
        int bc = colorRanNum();
        int w = x2 - x1;
        int h = y2 - y1;
        if(w<0) w = w* -1; //マイナスは不可
        if(h<0) h = h* -1; //マイナスは不可
        String method = "DrawRect(3," +
          x1 + "," + y1 + "," +
          w + "," + h + "," +
          rc +"," + gc + "," + bc + ");";
        f.cArea.append(method + "\n");
        startFlag = true;
        f.canvas.currentPointX = x2;
        f.canvas.currentPointY = y2;
        clear();
      }

      else if((canvasMouseMode == 2) && startFlag)
      { //●真円の第一段階：円の中心をクリック
        x1 = (int)(x/scaleAF +0.5); //端数四捨五入
        y1 = (int)(y/scaleAF +0.5);
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
        startFlag = false;
      }
      else if((canvasMouseMode == 2)&& !startFlag)
      {  //●真円の第二段階：円の右端か左端をクリック
        x2 = (int)(x/scaleAF +0.5)-x1; //端数四捨五入
        if(x2 <0)
          x2 = x2* -1; //絶対値に
        if(x2 == 0)
          x2 = 1; //半径0は、１に強制変更
        if(canvasMouseMode == 2) //●真円
        {
          int rc = colorRanNum();
          int gc = colorRanNum();
          int bc = colorRanNum();
          String method = "DrawCircle(3," +
            x1 + "," + y1 + "," + x2+ "," +
            rc +"," + gc + "," + bc + ");";
          f.cArea.append(method + "\n");
        }
        startFlag = true;
        clear();
      }

      else if((canvasMouseMode == 8) && startFlag)
      { //●楕円の第一段階：中心をクリック
        x1 = (int)(x/scaleAF +0.5); //端数四捨五入
        y1 = (int)(y/scaleAF +0.5);
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
        startFlag = false;
      }
      else if((canvasMouseMode == 8) && !startFlag &&
        horizontFlag)
      {  //●楕円の第二段階：右端か左端をクリック
        x2 = (int)(x/scaleAF +0.5)-x1; //端数四捨五入
        if(x2 <0)
          x2 = x2* -1;
        if(x2 == 0)
          x2 = 1;
        horizontFlag = false;
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
      }
      else if((canvasMouseMode == 8) &&
        !startFlag && !horizontFlag)
      {  //●楕円の第三段階：上端か下端をクリック
        y2 = (int)(y/scaleAF +0.5)-y1; //端数四捨五入
        if(y2 <0)
          y2 = y2* -1;
        if(y2 == 0)
          y2 = 1;
        if(canvasMouseMode == 8) //●楕円
        {
          int rc = colorRanNum();
          int gc = colorRanNum();
          int bc = colorRanNum();
          String method = "DrawEllipse(3," +
            x1 + "," + y1 + "," + x2 + "," + y2 + "," +
            rc +"," + gc + "," + bc + ");";
          f.cArea.append(method + "\n");
        }
        startFlag = true;
        horizontFlag = true;
        clear();
      }

      else if(canvasMouseMode == 9 && curveCnt == 1)
      { //●単独ベジェ曲線の第一段階：曲線の始点をクリック
        x1 = (int)(x/scaleAF +0.5); //端数四捨五入
        y1 = (int)(y/scaleAF +0.5);
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
        curveCnt++;
      }
      else if(canvasMouseMode == 9 && curveCnt == 2)
      {  //●単独ベジェ曲線の第二段階：曲線の第二点をクリック
        x2 = (int)(x/scaleAF +0.5); //端数四捨五入
        y2 = (int)(y/scaleAF +0.5);
        curveCnt++;
        String method = "  DrawLine2(3," + x1 + "," + y1 + "," +
            x2 + "," + y2 + ");";
        f.canvas.currentPointX = x2;
        f.canvas.currentPointY = y2;
        f.cArea.append(method + "\n");
      }
      else if(canvasMouseMode == 9 && curveCnt == 3)
      {  //●単独ベジェ曲線の第三段階：曲線の第三点をクリック
        x3 = (int)(x/scaleAF +0.5); //端数四捨五入
        y3 = (int)(y/scaleAF +0.5);
        curveCnt++;
        String method = "  DrawLine2(2," + x2 + "," + y2 + "," +
            x3 + "," + y3 + ");";
        f.canvas.currentPointX = x3;
        f.canvas.currentPointY = y3;
        f.cArea.append(method + "\n");
      }
      else if(canvasMouseMode == 9 && curveCnt == 4)
      {  //●単独ベジェ曲線の第四段階：曲線の終点をクリック
        x4 = (int)(x/scaleAF +0.5); //端数四捨五入
        y4 = (int)(y/scaleAF +0.5);
        String method = "  DrawLine2(3," + x3 + "," + y3 + "," +
            x4 + "," + y4 + ");";
        f.cArea.append(method + "\n");
        method =
          "DrawCurve(" +
          x1 + "," + y1 + "," +
          x2 + "," + y2 + "," +
          x3 + "," + y3 + "," +
          x4 + "," + y4 +  ");";
        f.cArea.append(method + "\n");
        f.canvas.currentPointX = x4;
        f.canvas.currentPointY = y4;
        curveCnt = 1;
        erase("DrawLine2");
        clear();
      }

      else if(canvasMouseMode == 13)
      { //●文字列描画
        int mX = (int)(x/scaleAF +0.5); //端数四捨五入
        int mY = (int)(y/scaleAF +0.5);
        String method = "WriteStringH(" + mX + "," + mY + "," +
          15 + "," + "\"sansserif\"" + ",\"□" + strCnt + "\");";
        f.cArea.append(method + "\n");
        strCnt++;
        startFlag = true;
        clear();
      }

      else if(canvasMouseMode == 4)
      { //●位置確認モード（FreeScale命令には、非対応）
        int mX = (int)(x/scaleAF +0.5); //端数四捨五入
        int mY = (int)(y/scaleAF +0.5);
        f.canvas.currentPointX = mX;
        f.canvas.currentPointY = mY;
        f.message("X=" + x + "  Y=" + y + "  [X=" + mX + "  Y=" + mY + "]");
        startFlag = true;
        clear();
      }

      else if(canvasMouseMode == 21)
      { //●色相確認モード
        //（注意）currentPointXおよびcurrentPointYの目印Ｘ字線をクリック位置に表示してはならない。
        //また、真円や楕円の中心点目印十字線も、中心点をクリックする可能性があり、表示してはならない。
        //これらを表示すると、その目印線の色相データが採取されてしまう。ただし、この問題は、対処済み。
        boolean flag = f.canvas.markFlag;
        f.canvas.markFlag = false; //目印線を一時的に消去
        int cR = 0;
        int cG = 0;
        int cB = 0;
        BufferedImage bImage = f.io.compImage2BufferedImage(f.canvas, 0, 0,
          (int)(f.canvas.imagePX_W*scaleAF +0.5),  //端数四捨五入
          (int)(f.canvas.imagePX_H*scaleAF +0.5)); //画像全体
        int rgbValue =  bImage.getRGB(x, y);
          //getRGB(x,y)は、デフォルトRGBカラー・モデル(TYPE_INT_ARGB)および
          //デフォルトsRGBカラー・スペースで整数型ピクセルを返すメソッド。
          //ただし、実際は、互換タイプ（TYPE_INT_RGB）に変換されている。
        String errMsg = "";
        cR = (rgbValue & 0x00ff0000) >>> 16;
        cG = (rgbValue & 0x0000ff00) >>> 8;
        cB = (rgbValue & 0x000000ff);
        String type =
          errMsg +
          "RGB={" + cR + ", " + cG + ", " + cB +"} " +
          "RGB_hex={" + Integer.toHexString(rgbValue) + "} ";
        int colorType = bImage.getType();
        if(colorType == BufferedImage.TYPE_3BYTE_BGR)
          f.message(type+"TYPE_3BYTE_BGR");
        else if(colorType == BufferedImage.TYPE_4BYTE_ABGR)
          f.message(type+"TYPE_4BYTE_ABGR");
        else if(colorType == BufferedImage.TYPE_4BYTE_ABGR_PRE)
          f.message(type+"TYPE_4BYTE_ABGR_PRE");
        else if(colorType == BufferedImage.TYPE_BYTE_BINARY)
          f.message(type+"TYPE_BYTE_BINARY");
        else if(colorType == BufferedImage.TYPE_BYTE_GRAY)
          f.message(type+"TYPE_BYTE_GRAY");
        else if(colorType == BufferedImage.TYPE_BYTE_INDEXED)
          f.message(type+"TYPE_BYTE_INDEXED");
        else if(colorType == BufferedImage.TYPE_CUSTOM)
          f.message(type+"TYPE_CUSTOM");
        else if(colorType == BufferedImage.TYPE_INT_ARGB)
          f.message(type+"TYPE_INT_ARGB");
        else if(colorType == BufferedImage.TYPE_INT_ARGB_PRE)
          f.message(type+"TYPE_INT_ARGB_PRE");
        else if(colorType == BufferedImage.TYPE_INT_BGR)
          f.message(type+"TYPE_INT_BGR");
        else if(colorType == BufferedImage.TYPE_INT_RGB)
          f.message(type+"TYPE_INT_RGB");
        else if(colorType == BufferedImage.TYPE_USHORT_555_RGB)
          f.message(type+"TYPE_USHORT_555_RGB");
        else if(colorType == BufferedImage.TYPE_USHORT_565_RGB)
          f.message(type+"TYPE_USHORT_565_RGB");
        else if(colorType == BufferedImage.TYPE_USHORT_GRAY)
          f.message(type+"TYPE_USHORT_GRAY");
        else
          f.message(type+"カラー・モデル不明" );
        startFlag = true;
        clear();
        f.canvas.markFlag = flag; //目印線表示可否を元に戻す。
      }

      else if(canvasMouseMode == 15)
      { //●命令文検索
        int mX = (int)(x/scaleAF +0.5);
        int mY = (int)(y/scaleAF +0.5);
        refer(mX,mY);
        startFlag = true;
        clear();
      }

      else if((canvasMouseMode == 6) && startFlag)
      { //●直線消去における始点位置
        x1 = (int)(x/scaleAF +0.5);
        y1 = (int)(y/scaleAF +0.5);
        startFlag = false;
      }
      else if((canvasMouseMode == 6) && !startFlag)
      { //●直線消去における終点位置
        x2 = (int)(x/scaleAF +0.5);
        y2 = (int)(y/scaleAF +0.5);
        eraseLine(x1, y1, x2, y2);
        startFlag = true;
        clear();
      }
      else if(canvasMouseMode == 32)
      { //●真円消去における中心位置
        int xC = (int)(x/scaleAF +0.5);
        int yC = (int)(y/scaleAF +0.5);
        eraseCircle(xC, yC);
        clear();
      }
      else if(canvasMouseMode == 33)
      { //●スプライン曲線制御点消去における指定位置
        int xS = (int)(x/scaleAF +0.5);
        int yS = (int)(y/scaleAF +0.5);
        eraseSplineControl(xS, yS);
        clear();
      }
      else if(canvasMouseMode == 34)
      { //●スプライン曲線制御点増殖（分裂増殖）における指定位置
        int xD = (int)(x/scaleAF +0.5);
        int yD = (int)(y/scaleAF +0.5);
        divideSplineControl(xD, yD);
        clear();
      }
      else if(canvasMouseMode == 103)
      { //●スプレー飛沫円盤中間点消去における指定位置
        int xS = (int)(x/scaleAF +0.5);
        int yS = (int)(y/scaleAF +0.5);
        eraseSprayNext(xS, yS);
        clear();
      }
      else if((canvasMouseMode == 10) && startFlag)
      { //●位置修正における旧点位置
        x1 = (int)(x/scaleAF +0.5);
        y1 = (int)(y/scaleAF +0.5);
        startFlag = false;
      }
      else if((canvasMouseMode == 10) && !startFlag)
      { //●位置修正における新点位置
        x2 = (int)(x/scaleAF +0.5);
        y2 = (int)(y/scaleAF +0.5);
        replacePoint(x1, y1, x2, y2);
        startFlag = true;
        clear();
      }

      else if(canvasMouseMode == 19 )
      { //●パレット混色での指定色で彩色変更。
        //パレットで混色指定済みの上で、図形指定（始点クリック）を行なうことで、
        //彩色変更がなされる。
        Color color = f.palette.mixColor2;
        if(color != null)
        {
          int cx = (int)(x/scaleAF +0.5);
          int cy = (int)(y/scaleAF +0.5);
          changeColor(cx, cy, color.getRed(),
            color.getGreen(), color.getBlue());
        }
      }

      //●自由図形は、直線とベジェ曲線とを混用して閉じた輪郭線の図形を描画し、
      //必要に応じて、その内部を色塗りする。
      //最終的に輪郭線を閉じさせるには、自由図形全体の始点に戻って左クリック。
      //大まかに言えば、左クリックは直線の指定で、右クリックは曲線の指定になる。
      //ただし、自由図形全体の始点は、常に左クリックとする。
      //また、自由図形全体の終点（始点への帰還）が曲線の終点（右クリック）でもある場合は、
      //その終点で左クリックを一つ追加して終了させる。
      //なお、正確に言えば、次のルールである。
      //自由図形の始点は、左クリック。
      //曲線部の第一制御点と第二制御点と終点は、右クリック。
      //直線部の終点は、左クリック。
      //最終的に輪郭線を閉じさせるには、自由図形全体の始点に戻って左クリック。
      //ただし、自由図形全体の終点（始点への回帰）が曲線部の終点（右クリック）でもある場合は、
      //その終点で左クリックを一つ追加して終了させる。
      //輪郭線を閉じさせるには、始点への回帰した時、左クリックが必要である。
      else if(canvasMouseMode == 14 && startFlag)
      { //●自由図形の第一段階（▼始点）
        x1 = (int)(x/scaleAF +0.5);
        y1 = (int)(y/scaleAF +0.5);

        int rc = colorRanNum();
        int gc = colorRanNum();
        int bc = colorRanNum();
        String method = "DrawShapeStart(4," + x1 + "," + y1 + "," +
          rc +"," + gc + "," + bc + ");";
        f.cArea.append(method + "\n");
        f.canvas.currentPointX = x1;
        f.canvas.currentPointY = y1;
        x2=x1; //x1,y1は、自由図形の始点として温存する。
        y2=y1; //x2,y2は、中間線での起点とする。
        startFlag = false;
      }
      else if(canvasMouseMode == 14 && !startFlag)
      { //●自由図形内＜直線＞の第二段階（中間点と終点）
        x3 = (int)(x/scaleAF +0.5); //x3,y3は、中間線での
        y3 = (int)(y/scaleAF +0.5); //末点として扱う。
        int Q = 2; //許容誤差（特に始点と終点との一致判定での許容誤差）
        if( ((x1+Q) >= x3 && (x1-Q) <= x3)  &&
          ((y1+Q) >= y3 && (y1-Q) <= y3)  )
        { //指定位置の近傍点をクリックした場合、
          //僅かにずれたものと見なして、一致させる。
          x3=x1;
          y3=y1;
        }
        if(!(x1==x3 && y1==y3)) //▼自由図形＜直線＞中間点
        {
          String method = "DrawShapeLine(" +
            x3 + "," + y3 + ");";
          f.cArea.append(method + "\n");
          method = "  DrawLine2(0," + x2 + "," + y2 + "," +
            x3 + "," + y3 + ");"; //直線部の合図として、マイナス値
          f.canvas.currentPointX = x3;
          f.canvas.currentPointY = y3;
          f.cArea.append(method + "\n");
          x2=x3; //次の線の始点を次の段階に伝える
          y2=y3;
        }
        else //▼自由図形終点
        {
          String method = "DrawShapeEnd();";
          f.cArea.append(method + "\n");
          method = "  DrawLine2(0," + x2 + "," + y2 + "," +
            x3 + "," + y3 + ");";
          f.cArea.append( method + "\n" + "//\n");
          f.canvas.currentPointX = x1;
          f.canvas.currentPointY = y1;
          startFlag = true;
          erase("DrawLine2");
          clear();
        }
      }
      f.canvas.repaint();
    }

    //●線描画モードで、右ボタンがクリックされる可能性がある場合の動作。
    //自由図形、スプライン曲線、折れ線、スプレーの場合、右ボタンも使われる。

    if((canvasMouseFlag == true) &&
      (eve.getButton() == MouseEvent.BUTTON3))
    {
         //●自由図形内＜ベジェ曲線＞の第一段階：曲線の始点（何もしなくて良い）
         //　自由図形内＜ベジェ曲線＞の始点は、左クリックである。
      if(canvasMouseMode == 14 && curveCnt == 1)
      {  //●自由図形内＜ベジェ曲線＞の第二段階：曲線の第一制御点を右クリック。
        x3 = (int)(x/scaleAF +0.5);
        y3 = (int)(y/scaleAF +0.5);
        curveCnt++;
        f.canvas.currentPointX = x3;
        f.canvas.currentPointY = y3;
        commandX = "DrawShapeCurve(" + x3 + "," + y3 + ",";
        String method = "  DrawLine2(1," + x2 + "," + y2 + "," +
          x3 + "," + y3 + ");";
        f.cArea.append(method + "\n");
        x2 = x3; //次の線の始点を次の段階に伝える
        y2 = y3;
      }
      else if(canvasMouseMode == 14 && curveCnt == 2)
      {  //●自由図形内＜ベジェ曲線＞の第三段階：曲線の第二制御点を右クリック。
        x3 = (int)(x/scaleAF +0.5);
        y3 = (int)(y/scaleAF +0.5);
        curveCnt++;
        f.canvas.currentPointX = x3;
        f.canvas.currentPointY = y3;
        commandX = commandX + x3 + "," + y3 + ",";
        String method = "  DrawLine2(2," + x2 + "," + y2 + "," +
          x3 + "," + y3 + ");";
        f.cArea.append(method + "\n");
        x2 = x3; //次の線の始点を次の段階に伝える
        y2 = y3;
      }
      else if(canvasMouseMode == 14 && curveCnt == 3)
      {  //●自由図形内＜ベジェ曲線＞の第四段階：曲線の終点を右クリック。
        x3 = (int)(x/scaleAF +0.5);
        y3 = (int)(y/scaleAF +0.5);
        commandX =  commandX + x3 + "," + y3 + ");";
        f.cArea.append(commandX + "\n");
        f.canvas.currentPointX = x3;
        f.canvas.currentPointY = y3;
        String method = "  DrawLine2(3," + x2 + "," + y2 + "," +
          x3 + "," + y3 + ");";
        f.cArea.append(method + "\n");
        curveCnt = 1;
        x2 = x3; //次の線の始点を次の段階に伝える
        y2 = y3;
        commandX = "";
      }
      f.canvas.repaint();
    }

    if(canvasMouseMode == 22 && splineCnt == 1 && (eve.getButton() == MouseEvent.BUTTON1))
    { //●スプライン曲線の第一段階：曲線の始点をクリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "DrawSplineStart(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      splineX0 = x1;
      splineY0 = y1;
      splineCnt++;
    }
    else if(canvasMouseMode == 22 && splineCnt > 1 && (eve.getButton() == MouseEvent.BUTTON1))
    { //●スプライン曲線の第二段階：曲線の制御点をクリック
      //制御点の位置指定が連続して同じ位置を間違ってクリックした場合、
      //終点を指定した後も、スプライン曲線が描画されず、補助線だけの表示となる。
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "DrawSplineControl(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      method = "  DrawLine2(" + 3 + "," + splineX0 + "," + splineY0 +  "," + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      splineX0 = x1;
      splineY0 = y1;
      splineCnt++;
    }
    else if(canvasMouseMode == 22 && splineCnt > 2 && (eve.getButton() == MouseEvent.BUTTON3))
    { //●スプライン曲線の最終段階：曲線の終点をクリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method =
        "DrawSplineEnd(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      f.cArea.append("//\n");
      clear();
      erase("DrawLine2");
    }

    if(canvasMouseMode == 30 && linkedLineCnt == 1 && (eve.getButton() == MouseEvent.BUTTON1))
    { //●折れ線の第一段階：折れ線の始点をクリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "LinkedLineStart(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      splineX0 = x1;
      splineY0 = y1;
      linkedLineCnt++;
    }
    else if(canvasMouseMode == 30 && linkedLineCnt > 1 && (eve.getButton() == MouseEvent.BUTTON1))
    { //●折れ線の途中段階：折れ線の継続点をクリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "LinkedLineNext(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      linkedLineCnt++;
    }
    else if(canvasMouseMode == 30 && linkedLineCnt > 2 && (eve.getButton() == MouseEvent.BUTTON3))
    { //●折れ線の最終段階：折れ線の終点をクリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method =
        "LinkedLineEnd(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      f.cArea.append("//\n");
      clear();
    }

    //●点描画の場合
    if( (canvasMouseFlag == true) && (canvasMouseMode == 101) &&
      (eve.getButton() == MouseEvent.BUTTON1) &&
      (brushSize >= 0) )
    {
      String methodP = "DrawCircle(2," +
        (int)(x/(scaleAF) +0.5) + "," +
        (int)(y/(scaleAF) +0.5) +
        "," + brushSize +
        "," + f.palette.mixColor2.getRed() +
        "," + f.palette.mixColor2.getGreen() +
        "," + f.palette.mixColor2.getBlue() + ");" ;
      f.cArea.append(methodP + "\n");
      f.canvas.repaint();
    }

    if(canvasMouseFlag == true && canvasMouseMode == 102 && sprayCnt == 1 &&
      (eve.getButton() == MouseEvent.BUTTON1))
    { //●スプレーの第一段階：始点を左クリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "SprayStart(" + x1 + "," + y1 + ", 1, 1.0, 30, 2000, 250, 150, 50, 255);";
      //座標値以外は、デフォルトの数値を設定するので、望みの数値に書き換えること。
      f.cArea.append(method + "\n");
      sprayCnt++;
      f.canvas.setInit();  //一般初期化
      f.canvas.repaint();  //描画実行
    }
    else if(canvasMouseFlag == true && canvasMouseMode == 102 && sprayCnt > 1 &&
      (eve.getButton() == MouseEvent.BUTTON1))
    { //●スプレーの中間段階：継続点を左クリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "SprayNext(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      sprayCnt++;
      f.canvas.setInit();  //一般初期化
      f.canvas.repaint();  //描画実行
    }
    else if(canvasMouseFlag == true && canvasMouseMode == 102 && sprayCnt > 1 &&
      (eve.getButton() == MouseEvent.BUTTON3))
    { //●スプレーの最終段階：終点を右クリック
      x1 = (int)(x/scaleAF +0.5); //端数四捨五入
      y1 = (int)(y/scaleAF +0.5);
      f.canvas.currentPointX = x1;
      f.canvas.currentPointY = y1;
      String method;
      method = "SprayEnd(" + x1 + "," + y1 + ");";
      f.cArea.append(method + "\n");
      f.cArea.append("//\n");
      sprayCnt = 1;
    }
  }

  //■座標位置変数の初期化
  void clear()
  {
    x1 = 0;
    y1 = 0;
    x2 = 0;
    y2 = 0;
    x3 = 0;
    y3 = 0;
    x4 = 0;
    y4 = 0;
    curveCnt = 1;
    splineCnt = 1;
    linkedLineCnt= 1;
    startFlag = true;
    horizontFlag = true;
    commandX = "";
    erase("DrawLine2");
  }

  //■直線消去
  //多用される直線については、専用の消去機能を作成。
  void eraseLine(int x1, int y1, int x2, int y2)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    //この時のStringTokenizerは、空行を削除する副作用あり。
    String command1; //命令1件（引数含む）
    for(int i=0; st.hasMoreTokens(); i++)
    { //●命令文を上から順に、全文調べる
      command1 = st.nextToken().trim();
      if(!command1.startsWith("DrawLine("))
      { //●該当しない命令の場合
        newCommand += command1 + "\n";
        continue;
      }
      else
      { //●該当する命令の場合
        StringTokenizer st2 = new StringTokenizer(command1,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox2 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy2 = (int)Double.parseDouble((st2.nextToken().trim()));

        if( //●近傍点の判定（精密さのため、許容誤差は最小に）
          ((x1<=ox1+1) && (x1>=ox1-1) &&
          (y1<=oy1+1) && (y1>=oy1-1) &&
          (x2<=ox2+1) && (x2>=ox2-1) &&
          (y2<=oy2+1) && (y2>=oy2-1))
            ||
          ((x1<=ox2+1) && (x1>=ox2-1) &&
          (y1<=oy2+1) && (y1>=oy2-1) &&
          (x2<=ox1+1) && (x2>=ox1-1) &&
          (y2<=oy1+1) && (y2>=oy1-1)))
        {
          newCommand += ("");
        }
        else
        { //●該当する直線でないのなら
          newCommand += command1 + "\n";
        }
      }
    }
    f.cArea.setText(newCommand);
  }

  //■真円消去
  //点描画で多用される真円については、専用の消去機能を作成。
  void eraseCircle(int x1, int y1)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    //この時のStringTokenizerは、空行を削除する副作用あり。
    String command1; //命令1件（引数含む）
    for(int i=0; st.hasMoreTokens(); i++)
    { //●命令文を上から順に、全文調べる
      command1 = st.nextToken().trim();
      if(!command1.startsWith("DrawCircle("))
      { //●該当しない命令の場合
        newCommand += command1 + "\n";
        continue;
      }
      else
      { //●該当する命令の場合
        //DrawCircle(int m, db x, db y, db rr, int r, int g, int b)
        StringTokenizer st2 = new StringTokenizer(command1,"(,)");
        st2.nextToken();
        st2.nextToken(); //モードは無視
        //●命令文における真円中心位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));

        if( //●近傍点の判定
          ((x1<=ox1+2) && (x1>=ox1-2) &&
          (y1<=oy1+2) && (y1>=oy1-2) ))
        {
          newCommand += ("");
        }
        else
        { //●該当する真円でないのなら
          newCommand += command1 + "\n";
        }
      }
    }
    f.cArea.setText(newCommand);
  }
  //■スプライン曲線制御点消去
  //多用されるスプライン曲線制御点については、専用の消去機能を作成。
  //ただし、スプライン曲線一本の描画では、最低でも一個の制御点が必要で、
  //最後の一個の制御点まで消去すると、実行時エラー（フリーズ状態）が生じる。
  //その実行時エラーを回避するため、スプライン曲線命令の記述規則チェックも行なう。
  void eraseSplineControl(int x1, int y1)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    //この時のStringTokenizerは、空行を削除する副作用あり。
    String command1; //命令1件（引数含む）
    for(int i=0; st.hasMoreTokens(); i++)
    { //●命令文を上から順に、全文調べる
      command1 = st.nextToken().trim(); //当該命令
      if(!command1.startsWith("DrawSplineControl("))
      { //●該当しない命令の場合
        newCommand += command1 + "\n";
        continue;
      }
      else
      { //●該当する命令の場合
        //DrawSplineControl(int x, int y)
        StringTokenizer st2 = new StringTokenizer(command1,"(,)");
        st2.nextToken();
        //●命令文における制御点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));

        if( //●近傍点の判定
          ((x1<=ox1+2) && (x1>=ox1-2) &&
          (y1<=oy1+2) && (y1>=oy1-2) ))  //近傍点であることを確認
        {
          //該当命令の直前命令および直後命令を検査し、
          //最後の一個の制御点でないことを確認する。
          String[] strCom = Util.splitReturn(commandZ);
          for(int j=1; j<strCom.length-1; j++)
          {
            if(strCom[j].trim().equals(command1.trim()) &&
              strCom[j-1].trim().startsWith("DrawSplineStart") &&
              strCom[j+1].trim().startsWith("DrawSplineEnd") )
            {
              newCommand += command1 + "\n";  //消去回避
              f.message("制御点消去できません。制御点は一個以上必要です。");
            }
            else
            { //制御点が複数続いている。
              newCommand += "\n"; //消去実行
            }
          }
        }
        else
        { //●近傍点ではない。
          newCommand += command1 + "\n";
        }
      }
    }
    f.cArea.setText(newCommand);
  }
  //■スプライン曲線制御点増殖（分裂増殖）
  //多用されるスプライン曲線制御点については、専用の増殖機能（分裂増殖）を作成。
  void divideSplineControl(int x1, int y1)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    //この時のStringTokenizerは、空行を削除する副作用あり。
    String command1; //命令1件（引数含む）
    for(int i=0; st.hasMoreTokens(); i++)
    { //●命令文を上から順に、全文調べる
      command1 = st.nextToken().trim(); //当該命令
      if(!command1.startsWith("DrawSplineControl("))
      { //●該当しない命令の場合
        newCommand += command1 + "\n";
        continue;
      }
      else
      { //●該当する命令の場合
        //DrawSplineControl(int x, int y)
        StringTokenizer st2 = new StringTokenizer(command1,"(,)");
        st2.nextToken();
        //●命令文における制御点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));

        if( //●近傍点の判定
          ((x1<=ox1+2) && (x1>=ox1-2) &&
          (y1<=oy1+2) && (y1>=oy1-2) ))  //近傍点であることを確認
        {
          //該当命令の直前命令および直後命令を検査し、
          //分裂増殖せさて配置する適当な位置を確保して挿入する。
          //ただし、分裂増殖させるに充分な隙間がなければならない。
          //該当命令と直前命令および直後命令との位置が接近していれば、実行時エラーが生じ得る。
          //マウスの操作不手際以外、そのようなことは、起きないだろう。
          //また、スプライン系命令が、コメント行なしの正規形式で、連続していなければならない。
          //なお、スプライン曲線制御点増殖の後、マウス操作による位置修正が必要となろう。
          String[] strCom = Util.splitReturn(commandZ);
          for(int j=0; j<strCom.length; j++)
          {
            if(strCom[j].trim().equals(command1.trim())  )
            {
              String strP = strCom[j-1].trim(); //直前命令
              String strN = strCom[j+1].trim(); //直後命令

              StringTokenizer st3 = new StringTokenizer(strP,"(,)");
              st3.nextToken(); //命令語を捨てる
              int xP = (int)Double.parseDouble((st3.nextToken().trim()));
              int yP = (int)Double.parseDouble((st3.nextToken().trim()));

              StringTokenizer st4 = new StringTokenizer(strN,"(,)");
              st4.nextToken(); //命令語を捨てる
              int xN = (int)Double.parseDouble((st4.nextToken().trim()));
              int yN = (int)Double.parseDouble((st4.nextToken().trim()));

              int xP2 = xP+(int)((x1-xP)/4)*3; //分裂させるに適当な距離を取る
              int yP2 = yP+(int)((y1-yP)/4)*3;

              int xN2 = x1+(int)((xN-x1)/4); //分裂させるに適当な距離を取る
              int yN2 = y1+(int)((yN-y1)/4);

              newCommand += ( //古い命令を除去して、分裂増殖した新しい命令を挿入。
                "DrawSplineControl(" + xP2 + "," + yP2 + ");\n" +
                "DrawSplineControl(" + xN2 + "," + yN2 + ");\n" );  //
            }
          }
        }
        else
        { //●近傍点ではない。
          newCommand += command1 + "\n"; //命令を温存
        }
      }
    }
    f.cArea.setText(newCommand);
  }
  //■スプレー飛沫円盤中間点消去
  //多用されるスプレー飛沫円盤中間点については、専用の消去機能を作成。
  void eraseSprayNext(int x1, int y1)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    //この時のStringTokenizerは、空行を削除する副作用あり。
    String command1; //命令1件（引数含む）
    for(int i=0; st.hasMoreTokens(); i++)
    { //●命令文を上から順に、全文調べる
      command1 = st.nextToken().trim(); //ある命令文の一行文
      if(!command1.startsWith("SprayNext("))
      { //●無関係命令や注釈文の場合
        newCommand += command1 + "\n";
        continue;
      }
      else
      { //●SprayNext命令の場合
        //SprayNext(int x, int y)
        StringTokenizer st2 = new StringTokenizer(command1,"(,)");
        st2.nextToken();
        //●命令文における制御点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));

        if( //●近傍点の判定
          ((x1<=ox1+2) && (x1>=ox1-2) &&
          (y1<=oy1+2) && (y1>=oy1-2) ))  //近傍点であることを確認
        {
          //該当命令の直前命令および直後命令を検査し、
          //最後の一個の制御点でないことを確認する。
          String[] strCom = Util.splitReturn(commandZ);
          for(int j=1; j<strCom.length-1; j++)
          {
            if(strCom[j].trim().equals(command1.trim()) )
            {
              newCommand += "\n";  //消去実施
            }
          }
        }
        else
        { //●近傍点ではない。
          newCommand += command1 + "\n";
        }
      }
    }
    f.cArea.setText(newCommand);
  }

  //■描画命令の座標点修正
  //  DrawLine(),DrawCurve(),
  //  DrawShapeStart(),DrawShapeCurve(),DrawShapeLine(),
  //  DrawSplineStart(),DrawSplineControl(),DrawSplineEnd(),
  //  SprayStart(),SprayNext(),SprayEnd(),
  //  これらの座標ポイントを書き替える。
  //  DrawEllipse(),DrawCircle(),DrawRect(),WriteStringH()系 は、始点を書き替える。
  //  Stamp()は、始点を書き替える。StampMulti()は、書き替えない。
  //  縮小表示では、マウス操作の位置指定で極度の正確さが必要となる。
  //  そのため、等倍表示以上で、位置修正の操作を推奨する。
  void replacePoint(int x1, int y1, int x2, int y2)
    //x1,y1 は、クリックされた移動前の古い座標点。
    //x2,y2 は、クリックされた移動後の新しい座標点。
  {
    //最初のクリックで旧点を指定し、二回目で移動先の新点を指定。
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    String command;
    int Q = 2; //●位置指定での許容誤差
    for(int i=0; st.hasMoreTokens(); i++)
    {
      command = st.nextToken().trim();
      if(command.startsWith("DrawLine("))
      { //●直線の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox2 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy2 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●始点と判定されたら修正実行
          newCommand += ("DrawLine(" +
            x2 + "," + y2 + "," +
            ox2 + "," + oy2 + ");\n");
        }
        else if((x1<=ox2+Q) && (x1>=ox2-Q) && //近傍点の判定
            (y1<=oy2+Q) && (y1>=oy2-Q))
        { //●終点と判定されたら修正実行
          newCommand += ("DrawLine(" +
            ox1 + "," + oy1 + "," +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      //●●スプライン曲線の位置修正の結果、命令文の並びで、連続した同一座標位置指定になると、
      //データ・エラーとなって、スプライン曲線の補助線は残るが、スプライン曲線本体が消える。
      //位置修正の結果、座標位置が同一点で連続し、スプライン曲線だけが消えた場合、
      //スプライン曲線の補助線の結節点を頼りに、命令文検索を行ない、
      //連続した座標位置指定になった部分を見付け出し、キーボード操作で修正しなければならない。
      //ただし、その操作の煩雑を避けるため、同一点連続の回避策（位置修正回避）を以下に組み込む。
      else if(command.startsWith("DrawSpline"))
      { //●スプライン曲線関連の三命令のどれかに該当
        String[] commandsArr = Util.splitReturn(commandZ);
        if(command.startsWith("DrawSplineStart("))
        { //●スプライン曲線始点の位置修正
          int xN = 0; //DrawSplineStartの直後にあるDrawSplineControlの座標値
          int yN = 0;
          for(int j=0; j<commandsArr.length; j++)
          {
            if(commandsArr[j].equals(command))
            {
              String nextCommand = commandsArr[j+1]; //「DrawSplineControl」命令を取得
              StringTokenizer st3 = new StringTokenizer(nextCommand,"(,)");
              st3.nextToken(); //命令語の「DrawSplineControl」は捨てる。
              xN = (int)Double.parseDouble((st3.nextToken().trim())); //座標値
              yN = (int)Double.parseDouble((st3.nextToken().trim()));
              break; //for文を途中終了
            }
          }
          StringTokenizer st2 = new StringTokenizer(command,"(,)");
          st2.nextToken(); //●命令文における旧点位置の取得
          int ox1 = (int)Double.parseDouble((st2.nextToken().trim())); //旧命令文
          int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
          if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
             (y1<=oy1+Q) && (y1>=oy1-Q) &&
             (x2 != xN && y2 != yN) //同一連続位置でない
            )
          { //●修正実行
            newCommand += ("DrawSplineStart(" +
              x2 + "," + y2 + ");\n"); //新命令文
          }
          else
          { //●該当点が見付からないなら
            newCommand += command+"\n";
          }
        }
        else if(command.startsWith("DrawSplineControl("))
        { //●スプライン曲線制御点の位置修正
          int xP = 0; //当該DrawSplineControlの直前にあるスプライン命令の座標値
          int yP = 0;
          int xN = 0; //当該DrawSplineControlの直後にあるスプライン命令の座標値
          int yN = 0;
          for(int j=0; j<commandsArr.length; j++)
          {
            if(commandsArr[j].equals(command))
            {
              String previousCommand = commandsArr[j-1]; //直前命令を取得
              StringTokenizer st3 = new StringTokenizer(previousCommand,"(,)");
              st3.nextToken(); //命令語部分は捨てる。
              xP = (int)Double.parseDouble((st3.nextToken().trim())); //座標値
              yP = (int)Double.parseDouble((st3.nextToken().trim()));

              String nextCommand = commandsArr[j+1]; //直後命令を取得
              StringTokenizer st4 = new StringTokenizer(nextCommand,"(,)");
              st4.nextToken(); //命令語部分は捨てる。
              xN = (int)Double.parseDouble((st4.nextToken().trim())); //座標値
              yN = (int)Double.parseDouble((st4.nextToken().trim()));
              break; //for文を途中終了
            }
          }
          StringTokenizer st2 = new StringTokenizer(command,"(,)");
          st2.nextToken(); //●命令文における旧点位置の取得
          int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
          int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
          if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
             (y1<=oy1+Q) && (y1>=oy1-Q) &&
             (x2 != xP && y2 != yP) && //同一連続位置でない
             (x2 != xN && y2 != yN)    //同一連続位置でない
            )
          { //●修正実行
            newCommand += ("DrawSplineControl(" +
              x2 + "," + y2 + ");\n");
          }
          else
          { //●該当点が見付からないなら
            newCommand += command+"\n";
          }
        }
        else if(command.startsWith("DrawSplineEnd("))
        { //●スプライン曲線終点の位置修正
          int xP = 0; //DrawSplineEndの直前にあるDrawSplineControlの座標値
          int yP = 0;
          for(int j=0; j<commandsArr.length; j++)
          {
            if(commandsArr[j].equals(command))
            {
              String previousCommand = commandsArr[j-1]; //「DrawSplineControl」命令を取得
              StringTokenizer st3 = new StringTokenizer(previousCommand,"(,)");
              st3.nextToken(); //命令語の「DrawSplineControl」は捨てる。
              xP = (int)Double.parseDouble((st3.nextToken().trim())); //座標値
              yP = (int)Double.parseDouble((st3.nextToken().trim()));
              break; //for文を途中終了
            }
          }
          StringTokenizer st2 = new StringTokenizer(command,"(,)");
          st2.nextToken(); //●命令文における旧点位置の取得
          int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
          int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
          if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
             (y1<=oy1+Q) && (y1>=oy1-Q) &&
             (x2 != xP && y2 != yP) //同一連続位置でない
            )
          { //●修正実行
            newCommand += ("DrawSplineEnd(" +
              x2 + "," + y2 + ");\n");
          }
          else
          { //●該当点が見付からないなら
            newCommand += command+"\n";
          }
        }
      }

      else if(command.startsWith("LinkedLineStart("))
      { //●折れ線始点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●修正実行
          newCommand += ("LinkedLineStart(" +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("LinkedLineNext("))
      { //●折れ線継続点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●修正実行
          newCommand += ("LinkedLineNext(" +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("LinkedLineEnd("))
      { //●折れ線終点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●修正実行
          newCommand += ("LinkedLineEnd(" +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      else if(command.startsWith("DrawCurve("))
      { //●単独ベジェ曲線の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox2 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy2 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox3 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy3 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox4 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy4 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●始点と判定されたら修正実行
          newCommand += ("DrawCurve(" +
            x2 + "," + y2 + "," +
            ox2 + "," + oy2 + "," +
            ox3 + "," + oy3 + "," +
            ox4 + "," + oy4 + ");\n");
        }
        else if((x1<=ox2+Q) && (x1>=ox2-Q) &&   //近傍点の判定
            (y1<=oy2+Q) && (y1>=oy2-Q))
        { //●第一制御点と判定されたら修正実行
          newCommand += ("DrawCurve(" +
            ox1 + "," + oy1 + "," +
            x2 + "," + y2 + "," +
            ox3 + "," + oy3 + "," +
            ox4 + "," + oy4 + ");\n");
        }
        else if((x1<=ox3+Q) && (x1>=ox3-Q) && //近傍点の判定
            (y1<=oy3+Q) && (y1>=oy3-Q))
        { //●第二制御点と判定されたら修正実行
          newCommand += ("DrawCurve(" +
            ox1 + "," + oy1 + "," +
            ox2 + "," + oy2 + "," +
            x2 + "," + y2 + "," +
            ox4 + "," + oy4 + ");\n");
        }
        else if((x1<=ox4+Q) && (x1>=ox4-Q) && //近傍点の判定
            (y1<=oy4+Q) && (y1>=oy4-Q))
        { //●終点と判定されたら修正実行
          newCommand += ("DrawCurve(" +
            ox1 + "," + oy1 + "," +
            ox2 + "," + oy2 + "," +
            ox3 + "," + oy3 + "," +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("DrawShapeStart("))
      { //●自由図形の始点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int m   = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int r   = (int)Double.parseDouble((st2.nextToken().trim()));
        int g   = (int)Double.parseDouble((st2.nextToken().trim()));
        int b   = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("DrawShapeStart(" +
            m + "," +
            x2 + "," + y2 + "," +
            r + "," +
            g + "," +
            b + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("DrawShapeLine(") ||
        command.startsWith("DSL("))
      { //●自由図形での直線部分の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("DrawShapeLine(" +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("DrawShapeCurve("))
      { //●自由図形での曲線（ベジェ曲線）部分の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox2 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy2 = (int)Double.parseDouble((st2.nextToken().trim()));
        int ox3 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy3 = (int)Double.parseDouble((st2.nextToken().trim()));
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●第一制御点と判定されたら修正実行
          newCommand += ("DrawShapeCurve(" +
            x2 + "," + y2 + "," +
            ox2 + "," + oy2 + "," +
            ox3 + "," + oy3 + ");\n");
        }
        else if((x1<=ox2+Q) && (x1>=ox2-Q) && //近傍点の判定
            (y1<=oy2+Q) && (y1>=oy2-Q))
        { //●第二制御点と判定されたら修正実行
          newCommand += ("DrawShapeCurve(" +
            ox1 + "," + oy1 + "," +
            x2 + "," + y2 + "," +
            ox3 + "," + oy3 + ");\n");
        }
        else if((x1<=ox3+Q) && (x1>=ox3-Q) && //近傍点の判定
            (y1<=oy3+Q) && (y1>=oy3-Q))
        { //●終点と判定されたら修正実行
          newCommand += ("DrawShapeCurve(" +
            ox1 + "," + oy1 + "," +
            ox2 + "," + oy2 + "," +
            x2 + "," + y2 + ");\n");
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("DrawCircle("))
      { //●真円の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        String em = st2.nextToken().trim(); //
        int ex = (int)Double.parseDouble((st2.nextToken().trim())); //
        int ey = (int)Double.parseDouble((st2.nextToken().trim())); //
        String str1 = st2.nextToken().trim(); //半径
        String str2 = st2.nextToken().trim(); //赤色
        String str3 = st2.nextToken().trim(); //緑色
        String str4 = st2.nextToken().trim(); //青色
        if((x1<=ex+Q) && (x1>=ex-Q) &&   //近傍点の判定
           (y1<=ey+Q) && (y1>=ey-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("DrawCircle(" + em +"," +
            x2 + "," + y2 + "," +
            str1 +"," + str2 +"," + str3 +"," + str4  +");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("DrawEllipse("))
      { //●楕円の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        String em = st2.nextToken().trim(); //
        int ex = (int)Double.parseDouble((st2.nextToken().trim())); //
        int ey = (int)Double.parseDouble((st2.nextToken().trim())); //
        String str1 = st2.nextToken().trim(); //横半径
        String str2 = st2.nextToken().trim(); //縦半径
        String str3 = st2.nextToken().trim(); //赤色
        String str4 = st2.nextToken().trim(); //緑色
        String str5 = st2.nextToken().trim(); //青色
        if((x1<=ex+Q) && (x1>=ex-Q) &&   //近傍点の判定
           (y1<=ey+Q) && (y1>=ey-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("DrawEllipse(" + em +"," +
            x2 + "," + y2 + "," +
            str1 +"," + str2 +"," + str3 +"," + str4 +"," + str5 +");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("DrawRect("))
      { //●長方形の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        String rm = st2.nextToken().trim(); //モード
        int rx = (int)Double.parseDouble((st2.nextToken().trim())); //x
        int ry = (int)Double.parseDouble((st2.nextToken().trim())); //y
        String str1 = st2.nextToken().trim(); //幅
        String str2 = st2.nextToken().trim(); //丈
        String str3 = st2.nextToken().trim(); //赤色
        String str4 = st2.nextToken().trim(); //緑色
        String str5 = st2.nextToken().trim(); //青色
        if((x1<=rx+Q) && (x1>=rx-Q) &&   //近傍点の判定
           (y1<=ry+Q) && (y1>=ry-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("DrawRect(" + rm +"," +
            x2 + "," + y2 + "," +
            str1 +"," + str2 +"," + str3 +"," + str4 +"," +str5 +");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      else if(command.startsWith("SprayStart("))
      { //●スプレー起点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int rx = (int)Double.parseDouble((st2.nextToken().trim())); //x
        int ry = (int)Double.parseDouble((st2.nextToken().trim())); //y
        String str1 = st2.nextToken().trim(); //分布タイプ
        String str2 = st2.nextToken().trim(); //飛沫大きさ
        String str3 = st2.nextToken().trim(); //飛沫円盤半径
        String str4 = st2.nextToken().trim(); //飛沫個数
        String str5 = st2.nextToken().trim(); //赤色
        String str6 = st2.nextToken().trim(); //緑色
        String str7 = st2.nextToken().trim(); //青色
        String str8 = st2.nextToken().trim(); //透明度
        if((x1<=rx+Q) && (x1>=rx-Q) &&   //近傍点の判定
           (y1<=ry+Q) && (y1>=ry-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("SprayStart(" +
            x2 + "," + y2 + "," +
            str1 +"," + str2 +"," + str3 + "," + str4 + "," + str5 + "," +
            str6 + "," + str7 + "," + str8 + ");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("SprayNext("))
      { //●スプレー継続点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int rx = (int)Double.parseDouble((st2.nextToken().trim())); //x
        int ry = (int)Double.parseDouble((st2.nextToken().trim())); //y
        if((x1<=rx+Q) && (x1>=rx-Q) &&   //近傍点の判定
           (y1<=ry+Q) && (y1>=ry-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("SprayNext(" +
            x2 + "," + y2  + ");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("SprayEnd("))
      { //●スプレー終点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int rx = (int)Double.parseDouble((st2.nextToken().trim())); //x
        int ry = (int)Double.parseDouble((st2.nextToken().trim())); //y
        if((x1<=rx+Q) && (x1>=rx-Q) &&   //近傍点の判定
           (y1<=ry+Q) && (y1>=ry-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("SprayEnd(" +
            x2 + "," + y2  + ");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      else if(command.startsWith("Stamp("))
      { //●前景画像の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int rx = Integer.parseInt((st2.nextToken().trim())); //x
        int ry = Integer.parseInt((st2.nextToken().trim())); //y
        String str1 = st2.nextToken().trim(); //幅
        String str2 = st2.nextToken().trim(); //丈
        String str3 = Util.trimAffix(st2.nextToken(),'\"','\"'); //ファイル名
        if((x1<=rx+Q) && (x1>=rx-Q) &&   //近傍点の判定
           (y1<=ry+Q) && (y1>=ry-Q))
        { //●該当点と判定されたら修正実行
          newCommand += ("Stamp(" +  x2 + "," + y2 + "," +
            str1 +"," + str2 +"," + str3+ ");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("WriteStringH(") ||
        command.startsWith("WriteString(") ||
        command.startsWith("WriteStringB(") ||
        command.startsWith("WriteStringV("))
      { //●文字列（並字、極太字、縦書き）の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置の取得
        int ox1 = (int)Double.parseDouble((st2.nextToken().trim()));
        int oy1 = (int)Double.parseDouble((st2.nextToken().trim()));
        String str1 = st2.nextToken().trim();
        String str2 = st2.nextToken().trim();
        String str3 = st2.nextToken().trim();
        if((x1<=ox1+Q) && (x1>=ox1-Q) &&   //近傍点の判定
           (y1<=oy1+Q) && (y1>=oy1-Q))
        { //●該当点と判定されたら修正実行
          if(command.startsWith("WriteStringH("))
            newCommand += ("WriteStringH(" +
            x2 + "," + y2 + "," +
            str1 + "," + str2 + "," + str3 + ");\n" );
          else if(command.startsWith("WriteString("))
            newCommand += ("WriteString(" +
            x2 + "," + y2 + "," +
            str1 + "," + str2 + "," + str3 + ");\n" );
          else if(command.startsWith("WriteStringB("))
            newCommand += ("WriteStringB(" +
            x2 + "," + y2 + "," +
            str1 + "," + str2 + "," + str3 + ");\n" );
          else if(command.startsWith("WriteStringV("))
            newCommand += ("WriteStringV(" +
            x2 + "," + y2 + "," +
            str1 + "," + str2 + "," + str3 + ");\n" );
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else
      { //●いずれにも該当しない命令の場合
        newCommand += command+"\n";
        continue;
      }
    }
    f.cArea.setText(newCommand);
  }

  //■指定のコマンドを全部消去する。
  void erase(String commandE)
  {  //一時使用するだけの「DrawLine2」コマンドにのみ利用
    String commandZ = f.cArea.getText(); //コマンド全文取得
    String newCommandZ = ""; //新しいコマンド全文
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    String command1;  //検査対象の描画コマンド1件
    for(int i=0; st.hasMoreTokens(); i++)
    {
      command1 = st.nextToken().trim();
      if(!(command1.startsWith(commandE)) )
      {  //不一致
        newCommandZ += command1+"\n";
        continue;
      }
      else
      {  //一致
        ; //拾わずに捨てる（消去）
      }
    }
    f.cArea.setText(newCommandZ);  //編集済みコマンド全文の格納
    f.canvas.repaint();
  }

  //■描画命令文検索
  //  クリックされた位置を始点とする線描画命令を探し出し、
  //  命令文の末尾に、コメント（//★★★）を付けて、表示する。
  void refer(int x, int y)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n"); //行毎に分解
    String command;
    for(int i=0; st.hasMoreTokens(); i++)
    {
      command = st.nextToken().trim(); //命令１行を取得
      StringTokenizer st2 = new StringTokenizer(command,"(),;"); //命令１行を分解
      st2.nextToken().trim(); //コマンド名の部分を捨てる
      if(command.endsWith("//★★★"))
      { //●命令文の末尾に、既に「//★★★」があれば、削除する
        command = command.substring(0,command.length()-5);
      }

      if(command.startsWith("DrawLine"))
      { //●直線の始点または終点
        String x1, y1, x2, y2;
        x1 = st2.nextToken().trim();
        y1 = st2.nextToken().trim();
        x2 = st2.nextToken().trim();
        y2 = st2.nextToken().trim();
        if(nearEquals(x, x1) && nearEquals(y, y1))
          newCommand += command+"//★★★\n";
        else if(nearEquals(x, x2) && nearEquals(y, y2))
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }
      else if(command.startsWith("DrawCurve"))
      { //●単独ベジェ曲線
        String x1, y1, x2, y2, x3, y3, x4, y4;
        x1 = st2.nextToken().trim();
        y1 = st2.nextToken().trim();
        x2 = st2.nextToken().trim();
        y2 = st2.nextToken().trim();
        x3 = st2.nextToken().trim();
        y3 = st2.nextToken().trim();
        x4 = st2.nextToken().trim();
        y4 = st2.nextToken().trim();
        if(nearEquals(x, x1) && nearEquals(y, y1))
          newCommand += command+"//★★★\n";
        else if(nearEquals(x, x2) && nearEquals(y, y2))
          newCommand += command+"//★★★\n";
        else if(nearEquals(x, x3) && nearEquals(y, y3))
          newCommand += command+"//★★★\n";
        else if(nearEquals(x, x4) && nearEquals(y, y4))
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }
      else if(
        command.startsWith("DrawSplineStart") ||
        command.startsWith("DrawSplineControl") ||
        command.startsWith("DrawSplineEnd"))
      { //●スプライン曲線
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }

      else if(
        command.startsWith("LinkedLineStart") ||
        command.startsWith("LinkedLineNext") ||
        command.startsWith("LinkedLineEnd"))
      { //●折れ線
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }

      else if(command.startsWith("DrawShapeStart"))
      { //●自由図形の始点
        st2.nextToken().trim(); //描画モードは不用
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }
      else if(command.startsWith("DrawShapeLine"))
      { //●自由図形の直線部終点
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }
      else if(command.startsWith("DrawShapeCurve"))
      { //●自由図形の曲線部
        String x1, y1, x2, y2, x3, y3;
        x1 = st2.nextToken().trim();
        y1 = st2.nextToken().trim();
        x2 = st2.nextToken().trim();
        y2 = st2.nextToken().trim();
        x3 = st2.nextToken().trim();
        y3 = st2.nextToken().trim();
        if((nearEquals(x, x1) && nearEquals(y, y1)) ||
          (nearEquals(x, x2) && nearEquals(y, y2)) ||
          (nearEquals(x, x3) && nearEquals(y, y3)) )
        {
          newCommand += command+"//★★★\n";
        }
        else
          newCommand += command+"\n";
      }

      else if(command.startsWith("DrawEllipse"))
      { //●楕円の始点（中心点）
        st2.nextToken().trim(); //描画モードは不用
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }
      else if(command.startsWith("DrawCircle"))
      { //●真円の始点（中心点）
        st2.nextToken().trim(); //描画モードは不用
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }
      else if(command.startsWith("DrawRect"))
      { //●長方形の始点（左上点）
        st2.nextToken().trim(); //描画モードは不用
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }

      else if(command.startsWith("WriteStringH") || command.startsWith("WriteString"))
      { //●文字列の始点（左下点）
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }

      else if(
        command.startsWith("SprayStart") ||
        command.startsWith("SprayNext") ||
        command.startsWith("SprayEnd"))
      { //●スプレー
        if(nearEquals(x, st2.nextToken().trim()) &&
        nearEquals(y, st2.nextToken().trim()) )
          newCommand += command+"//★★★\n";
        else
          newCommand += command+"\n";
      }

      else
      {
        newCommand += command+"\n";
      }
    }
    f.cArea.setText(newCommand);
    f.canvas.repaint();
  }

  int colorRanNum()
  { //●ランダムなRGBのどれか一つを作る
    Random ran = new Random();
    return (10 + ran.nextInt(240));
  }

  boolean nearEquals(int a, String s)
  { //●近似値判定、（sは整数または実数で数値表現された文字列）
    double d = Double.parseDouble(s);
    if((a+2 >= d) && (a-2 <= d))
      return true;
    else
      return false;
  }

  boolean nearEquals(double a, double b)
  { //●近似値判定
    if((a+2 >= b) && (a-2 <= b))
      return true;
    else
      return false;
  }

  //■図形彩色変更
  //  クリックされた位置を始点とする図形描画命令を探し出し、
  //  パレットで混色されている色を使って、
  //  命令の彩色指定部分を書き変える。
  void changeColor(int x, int y, int r, int g, int b)
  {
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    String command = "";
    for(int i=0; st.hasMoreTokens(); i++)
    {
      command = st.nextToken().trim();
      String[] strArray = Util.csv2Array(command,0);

      if( //●自由図形の彩色変更
        (strArray[0].startsWith("DrawShapeStart")))
      {
        int x0 = (int)Double.parseDouble(strArray[1]);
        int y0 = (int)Double.parseDouble(strArray[2]);
        if(nearEquals(x0,x) && nearEquals(y0,y))
        {
          newCommand += strArray[0] + "," +
            strArray[1] + "," + strArray[2] + "," +
            r  + "," + g  + "," + b  + ");\n" ;
        }
        else
        {
          newCommand += command+"\n" ;
        }
      }
      else if( //●真円の彩色変更
        (strArray[0].startsWith("DrawCircle")))
      {
        int x0 = (int)Double.parseDouble(strArray[1]);
        int y0 = (int)Double.parseDouble(strArray[2]);
        if(nearEquals(x0,x) && nearEquals(y0,y))
        {
          newCommand += strArray[0] + "," +
            strArray[1] + "," + strArray[2] + "," +
            strArray[3] +  "," +
            r  + "," + g  + "," + b  + ");\n" ;
        }
        else
        {
          newCommand += command+"\n" ;
        }
      }
      else if( //●楕円の彩色変更
        (strArray[0].startsWith("DrawEllipse")))
      {
        int x0 = (int)Double.parseDouble(strArray[1]);
        int y0 = (int)Double.parseDouble(strArray[2]);
        if(nearEquals(x0,x) && nearEquals(y0,y))
        {
          newCommand += strArray[0] + "," +
            strArray[1] + "," + strArray[2] + "," +
            strArray[3] + "," + strArray[4] + "," +
            r  + "," + g  + "," + b  + ");\n" ;
        }
        else
        {
          newCommand += command+"\n" ;
        }
      }
      else if( //●長方形の彩色変更
        (strArray[0].startsWith("DrawRect")))
      {
        int x0 = (int)Double.parseDouble(strArray[1]);
        int y0 = (int)Double.parseDouble(strArray[2]);
        if(nearEquals(x0,x) && nearEquals(y0,y))
        {
          newCommand += strArray[0] + "," +
            strArray[1] + "," + strArray[2] + "," +
            strArray[3] + "," + strArray[4] + "," +
            r  + "," + g  + "," + b  + ");\n" ;
        }
        else
        {
          newCommand += command+"\n" ;
        }
      }
      else
      {
        newCommand += command+"\n" ;
      }
    }
    f.cArea.setText(newCommand);
    f.canvas.repaint();
  }

  //以下は、MouseListenerの実装で、無反応にする部分

  public void mouseEntered(MouseEvent e)
  {}
  public void mouseExited(MouseEvent e)
  {}
  public void mouseClicked(MouseEvent e)
  {}
  public void mouseReleased(MouseEvent e)
  {}
} //EOF (GCreatorCanMouseLis.java)

◆GCreatorPalMouseLis.java

//■■GCreatorPalMouseLis.java
//Ver.4.1

//■■インポート
import java.awt.*;  //必須
import java.awt.event.*;  //必須

//■■マウスのクリックで呼び出されるリスナー（パレット用）
class GCreatorPalMouseLis implements MouseListener
{
  //■メンバー変数
  GCreator f;
  int colorNum = 0;     //基準色１６色の順序番号
  int selectColor = 0;  //１番目から三番目の色選択順

  //パレットの配置状況
  final int x = 5;  //left margin
  final int y = 5;  //top margin
  final int w =50;  //box width
  final int h =50;  //box height

  //パレット上の絵の具位置
  final int colorP[][] = {
  {x+  0,y+  0},  //red
  {x+ 50,y+  0},  //maroon
  {x+100,y+  0},  //magenta
  {x+150,y+  0},  //purple
  {x+  0,y+100},  //green
  {x+ 50,y+100},  //d.green
  {x+100,y+100},  //yellow
  {x+150,y+100},  //olive
  {x+  0,y+200},  //blue
  {x+ 50,y+200},  //navy
  {x+100,y+200},  //cyan
  {x+150,y+200},  //teal
  {x+  0,y+300},  //white
  {x+ 50,y+300},  //silver
  {x+100,y+300},  //gray
  {x+150,y+300}}; //black

  //基準色の色価
  final int colorV[][] = {
  {0xff, 0x00, 0x00},  //red
  {0x80, 0x00, 0x00},  //maroon
  {0xff, 0x00, 0xff},  //magenta
  {0x80, 0x00, 0x80},  //purple
  {0x00, 0xff, 0x00},  //green
  {0x00, 0x80, 0x00},  //d.green
  {0xff, 0xff, 0x00},  //yellow
  {0x80, 0x80, 0x00},  //olive
  {0x00, 0x00, 0xff},  //blue
  {0x00, 0x00, 0x80},  //navy
  {0x00, 0xff, 0xff},  //cyan
  {0x00, 0x80, 0x80},  //teal
  {0xff, 0xff, 0xff},  //white
  {0xc0, 0xc0, 0xc0},  //silver
  {0x80, 0x80, 0x80},  //gray
  {0x00, 0x00, 0x00}}; //black

  //■コンストラクタ
  GCreatorPalMouseLis(GCreator flame)
  {
    f = flame;
  }

  //■イベントハンドラ
  public void mousePressed(MouseEvent eve)
  {
    //●点描マウス入力モードが解除状態または左クリックでない場合
    if(eve.getButton() != MouseEvent.BUTTON1)
    {
      return;
    }
    int x = eve.getX(); //マウスのクリック位置を取得
    int y = eve.getY();
    //●1回目の色選択
    if(selectColor == 0)
    { //●座標位置から指定されたパレット色（未混色）を割り出す。
      for(colorNum=0; colorNum<16; colorNum++)
      {
        if((x > colorP[colorNum][0]) && (x < colorP[colorNum][0]+w) &&
          (y > colorP[colorNum][1]) && (y < colorP[colorNum][1]+h))
        {
          f.palette.choiceN = 1;
          f.palette.choiceC1 = new Color(
            colorV[colorNum][0], colorV[colorNum][1],
            colorV[colorNum][2]);
          selectColor =1;
          f.sldR.setValue(0);
          f.sldG.setValue(0);
          f.sldB.setValue(0);
          break;
        }
      }
    }
    //●2回目の色選択
    else if(selectColor == 1)
    { //●座標位置から指定されたパレット色（未混色）を割り出す。
      for(colorNum=0; colorNum<16; colorNum++)
      {
        if((x > colorP[colorNum][0]) && (x < colorP[colorNum][0]+w) &&
          (y > colorP[colorNum][1]) && (y < colorP[colorNum][1]+h))
        {
          f.palette.choiceN = 2;
          f.palette.choiceC2 = new Color(
            colorV[colorNum][0], colorV[colorNum][1],
            colorV[colorNum][2]);
          selectColor = 2;
          break;
        }
      }
    }
    //●3回目の色選択
    else if(selectColor == 2)
    { //●座標位置から指定されたパレット色（未混色）を割り出す。
      for(colorNum=0; colorNum<16; colorNum++)
      {
        if((x > colorP[colorNum][0]) && (x < colorP[colorNum][0]+w) &&
          (y > colorP[colorNum][1]) && (y < colorP[colorNum][1]+h))
        {
          f.palette.choiceN = 3;
          f.palette.choiceC3 = new Color(
            colorV[colorNum][0], colorV[colorNum][1],
            colorV[colorNum][2]);
          selectColor = 3;
          break;
        }
      }
    }
    //●4回目の色選択
    else if(selectColor == 3)
    { //●座標位置から指定されたパレット色（未混色）を割り出す。
      for(colorNum=0; colorNum<16; colorNum++)
      {
        if((x > colorP[colorNum][0]) && (x < colorP[colorNum][0]+w) &&
          (y > colorP[colorNum][1]) && (y < colorP[colorNum][1]+h))
        {
          f.palette.choiceN = 4;
          f.palette.choiceC4 = new Color(
            colorV[colorNum][0], colorV[colorNum][1],
            colorV[colorNum][2]);
          selectColor = 0;
          break;
        }
      }
    }
  }

  //■座標位置変数の初期化
  void clear()
  {
    selectColor = 0;
    f.palette.choiceN = 0;
  }

  public void mouseEntered(MouseEvent e)
  {}
  public void mouseExited(MouseEvent e)
  {}
  public void mouseClicked(MouseEvent e)
  {}
  public void mouseReleased(MouseEvent e)
  {}
} //EOF (GCreatorPalMouseLis.java)

◆GCreatorSliderLis.java

//■■GCreatorSliderLis.java
//Ver.4.1

//■■インポート
import javax.swing.*;  //必須
import javax.swing.event.*;  //必須

//■■JSliderのイベントリスナー
class GCreatorSliderLis implements ChangeListener
{
  GCreator f;
  int adjustR;
  int adjustG;
  int adjustB;

  //■コンストラクタ
  GCreatorSliderLis(GCreator flame)
  {
    f = flame;
  }

  //■JSliderのイベントハンドラ
  public void stateChanged(ChangeEvent e)
  {
    JSlider sld = (JSlider)e.getSource();
    if(sld == f.sldR)
    {
      if(!sld.getValueIsAdjusting()) //スライダー・ノブで数値が決定した
      {
        adjustR = sld.getValue();
      }
    }
    else if(sld == f.sldG)
    {
      if(!sld.getValueIsAdjusting()) //スライダー・ノブで数値が決定した
      {
        adjustG = sld.getValue();
      }
    }
    else if(sld == f.sldB)
    {
      if(!sld.getValueIsAdjusting()) //スライダー・ノブで数値が決定した
      {
        adjustB = sld.getValue();
      }
    }
  }
} //EOF (GCreatorSliderLis.java)

◆GCreatorToneCurveMouseLis.java

//■■GCreatorToneCurveMouseLis.java
//Ver.4.1

//■■インポート
import java.awt.event.*;  //必須
import java.util.*;  //必須

//■■トーン・カーブ図表上のマウスのクリックで呼び出されるリスナー。
class GCreatorToneCurveMouseLis implements MouseListener
{
  //■メンバー変数
  GCreator f;
  double x1 = 0.0d;
  double y1 = 0.0d;
  double x2 = 0.0d;
  double y2 = 0.0d;
  boolean startFlag = true;

  //■コンストラクタ
  GCreatorToneCurveMouseLis(GCreator flame)
  {
    f = flame;
  }

  //■イベントハンドラ
  public void mousePressed(MouseEvent eve)
  {
    double x = eve.getX(); //マウスのクリック位置を取得
    double y = eve.getY();

    if(startFlag)
    { //●位置修正における旧点位置（絶対座標）
      x1 = x;
      y1 = y;
      startFlag = false;
    }
    else
    { //●位置修正における新点位置（絶対座標）
      x2 = x;
      y2 = y;
      replacePoint(x1, y1, x2, y2);
      startFlag = true;
      x1 =0;
      y1 =0;
      x2 =0;
      y2 =0;
    }
  }

  //■描画命令の座標点修正
  void replacePoint(double x1, double y1, double x2, double y2)
    //x1,y1 は、クリックされた移動前の古い座標点（絶対座標）。
    //x2,y2 は、クリックされた移動後の新しい座標点（絶対座標）。
  {
    //最初のクリックで旧点を指定し、二回目で移動先の新点を指定。
    String commandZ = f.cArea.getText();
    String newCommand = "";
    StringTokenizer st = new StringTokenizer(commandZ,"\n");
    String command;
    int Q = 3; //●位置指定でのマウス・クリック位置の許容誤差
    for(int i=0; st.hasMoreTokens(); i++)
    {
      command = st.nextToken().trim();

      if(command.startsWith("ToneCurveStart(") && command.endsWith("red"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 158 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行（範囲逸脱修正を含む）
          newCommand += ("ToneCurveStart(" +
            (0) + "," + (158 - y2) + "); //red\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("ToneCurveStart(") && command.endsWith("green"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 323 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行（範囲逸脱修正を含む）
          newCommand += ("ToneCurveStart(" +
            (0) + "," + (323 - y2) + "); //green\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("ToneCurveStart(") && command.endsWith("blue"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 488 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行（範囲逸脱修正を含む）
          newCommand += ("ToneCurveStart(" +
            (0) + "," + (488 - y2) + "); //blue\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      else if(command.startsWith("ToneCurveControl(") && command.endsWith("red"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 158 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行
          newCommand += ("ToneCurveControl(" +
            (x2 - 30) + "," + (158 - y2) + "); //red\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("ToneCurveControl(") && command.endsWith("green"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 323 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行
          newCommand += ("ToneCurveControl(" +
            (x2 - 30) + "," + (323 - y2) + "); //green\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("ToneCurveControl(") && command.endsWith("blue"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 488 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行
          newCommand += ("ToneCurveControl(" +
            (x2 - 30) + "," + (488 - y2) + "); //blue\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      else if(command.startsWith("ToneCurveEnd(") && command.endsWith("red"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 158 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行（範囲逸脱修正を含む）
          newCommand += ("ToneCurveEnd(" +
            (127.5) + "," + (158 - y2) + "); //red\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("ToneCurveEnd(") && command.endsWith("green"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 323 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行（範囲逸脱修正を含む）
          newCommand += ("ToneCurveEnd(" +
            (127.5) + "," + (323 - y2) + "); //green\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }
      else if(command.startsWith("ToneCurveEnd(") && command.endsWith("blue"))
      { //●トーン・カーブ曲線制御点の位置修正
        StringTokenizer st2 = new StringTokenizer(command,"(,)");
        st2.nextToken(); //●命令文における旧点位置（相対座標）の取得と変換
        double ox1 = Double.parseDouble((st2.nextToken().trim())) + 30; //（絶対座標へ変換）
        double oy1 = 488 - Double.parseDouble((st2.nextToken().trim())); //（絶対座標へ変換）
        if((x1 <= ox1+Q) && (x1 >= ox1-Q) &&   //近傍点の判定
           (y1 <= oy1+Q) && (y1 >= oy1-Q))
        { //●修正実行（範囲逸脱修正を含む）
          newCommand += ("ToneCurveEnd(" +
            (127.5) + "," + (488 - y2) + "); //blue\n"); //相対座標に変換
        }
        else
        { //●該当点が見付からないなら
          newCommand += command+"\n";
        }
      }

      else
      { //●該当点が見付からないなら
        newCommand += command+"\n";
      }
    }
    f.cArea.setText(newCommand);
    f.canvas.setInit2(); //特殊初期化（先行実施）
    f.canvas.setInit();  //一般初期化（後続実施）
    f.canvas.setInit3(); //追加特殊初期化（最終実施）
    f.toneCurve.repaint();
  }

  //以下は、MouseListenerの実装で、無反応にする部分
  public void mouseEntered(MouseEvent e)
  {}
  public void mouseExited(MouseEvent e)
  {}
  public void mouseClicked(MouseEvent e)
  {}
  public void mouseReleased(MouseEvent e)
  {}
} //EOF (GCreatorToneCurveMouseLis.java)

◆StackTraceMonitor.java

//■■StackTraceMonitor.java

import java.awt.*;
import javax.swing.*;
import java.io.*;

//■■キャッチできない例外によるスタックトレース出力監視と出力先切替スレッド
public class StackTraceMonitor extends Thread
{
    //■メンバー変数
    //smの実質は、JFrameとSystemMessageの合流
    private SystemMessage sm;
    //■コンストラクタ
    public StackTraceMonitor(SystemMessage sm)
    {
        this.sm = sm;
    }

    //■標準エラー出力を横取りして、フレーム内の所定場所に表示
    public void run()
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); //バッファ
        try
        { //エラー出力先をバッファに切替え
            System.setErr(new PrintStream(baos));
        }
        catch(Exception e)
        {
            sm.message(e.toString());
            return;
        }
        for(;;) //プログラム終了まで監視を続ける
        {
            try
            {
                sleep(500); //実行時間独占防止の休眠時間
            }
            catch(Exception e)
            {
                sm.message(e.toString());
            }
            if(baos.size() > 0) //エラー出力の蓄積があれば
            {
                synchronized(baos)
                { //baosをロックし、下の文を排他的に実行
                        sm.message(baos.toString()); //エラー表示
                        baos.reset(); //バッファを空にし、次に備える
                }
            }
        }
    }
    //■SystemMessage の切り替え
    public void setFrame(SystemMessage sm)
    {
        this.sm = sm;
    }
} //EOF (StackTraceMonitor.java)

◆SystemMessage.java

//■■SystemMessage.java

public interface SystemMessage
{
    public void message(String s);
} //EOF (SystemMessage.java)

◆Util.java

//■■Util.java

import java.awt.*;
import java.awt.event.*;
import java.awt.im.InputSubset;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;
import java.text.*;

public class Util
{
    static final Font fontM = new Font("MonoSpaced",Font.PLAIN,13);

    //■テキストファイル閲覧サブウィンドウ
    public static void textBrowse(SystemMessage sm, File file)
    {
        String line = null;
        JDialog subWindow = null;
        try
        {
            BufferedReader reader = new BufferedReader(
                new FileReader(file)); //エラーになればsubWindowは生成しない

            subWindow = new JDialog((Frame)sm, file.getName(), true);
            Container pane = subWindow.getContentPane();
            //クローズボタンでサブウィンドウを破棄し、プロセスは継続させる
            //subWindow.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            JTextArea tArea = new JTextArea(25,80); //行数と１行の文字数
            pane.add(
                new JScrollPane(
                    tArea,
                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
            tArea.setFont(fontM);
            tArea.setBorder(new EmptyBorder(20,20,20,20));
            try
            {
                for (;;)
                {
                    line = reader.readLine();
                    if(line == null)
                        break;
                    tArea.append(line + "\n");
                }
                tArea.select(0, 0); //先頭位置を表示
                tArea.setEditable(false); //編集禁止
            }
            catch(IOException e)
            {
                sm.message("読取エラー>>\n"+e);
            }
            finally
            {
                reader.close();
                subWindow.pack();
                subWindow.setVisible(true);
            }
        }
        catch(FileNotFoundException e)
        {
            sm.message("オープンエラー>>\n"+e);
        }
        catch(IOException e)
        {
            sm.message("クローズエラー>>\n"+e);
        }
    }
    //■テキストファイル閲覧サブウィンドウ（クリップ・ボード機能付き）
    public static void textBrowseCCP(SystemMessage sm, File file)
    {
        String line = null;
        JDialog subWindow = null;
        try
        {
            BufferedReader reader = new BufferedReader(
                new FileReader(file)); //エラーになればsubWindowは生成しない

            subWindow = new JDialog((Frame)sm, file.getName(), true);
            Container pane = subWindow.getContentPane();
            JPanel panel = new JPanel();
            panel.setLayout(new FlowLayout(FlowLayout.LEFT));

            Box vBox = Box.createVerticalBox();
            pane.add(vBox);
            JTextArea tArea = new JTextArea(25,80); //行数と１行の文字数
            tArea.setFont(fontM);
            tArea.setBorder(new EmptyBorder(20,20,20,20));

            JButton cutButton = new JButton("削除");
            cutButton.addActionListener(
            	new ActionListener()
            	{ public void actionPerformed(ActionEvent event)
              	{ tArea.cut(); } }
            );
            JButton copyButton = new JButton("複写");
            copyButton.addActionListener(
            	new ActionListener()
            	{ public void actionPerformed(ActionEvent event)
              	{ tArea.copy(); } }
            );
            JButton pasteButton = new JButton("挿入");
            pasteButton.addActionListener(
            	new ActionListener()
            	{ public void actionPerformed(ActionEvent event)
              	{ tArea.paste(); } }
            );
            panel.add(cutButton);
            panel.add(copyButton);
            panel.add(pasteButton);
            vBox.add(panel);
            vBox.add(
                new JScrollPane(
                    tArea,
                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));

            try
            {
                for (;;)
                {
                    line = reader.readLine();
                    if(line == null)
                        break;
                    tArea.append(line + "\n");
                }
                tArea.select(0, 0); //先頭位置を表示
                tArea.setEditable(true); //編集可
            }
            catch(IOException e)
            {
                sm.message("読取エラー>>\n"+e);
            }
            finally
            {
                reader.close();
                subWindow.pack();
                subWindow.setVisible(true);
            }
        }
        catch(FileNotFoundException e)
        {
            sm.message("オープンエラー>>\n"+e);
        }
        catch(IOException e)
        {
            sm.message("クローズエラー>>\n"+e);
        }
    }

    //■改行コードを含む文字列を改行位置で分解し、Stringの配列に変換して返却
    public static String[] splitReturn(String str)
    {
        if(str.charAt(str.length()-1)!='\n')
            str = str + "\n";
        int lines=0;
        for(int i=0; i<str.length(); i++)
        {
            if(str.charAt(i)=='\n')
                lines++;
        }
        String [] stringArray = new String[lines];
        int c1=0;
        int c2=0;
        int lineNum=0;
        int i=0;
        for(; i<str.length(); i++)
        {
            if(str.charAt(i)=='\n')
            {
                c2=i;
                stringArray[lineNum] = str.substring(c1,c2);
                lineNum++;

                c1=c2+1;
            }
        }
        return stringArray;
    }

    //■CSV形式の文字列を想定し、区切り文字（デリミタ）の数を数えて、その数を返却
    public static int countDelimiter(String str, char ch)
    {
      int cnt=0;
      for(int i=0; i<str.length(); i++)
      {
        if(str.charAt(i)==ch)
          cnt++;
      }
      return cnt;
    }

    //■CSV形式の文字列を区切り文字の位置で分解し、Stringの配列に変換して返却
    public static String[] csv2Array(String csv, int cols)
    {
        return csv2Array(csv, cols, ',');
    }
    public static String[] csv2Array(String csv, int cols, char delimiter)
    {
        char [] cArr = {delimiter};
        String delimiterStr = new String(cArr);
        StringTokenizer st = new StringTokenizer(csv, delimiterStr, true);
        int cols2 = 0;
        for(int i=0; i<csv.length(); i++)
        {
            if(csv.charAt(i) == delimiter)
                cols2++;
        }
        cols2++; //カラム数
        if(cols > 0) //カラム数チェック必要
        {
            if(cols != cols2) //カラム数異常
                return null;
        }
        else if(cols == 0) //カラム数チェック不用
            cols = cols2;
        else if(cols < 0) //program error
            ; //次の文で例外発生
        String [] stringArray = new String[cols];
        for(int colCount=0; colCount<cols; colCount++)
        {
            String str;
            if(st.hasMoreTokens()) //トークンがあれば
                str = (st.nextToken()).trim();//区切り文字かデータが得られ
            else                   //トークンがなければ
                str = "";          //最終カラムで、空のカラム

            if(str.equals(delimiterStr))    //トークンが区切り文字か
                str = "";          //最終カラム以外で、空のカラム
            else                   //トークンがデータなら
            {
                if(st.hasMoreTokens()) //最終カラムでないことを確認し
                    st.nextToken();    //次のコンマ除去
            }
            stringArray[colCount] = str; //データか空文字列を格納
        }
        return stringArray;
    }

    //■文字列の先頭と末尾を囲む特定文字を除去。
    //主に引用符や括弧で囲まれた文字列に適用。
    //前後を除去文字に囲まれていなければ、そのまま返却。
    public static String trimAffix(String str, char prefix, char suffix)
    {
        if(str.length()>=2 && str.charAt(0)==prefix && str.charAt(str.length()-1)==suffix)
            return str.substring(1, str.length()-1);
        else
            return str;
    }

    //■JTextField の日本語ＩＭモード切替
    public static void kanjiIn(final JTextField tf, boolean b)
    {
        if(b)
        {
            tf.addFocusListener(new FocusAdapter()
            {
                public void focusGained(FocusEvent event)
                {
                    tf.getInputContext().setCharacterSubsets(
                        new Character.Subset[] {InputSubset.KANJI});
                }
            });
        }
        else
        {
            tf.addFocusListener(new FocusAdapter()
            {
                public void focusGained(FocusEvent event)
                {
                    tf.getInputContext().setCharacterSubsets(null);
                }
            });
        }
    }

    //■数値文字列の整形
    //返却値 String : 整形後の文字列
    //引数 String decimal : 十進実数文字列
    //引数 int fractionDigit : 整形後の小数点桁数
    //引数 boolean comma ：コンマが必要か
    //機能 : 指定の小数点桁数で揃え、必要ならコンマを付加
    public static String decimalStringFormat(String decimal, int fractionDigit, boolean comma)
        throws NumberFormatException
    {
        String s0 = "";
        String s1 = "";
        NumberFormat nf = NumberFormat.getInstance(Locale.JAPANESE);

        if(decimal==null)                  //nullなら
            throw new NumberFormatException("文字列がnull");
        else if(decimal.trim().equals("")) //空文字列なら
            return "";
        else                               //有効文字列なら
        {
            if(decimal.indexOf(".")==-1) //整数表記されていたらコンマ要求とみなし
            {
                s0 = nf.format(Long.parseLong(decimal)); //整数にコンマ付加
                s1 = "";
            }
            else if(comma==true) //実数表記でコンマ要求されていたら
            {
                s0 = decimal.substring(0,decimal.indexOf(".")); //整数部
                if(!s0.equals("-0")) //実数が１未満の場合には符号温存
                    s0 = nf.format(Long.parseLong(s0));   //整数部コンマ付加
                s1 = decimal.substring(decimal.indexOf(".")+1); //小数部
            }
            else //実数表記でコンマ要求なし
            {
                s0 = decimal.substring(0,decimal.indexOf(".")); //整数部
                s1 = decimal.substring(decimal.indexOf(".")+1); //小数部
            }
            if(fractionDigit == 0)     //整数要求
                return s0;
            else if(fractionDigit > 0) //実数要求
            {
                for(int i=0; s1.length()>i; i++)                //小数部チェック
                    if(!Character.isDigit(s1.charAt(i)))
                        throw new NumberFormatException();
                if(fractionDigit < s1.length())
                    s1 = s1.substring(0,fractionDigit);         //末尾切捨
                else if(fractionDigit > s1.length())
                    while(fractionDigit>s1.length())
                        s1 += "0";                              //不足の0を付加
                return (s0 + "." + s1);
            }
            else //小数のマイナス桁は認めない
                throw new NumberFormatException("小数桁がマイナス値");
        }
    }
    public static String decimalStringFormat(String decimal, int fractionDigit)
        throws NumberFormatException
    {
        return decimalStringFormat(decimal, fractionDigit, true);
    }

    //■数値データの変換と照合
    public static int checkInt(String str, int min, int max) throws Exception
    {
        try
        {
            int value = Integer.parseInt(str);
            if(value<min || value>max)
                throw new Exception("数値異常");
            return value;
        }
        catch(NumberFormatException e)
        {
            throw new Exception("数値表記間違");
        }
    }
    public static long checkLong(String str, long min, long max) throws Exception
    {
        try
        {
            long value = Long.parseLong(str);
            if(value<min || value>max)
                throw new Exception("数値異常");
            return value;
        }
        catch(NumberFormatException e)
        {
            throw new Exception("数値表記間違");
        }
    }
    public static double checkDouble(String str, double min, double max) throws Exception
    {
        try
        {
            double value = Double.parseDouble(str);
            if(value<min || value>max)
                throw new Exception("数値異常");
            return value;
        }
        catch(NumberFormatException e)
        {
            throw new Exception("数値表記間違");
        }
    }
    //■CSV簡易データベース
    public static String[] searchCSV(String fileName, String keyWord, int cols, int col)
    //colsは１起算
    //col は０起算
    {
        File file = new File(fileName);
        String ret = null;
        //データ形式は、CSV
        String[] strArr = new TextIO().loadStrArr(file);
        if(strArr==null || strArr.length==0)
        {
            System.err.println("データ・ファイルに問題。"+file.getName());
            return null;
        }
        String[] datArr = null;
        for(int i=0; i<strArr.length; i++)
        {
            datArr = csv2Array(strArr[i], cols);
            if(datArr==null)
                System.err.println("データベースの一部が損壊。"+file.getName());
            else if(datArr[col].equals(keyWord))
                return datArr;
        }
        System.err.println("データベースに該当項目なし。"+file.getName());
        return null;
    }
} //EOF (Util.java)

◆SingleFileFilter.java

//■■SingleFileFilter.java

import java.io.File;
import javax.swing.filechooser.FileFilter;

//■■単一拡張子によるファイルフィルター
public class SingleFileFilter extends FileFilter
{
    private String extention;   //拡張子
    private String description; //説明文
    public SingleFileFilter(String ext)
    {
        extention = ext.toLowerCase(); //小文字に統一
        description = "*." + extention;
    }
    public boolean accept(File f)
    {
        if(f.isDirectory())
            return true;
        return f.getName().toLowerCase().endsWith(
            "." + extention); //ファイル名の末尾判定合否を通知
    }
    public String getDescription()
    {
        return description; //説明文を通知
    }
} //EOF (SingleFileFilter.java)

◆TextIO.java

//■■TextIO.java

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.nio.file.Files;
import java.nio.file.Path;
import java.awt.*;
import javax.swing.*;

public class TextIO
{

    public static File callFileChooser(String mode, Component parent, String dir, String ext)
    {
        JFileChooser fileChooser = new JFileChooser(dir);
        if(!ext.equals("*"))
        {
          SingleFileFilter filter = new SingleFileFilter(ext);
          fileChooser.setFileFilter(filter);
        }
        int ret;
        if(mode.equals("open"))
            ret = fileChooser.showOpenDialog(parent);
        else if(mode.equals("save"))
            ret = fileChooser.showSaveDialog(parent);
        else
            return null;
        File file = fileChooser.getSelectedFile();
        if(ret != JFileChooser.APPROVE_OPTION || file == null)
            return null;
        else
            return file;
    }

    public static String[] loadStrArr(File file)
    { //デフォルト文字コード
        BufferedReader reader = null;
        Object[] objArr = null;
        String[] strArr = null;
        List<String> list = new LinkedList<String>();
        try
        {
            reader = new BufferedReader(new FileReader(file));
            try
            {
                String line  = "";
                for(int i=0;;i++) //データ読取り
                {
                    line = reader.readLine();
                    if(line == null) //終端超越なら
                        break;
                    list.add(line);
                }
                objArr = list.toArray();
                strArr = new String[objArr.length];
                for(int i=0; i<objArr.length; i++)
                {
                    strArr[i] = (String)objArr[i];
                }
            }
            catch(IOException e)
            {
                System.err.println(file.getName() + ": read error");
                strArr = null;
            }
            reader.close();
        }
        catch(FileNotFoundException e)
        {
            System.err.println(file.getName() + ": open error");
            strArr = null;
        }
        catch(IOException e)
        {
            System.err.println(file.getName() + ": close error");
            strArr = null;
        }
        return strArr;
    }

     public static String loadStr(File file)
    { //デフォルト文字コード
        BufferedReader reader = null;
        String retStr = "";
        try
        {
            reader = new BufferedReader(new FileReader(file));
            try
            {
                String line  = "";
                for(int i=0;;i++) //データ読取り
                {
                    line = reader.readLine();
                    if(line == null) //終端超越なら
                        break;
                    retStr = retStr + line + "\n";
                }
            }
            catch(IOException e)
            {
                System.err.println(file.getName() + ": read error");
                retStr = null;
            }
            reader.close();
        }
        catch(FileNotFoundException e)
        {
            System.err.println(file.getName() + ": open error");
            retStr = null;
        }
        catch(IOException e)
        {
            System.err.println(file.getName() + ": close error");
            retStr = null;
        }
        return retStr;
    }

    public static boolean saveStr(File file, String data)
    { //デフォルト文字コード
        BufferedWriter writer = null;
        boolean b = true;
        try
        {
            writer = new BufferedWriter(new FileWriter(file));
            try
            {
                writer.write(data);
                writer.flush();
            }
            catch(IOException e)
            {
                System.err.println(file.getName() + ": write error");
                b = false;
            }
            writer.close();
        }
        catch(IOException e)
        {
            if(writer == null)
            {
                System.err.println(file.getName() + ": open error");
            }
            else
            {
                System.err.println(file.getName() + ": close error");
            }
            b = false;
        }
        return b;
    }

    public static void saveText(File outputFile, String data, String charCode)
    { //charCode: "UTF-16", "UTF-8", "Shift_JIS", "MS932"
        PrintWriter pw = null;
        try //●書き出しファイルの準備
        {
            pw = new PrintWriter(new OutputStreamWriter(
                new FileOutputStream(outputFile), charCode));
        }
        catch(Exception e)
        {
            System.err.println("Exception1: saveText() " +
                charCode + "> \n" + e.toString());
        }

        try //●ファイルへの書き出し
        {
            if(data==null)
                System.err.println("data==null");
            if(pw==null)
                System.err.println("pw==null");
            if(data!=null && pw!=null)
                pw.print(data);
            pw.close();
        }
        catch(Exception e)
        {
            System.err.println("Exception2: saveText() " +
                charCode + "> \n" + e.toString());
        }
    }

    public static String loadText(File inputFile, String charCode)
    { //charCode: "UTF-16", "UTF-8", "Shift_JIS", "MS932"
        try //●ファイルからの読み取り
        {
            BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(inputFile),
                charCode));
            String text1 = "";
            String text2 = "";
            while ((text1 = br.readLine()) != null)
            {
                text2 = text2 + text1 + "\n";
            }
            return text2;
        }
        catch(Exception e)
        {
            System.err.println("Exception2: loadText() " +
                charCode + "> \n" + e.toString());
            return null;
        }
    }
} //EOF (TextIO.java)

◆Spline.java

//■■Spline.java

public class Spline
{ //参考文献：奥村晴彦 他 共著『Javaによるアルゴリズム事典』技術評論社、平成15年
  //参考文献：市村浩三 吉本富士市 共著『スプライン関数とその応用』教育出版、1979年

  private double[] x,y,z;

  public Spline(double[] x, double[]y)
  {
    int n = x.length;
    this.x = x; this.y = y;
    z = new double[n];
    double[] h = new double[n], d = new double[n];
    z[0] = z[n-1] = 0;
    for(int i=0; i<n-1; i++)
    {
      h[i]   = x[i+1] - x[i];
      d[i+1] = (y[i+1] - y[i])/h[i];
    }
    z[1] = d[2] - d[1] - h[0]*z[0];
    d[1] = 2*(x[2] - x[0]);
    for(int i=1; i<n-2; i++)
    {
      double t = h[i]/d[i];
      z[i+1] = d[i+2] -d[i+1] - z[i]*t;
      d[i+1] = 2*(x[i+2] - x[i]) - h[i]*t;
    }
    z[n-2] -= h[n-2]*z[n-1];
    for(int i=n-2; i>0; i--)
    {
      z[i] = (z[i] - h[i]*z[i+1])/d[i];
    }
  }

  public double interpolate(double t)
  {
    int i=0, j=x.length-1;
    while(i<j)
    {
      int k = (i+j)/2;
      if(x[k] < t)
        i=k+1;
      else
        j=k;
    }
    if(i>0)
      i--;
    double h = x[i+1]-x[i], d = t-x[i];
    return (((z[i+1] - z[i])*d/h + z[i]*3)*d
      +((y[i+1] - y[i])/h
      -(z[i]*2 + z[i+1])*h))*d + y[i];
  }
} //EOF (Spline)

◆Spline2.java

//■■Spline2.java

public class Spline2
{ //参考文献：奥村晴彦 他 共著『Javaによるアルゴリズム事典』技術評論社、平成15年
  //参考文献：市村浩三 吉本富士市 共著『スプライン関数とその応用』教育出版、1979年

  private double[] p;
  private Spline sx, sy;

  public Spline2(double[] x, double[] y)
  {
    int n = x.length;
    p = new double[n];
    p[0] = 0;
    for(int i=1; i<n; i++)
    {
      double t1 = x[i] - x[i-1], t2 = y[i] - y[i-1];
      p[i] = p[i-1] + Math.sqrt(t1*t1 + t2*t2);
    }
    for(int i=1; i<n; i++)
      p[i] /= p[n-1];
    sx = new Spline(p,x);
    sy = new Spline(p,y);
  }

  public double[] interpolate(double t)
  {
    return new double[] {sx.interpolate(t), sy.interpolate(t)};
  }
} //EOF (Spline2)

◆Spline3.java

//■■Spline3.java

public class Spline3
{
  double[]   tArr;   //0から1までを必要な補間数で、均等に区切った等差数列
  double[]   ipArr1; //スプライン補間を実行したｘｙ座標一点の配列
  double[][] ipArr2; //スプライン補間を実行したｘｙ座標多点の配列
  public Spline3(double[] x, double[] y, int tP)
  { //tPは、曲線を描く上で、座標数値として充分に大きい任意の数値。
    //例えば、描画範囲を示すWおよびHのピクセル数で、大きい方の数値。
    //ベクター画像の拡大を想定するなら、さらにその数倍の数値。
    Spline2 spline2 = new Spline2(x,y);
    tArr = new double[tP];;
    double t = 1.0/tP;
    for(int i=0; i<tP; i++)
    {
      tArr[i] = i*t;
    }
    tArr[tArr.length-1] = 1; //配列末尾は正確に１の値にする。

    ipArr2 = new double[tP][2];
    for(int i=0; i<tArr.length; i++)
    {
      ipArr1 = spline2.interpolate(tArr[i]);
      ipArr2[i][0] = ipArr1[0];
      ipArr2[i][1] = ipArr1[1];
    }
  }
  public double[][] getInterpolateXY()
  {
    return ipArr2;
  }
} //EOF (Spline3)

◆GCreator_Manual.txt

GCreator_Manual.txt
Ver.4.1

■■"GCreator" の命令文（コマンド）仕様書
●コマンド・エリアに記述する命令文は、この仕様書に従うこと。
●命令文書は、一行に一命令だけを記述すること。
●「double」と書くべきところを、便宜上「db」と省略表記することもある。
●「float」と書くべきところを、便宜上「ft」と省略表記することもある。
●「int」と書くべきところを、便宜上「it」と省略表記することもある。
●「String」と書くべきところを、便宜上「Str」と省略表記することもある。
●行頭または命令文終了直後に「//」があれば、これ以降行末までを注釈と見なす。
●行頭が「/@」の行と行頭が「@/」の行とで挟まれた複数行は、注釈と見なす。
●行頭に「Break;」があれば、これ以降の命令文の全部を注釈と見なす。

■■インポート処理（既存命令文書の先頭部導入）
★ Import(String s)
  s:      先頭部に導入する既存命令文書のファイル名（パス含む）
  ▽この命令は、一行目にだけ書くことが出来、一行しか書けない。
■■輪郭スムージング処理
★ Antialias(boolean a)
  a:      trueがアンチエイリアス処理あり
  ▽このギザギザ緩和処理で、細い線の色が薄くなる副作用あり。
■■画像サイズ
★ Size(double w, double h, String s)
  w:      巾
  h:      丈
  s:      pxかmmを指定
★ Size(double w, double h)
  w:      巾 px
  h:      丈 px
★ Size(String s)
  s:      "A4"または"B5"を指定
■■前景色の指定（線または文字の色）
★ ForegroundColorL(int r, int g, int b)
★ ForegroundColor(int r, int g, int b)
  r:       赤色成分　0～255
  g:       緑色成分
  b:       青色成分
★ ForegroundColorS(int r, int g, int b)
  r:       赤色成分　0～255
  g:       緑色成分
  b:       青色成分
★ ForegroundColorB(int r, int g, int b)
  r:       赤色成分　0～255
  g:       緑色成分
  b:       青色成分
  ▽ForegroundColorLは線色。
  ▽ForegroundColorは、ForegroundColorLの略称。
  ▽ForegroundColorSは文字色。
  ▽ForegroundColorBは極太文字色。
■■背景色の指定
★ BackgroundColor(int r, int g, int b)
  r:       赤色成分　0～255
  g:       緑色成分
  b:       青色成分
■■シフト（全体画像の移動）
★ Shift(int m, double x, double y)
  m:      モード（0がシフト無効、1がシフト有効）
  x:      X軸のシフト量
  y:      Y軸のシフト量
■■画像回転指定
★ Rotate(boolean b)
  b:      trueの時だけ90度回転
★ RotateFree(int d, int w, int h)
  d:      回転角度（ディグリー）
  w:      横方向原点移動
  h:      縦方向原点移動
★ RotateMulti(double sd, double d, int t, String f)
  sd:     回転開始角度（ディグリー）
  d:      回転角度（ディグリー）
  t:      回転回数
  f:      回転対象画像ファイル名
■■画像鏡像反転指定（回転処理も付属）
★ ReverseImage(String f, int m)
  f:      反転対象の画像ファイル名（パス含む）
  m:      1が左右鏡像反転、2が上下鏡像反転、3が左右対称、4が上下対称
          5が90度回転、6が180度回転、7が270度回転
■■標準拡大倍率指定
★ AffineScale(double sc)
★ DisplayScale(double sc)
  sc:     表示、画像保存に有効な標準拡大倍率
  ▽「DisplayScale」は、「AffineScale」の別名。
  ▽印刷では、無効な倍率。
■■自由拡大倍率指定
★ FreeScale(double sc)
★ PrintScale(double sc)
  sc:     表示、画像保存、印刷に有効な自由拡大倍率
  ▽「PrintScale」は、「FreeScale」の別名。
  ▽印刷時には、AffineScaleの倍率が無視される。
■■JPEG保存での画質指定オプション
★ SetJPEG_Op(float q)
  q:      JPEG出力画質。「0」から「1.0」を指定。
■■線の太さ指定
★ LineWidth(float  w)
  w:      線の太さ
■■直線の描線指定
★ DrawLine(double x1, double y1, double x2, double y2)
★ DrawLine2(double x1, double y1, double x2, double y2)
  x1:     起点座標X
  y1:     起点座標Y
  x2:     終点座標X
  y2:     終点座標Y
  ▽ただし、DrawLine2 は、マウス入力時の一時的描画専用の仮直線。
■■折れ線の描線指定
★ LinkedLineStart(double x, double y)
  x:      始点座標X
  y:      始点座標Y
★ LinkedLineNext(double x, double y)
  x:      継続点座標X
  y:      継続点座標Y
★ LinkedLineEnd(double x, double y)
  x:      終点座標X
  y:      終点座標Y
■■ベジェ曲線の描線指定
★ DrawCurve(db x1, db y1, db x2, db y2, db x3, db y3, db x4, db y4)
  x1:     始点座標X
  y1:     始点座標Y
  x2:     第一制御点座標X
  y2:     第一制御点座標Y
  x3:     第二制御点座標X
  y3:     第二制御点座標Y
  x4:     終点座標X
  y4:     終点座標Y
■■スプライン曲線の描線指定
★ DrawSplineStart(double x, double y)
  x:      始点座標X
  y:      始点座標Y
★ DrawSplineControl(double x, double y)
  x:      制御点座標X
  y:      制御点座標Y
  ▽制御点は、スプライン曲線１本につき、１箇所以上で、箇所数上限なし
★ DrawSplineEnd(double x, double y)
  x:      終点座標X
  y:      終点座標Y
★ DrawSplineOp(int op)
  op:     曲線を構成する短い直線の本数（曲線精細度オプション）
■■長方形の描画指定
★ DrawRect(int m, db x, db y, db w, db h, int r, int g, int b)
  m:      0は非描画、1は線、2は色塗り、3は線と色塗り、4は透明色
  x:      x座標
  y:      y座標
  w:      幅
  h:      高さ
  r:      赤色成分　0～255
  g:      緑色成分　0～255
  b:      青色成分　0～255
■■楕円の描画指定
★ DrawEllipse(int m, db x, db y, db hr, db vr, int r, int g, int b)
  m:      0は非描画、1は線、2は色塗り、3は線と色塗り、4は透明色
  x:      楕円の中心のｘ座標
  y:      楕円の中心のｙ座標
  hr:     横半径
  vr:     縦半径
  r:      赤色成分　0～255
  g:      緑色成分　0～255
  b:      青色成分　0～255
  ▽hrとvrとが、違う値なら楕円で、同じ値なら真円。
■■真円の描画指定
★ DrawCircle(int m, db x, db y, db rr, int r, int g, int b)
  m:      0は非描画、1は線、2は色塗り、3は線と色塗り、4は透明色
  x:      円の中心のｘ座標
  y:      円の中心のｙ座標
  rr:     半径
  r:      赤色成分　0～255
  g:      緑色成分　0～255
  b:      青色成分　0～255
■■自由図形の描画指定
★ DrawShapeStart(int m, double x, double y, int r, int g, int b)
  m:      0が非描画、1が線描、2が色塗り、3が線描と色塗り、4は透明色
  x:      自由図形の起点座標X
  y:      自由図形の起点座標Y
  r:      赤色成分　0～255
  g:      緑色成分　0～255
  b:      青色成分　0～255
★ DrawShapeLine(double x, double y)
  x:      自由図形の中間点座標X
  y:      自由図形の中間点座標Y
★ DrawShapeCurve(db x1, db y1, db x2, db y2, db x3, db y3)
  x1,x2,x3: 自由図形の中間点座標X（三点）
  y1,y2,y3: 自由図形の中間点座標Y（三点）
★ DrawShapeEnd()
  ▽引数なし（自由図形の始点回帰で終点を宣言）。
■■スプレーの描画指定
★ SprayStart(it x, it y, it tp, db ss, it sr, it st, it r, it g, it b, it a)
  x:     スプレイ円盤状飛沫集団（円盤）の中心ｘ座標
  y:     スプレイ円盤状飛沫集団（円盤）の中心ｙ座標
  tp:    スプレイ飛沫の分散タイプ（0,1,2のどれかを指定、標準は1）
  ss:    スプレイ飛沫一個のサイズ（px相当）
  sr:    スプレイ飛沫の円盤状拡散分布半径（px相当）
  st:    スプレイ飛沫の分布個数
  r:     スプレイ飛沫の色相、赤成分
  g:     スプレイ飛沫の色相、緑成分
  b:     スプレイ飛沫の色相、青成分
  a:     スプレイ飛沫の色相、透明度（0～255。0は無色透明、255は不透明、中間は半透明）
  ▽スプレー・ユニットの開始
★ SprayNext(int x, int y)
  x:     スプレイ円盤状飛沫集団（円盤）の中心ｘ座標
  y:     スプレイ円盤状飛沫集団（円盤）の中心ｙ座標
  ▽スプレー・ユニットの継続
★ SprayEnd(int x, int y)
  x:     スプレイ円盤状飛沫集団（円盤）の中心ｘ座標
  y:     スプレイ円盤状飛沫集団（円盤）の中心ｙ座標
  ▽スプレー・ユニットの終了
★ SprayGaussianOp(double g)
  g:      正規分布スプレーでの分布係数
  ▽正規分布スプレーでのみ有効なオプション（0.4～0.6を推奨、デフォルトは0.45）
■■文字の太さ指定（WriteStringHに対応）
★ FontBold(boolean b)
  b:      太字指定なら true
■■文字列の描画指定
★ WriteStringH(double x, double y, int si, String st, String s)
★ WriteString(double x, double y, int si, String st, String s)
★ WriteStringB(double x, double y, int si, String st, String s)
★ WriteStringB(double x, double y, int si, int sw, String st, String s)
★ WriteStringV(double x, double y, int si, String st, String s)
  x:      ｘ座標
  y:      ｙ座標
  si:     フォント・サイズ
  sw:     フォント・太さ拡張
  st:     字形（"sansserif" / "serif" など）
  s:      表示する文字列
  ▽WriteStringHは、横書き文字。
  ▽WriteStringは、WriteStringHの省略表記。
  ▽WriteStringBは、横書き極太文字。
  ▽WriteStringVは、縦書き文字。（画像精細度が低下する。）
■■挿入画像の表示指定
★ Image(int x, int y, int w, int h, String f)
  x:       表示ｘ座標位置
  y:       表示ｙ座標位置
  w:       画像の表示幅
  h:       画像の表示丈
  f:       画像ファイル名（パス付き）
■■スタンプ画像の上書き
★ Stamp(int x, int y, int w, int h, String f)
  x:       表示ｘ座標位置
  y:       表示ｙ座標位置
  w:       画像の表示幅
  h:       画像の表示丈
  f:       スタンプ画像（上書き画像）ファイル名（パス含む）
  ▽スタンプの灰色部分を無色透明に変換してスタンプ画像を、表示中の画像に上書き。
★ StampOp(int r, int g, int b)
  r:       グレー・マスク代替色の赤成分
  g:       グレー・マスク代替色の緑成分
  b:       グレー・マスク代替色の青成分
  ▽スタンプのグレー・マスクを指定色に変更するオプション。
★ StampMulti(int x, int y, int w, int h, int sx, int sy, int tx, int ty, String f)
  x:       当初表示ｘ座標位置
  y:       当初表示ｙ座標位置
  w:       画像の表示幅
  h:       画像の表示丈
  sx:      画像の横方向スキップのピクセル数
  sy:      画像の縦方向スキップのピクセル数
  tx:      画像の横方向表示反復回数
  ty:      画像の縦方向表示反復回数
  f:       画像ファイル（パス含む）
  ▽同一画像スタンプの位置を変えての連続処理（タイル貼り）
■■画像の切り貼り
★ CutAndPasteMask(String f)
  f:       切り貼り指定のマルチ・マスク画像ファイル名（パス含む）
★ CutAndPaste(String f, int r, int g, int b)
  f:       切り貼り指定の模様画像ファイル名（パス含む）
  r:       赤色成分（マルチ・マスクでの指定該当色　0～255）
  g:       緑色成分
  b:       青色成分
■■連続色相変更
★ ChangeColorMultiBase(String f)
  f:       連続色相変更元画像ファイル名（パス含む）
★ ChangeColorMulti(int r0, int g0, int b0, int r1, int g1, int b1)
  r0:      赤色成分（元画像での変更対象色　0～255）
  g0:      緑色成分
  b0:      青色成分
  r1:      赤色成分（新画像での変更実施色　0～255）
  g1:      緑色成分
  b1:      青色成分
■■単独色相変更
★ ChangeColor(Str f,it c,it mode,it r1,it g1,it b1,it r2,it g2,it b2)
★ ChangeColor(Str f,it c,it r1,it g1,it b1,it r2,it g2,it b2)
  f :      色相変更する既存画像ファイル名（パス含む）
  c :      微妙な色変動の許容値
  mode :   一般用途の１、または、特殊用途の２
  r1:      旧色
  g1:
  b1:
  r2:      新色
  g2:
  b2:
  ▽モード１は、写真などの階調画像からマルチ・マスク画像を作成する場合など、一般用途に使用
  ▽モード２は、写真などの階調画像からグレー・マスク画像を作成する場合など、特殊用途に使用
■■トーン・カーブ式色調変更
★ ToneCurveStart(double x, double y)
  x:   起点座標X
  y:   起点座標Y
★ ToneCurveControl(double x, double y)
  x:   制御点座標X
  y:   制御点座標Y
★ ToneCurveEnd(double x, double y)
  x:   終点座標X
  y:   終点座標Y
  ▽トーン・カーブは、メニュー、ボタン、マウスで、全て操作する。
  ▽キーボードによる命令文入力は、命令文末尾に特殊コメントが付くため、避けること。
■■図形内部彩色変更（輪郭線の内側を指定色で塗り直す）
★ ChangeColorInner(Str f, it r0, it g0, it b0, it r1, it g1, it b1, it x, it y, it mode)
  f:       彩色変更対象画像ファイル名（パス含む）
  r0:      輪郭線色
  g0:
  b0:
  r1:      内部彩色指定色
  g1:
  b1:
  x:       図形内側代表位置のx座標
  y:       図形内側代表位置のy座標
  mode     輪郭線をどの色にするかの選択肢
  ▽モード0は、何もしないで、もとの色のまま
  ▽モード1は、内部彩色と同じにする
  ▽モード2は、黒色(0,0,0)にする
  ▽モード3は、灰色(200,200,200)にする
  ▽モード4は、白色(255,255,255)にする
★ ChangeColorInnerMultiMask(Str f, int r, int g, int b)
  f:       彩色変更対象画像ファイル名（パス含む）
  r:       輪郭線色
  g:
  b:
★ ChangeColorInnerMulti(int r, int g, int b, int x, int y)
  r:       内部彩色指定色
  g:
  b:
  x:       図形内側代表位置のx座標
  y:       図形内側代表位置のy座標
★ ChangeColorInnerAuto(Str f)
  f:       彩色変更対象画像ファイル名（パス含む）
  ▽地色のデフォルトは、白色(255,255,255)、輪郭線色のデフォルトは、黒色(0,0,0)。
★ ChangeColorInnerAutoOp(int r1, int g1, int b1, int r2, int g2, int b2)
  r1:      地色（デフォルト色を変更）
  g1:
  b1:
  r2:      輪郭線色（デフォルト色を変更）
  g2:
  b2:
■■背景パターン模様の指定
★ StripePattern(int tp, int w, int r, int g, int b)
  tp:      ストライプ模様の無効または水平または垂直
  w:       ストライプ幅
  r:       赤基調色
  g:       緑基調色
  b:       青基調色
★ MatrixPatternSt(int pn, int wh, int r, int g, int b, int lm)
  pn:      柄紋番号
  wh:      柄紋の幅丈（ピクセル数、正方形柄紋）
  r:       赤基調色　5～250
  g:       緑基調色
  b:       青基調色
  lm:      色成分の乱数変動幅の制限（1～10）
★ MatrixPatternStOp(db sH,db sV,db dH,db dV,it pH,it pV,it rH,it rV,it in)
  sH:      横シフト（コマ数）
  sV:      縦シフト（コマ数）
  dH:      横ドロップ（コマ数）
  dV:      縦ドロップ（コマ数）
  pH:      横スキップ（コマ数）
  pV:      縦スキップ（コマ数）
  rH:      横リピート（回数）、0なら自動計算
  rV:      縦リピート（回数）、0なら自動計算
  in:      間欠描画指定。1～9なら間欠描画、10なら通常描画
★ MatrixPatternEx(int pn, int wh, int r, int g, int b, int lm)
  pn:      柄紋番号
  wh:      柄紋の幅丈（ピクセル数、正方形柄紋）
  r:       赤基調色
  g:       緑基調色
  b:       青基調色
  lm:      色成分の乱数変動幅の制限（1～10）
★ MatrixPatternExOp(db sH,db sV,db dH,db dV,it pH,it pV,it rH,it rV,it in)
  sH:      横シフト（コマ数）
  sV:      縦シフト（コマ数）
  dH:      横ドロップ（コマ数）
  dV:      縦ドロップ（コマ数）
  pH:      横スキップ（コマ数）
  pV:      縦スキップ（コマ数）
  rH:      横リピート（回数）、0なら自動計算
  rV:      縦リピート（回数）、0なら自動計算
  in:      間欠描画指定。1～9なら間欠描画、10なら通常描画
■■色相階調加工
★ ColorGradient(String f, int y1, int y2, double r, double g, double b)
  f:       元画像ファイル名（パス含む）
  y1:      加工開始y軸位置
  y2:      加工反転y軸位置
  r:       赤成分の追加数値
  g:       緑成分の追加数値
  b:       青成分の追加数値
■■ソフト・フォーカス処理
★ SoftFocus(String f, int d)
  f:       ソフト・フォーカスの対象となる元画像ファイル（パス含む）
  d:       ソフト・フォーカス処理の反復回数（0～100）
■■畳み込み処理（画像の鮮鋭化または朦朧化）
★ Convolve(Str f, ft v0, ft v1, ft v2, int d, int k, int t, int c)
★ Convolve(Str f, ft v0, ft v1, ft v2, ft v3, ft v4, ft v5, int d, int k, int t, int c)
  f:       畳み込み処理の対象となる画像ファイル（パス含む）
  v0:      畳み込みフィルター値（カーネル3x3と5x5での共用。対象ピクセルでの値）
  v1:      畳み込みフィルター値（カーネル3x3と5x5での共用。上下左右隣接ピクセルでの値）
  v2:      畳み込みフィルター値（カーネル3x3と5x5での共用。斜め方向隣接ピクセルでの値）
  v3:      畳み込みフィルター値（カーネル5x5での外周部）5x5の使用は、非推奨。
  v4:      畳み込みフィルター値（カーネル5x5での外周部）5x5の使用は、非推奨。
  v5:      畳み込みフィルター値（カーネル5x5での外周部）5x5の使用は、非推奨。
  d:       畳み込み処理の反復回数（1～100）
  k:       カーネル・サイズ（3 / 5）
  m:       ノイズ許容度（1以上で、カーネル・サイズの自乗未満）
  c:       ノイズ識別色段差（1～254）
  ▽「鮮鋭化」の場合、フィルター値の標準は、3x3の場合、v0が5, v1が-1, v2が0。
  ▽「鮮鋭化」でのフィルター値を調整するなら、微調整にとどめること。
  ▽「鮮鋭化」での反復回数は、偽解像やノイズの発生があり、1にとどめること。
  ▽「朦朧化」の場合、フィルター値の標準は、3x3の場合、v0が-0.14, v1が0.14, v2が0.14。
  ▽「朦朧化」でのフィルター値を調整するなら、微調整にとどめること。
  ▽畳み込みは、輪郭の強調やボカシにはなるが、全面にノイズ（砂目や不鮮明）を発生させる。
  ▽ノイズ許容度は、1以上の小さな数値を指定すること。
■■輪郭線抽出処理
★ GetOutline(String f, int d, int k, int t)
  f:     元画像ファイル（パス含む）
  d:     輪郭線位置での色段差（1～254）
  k:     ノイズ除去でのカーネル・サイズ（3 / 5 / 7）
  t:     ノイズ許容度（1以上で、カーネル・サイズの自乗未満）
  ▽ノイズ許容度は、1以上の小さな数値を指定すること。
  ▽一般的には、カーネル・サイズを「5」、ノイズ許容度を「2」とする。
■■二重像画像加工
★ MixImage(String f1, String f2)
 f1:       元画像ファイル名（パス含む）
 f2:       追加画像ファイル名（パス含む）
★ MixImage(int mode, String f1, String f2)
 mode      ０の指定で、拡大縮小のないStamp機能となる
 f1:       元画像ファイル名（パス含む）
 f2:       追加画像ファイル名（パス含む）
■■平行線の太さ指定
★ ParallelLineWidth(float  w)
  w:      平行線の太さ
■■平行線描画（横罫線や縦罫線または方眼のための特殊用途）
★ DrawParallelLineH(db x, db y, db l, db w, int t, int m, int h)
★ DrawParallelLineH2(db x, db y, db l, db w, int t, int m, int h)
  x:       起点座標X
  y:       起点座標Y
  l:       線の長さ
  w:       線の間隔
  t:       線の本数
  m:       線の種類（0：実線、1：密の点線、2：粗の点線）
  h:       中間線の有無（0：無し、1：有り）
★ DrawParallelLineV(db x, db y, db l, db w, int t, int m, int h)
★ DrawParallelLineV2(db x, db y, db l, db w, int t, int m, int h)
  x:       起点座標X
  y:       起点座標Y
  l:       線の長さ
  w:       線の間隔
  t:       線の本数
  m:       線の種類（0：実線、1：密の点線、2：粗の点線）
  h:       中間線の有無（0：無し、1：有り）
■■ファイル入出力の指定（「保存」や「切取」のボタンに対処）
★ SaveCommands(String f)
  f：      命令文書の保存ファイル名（パス含む）
★ SaveImage(String f)
  f：      作成画像の保存ファイル名（パス含む）
★ CutAndSaveImage(int x1.int y1, int x2, int y2, String f)
  f：      切り取り画像の保存ファイル名（パス含む）
  x1:      切り取り画像左上座標ｘ
  y1:      切り取り画像左上座標ｙ
  x2:      切り取り画像右下座標ｘ
  y2:      切り取り画像右下座標ｙ

■■"GCreator" におけるマウス描画の方法
　メニューの「マウス描画モード」の「マウス描画有効モード」を選択し、
以下の項目を選ぶことで、「描画処理」や「対処要求」や「情報要求」が可能になる。
なお、キャンバス内で、マウス・ポインターを操作し、位置指定のクリックによって行なう。

●直線
　始点および終点の二箇所を左クリックすることで、二点間に直線が描画される。
●直線消去
　描画されている直線の始点および終点を左クリックすることで、その直線が消去される。
●ベジェ曲線
　始点、第一制御点、第二制御点、終点の四箇所を左クリックすることで、曲線が描画される。
●スプライン曲線
　始点、一箇所以上の制御点、これらを左クリックし、終点を右クリックすることで、曲線が描画される。
●文字列
　一箇所を左クリックすることで、デフォルトの文字列が、その位置に記入される。
●真円
　真円の中心および右端（左端）を左クリックすることで、真円が描画される。
●真円消去
　真円の中心を左クリックすることで、その真円が消去される。同心円は、その全部が消去される。
●楕円
　楕円の中心および右端（左端）さらに下端（上端）を左クリックすることで、楕円が描画される。
●四角形
　直角四角形の左上および右下を左クリックすることで、水平の直角四角形が描画される。
●自由図形
　自由図形は、直線とベジェ曲線とを混用して閉じた輪郭線の図形を描画し、
　必要に応じて、その内部を色塗りする。
　最終的に輪郭線を閉じさせるには、自由図形全体の始点に戻って左クリック。
　大まかに言えば、左クリックは直線の指定で、右クリックは曲線の指定になる。
　ただし、自由図形全体の始点は、常に左クリックとする。
　また、自由図形全体の終点（始点への帰還）が曲線の終点（右クリック）でもある場合は、
　その終点で左クリックを一つ追加して終了させる。
　なお、正確に言えば、次のルールである。
　自由図形の始点は、左クリック。
　曲線部の第一制御点と第二制御点と終点は、右クリック。
　直線部の終点は、左クリック。
　最終的に輪郭線を閉じさせるには、自由図形全体の始点に戻って左クリック。
　ただし、自由図形全体の終点（始点への回帰）が曲線部の終点（右クリック）でもある場合は、
　その終点で左クリックを一つ追加して終了させる。
　輪郭線を閉じさせるには、始点への回帰した時、左クリックが必要である。
●目印線消去
　この項目を選ぶだけで、一時的に目印線が消去される。
●目印線復活
　この項目を選ぶだけで、一時的に目印線が復活される。
●位置確認
　一箇所を左クリックすることで、その位置の座標値がメッセージ・エリアに表示される。
●位置修正
　始点、制御点、終点のどれかを左クリックし、別の位置を左クリックすることで、位置移動がなされる。
　ただし、文字列、真円、楕円、四角形は、それぞれの始点にだけ反応する。
●色相確認
　一箇所を左クリックすることで、その位置の色相がメッセージ・エリアに表示される。
●図形彩色変更指定
　事前にパレットで混色を行なった上で、
　彩色された図形の始点を左クリックすることで、パレットで混色された色相に変更される。
●命令文検索
　描画されている直線や曲線や図形などの始点を左クリックすることで、コマンド・エリアの命令文の末尾に,
　コメントとして「★★★」の目印が付けられる。
●点描画筆（大）（中）（小）
　一箇所を左クリックすることで、パレットで選ばれた色相によって、小円が描画される。
●スプレー機能
　一箇所を左クリックすることで、デフォルトの設定で、指定箇所の周辺にスプレー画像を描画する。
　ただし、同じ設定のスプレーを数度繰り返した後、スプレー終了の合図として右クリックを行なう。

//EOF (GCreator_Manual.txt)

◆GCreator_Pattern.txt

//GCreator_Pattern.txt
//Ver.4.1
//
//以下２桁以内の配色番号は、６ｘ６コマで、０を含まないマトリックス模様データ。
//
PTN,0001,06,枡に五つ星
1,1,1,3,3,3
1,6,1,3,6,3
1,1,6,6,3,3
4,4,6,6,5,5
4,6,4,5,6,5
4,4,4,5,5,5
PTN,0002,06,市松
1,1,1,2,2,2
1,1,1,2,2,2
1,1,1,2,2,2
2,2,2,1,1,1
2,2,2,1,1,1
2,2,2,1,1,1
PTN,0003,06,市松崩し
1,1,1,2,2,2
1,3,1,2,4,2
1,1,1,2,2,2
2,2,2,1,1,1
2,5,2,1,6,1
2,2,2,1,1,1
PTN,0004,06,松皮菱崩し
1,1,1,2,3,3
1,2,2,2,3,3
1,2,3,3,2,2
2,2,3,3,2,1
3,3,2,2,2,1
3,3,2,1,1,1
PTN,0005,06,大十字紋
1,2,2,2,2,1
3,1,2,2,1,3
3,3,1,1,3,3
3,3,1,1,3,3
3,1,2,2,1,3
1,2,2,2,2,1
PTN,0006,06,十字紋尽くし
1,2,1,3,4,3
2,5,2,4,4,4
1,2,1,2,4,3
3,4,2,1,2,1
4,4,4,2,5,2
3,4,3,1,2,1
PTN,0007,06,十字紋斜め崩し
1,1,7,3,6,6
1,4,3,3,3,6
4,4,4,3,2,7
7,4,5,2,2,2
6,5,5,5,2,1
6,6,5,7,1,1
PTN,0008,06,市松大十字紋
1,2,3,3,1,2
2,3,2,1,3,1
3,2,1,2,1,3
3,1,2,1,2,3
1,3,1,2,3,2
2,1,3,3,2,1
PTN,0009,06,網目市松合わせ
1,1,3,3,2,2
1,1,3,3,2,2
3,3,1,1,3,3
3,3,1,1,3,3
2,2,3,3,1,1
2,2,3,3,1,1
PTN,0010,06,二重網目
4,2,2,2,2,4
2,1,3,3,1,2
2,3,4,4,3,2
2,3,4,4,3,2
2,1,3,3,1,2
4,2,2,2,2,4
PTN,0011,06,入れ子枡
1,1,1,1,1,1
1,2,2,2,2,1
1,2,3,3,2,1
1,2,3,3,2,1
1,2,2,2,2,1
1,1,1,1,1,1
PTN,0012,06,鍵尽くし
4,4,4,5,5,5
4,2,2,3,3,5
4,2,1,6,3,5
5,3,6,1,2,4
5,3,3,2,2,4
5,5,5,4,4,4
PTN,0013,06,多色砂目
1,3,2,3,1,4
3,4,5,1,3,2
4,1,3,2,1,1
1,2,4,1,2,3
2,3,1,2,1,4
3,1,3,5,2,1
PTN,0014,06,枡尽くし
1,1,1,2,2,2
1,5,5,5,5,2
1,5,1,2,5,2
4,5,4,3,5,3
4,5,5,5,5,3
4,4,4,3,3,3
PTN,0015,06,枡尽くし改
1,1,1,2,2,2
1,3,3,3,4,2
1,4,1,2,4,2
2,4,2,1,4,1
2,4,3,3,3,1
2,2,2,1,1,1
PTN,0016,06,重ね枡
1,2,3,3,3,3
2,2,3,5,5,3
4,4,3,4,5,3
4,5,3,4,3,3
4,5,5,4,2,2
4,4,4,4,2,1
PTN,0017,06,枡と市松
4,1,3,6,1,3
1,2,2,2,2,1
6,2,7,5,2,3
3,2,5,7,2,6
1,2,2,2,2,1
3,1,6,3,1,4
PTN,0018,06,枡と市松崩し
4,1,1,6,1,3
1,2,2,2,2,1
1,2,7,5,2,3
3,2,5,7,2,1
1,2,2,2,2,1
3,1,6,1,1,4
PTN,0019,06,Ｙ字紋
1,2,1,4,1,4
2,2,2,4,4,4
2,1,2,1,4,1
1,3,1,5,1,5
3,3,3,5,5,5
3,1,3,1,5,1
PTN,0020,06,Ｙ字紋改
1,2,1,4,4,1
2,2,2,1,4,4
2,1,2,4,4,1
1,3,3,5,1,5
3,3,1,5,5,5
1,3,3,1,5,1
PTN,0021,06,鱗尽くし
1,1,1,2,1,1
1,1,2,2,2,1
1,2,2,2,2,2
2,1,1,1,1,1
2,2,1,1,1,2
2,2,2,1,2,2
PTN,0022,06,三角波
1,2,2,3,2,2
1,1,2,2,2,1
3,1,1,2,1,1
3,3,1,1,1,3
2,3,3,1,3,3
2,2,3,3,3,2
PTN,0023,06,横縞
1,1,1,1,1,1
2,2,2,2,2,2
3,3,3,3,3,3
4,4,4,4,4,4
5,5,5,5,5,5
6,6,6,6,6,6
PTN,0024,06,縦縞
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
//
//以下３桁の配色番号は、６ｘ６コマで、０を含む模様データ。
//
PTN,0100,06,外抜き枡
0,0,0,0,0,0
0,2,2,2,2,0
0,2,3,3,2,0
0,2,3,3,2,0
0,2,2,2,2,0
0,0,0,0,0,0
PTN,0101,06,中抜き枡
1,1,1,1,1,1
1,0,0,0,0,1
1,0,0,0,0,1
1,0,0,0,0,1
1,0,0,0,0,1
1,1,1,1,1,1
PTN,0102,06,外抜き十字紋
0,0,0,0,0,0
0,0,1,3,0,0
0,1,1,3,3,0
0,2,2,4,4,0
0,0,2,4,0,0
0,0,0,0,0,0
PTN,0103,06,星散らし
0,0,0,0,0,0
0,1,0,0,1,0
0,0,0,0,0,0
0,0,0,0,0,0
0,1,0,0,1,0
0,0,0,0,0,0
PTN,0104,06,外抜き五つ星
0,0,0,0,0,0
0,1,0,0,1,0
0,0,1,1,0,0
0,0,1,1,0,0
0,1,0,0,1,0
0,0,0,0,0,0
PTN,0105,06,白抜き市松
1,1,1,0,0,0
1,1,1,0,0,0
1,1,1,0,0,0
0,0,0,1,1,1
0,0,0,1,1,1
0,0,0,1,1,1
PTN,0106,06,点入り十字紋（右下がり）
0,1,0,0,0,0
1,1,1,0,1,0
0,1,0,0,0,0
0,0,0,0,1,0
0,1,0,1,1,1
0,0,0,0,1,0
PTN,0107,06,点入り十字紋（右上がり）
0,0,0,0,1,0
0,1,0,1,1,1
0,0,0,0,1,0
0,1,0,0,0,0
1,1,1,0,1,0
0,1,0,0,0,0
PTN,0108,06,交叉一点鎖線（右下がり）
0,1,0,0,0,0
0,1,0,0,1,0
0,1,0,0,0,0
0,0,0,0,0,0
0,1,0,1,1,1
0,0,0,0,0,0
PTN,0109,06,交叉一点鎖線（右上がり）
0,0,0,0,1,0
0,1,0,0,1,0
0,0,0,0,1,0
0,0,0,0,0,0
1,1,1,0,1,0
0,0,0,0,0,0
PTN,0110,06,Ｗ字紋囲み
0,1,1,2,2,0
1,1,0,0,2,2
1,0,0,0,0,2
2,0,0,0,0,1
2,2,0,0,1,1
0,2,2,1,1,0
PTN,0111,06,八角紋
0,0,1,1,0,0
0,1,2,2,1,0
1,2,2,2,2,1
1,2,2,2,2,1
0,1,2,2,1,0
0,0,1,1,0,0
PTN,0112,06,Ｌ字囲み枡
0,0,0,0,0,0
0,1,1,2,2,0
0,1,2,2,2,0
0,2,2,2,1,0
0,2,2,1,1,0
0,0,0,0,0,0
PTN,0113,06,白抜き十字紋尽くし改
0,0,0,3,0,0
0,4,3,3,3,0
4,4,4,3,2,0
0,4,5,2,2,2
0,5,5,5,2,0
0,0,5,0,0,0
PTN,0114,06,白抜きＴ字紋尽くし
0,0,0,0,0,0
0,4,3,3,3,0
0,4,4,3,2,0
0,4,5,2,2,0
0,5,5,5,2,0
0,0,0,0,0,0
PTN,0115,06,白抜き横縞
0,0,0,5,0,0
0,1,1,1,1,0
2,2,2,2,2,0
0,3,3,3,3,3
0,4,4,4,4,0
0,0,5,0,0,0
PTN,0116,06,白抜き縦縞
0,0,0,3,0,0
0,1,2,3,4,0
5,1,2,3,4,0
0,1,2,3,4,5
0,1,2,3,4,0
0,0,2,0,0,0
PTN,0117,06,外白抜き十字網文
0,0,0,0,0,0
0,3,2,2,3,0
0,2,2,2,2,0
0,2,2,2,2,0
0,3,2,2,3,0
0,0,0,0,0,0
PTN,0118,06,網代,Op(0,0,0,0,-2,-2,0,0,10)
0,2,0,4,4,2
1,2,3,3,1,2
1,4,4,2,1,0
3,3,1,2,4,4
0,2,1,3,3,2
0,2,0,0,0,2
//
//以下の配色番号１０００番以上は、６ｘ６コマを超える大柄
//
PTN,1000,07,斜め格子(7x7)
1,2,2,2,2,2,1
2,1,2,2,2,1,2
2,2,1,2,1,2,2
2,2,2,1,2,2,2
2,2,1,2,1,2,2
2,1,2,2,2,1,2
1,2,2,2,2,2,1
PTN,1001,09,入れ子枡(9x9)
5,5,5,5,5,5,5,5,5
5,1,1,1,1,1,1,1,5
5,1,2,2,2,2,2,1,5
5,1,2,3,3,3,2,1,5
5,1,2,3,4,3,2,1,5
5,1,2,3,3,3,2,1,5
5,1,2,2,2,2,2,1,5
5,1,1,1,1,1,1,1,5
5,5,5,5,5,5,5,5,5
PTN,1002,08,十文字尽くし(8x8),Op(0,0,0,0,-3,-3,0,0,10)
0,1,0,0,0,0,2,0
1,1,1,0,4,2,2,2
0,1,3,4,4,4,2,0
0,3,3,3,4,6,0,0
0,0,3,5,6,6,6,0
0,7,5,5,5,6,8,0
7,7,7,5,0,8,8,8
0,7,0,0,0,0,8,0
PTN,1003,25,亀甲十字紋(25x25),Op(-3.5,-8.5,0,-21,-11,17,0,0,10)
0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,1,1,1,1,5,5,5,1,1,1,1,0,0,0,0,0,0,0
0,0,0,0,0,1,1,1,1,5,5,5,3,5,5,5,1,1,1,1,0,0,0,0,0
0,0,0,1,1,1,1,5,5,5,5,3,3,3,5,5,5,5,1,1,1,1,0,0,0
0,1,1,1,1,5,5,5,3,5,5,5,3,5,5,5,3,5,5,5,1,1,1,1,0
1,1,1,5,5,5,5,3,3,3,5,5,5,5,5,3,3,3,5,5,5,5,1,1,1
1,1,5,5,3,5,5,5,3,5,5,5,4,5,5,5,3,5,5,5,3,5,5,1,1
1,1,5,3,3,3,5,5,5,5,5,4,4,4,5,5,5,5,5,3,3,3,5,1,1
1,1,5,5,3,5,5,5,5,4,5,5,4,5,5,4,5,5,5,5,3,5,5,1,1
1,1,5,5,5,5,5,5,5,5,5,4,4,4,5,5,5,5,5,5,5,5,5,1,1
1,1,5,5,3,5,5,5,4,5,4,4,4,4,4,5,4,5,5,5,3,5,5,1,1
1,1,5,3,3,3,5,4,4,4,4,4,4,4,4,4,4,4,5,3,3,3,5,1,1
1,1,5,5,3,5,5,5,4,5,4,4,4,4,4,5,4,5,5,5,3,5,5,1,1
1,1,5,5,5,5,5,5,5,5,5,4,4,4,5,5,5,5,5,5,5,5,5,1,1
1,1,5,5,3,5,5,5,5,4,5,5,4,5,5,4,5,5,5,5,3,5,5,1,1
1,1,5,3,3,3,5,5,5,5,5,4,4,4,5,5,5,5,5,3,3,3,5,1,1
1,1,5,5,3,5,5,5,3,5,5,5,4,5,5,5,3,5,5,5,3,5,5,1,1
1,1,1,5,5,5,5,3,3,3,5,5,5,5,5,3,3,3,5,5,5,5,1,1,1
0,1,1,1,1,5,5,5,3,5,5,5,3,5,5,5,3,5,5,5,1,1,1,1,0
0,0,0,1,1,1,1,5,5,5,5,3,3,3,5,5,5,5,1,1,1,1,0,0,0
0,0,0,0,0,1,1,1,1,5,5,5,3,5,5,5,1,1,1,1,0,0,0,0,0
0,0,0,0,0,0,0,1,1,1,1,5,5,5,1,1,1,1,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0
PTN,1004,25,亀甲六芒星紋(25x25),Op(-3.5,-8.5,0,-21,-11,17,0,0,10)
0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,1,1,1,1,2,2,2,1,1,1,1,0,0,0,0,0,0,0
0,0,0,0,0,1,1,1,1,2,2,3,2,3,2,2,1,1,1,1,0,0,0,0,0
0,0,0,1,1,1,1,2,2,2,2,2,3,2,2,2,2,2,1,1,1,1,0,0,0
0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,0
1,1,1,2,2,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,2,2,1,1,1
1,1,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,2,2,1,1
1,1,2,3,3,2,2,2,2,2,2,2,3,2,2,2,2,2,2,2,3,3,2,1,1
1,1,2,2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,3,2,2,2,2,1,1
1,1,2,2,2,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,2,2,2,1,1
1,1,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,1,1
1,1,2,2,3,2,2,2,2,2,3,3,3,3,3,2,2,2,2,2,3,2,2,1,1
1,1,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,1,1
1,1,2,2,2,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,2,2,2,1,1
1,1,2,2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,3,2,2,2,2,1,1
1,1,2,3,3,2,2,2,2,2,2,2,3,2,2,2,2,2,2,2,3,3,2,1,1
1,1,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,2,2,1,1
1,1,1,2,2,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,2,2,1,1,1
0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,0
0,0,0,1,1,1,1,2,2,2,2,2,3,2,2,2,2,2,1,1,1,1,0,0,0
0,0,0,0,0,1,1,1,1,2,2,3,2,3,2,2,1,1,1,1,0,0,0,0,0
0,0,0,0,0,0,0,1,1,1,1,2,2,2,1,1,1,1,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0
PTN,1005,09,三角形(9x9),Op(-0.5,-1,-5,0,1,-4,10,27,10)
0,0,0,0,1,0,0,0,0
0,0,0,1,1,1,0,0,0
0,0,1,1,1,1,1,0,0
0,1,1,1,1,1,1,1,0
1,1,1,1,1,1,1,1,1
0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0
PTN,1006,11,菱形(11x11)
0,0,0,0,0,1,0,0,0,0,0
0,0,0,0,1,1,1,0,0,0,0
0,0,0,1,1,1,1,1,0,0,0
0,0,1,1,1,1,1,1,1,0,0
0,1,1,1,1,1,1,1,1,1,0
1,1,1,1,1,1,1,1,1,1,1
0,1,1,1,1,1,1,1,1,1,0
0,0,1,1,1,1,1,1,1,0,0
0,0,0,1,1,1,1,1,0,0,0
0,0,0,0,1,1,1,0,0,0,0
0,0,0,0,0,1,0,0,0,0,0
PTN,1007,12,朝霞(12x12),MatrixPatternExOp(0,0, 0,0, -5,0, 0,0, 10)
0,0,0,1,1,1,1,1,1,1,0,0
0,0,0,0,1,1,1,1,1,1,1,0
0,0,0,1,1,1,1,1,1,1,0,0
0,0,1,1,1,1,1,1,1,0,0,0
0,0,0,2,2,2,2,2,2,2,0,0
0,0,0,0,2,2,2,2,2,2,2,0
0,0,0,2,2,2,2,2,2,2,0,0
0,0,2,2,2,2,2,2,2,0,0,0
3,3,3,3,3,3,3,0,0,0,0,0
0,3,3,3,3,3,3,3,0,0,0,0
0,0,3,3,3,3,3,3,3,0,0,0
0,3,3,3,3,3,3,3,0,0,0,0
PTN,1008,12,朝霞逆向き(12x12),MatrixPatternExOp(0,0, 0,0, -5,0, 0,0, 10)
0,0,1,1,1,1,1,1,1,0,0,0
0,1,1,1,1,1,1,1,0,0,0,0
0,0,1,1,1,1,1,1,1,0,0,0
0,0,0,1,1,1,1,1,1,1,0,0
0,0,2,2,2,2,2,2,2,0,0,0
0,2,2,2,2,2,2,2,0,0,0,0
0,0,2,2,2,2,2,2,2,0,0,0
0,0,0,2,2,2,2,2,2,2,0,0
0,0,0,0,0,3,3,3,3,3,3,3
0,0,0,0,3,3,3,3,3,3,3,0
0,0,0,3,3,3,3,3,3,3,0,0
0,0,0,0,3,3,3,3,3,3,3,0
//
//EOF (GCreator_Pattern.txt)