From beac355a0f1b5f75020760c36061283e44e9636c Mon Sep 17 00:00:00 2001
From: curtis <curtis@i-mps.com>
Date: 星期二, 24 三月 2026 08:48:20 +0800
Subject: [PATCH] doc

---
 doc/curtis/Local_IO_抽像方法列表.md                  |    0 
 separate/scanImp/CB_IMGPSScanImp_Utils.pas     | 2545 +++++++
 .idea/git_toolbox_prj.xml                      |   15 
 separate/scanImp/CB_IMGPSScanImp_Scan.pas      | 1050 ++
 CB_IMGPSScanImp.ts                             |  694 +
 separate/scanImp/CB_IMGPSScanImp_Scan.ts       |  124 
 doc/curtis/Delphi_套件_EnScan_webAssembly_可行性.md |   77 
 doc/curtis/index.md                            |   15 
 separate/scanImp/CB_IMGPSScanImp_Data.pas      | 5178 ++++++++++++++
 doc/curtis/Scanner_Controller_Analysis.md      |   62 
 CB_IMGPSScan_TLB.ts                            |  123 
 .idea/misc.xml                                 |    6 
 .idea/vcs.xml                                  |    7 
 doc/curtis/AI可能讀不到的_TLB_介面.md                  |   44 
 .idea/modules.xml                              |    8 
 doc/curtis/Local_IO_路徑與檔案操作分析.md               |  233 
 doc/curtis/分析_尚進行中.md                          |  830 ++
 doc/curtis/Transport_Manager_Analysis.md       |   69 
 doc/curtis/remote_相關方法.md                      |    0 
 doc/curtis/UI_View_Analysis.md                 |   86 
 split_pascal.js                                |   98 
 doc/curtis/Business_Logic_Analysis.md          |   64 
 separate/scanImp/CB_IMGPSScanImp_UI.ts         |   78 
 doc/curtis/delphi_conventions.md               |  249 
 separate/scanImp/CB_IMGPSScanImp_Data.ts       |  819 ++
 separate/scanImp/CB_IMGPSScanImp_Main.pas      | 1089 +++
 doc/curtis/Image_Processer_Analysis.md         |   69 
 .idea/codeStyles                               |  116 
 .idea/.gitignore                               |    8 
 doc/curtis/OCX_溝通與_抽象層抽換.md                    |  249 
 separate/scanImp/CB_IMGPSScanImp_Utils.ts      |   59 
 doc/curtis/ScanImp_源碼分析.md                     |  242 
 doc/curtis/Delphi_套件相依.md                      |  115 
 separate/scanImp/CB_IMGPSScanImp_Main.ts       |   17 
 separate/scanImp/CB_IMGPSScanImp_UI.pas        | 6592 ++++++++++++++++++
 35 files changed, 21,030 insertions(+), 0 deletions(-)

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/codeStyles b/.idea/codeStyles
new file mode 100644
index 0000000..dc4aa1e
--- /dev/null
+++ b/.idea/codeStyles
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectCodeStyleConfiguration">
+    <code_scheme name="Project" version="173">
+      <codeStyleSettings language="XML">
+        <arrangement>
+          <rules>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>xmlns:android</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>^$</XML_NAMESPACE>
+                  </AND>
+                </match>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>xmlns:.*</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>^$</XML_NAMESPACE>
+                  </AND>
+                </match>
+                <order>BY_NAME</order>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>.*:id</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                  </AND>
+                </match>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>.*:name</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                  </AND>
+                </match>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>name</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>^$</XML_NAMESPACE>
+                  </AND>
+                </match>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>style</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>^$</XML_NAMESPACE>
+                  </AND>
+                </match>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>.*</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>^$</XML_NAMESPACE>
+                  </AND>
+                </match>
+                <order>BY_NAME</order>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>.*</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                  </AND>
+                </match>
+                <order>ANDROID_ATTRIBUTE_ORDER</order>
+              </rule>
+            </section>
+            <section>
+              <rule>
+                <match>
+                  <AND>
+                    <NAME>.*</NAME>
+                    <XML_ATTRIBUTE />
+                    <XML_NAMESPACE>.*</XML_NAMESPACE>
+                  </AND>
+                </match>
+                <order>BY_NAME</order>
+              </rule>
+            </section>
+          </rules>
+        </arrangement>
+      </codeStyleSettings>
+    </code_scheme>
+  </component>
+</project>
diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml
new file mode 100644
index 0000000..cca44d7
--- /dev/null
+++ b/.idea/git_toolbox_prj.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GitToolBoxProjectSettings">
+    <option name="commitMessageIssueKeyValidationOverride">
+      <BoolValueOverride>
+        <option name="enabled" value="true" />
+      </BoolValueOverride>
+    </option>
+    <option name="commitMessageValidationEnabledOverride">
+      <BoolValueOverride>
+        <option name="enabled" value="true" />
+      </BoolValueOverride>
+    </option>
+  </component>
+</project>
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..83fb565
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+<project version="4">
+  <component name="MarkdownNavigator.ProfileManager" plain-text-search-scope="Project Files" />
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-11" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..3765b7b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/CB_IMGPSScan.iml" filepath="$PROJECT_DIR$/.idea/CB_IMGPSScan.iml" />
+    </modules>
+  </component>
+</project>
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..20620ba
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
diff --git a/CB_IMGPSScanImp.ts b/CB_IMGPSScanImp.ts
new file mode 100755
index 0000000..0adddc1
--- /dev/null
+++ b/CB_IMGPSScanImp.ts
@@ -0,0 +1,694 @@
+import * as fs from 'fs';
+import * as path from 'path';
+
+// ============================================================================
+// 模擬 Delphi 與 VCL/硬體 相依介面 (Node.js 中不存在的實體)
+// ============================================================================
+export type TObject = any;
+export type TMouseButton = 'mbLeft' | 'mbRight' | 'mbMiddle';
+export type TShiftState = any;
+export type THandle = number;
+export type TDibGraphic = any;
+export type TTiffGraphic = any;
+export type TImageFormat = 'ifBlackWhite' | 'ifGray256' | 'ifTrueColor' | 'ifColor256';
+export type TMouseMode = 'mmUser' | 'mmAmplifier' | 'mmZoom' | 'mmDrag' | 'mmR270' | 'mmR180' | 'mmR90' | 'mmDelete';
+export type TxActiveFormBorderStyle = number;
+export type TxPrintScale = number;
+export type TxPopupMode = number;
+export type OLE_COLOR = number;
+export type IFontDisp = any;
+
+export interface TTreeNode {
+    Text: string;
+    Level: number;
+    ImageIndex: number;
+    SelectedIndex: number;
+    Parent?: TTreeNode;
+    Count: number;
+    Item: TTreeNode[];
+    Expand(expand: boolean): void;
+    Delete(): void;
+}
+
+export interface TImageScrollBox {
+    Name: string;
+    FileName: string;
+    Graphic: any;
+    DisplayedGraphic: any;
+    MouseMode: TMouseMode;
+    ZoomMode: any;
+    ZoomPercent: number;
+    AntiAliased: boolean;
+    Parent: any;
+    LoadFromFile(filename: string, index: number): void;
+    SaveToFile(filename: string): void;
+    Redraw(force: boolean): void;
+    SetFocus(): void;
+    BeginDrag(immediate: boolean): void;
+}
+
+export interface TListView {
+    Items: { Count: number; Item: any[], Add(): any, Clear(): void };
+    Selected: any;
+    ItemIndex: number;
+    ClearSelection(): void;
+    Clear(): void;
+}
+
+export interface TTreeView {
+    Items: { Add(node: any, text: string): TTreeNode; AddChild(node: any, text: string): TTreeNode; Clear(): void };
+    Selected: TTreeNode;
+}
+
+// ============================================================================
+// 模擬 Delphi TStringList 檔案字串處理功能
+// ============================================================================
+export class TStringList {
+    private _strings: string[] = [];
+
+    get Count(): number { return this._strings.length; }
+    get Strings(): string[] { return this._strings; }
+    set Strings(value: string[]) { this._strings = value; }
+    get Text(): string { return this._strings.join('\n'); }
+    set Text(value: string) { this._strings = value.split('\n'); }
+    get CommaText(): string { return this._strings.join(','); }
+    set CommaText(value: string) { this._strings = value.split(','); }
+
+    public Add(item: string) { this._strings.push(item); }
+    public Insert(index: number, item: string) { this._strings.splice(index, 0, item); }
+    public Delete(index: number) { this._strings.splice(index, 1); }
+    public Clear() { this._strings = []; }
+    public IndexOf(item: string): number { return this._strings.indexOf(item); }
+    
+    public LoadFromFile(filepath: string) {
+        if (fs.existsSync(filepath)) {
+            const data = fs.readFileSync(filepath, 'utf8');
+            this._strings = data.split(/\r?\n/).filter(line => line.length > 0);
+        }
+    }
+    
+    public SaveToFile(filepath: string) {
+        fs.writeFileSync(filepath, this._strings.join('\n'), 'utf8');
+    }
+    
+    public Sort() { this._strings.sort(); }
+    public Assign(source: TStringList) { this._strings = [...source.Strings]; }
+}
+
+// ============================================================================
+// 列舉與資料結構
+// ============================================================================
+export enum TTransMode { tsHttp, tsFtp, tsNone }
+export enum TScanMode { smNew, smReplace, smInsert, smSample, smRTS }
+export enum TFtpProtocol { fpftp, fpftps }
+
+export interface TScanInfo {
+    MultiPage: boolean;
+    Graphic: TTiffGraphic;
+    Stream: any;
+    ImageCount: number;
+}
+
+export interface TOMRErrInfo {
+    Display: boolean;
+    Ignore: boolean;
+    Info: string;
+    Mode: string;
+}
+
+export interface TScrollRec {
+    HScroll: number;
+    VScroll: number;
+    Rate: number;
+}
+
+export interface TPoint {
+    X: number;
+    Y: number;
+}
+
+export interface TMpsBarcodeinf {
+    Count: number;
+    Text: string[];
+    r180: number[];
+}
+
+// ============================================================================
+// 主要實作類別 (對應 TCB_IMGPSScanX)
+// ============================================================================
+export class TCB_IMGPSScanX {
+    // ===== 系統全域變數 =====
+    private Ch_WriteNote: boolean = false;
+    private RejectCase: boolean = false;
+    private ErrIndex: number = 0;
+
+    // ===== 預設區 =====
+    private Def_DeviceDelete: boolean = true;
+    private Def_DeviceDeleteSize: number = 3072;
+    private Def_ScannerReverse: boolean = false;
+    private Def_BoardClear: boolean = false;
+    private Def_ScanDpi: number = 300;
+    private Def_ScanDuplex: boolean = true;
+    private Def_ScanRotate: number = 0;
+    private Def_ScanDeskew: boolean = false;
+    private Def_ScanBright: number = 0;
+    private Def_ScanContrast: number = 0;
+    private Def_ScanImgShowMode: number = 2;
+    private Def_ScanImgSetUse: boolean = false;
+
+    // ===== 傳入參數 =====
+    private FUrl: string = '';
+    private FCaseID: string = '';
+    private FMode: string = '';
+    private FModeName: string = '';
+    private FWork_no: string = '';
+    private FUserID: string = '';
+    private FUserName: string = '';
+    private FUserUnit: string = '';
+    private FData: string = '';
+    private FVerify: string = '';
+    private FReWrite: string = '';
+    private FLanguage: string = 'zh_tw';
+    private FLoanDoc_Value: string = '';
+    private FLoanDoc_Enable: string = '';
+    private FUseProxy: string = '';
+    private FC_DocNoList: string = '';
+    private FC_DocNameList: string = '';
+    private FFixFileList: string = '';
+    private FIs_In_Wh: string = '';
+    private FOldCaseInfo: string = '';
+    private FPrintyn: string = '';
+    private FIs_OldCase: string = '';
+    private FCustDocYN: string = '';
+    private FImgDPI: number = 300;
+    private FScanColor: number = 0;
+    private FFileSizeLimit: number = 5120; // 5 * 1024
+    private FCaseNoLength: number = 16;
+    private FImgDelete: string = 'N';
+    private FIsExternal: string = 'N';
+    private FCheck_main_form: string = 'N';
+    private FWH_category: string = 'N';
+
+    // ===== 狀態變數 =====
+    private TransMode: TTransMode = TTransMode.tsNone;
+    private HttpErrStr: string = '';
+    private ScanColor: TImageFormat = 'ifBlackWhite';
+    private ServerDate: string = '';
+    private ServerTime: string = '';
+    private Balance: number = 0;
+    private ScanDenialTime: string = '';
+    private ScanDenialHint: string = '';
+
+    // ===== 路徑區 =====
+    private ScanPath: string = '';
+    private ImagePath: string = '';
+    private ImageSavePath: string = '';
+    private ScaniniPath: string = '';
+    private LngPath: string = '';
+    private CheckXmlPath: string = '';
+    private SitePath: string = '';
+    private SamplePath: string = '';
+    private TransPath: string = '';
+
+    // ===== 清單區 =====
+    private Doc_Inf_List: TStringList = new TStringList();
+    private DM_FORM_INF_List: TStringList = new TStringList();
+    private FORM_INF_List: TStringList = new TStringList();
+    private CHECK_RULE_INF_List: TStringList = new TStringList();
+    private MEMO_INF_List: TStringList = new TStringList();
+    private WORK_INF_List: TStringList = new TStringList();
+    private LASTEST_FORM_INF_List: TStringList = new TStringList();
+    private FindResult: TStringList = new TStringList();
+    private CaseList: TStringList = new TStringList();
+    private Context_DocnoList: TStringList = new TStringList();
+    private CaseDocNoList: TStringList = new TStringList();
+    private CaseDocNo_CopiesList: TStringList = new TStringList();
+    private ContextList: TStringList = new TStringList();
+    private AttContextList: TStringList = new TStringList();
+    private OMRFileList: TStringList = new TStringList();
+    private Cust_DocNoList: TStringList = new TStringList();
+    private IN_WH_DocNoList: TStringList = new TStringList();
+    private FormCode_PageSize: TStringList = new TStringList();
+    private DocNo_NeedDoc: TStringList = new TStringList();
+    private DocNo_NoDoc: TStringList = new TStringList();
+    private DocNo_VerinCase: TStringList = new TStringList();
+    private NoSaveBarCodeList: TStringList = new TStringList();
+    private FormID_List: TStringList = new TStringList();
+    private DocNo_List: TStringList = new TStringList();
+    private NowShowFileList: TStringList = new TStringList();
+    private NowSelectFileList: TStringList = new TStringList();
+    private GuideFormIDList: TStringList = new TStringList();
+    private DivPageFormIDList: TStringList = new TStringList();
+    private LastInitFormidList: TStringList = new TStringList();
+    private LastAddFormidList: TStringList = new TStringList();
+    private SampleFormIDList: TStringList = new TStringList();
+    private ExistImgList: TStringList = new TStringList();
+    private reSizeExistImgList: TStringList = new TStringList();
+
+    // ===== 顯示區變數 =====
+    private NowCaseno: string = '';
+    private NowDocNo: string = '';
+    private NowDocDir: string = '';
+    private NowFormCode: string = '';
+    private NowFormName: string = '';
+    private NowPage: number = 0;
+    private DisplayPath: string = '';
+    private Case_loandoc: string = '';
+
+    // ===== 其他狀態 =====
+    private ScanModeState: TScanMode = TScanMode.smNew;
+    private InitialOk: boolean = false;
+    private ShowText: string = '';
+    private SafePixel: number = 20;
+    private OMRErrInfo: TOMRErrInfo[] = []; // length 11
+
+    // UI Mocks
+    private TreeView1: TTreeView = {} as TTreeView;
+    private PageLV: TListView = {} as TListView;
+    private ISB1: TImageScrollBox = {} as TImageScrollBox;
+    private DisplayISB: TImageScrollBox = {} as TImageScrollBox;
+    private SelectISB: TImageScrollBox = {} as TImageScrollBox;
+    private NewTreeNode: TTreeNode = {} as TTreeNode;
+    private MyTreeNode1: TTreeNode = {} as TTreeNode;
+    private MyTreeNode2: TTreeNode = {} as TTreeNode;
+    private MyTreeNode3: TTreeNode = {} as TTreeNode;
+
+    constructor() {
+        // Constructor initialization
+    }
+
+    // ============================================================================
+    // COM 屬性 (Getters & Setters)
+    // ============================================================================
+    get url(): string { return this.FUrl; }
+    set url(value: string) { this.FUrl = value; }
+
+    get caseid(): string { return this.FCaseID; }
+    set caseid(value: string) { this.FCaseID = value; }
+
+    get mode(): string { return this.FMode; }
+    set mode(value: string) { this.FMode = value.toUpperCase(); }
+
+    get work_no(): string { return this.FWork_no; }
+    set work_no(value: string) { this.FWork_no = value; }
+
+    get userid(): string { return this.FUserID; }
+    set userid(value: string) { this.FUserID = value; }
+
+    get username(): string { return this.FUserName; }
+    set username(value: string) { this.FUserName = value; }
+
+    get userunit(): string { return this.FUserUnit; }
+    set userunit(value: string) { this.FUserUnit = value; }
+
+    get data(): string { return this.FData; }
+    set data(value: string) { this.FData = value; }
+
+    get verify(): string { return this.FVerify; }
+    set verify(value: string) { this.FVerify = value; }
+
+    get rewrite(): string { return this.FReWrite; }
+    set rewrite(value: string) { this.FReWrite = value; }
+
+    get modename(): string { return this.FModeName; }
+    set modename(value: string) { this.FModeName = value; }
+
+    get language(): string { return this.FLanguage; }
+    set language(value: string) { this.FLanguage = value.toLowerCase(); }
+
+    get loandoc_value(): string { return this.FLoanDoc_Value; }
+    set loandoc_value(value: string) { this.FLoanDoc_Value = value; }
+
+    get loandoc_enable(): string { return this.FLoanDoc_Enable; }
+    set loandoc_enable(value: string) { this.FLoanDoc_Enable = value; }
+
+    get c_docnolist(): string { return this.FC_DocNoList; }
+    set c_docnolist(value: string) { this.FC_DocNoList = value; }
+
+    get c_docnamelist(): string { return this.FC_DocNameList; }
+    set c_docnamelist(value: string) { this.FC_DocNameList = value; }
+
+    get is_in_wh(): string { return this.FIs_In_Wh; }
+    set is_in_wh(value: string) { this.FIs_In_Wh = value.toUpperCase(); }
+
+    get oldcaseinfo(): string { return this.FOldCaseInfo; }
+    set oldcaseinfo(value: string) { this.FOldCaseInfo = value; }
+
+    get scancolor(): string { return this.FScanColor.toString(); }
+    set scancolor(value: string) { 
+        this.FScanColor = value ? parseInt(value) : 0; 
+        this.ScanColor = this.FScanColor === 2 ? 'ifTrueColor' : (this.FScanColor === 1 ? 'ifGray256' : 'ifBlackWhite');
+    }
+
+    get imgdpi(): string { return this.FImgDPI.toString(); }
+    set imgdpi(value: string) { 
+        this.FImgDPI = value ? parseInt(value) : 300; 
+        this.Def_ScanDpi = this.FImgDPI;
+    }
+
+    get filesizelimit(): string { return this.FFileSizeLimit.toString(); }
+    set filesizelimit(value: string) { this.FFileSizeLimit = value ? parseInt(value) : 5120; }
+
+    get casenolength(): string { return this.FCaseNoLength.toString(); }
+    set casenolength(value: string) { this.FCaseNoLength = value ? parseInt(value) : 0; }
+
+    get WH_CATEGORY(): string { return this.FWH_category; }
+    set WH_CATEGORY(value: string) { this.FWH_category = value; }
+
+    // ============================================================================
+    // 核心資料庫 / 字串解析方法 (移植自 Pascal)
+    // ============================================================================
+
+    /**
+     * 依欄位及索引取值
+     */
+    private GetSQLData(TableList: TStringList, ColName: string, colNo: number): string {
+        if (TableList.Count === 0 || colNo >= TableList.Count) return '';
+        
+        const ColStr = TableList.Strings[0].split(',');
+        const TmpStr = TableList.Strings[colNo];
+        const DataStr = TmpStr.split('!@!'); // Delphi 用 '!@!' 分隔
+        
+        const idx = ColStr.indexOf(ColName);
+        if (idx !== -1 && idx < DataStr.length) {
+            return DataStr[idx];
+        }
+        return '';
+    }
+
+    /**
+     * 找指定的資料
+     */
+    private FindSQLData(TableList: TStringList, ColumeStr: string, KeyColumeStr: string, KeyStr: string, ColNo: number, ResultList: TStringList): boolean {
+        ResultList.Clear();
+        if (!KeyStr || TableList.Count <= 1) return false;
+
+        const ColList = ColumeStr.split(',');
+        const KeyColList = KeyColumeStr.split(',');
+        const KeyList = KeyStr.split(',');
+
+        let findIndex = -1;
+        let found = false;
+
+        if (ColNo === 0) {
+            for (let i = 1; i < TableList.Count; i++) {
+                let match = true;
+                for (let n = 0; n < KeyColList.length; n++) {
+                    const keyCol = KeyColList[n];
+                    const keyVal = KeyList[n];
+                    if (this.GetSQLData(TableList, keyCol, i) !== keyVal) {
+                        match = false;
+                        break;
+                    }
+                }
+                if (match) {
+                    found = true;
+                    findIndex = i;
+                    break;
+                }
+            }
+        } else {
+            // Specific Row Check
+            let match = true;
+            for (let n = 0; n < KeyColList.length; n++) {
+                const keyCol = KeyColList[n];
+                const keyVal = KeyList[n];
+                const rowData = TableList.Strings[ColNo];
+                if (rowData.indexOf(`!@!${keyVal}!@!`) === -1) {
+                    match = false;
+                    break;
+                }
+            }
+            if (match) {
+                found = true;
+                findIndex = ColNo;
+            }
+        }
+
+        if (found) {
+            for (let n = 0; n < ColList.length; n++) {
+                const col = ColList[n];
+                ResultList.Add(`${col},${this.GetSQLData(TableList, col, findIndex)}`);
+            }
+        }
+        return found;
+    }
+
+    private GetFindResult(Col: string): string {
+        for (let i = 0; i < this.FindResult.Count; i++) {
+            const s = this.FindResult.Strings[i];
+            const idx = s.indexOf(',');
+            if (idx > -1) {
+                const rCol = s.substring(0, idx);
+                const rValue = s.substring(idx + 1);
+                if (Col === rCol) return rValue;
+            }
+        }
+        return '';
+    }
+
+    // ============================================================================
+    // 文件、表單、名稱轉換方法
+    // ============================================================================
+
+    private FormCode2DocNo(FormCode: string): string {
+        let result = '';
+        for (let i = 0; i < this.FormID_List.Count; i++) {
+            if (this.FormID_List.Strings[i] === FormCode) {
+                result = this.DocNo_List.Strings[i];
+                break;
+            }
+        }
+        if (FormCode && !result) {
+            result = FormCode.substring(0, 8); // 自訂文件
+        }
+        return result;
+    }
+
+    private FormCode2Version(FormCode: string): string {
+        return FormCode.substring(10, 15); // Delphi is 1-based (11,5) -> JS is 0-based (10, 15)
+    }
+
+    private FormCode2Page(FormCode: string): string {
+        return FormCode.substring(8, 10); // Delphi is (9,2)
+    }
+
+    private FileName2FormCode(FileName: string): string {
+        const fname = path.basename(FileName);
+        const v = fname.indexOf('_');
+        const v1 = fname.lastIndexOf('.');
+        if (v > -1 && v1 > v) {
+            return fname.substring(v + 1, v1);
+        }
+        return ''; // 附件
+    }
+
+    private DocNo2DocNoDir(savePath: string, DocNo: string): string {
+        if (DocNo) {
+            let i = 0;
+            let iDocNo = '';
+            do {
+                i++;
+                iDocNo = `${DocNo}(${i})`;
+            } while (fs.existsSync(path.join(savePath, iDocNo)));
+            return iDocNo;
+        }
+        return 'Attach';
+    }
+
+    private DocNoDir2DocNo(DocNoDir: string): string {
+        if (DocNoDir !== 'Attach' && DocNoDir !== 'S_Attach') {
+            const v = DocNoDir.indexOf('(');
+            if (v > 0) return DocNoDir.substring(0, v);
+            return DocNoDir;
+        }
+        return DocNoDir;
+    }
+
+    // ============================================================================
+    // 系統初始化與清單載入 (模擬 Delphi 的 Timer1Timer)
+    // ============================================================================
+    public async InitSystem() {
+        this.InitialOk = false;
+        this.FMaxUploadSize = '10';
+        
+        if (!this.FUrl) {
+            console.error('URL cannot be empty, please contact system administrator');
+            return;
+        }
+        if (!this.FUrl.endsWith('/')) this.FUrl += '/';
+        
+        // 在 Node.js 中通常依賴環境變數或 config 檔案,這裡模擬建立目錄
+        this.ImagePath = path.join(__dirname, 'Scantemp', this.FWork_no, this.FUserUnit, this.FMode);
+        this.ImageSavePath = this.ImagePath;
+        
+        if (!fs.existsSync(this.ImagePath)) fs.mkdirSync(this.ImagePath, { recursive: true });
+
+        this.DataLoading(true, true);
+
+        // TODO: 模擬 HTTP API 請求 (GetServerDate, GetSetInf1~7 等)
+        // await this.GetServerDate();
+        // await this.GetSetInf1(); 
+        
+        this.InitialOk = true;
+        this.DataLoading(false, false);
+    }
+
+    // ============================================================================
+    // 按鈕動作邏輯:上傳 (TransBtnClick)
+    // ============================================================================
+    public async TransBtnClick() {
+        if (!this.InitialOk) {
+            console.log('資訊尚未下載完成,請稍候或重新進入');
+            return;
+        }
+        this.RejectCase = false;
+        
+        if (this.NewTreeNode.Count === 0) {
+            console.log('無影像需傳送');
+            return;
+        }
+
+        let SuccessCount = 0;
+        let ReCasecount = 0;
+        let CheckErrCount = 0;
+
+        this.DataLoading(true, true);
+
+        // 巡覽所有案件節點
+        for (let i = 0; i < this.NewTreeNode.Count; i++) {
+            const nodeText = this.NewTreeNode.Item[i].Text;
+            const v = nodeText.indexOf('-');
+            const CaseID = nodeText.substring(0, v);
+
+            this.CreateIn_WH(CaseID);
+            this.Case2upload(CaseID);
+            this.TransPath = path.join(this.ImageSavePath, CaseID, 'Upload');
+
+            // 是否可以上傳?
+            const CaseTrans = this.CaseAsk(CaseID); // 0: 可以, 1: 重複, -1: 失敗
+            if (CaseTrans === -1) {
+                console.error(this.HttpErrStr);
+                this.DataLoading(false, false);
+                return;
+            }
+            if (CaseTrans === 1) {
+                ReCasecount++;
+                continue;
+            }
+
+            if (CaseTrans === 0) {
+                // 進行 OMR 檢核
+                if (this.FMode !== 'FSCAN') {
+                    if (!this.OMRCheckCase(CaseID)) {
+                        CheckErrCount++;
+                        continue;
+                    }
+                }
+                
+                // 執行傳送 (ZIP 壓縮 + HTTP/FTP Upload)
+                const isTransOk = await this.TransCaseID(this.TransPath, CaseID, true);
+                if (!isTransOk) {
+                    this.DataLoading(false, false);
+                    return;
+                }
+                SuccessCount++;
+            }
+        }
+
+        this.DataLoading(false, false);
+        console.log(`傳送完成。成功件【${SuccessCount}】件,失敗件【${ReCasecount}】,檢核失敗【${CheckErrCount}】`);
+    }
+
+    // ============================================================================
+    // OMR 檢核邏輯 (OMRCheckCase)
+    // ============================================================================
+    private OMRCheckCase(CaseID: string): boolean {
+        let CaseOk = true;
+        const errIniPath = path.join(this.ImageSavePath, CaseID, 'upload', 'Checkerr.ini');
+        if (fs.existsSync(errIniPath)) fs.unlinkSync(errIniPath);
+        
+        const MainFormID = this.GetCaseFormID(path.join(this.ImageSavePath, CaseID, 'upload'));
+        
+        // 這裡會實作根據 MainFormID 取得 OMR 檢核 XML 設定的邏輯
+        // 並比對掃描圖檔的影像黑點數量,決定是否缺件或缺漏必填欄位。
+        // TODO: 完整的 OMR Check (XML Parsing and Image Pixel counting)
+        
+        return CaseOk;
+    }
+
+    // ============================================================================
+    // 壓縮與傳送封裝 (TransCaseID)
+    // ============================================================================
+    private async TransCaseID(TransPath: string, CaseID: string, MainCase: boolean): Promise<boolean> {
+        // 1. 產生必要的 Data 檔案 (FormCode_Name.dat, DocNo_Name.dat 等)
+        this.CreateFormID_FormName(TransPath, CaseID);
+        this.CreateDocNo_DocName(TransPath, CaseID);
+        
+        // 2. 壓縮檔案為 Img.zip (模擬)
+        const zipPath = path.join(TransPath, 'Img.zip');
+        console.log(`[ZIP] Zipping files in ${TransPath} to ${zipPath}`);
+        
+        // 3. 檢查檔案大小是否超過限制 FMaxUploadSize
+        // const stat = fs.statSync(zipPath);
+        // if (stat.size > parseInt(this.FMaxUploadSize) * 1048576) { ... }
+
+        // 4. 根據 TransMode 進行 Http POST 或 FTP 上傳
+        if (this.TransMode === TTransMode.tsHttp) {
+            console.log(`[HTTP] Uploading file to ${this.FUrl}...`);
+            // TODO: Axios or fetch POST request
+        } else if (this.TransMode === TTransMode.tsFtp) {
+            console.log(`[FTP] Uploading file to FTP server...`);
+            // TODO: FTP Client put
+        }
+        
+        // 5. 刪除本機暫存
+        const caseDir = path.join(this.ImageSavePath, CaseID);
+        if (fs.existsSync(caseDir)) {
+            fs.rmSync(caseDir, { recursive: true, force: true });
+        }
+        
+        return true;
+    }
+
+    // ============================================================================
+    // UI 與工具抽象 (Stubbing)
+    // ============================================================================
+    private DataLoading(loading: boolean, useTimer: boolean) {
+        if (loading) {
+            console.log(`Loading... ${this.ShowText}`);
+        } else {
+            console.log('Loading complete.');
+        }
+    }
+
+    private CreateIn_WH(CaseID: string) {
+        // 模擬產生 In_Wh.dat
+    }
+    
+    private Case2upload(CaseID: string) {
+        // 模擬搬移/複製檔案結構準備上傳
+    }
+    
+    private CaseAsk(CaseID: string): number {
+        // 模擬詢問 Server 案件是否允許上傳
+        return 0; // 0: OK
+    }
+    
+    private GetCaseFormID(path: string): string {
+        return '11A000000000000'; // Mock FormID
+    }
+    
+    private CreateFormID_FormName(path: string, CaseID: string) {}
+    private CreateDocNo_DocName(path: string, CaseID: string) {}
+    
+    private _Msg(msg: string): string {
+        return msg; // 模擬多國語系轉換
+    }
+    
+    private Add_Zoo(num: number, length: number): string {
+        let str = num.toString();
+        while (str.length < length) str = '0' + str;
+        return str;
+    }
+}
\ No newline at end of file
diff --git a/CB_IMGPSScan_TLB.ts b/CB_IMGPSScan_TLB.ts
new file mode 100755
index 0000000..01dc53a
--- /dev/null
+++ b/CB_IMGPSScan_TLB.ts
@@ -0,0 +1,123 @@
+// ************************************************************************ //
+// WARNING
+// -------
+// The types declared in this file were converted from a Pascal Type Library.
+// ************************************************************************ //
+
+export const CB_IMGPSScanMajorVersion = 1;
+export const CB_IMGPSScanMinorVersion = 0;
+
+export const LIBID_CB_IMGPSScan = '{F7D1C429-BE85-4FAD-A058-36A41C2AAA89}';
+
+export const IID_ICB_IMGPSScanX = '{E68A01E9-2798-497F-9FB8-4EAFB7CCE5B9}';
+export const DIID_ICB_IMGPSScanXEvents = '{B7FB8B05-8BDA-4DFD-BCCF-2B657E8A108A}';
+export const CLASS_CB_IMGPSScanX = '{8B54EA2A-547C-48AD-BC71-C11C1340B37E}';
+
+export enum TxActiveFormBorderStyle {
+  afbNone = 0x00000000,
+  afbSingle = 0x00000001,
+  afbSunken = 0x00000002,
+  afbRaised = 0x00000003,
+}
+
+export enum TxPrintScale {
+  poNone = 0x00000000,
+  poProportional = 0x00000001,
+  poPrintToFit = 0x00000002,
+}
+
+export enum TxMouseButton {
+  mbLeft = 0x00000000,
+  mbRight = 0x00000001,
+  mbMiddle = 0x00000002,
+}
+
+export enum TxPopupMode {
+  pmNone = 0x00000000,
+  pmAuto = 0x00000001,
+  pmExplicit = 0x00000002,
+}
+
+// OLE_COLOR can be represented as a number
+export type OLE_COLOR = number;
+// IFontDisp can be represented as any for simplicity in Node.js
+export type IFontDisp = any;
+
+export interface ICB_IMGPSScanX {
+  Visible: boolean;
+  AutoScroll: boolean;
+  AutoSize: boolean;
+  AxBorderStyle: TxActiveFormBorderStyle;
+  Caption: string;
+  Color: OLE_COLOR;
+  Font: IFontDisp;
+  KeyPreview: boolean;
+  PixelsPerInch: number;
+  PrintScale: TxPrintScale;
+  Scaled: boolean;
+  readonly Active: boolean;
+  DropTarget: boolean;
+  HelpFile: string;
+  PopupMode: TxPopupMode;
+  ScreenSnap: boolean;
+  SnapBuffer: number;
+  DockSite: boolean;
+  DoubleBuffered: boolean;
+  readonly AlignDisabled: boolean;
+  readonly MouseInClient: boolean;
+  readonly VisibleDockClientCount: number;
+  ParentDoubleBuffered: boolean;
+  UseDockManager: boolean;
+  Enabled: boolean;
+  readonly ExplicitLeft: number;
+  readonly ExplicitTop: number;
+  readonly ExplicitWidth: number;
+  readonly ExplicitHeight: number;
+  AlignWithMargins: boolean;
+  ParentCustomHint: boolean;
+  url: string;
+  caseid: string;
+  mode: string;
+  work_no: string;
+  userid: string;
+  username: string;
+  userunit: string;
+  data: string;
+  verify: string;
+  rewrite: string;
+  modename: string;
+  language: string;
+  loandoc_value: string;
+  loandoc_enable: string;
+  useproxy: string;
+  c_docnolist: string;
+  c_docnamelist: string;
+  fixfilelist: string;
+  is_in_wh: string;
+  oldcaseinfo: string;
+  printyn: string;
+  is_oldcase: string;
+  custdocyn: string;
+  scancolor: string;
+  imgdpi: string;
+  filesizelimit: string;
+  casenolength: string;
+  imgdelete: string;
+  isExternal: string;
+  check_main_form: string;
+  WH_CATEGORY: string;
+}
+
+export interface ICB_IMGPSScanXEvents {
+  OnActivate(): void;
+  OnClick(): void;
+  OnCreate(): void;
+  OnDblClick(): void;
+  OnDestroy(): void;
+  OnDeactivate(): void;
+  OnKeyPress(Key: number): void;
+  OnMouseEnter(): void;
+  OnMouseLeave(): void;
+  OnPaint(): void;
+  OnClosePage(): void;
+}
diff --git "a/doc/curtis/AI\345\217\257\350\203\275\350\256\200\344\270\215\345\210\260\347\232\204_TLB_\344\273\213\351\235\242.md" "b/doc/curtis/AI\345\217\257\350\203\275\350\256\200\344\270\215\345\210\260\347\232\204_TLB_\344\273\213\351\235\242.md"
new file mode 100644
index 0000000..569f6bb
--- /dev/null
+++ "b/doc/curtis/AI\345\217\257\350\203\275\350\256\200\344\270\215\345\210\260\347\232\204_TLB_\344\273\213\351\235\242.md"
@@ -0,0 +1,44 @@
+
+
+
+
+# IO 相關方法
+## Dir
+```Pascal
+function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
+function str2Dir(const path: string[]): void
+```
+
+
+## String ini 相關
+```Pascal
+TIniFile = class(TCustomIniFile)
+  public
+    destructor Destroy; override;
+    function ReadString(const Section, Ident, Default: string): string; override;
+    procedure WriteString(const Section, Ident, Value: String); override;
+    procedure ReadSection(const Section: string; Strings: TStrings); override;
+    procedure ReadSections(Strings: TStrings); override;
+    procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
+    procedure EraseSection(const Section: string); override;
+    procedure DeleteKey(const Section, Ident: String); override;
+    procedure UpdateFile; override;
+  end;
+```
+
+
+## String dat 相關 
+delphi 大量使用 字串.LoadFromFile, 字串.SaveToFile
+- LoadFromFile
+- SaveToFile
+```Pascal
+procedure LoadFromFile(const FileName: string); overload; virtual;
+procedure LoadFromFile(const FileName: string; Encoding: TEncoding); overload; virtual;
+procedure LoadFromStream(Stream: TStream); overload; virtual;
+procedure LoadFromStream(Stream: TStream; Encoding: TEncoding); overload; virtual;
+procedure Move(CurIndex, NewIndex: Integer); virtual;
+procedure SaveToFile(const FileName: string); overload; virtual;
+procedure SaveToFile(const FileName: string; Encoding: TEncoding); overload; virtual;
+procedure SaveToStream(Stream: TStream); overload; virtual;
+procedure SaveToStream(Stream: TStream; Encoding: TEncoding); overload; virtual;
+```
diff --git a/doc/curtis/Business_Logic_Analysis.md b/doc/curtis/Business_Logic_Analysis.md
new file mode 100644
index 0000000..aa486eb
--- /dev/null
+++ b/doc/curtis/Business_Logic_Analysis.md
@@ -0,0 +1,64 @@
+# 業務邏輯與資料解析模組 (Business Logic & Parser) 深度分析
+
+在 `CB_IMGPSScanImp.pas` 中,「業務邏輯與資料解析模組」扮演了將底層掃描影像與上層銀行/保險業務需求結合的橋樑。它將前端網頁傳入的原始設定資料,轉換為系統可理解的「案件 (Case)」、「文件 (Document)」與「表單 (Form)」結構,並執行極度複雜的業務規則檢核 (OMR 檢核)。
+
+若要將此模組進一步細拆,其內部組成可分為以下四大子分類:
+
+---
+
+## 1. 系統參數與組態儲存庫 (Config & Parameter Repository)
+
+**職責**:負責解析由 Web 端透過字串傳入的各類系統設定表(通常以 `!@!` 等特殊符號分隔),並將其儲存於記憶體中供全局查詢。
+**核心實作特性**:
+*   **字串表解析**:大量使用 `TStringList` 作為輕量級的記憶體資料庫 (`SetSQLData`, `GetSQLData`, `FindSQLData`)。
+*   **系統設定下載與維護** (`GetSetInf1` ~ `GetSetInf7`):
+    *   `DOC_INF`:文件設定檔(定義文件類型、是否需入庫等)。
+    *   `FORM_INF`:表單設定檔(定義條碼對應、長寬、十字定位點、最大頁數)。
+    *   `DM_FORM_INF`:相依與互斥規則檔。
+    *   `CHECK_RULE_INF`:檢核規則錯誤訊息定義檔。
+    *   `WORK_INF`:系統與硬體掃描的預設參數。
+
+## 2. 領域實體對映與結構管理器 (Entity Mapping & Structure Manager)
+
+**職責**:將抽象的條碼 (Barcode) 對映至具體的業務實體,並在檔案系統上維護「案件 -> 文件分份 -> 頁面」的實體目錄與虛擬樹狀結構 (`.dat` 索引檔)。
+**核心實作特性**:
+*   **條碼解析對映**:`BarCode2FormID`、`BarCode2CaseID`、`FormCode2DocNo`、`DocNo2DocName`。
+*   **虛擬檔案系統維護**:
+    *   處理文件是否需要拆分多份 (`DocNoNeedDiv`)。
+    *   管理 `Context.dat`、`CaseDocNo.dat`、`CaseDocNo_Copies.dat` 等索引檔,以記錄掃描影像與業務文件的歸屬關係。
+*   **封裝資訊產生器**:`CreateDocNo_Info`、`CreateCustDocNo_Info` (將目錄結構轉換回 Web 端所需的特定字串格式)。
+
+## 3. OMR 與業務規則檢核引擎 (OMR & Business Rule Engine)
+
+**職責**:整個系統最龐大且複雜的業務邏輯核心,負責確保掃描進來的影像完全符合進件規定,防止缺件或矛盾。
+**核心實作特性** (`OMRCheckCase`):
+*   **文件級別檢核 (Document-Level Rules)**:
+    *   **主文件檢核**:檢查主要文件是否齊全、頁數是否符合資料庫預期。
+    *   **相依/互斥檢核**:依據 `DM_FORM_INF`,判斷若存在 A 文件,是否遺漏了必附的 B 文件,或錯誤附上了互斥的 C 文件。
+    *   **生命週期檢核**:判斷表單條碼是否已超過停用日期、或超過允許的最大掃描頁數。
+*   **OMR 畫記與欄位級別檢核 (Field-Level OMR Rules)** (透過 `Xmltool` 解析 `.xml` 設定檔,並計算指定 `(X, Y)` 座標的黑白像素點 `GetSiteOMR`):
+    *   `settype1` (必填檢核):特定的 OMR 區塊必須有畫記。
+    *   `settype3` (有值連動必填):A 欄位有畫記時,相關的 B 欄位也必須畫記。
+    *   `settype8` (有值連動互斥):A 欄位有畫記時,相關的 B 欄位不能畫記。
+    *   `settype4` (有值相依文件):特定欄位有畫記時,系統必須檢查是否已附上指定的文件。
+    *   `settype5` (有值互斥文件):特定欄位有畫記時,系統必須檢查不能附上指定的文件。
+    *   `settype6` (強制備註):特定欄位有畫記時,要求使用者必須手動輸入備註說明。
+    *   `settype7` (OMR 帶值提取):讀取畫記並轉換為特定的業務數值 (`GetValue.xml`),隨後傳回後端。
+
+## 4. 案件異動與舊案引用處理器 (Case Modification & Legacy Handler)
+
+**職責**:處理「補件 (ESCAN)」、「重掃 (RSCAN)」、「引用舊件」等極度複雜的邊界狀態與跨案件資料流動。
+**核心實作特性**:
+*   **文件引用管理**:`SetUseCase`、`GetUseCase` 記錄與追蹤不同案件之間文件的借用與引用關係 (記錄於 `UseCase.ini`)。
+*   **版本相容與轉換**:`OldCasetoNewCase`、`ErrFormtoCurrentForm` (處理舊系統升級或表單版本更迭時的自動替換邏輯)。
+*   **防呆與鎖定**:`DeleteDocNoFileForESCAN` 等邏輯,防止在補件模式下誤刪非當次掃描的既有影像。
+
+---
+
+## 💡 未來重構與微服務化建議
+
+若要將此「業務邏輯模組」進行現代化重構,強烈建議引入以下設計模式:
+
+1.  **Repository Pattern (儲存庫模式)**:將目前散落的 `FindSQLData` 與 `TStringList` 查詢,封裝為 `FormConfigRepository`、`DocConfigRepository` 等強型別介面,隔離底層字串處理細節。
+2.  **Rule Engine (規則引擎)**:將 `OMRCheckCase` 內部數百行的 `if/else` 與 XML 巡覽,拆分為獨立的實體類別(例如 `RequiredFieldRule`, `DependencyDocumentRule`, `MutexFieldRule`),並透過統一的 `Validator` 介面依序執行,大幅提升可測試性 (Testability) 與維護性。
+3.  **Domain Driven Design (領域驅動設計)**:將依賴實體 `.dat` 檔案的狀態管理,重構成記憶體中的 `TCase`, `TDocument`, `TPage` 領域物件,只有在最終儲存或打包時才寫入實體檔案系統。
diff --git "a/doc/curtis/Delphi_\345\245\227\344\273\266_EnScan_webAssembly_\345\217\257\350\241\214\346\200\247.md" "b/doc/curtis/Delphi_\345\245\227\344\273\266_EnScan_webAssembly_\345\217\257\350\241\214\346\200\247.md"
new file mode 100644
index 0000000..493a532
--- /dev/null
+++ "b/doc/curtis/Delphi_\345\245\227\344\273\266_EnScan_webAssembly_\345\217\257\350\241\214\346\200\247.md"
@@ -0,0 +1,77 @@
+
+
+# EnScan 的功能打包成 webAssembly 處理 Scan 是否可行
+
+
+這是一個非常深入的技術架構問題。簡短的回答是:**「直接打包」不可行,但「功能移轉」與「資料對接」是可行的,只是架構需要完全翻轉。**
+
+我們必須從 WebAssembly (Wasm) 的底層本質,來分析為什麼 `EnScan` 與 `DibHandle` 無法直接放入 Wasm:
+
+---
+
+### 1. 為什麼無法將 EnScan 打包成 WebAssembly 進行「掃描」?
+
+**核心障礙:硬體存取與沙盒 (Sandbox) 限制**
+
+* **Wasm 的隔離性:** WebAssembly 運行在瀏覽器的安全沙盒中。它**完全無法**存取你電腦的硬體(如 USB 接口、掃描機)。它甚至看不到你的 C 槽或 Windows 登錄表。
+* **TWAIN 協定限制:** `EnScan` 的核心是封裝 Windows 的 **TWAIN API**。TWAIN 是一個極度依賴作業系統訊息(Window Messages)與本地驅動程式(`.ds` 檔案)的協定。Wasm 無法呼叫 Windows API,也無法載入掃描機的 `.dll` 驅動程式。
+* **VCL 與 WinAPI 依賴:** `EnScan` 是一個 VCL 元件,深層綁定了 Windows 的 GDI(圖形設備介面)。Wasm 並沒有 Windows GDI,它只有一塊線性記憶體(Linear Memory)和 Canvas API。
+
+---
+
+### 2. Wasm 能處理 `DibHandle` 或 `TMemoryStream` 嗎?
+
+這涉及到兩者記憶體模型的完全不相容:
+
+#### **關於 DibHandle (Windows HGLOBAL)**
+* **不可行:** `DibHandle` 本質上是一個 Windows 作業系統核心管理的**記憶體地址代號**。
+* **原因:** Wasm 的記憶體是「封閉的線性陣列」。它無法透過一個 Windows 句柄(Handle)去讀取 Windows 系統層級的記憶體。如果你把 `DibHandle` 傳給 Wasm,Wasm 只會把它看作一個無意義的整數。
+
+#### **關於 TMemoryStream**
+* **有條件可行:** 如果你使用如 **TMS WEB Core** 這類支援 Delphi 語法轉 Wasm 的工具,它們有實作虛擬的 `TMemoryStream`。
+* **本質差異:** * **Delphi Win32 的 `TMemoryStream`**:操作的是實體 RAM。
+    * **Wasm 的 `TMemoryStream`**:操作的是瀏覽器分配給 Wasm 實例的一塊 **`ArrayBuffer`**。
+    * **兩者不通:** 你無法直接將 Win32 的記憶體指針直接「丟進」Wasm 的記憶體空間。
+
+---
+
+### 3. 可行的「現代化」架構建議:混合模式 (Hybrid)
+
+如果你想用 Wasm 處理掃描後的影像,正確的架構應該是:
+
+
+
+#### **第一步:本地端代理 (Local Agent/Service)**
+你仍需要一個小的 Delphi Win32 程式(或 Service)跑在使用者電腦上:
+1.  呼叫 `EnScan` 進行掃描。
+2.  在 `OnAcquire` 中拿到 `DibHandle`。
+3.  **關鍵轉化**:在本地端將 `DibHandle` 轉成標準的影像格式(如 **Base64 String** 或 **Uint8Array 二進位流**)。
+
+#### **第二步:通訊橋樑**
+本地程式透過 **WebSocket** 或 **Local HTTP Server (REST)** 將這串二進位資料傳送給瀏覽器。
+
+#### **第三步:Wasm 接收與處理**
+1.  瀏覽器收到二進位流。
+2.  將資料寫入 Wasm 的記憶體(`ArrayBuffer`)。
+3.  **這時 Wasm 就可以發揮威力了**:你可以用 Wasm 來做影像分析、條碼辨識、或是用 C++/Rust 編譯出來的高效能演算法進行影像優化。
+
+---
+
+### 4. 總結對照表
+
+| 功能特性 | 原有的 Delphi OCX | 現代 WebAssembly 方案 |
+| :--- | :--- | :--- |
+| **硬體控制 (TWAIN)** | 直接呼叫 (OK) | **無法存取** (需透過本地 Service 轉發) |
+| **記憶體管理** | 使用 Windows Handle (`DibHandle`) | 使用 Wasm 線性記憶體 (`ArrayBuffer`) |
+| **影像處理速度** | 極快 (Native) | 極快 (Wasm 近乎 Native) |
+| **跨瀏覽器支援** | 僅限 IE / Edge IE Mode | **全瀏覽器支援** (Chrome, Safari, Edge) |
+| **安全風險** | 高 (ActiveX 有權限漏洞) | 極高 (沙盒保護) |
+
+### **我的建議:**
+不要嘗試把 `EnScan` 直接「編譯」成 Wasm,那會導致數千個 WinAPI 連結錯誤。
+
+你應該將 **`CB_IMGPSScanImp.pas`** 拆分成兩部分:
+1.  **Backend (Win32)**: 只負責掃描與存成檔案/串流。
+2.  **Frontend (Wasm/Web)**: 負責顯示 `ImageScrollBox` 的功能、UI 邏輯與上傳伺服器。
+
+**你想了解如何寫一個簡單的 Local Service,讓 Delphi 掃描後把資料傳給網頁嗎?** 這通常是目前銀行系統現代化(去 IE 化)最普遍的作法。
diff --git "a/doc/curtis/Delphi_\345\245\227\344\273\266\347\233\270\344\276\235.md" "b/doc/curtis/Delphi_\345\245\227\344\273\266\347\233\270\344\276\235.md"
new file mode 100644
index 0000000..d343a80
--- /dev/null
+++ "b/doc/curtis/Delphi_\345\245\227\344\273\266\347\233\270\344\276\235.md"
@@ -0,0 +1,115 @@
+# **相依套件分析報告**
+
+本報告針對 ActiveX 元件核心實作檔 CB_IMGPSScanImp.pas 進行功能解構,並分析其與第三方套件的綁定關係,以作為後續維護或現代化升級之參考。
+
+## **壹、 依功能拆分模組與第三方套件綁定分析**
+
+根據原始碼結構,CB_IMGPSScanImp.pas 是一個將介面、硬體、網路與業務邏輯高度耦合的「上帝物件 (God Object)」。若要進行重構或拆件,建議依據以下五個核心模組進行解耦:
+
+### **1. 硬體掃描控制模組 (Scanner Controller)**
+
+- **功能描述**:負責與實體掃描機溝通,處理 TWAIN 介面初始化、設定掃描參數(DPI、色彩、雙面)、觸發掃描指令,以及接收掃描完成的記憶體影像 (DibHandle)。
+- **子模組細分建議**:
+  - **TWAIN 介面封裝 (TWAIN Wrapper)**:專門負責底層 TWAIN 驅動程式的呼叫、狀態機管理與錯誤處理。
+  - **掃描參數管理器 (Scanner Profile Manager)**:負責載入、儲存與套用各類掃描設定 (DPI、對比、亮度、單雙面等)。
+  - **事件與回呼接收器 (Acquisition Event Handler)**:專責處理非同步的 `OnAcquire` 事件,負責將底層 `DibHandle` 安全地轉換為應用程式可用的影像物件,並通知上層模組。
+- **關鍵方法**:initkscan、StatrTwainScan、OnAcquire、PageEnd、PageDone。
+- **第三方套件綁定 (強綁定)**:
+  - 依賴 **Envision Imaging SDK** (EnScan) 進行 TWAIN 驅動控制。
+  - 依賴 EnMisc 處理底層記憶體或雜項運算。
+
+### **2. 影像處理與轉換模組 (Image Processor)**
+
+- **功能描述**:負責對擷取到的原始影像進行後製處理,包括:裁切(如 A3 裁 A4)、去斜 (Deskew)、旋轉、二值化 (轉黑白)、格式轉換 (轉 TIFF/JPEG),以及讀取影像上的條碼。
+- **子模組細分建議**:
+  - **影像幾何變換引擎 (Image Transformation Engine)**:專責處理去斜 (Deskew)、旋轉、縮放與裁切等座標/空間運算。
+  - **色彩與格式處理器 (Color & Format Converter)**:負責二值化、灰階/彩色轉換,以及 TIFF/JPEG 等不同檔案格式的壓縮與編解碼。
+  - **條碼與標記識別器 (Barcode & Marker Recognizer)**:獨立負責分析影像中的條碼內容,或進行 OMR (光學標記辨識) 的初步像素比對。
+  - **OMR 與十字定位點分析器 (OMR & Anchor Analyzer)**:專門為「光學標記辨識 (OMR)」服務,負責找出影像上的基準定位點,並計算特定區域內的黑白像素分佈。
+- **關鍵方法**:ImageReSize_FormID、CheckNeedCrop、DeskewImg、ConvertToBW。
+- **第三方套件綁定 (強綁定)**:
+  - 依賴 **Envision Imaging SDK** (EnTifGr, EnDiGrph) 進行 TIFF (CCITT Group 4) 壓縮與 DIB 物件封裝。
+  - 依賴 **MPS Barcode** (mpsBarco, BarcodesFinder) 進行影像條碼掃描與解析。
+
+### **3. 安全傳輸與 API 通訊模組 (Transport Manager)**
+
+- **功能描述**:負責將掃描並壓縮後的檔案上傳至伺服器,或從伺服器下載檔案。同時處理與後端 Java Servlet 的參數交換(如校時、取得 FTP 資訊、更新案件狀態)。
+- **子模組細分建議**:
+  - **HTTP/HTTPS API 請求管理器 (RESTful / Servlet Client Wrapper)**: 專責透過 HTTP(S) 協定,向後端的 Java Servlet 端點發送 GET/POST 請求。
+  - **雙協定檔案上傳/下載引擎 (Dual-Protocol File Transfer Engine)**: 處理實體影像檔案的實體傳輸,並根據系統設定動態切換 HTTP 或 FTP 協定。
+  - **安全加密與雜湊模組 (Security, Crypto & Hashing Utils)**: 負責資料傳輸前後的加解密運算,以及檔案完整性的 MD5 校驗,確保通訊過程不被竄改。
+  - **傳輸前置準備與封裝器 (Payload Archiver & Preparer)**: 在真正啟動傳輸前,將硬碟上散落的 TIFF/JPG 檔案、`.dat` 索引檔打包成單一的 ZIP 封裝檔。
+- **關鍵方法**:upFile、dnFile_Get、ProcessServlet_Get、GetServerDate、GetftpInfo。
+- **第三方套件綁定 (強綁定)**:
+  - 依賴 **SecureBlackbox** (SBSimpleSSL, SBHTTPSClient, SBSimpleFTPS 等) 處理 HTTPS/FTPS 安全加密通訊。
+  - 依賴 **Indy** (IdHashMessageDigest) 產生檔案的 MD5 檢核碼。
+  - 依賴自訂/第三方加密庫 (Encryp) 處理字串加解密。
+
+### **4. 業務邏輯與資料解析模組 (Business Logic & Parser)**
+
+- **功能描述**:專案核心的領域邏輯,包含接收網頁端傳入的參數字串進行解析、定義文件歸類邏輯(由條碼推導文件類型)、OMR (光學標記辨識) 檢核定義等。
+- **子模組細分建議**:
+  - **系統參數與組態儲存庫 (Config & Parameter Repository)**:負責解析由 Web 端透過字串傳入的各類系統設定表(如 DOC_INF、FORM_INF 等),並將其儲存於記憶體中供全局查詢。
+  - **領域實體對映與結構管理器 (Entity Mapping & Structure Manager)**:將抽象的條碼對映至具體的業務實體,並在檔案系統上維護「案件 -> 文件分份 -> 頁面」的虛擬樹狀結構。
+  - **OMR 與業務規則檢核引擎 (OMR & Business Rule Engine)**:處理最核心的檢核邏輯,包含主文件/相依互斥文件檢核、欄位級別的 OMR 畫記檢核,以及基於 XML 設定的各種業務規則。
+  - **案件異動與舊案引用處理器 (Case Modification & Legacy Handler)**:專責處理「補件」、「重掃」、「引用舊件」等複雜的邊界狀態與跨案件資料流動。
+- **關鍵方法**:SetSQLData、GetSQLData、FormCode2DocNo、OMRCheckCase。
+- **第三方套件綁定 (中度綁定)**:
+  - 依賴 **Xmltool** 解析 XML 格式的 OMR 座標定義。
+  - 依賴 **VCLZip** (VCLZip, VCLUnZip) 將多個影像檔打包成 ZIP 進行單一傳輸。
+
+### **5. UI 與介面呈現模組 (UI View)**
+
+- **功能描述**:負責 ActiveX 控制項的視覺化介面,包含左側的樹狀文件清單 (TreeView)、右側的影像預覽區 (ScrollBox),以及按鈕與多國語言切換。
+- **子模組細分建議**:
+  - **案件樹狀檢視元件 (TreeView UI)**: 獨立管理左側的案件與文件節點,負責節點的建立、刪除與圖示切換。
+  - **多影像滾動視窗 (ScrollBox View)**: 管理右側大圖及縮圖的並排顯示,支援拖拉、選取以及快捷鍵操作。
+  - **多國語系引擎 (I18N Manager)**: 統一從設定檔中載入字串,替換畫面上所有的 Label、Button 與 Message 提示。
+  - **核心版面與容器管理 (Layout & Container Management)**: 定義整個 ActiveX 控制項的視覺區塊,並透過階層式的 Panel 進行排版管理。
+  - **系統狀態與進度回饋 (Status & Progress Feedback)**: 在進行耗時的任務時,鎖定 UI 並給予使用者明確的等待提示。
+- **關鍵方法**:InitialLanguage、各類 OnClick 事件。
+- **第三方套件綁定 (輕度綁定)**:
+  - 依賴 **Envision Imaging** (EnImgScr) 作為支援大影像拖曳的滾動視窗。
+  - 依賴 PJMenuSpeedButtons 作為自訂外觀的按鈕元件。
+
+## **貳、 第三方套件功能總覽**
+
+為達成上述複雜的業務需求,本專案引入了多個 Delphi 著名的第三方套件。以下為各套件的大致功能說明:
+
+### **1. Envision Imaging SDK (前綴 En)**
+
+這是一套專為 Delphi 設計的高效能影像與 TWAIN 處理套件,在金融與保險業的文件電子化系統中非常常見。
+
+- **EnScan**:封裝了 TWAIN 協定,讓程式能直接控制實體掃描機,控制進紙、解析度與雙面掃描。
+- **EnDiGrph (TDibGraphic)**:封裝 Windows 底層的 DIB (Device Independent Bitmap) 記憶體句柄,讓開發者能像操作一般圖片一樣操作掃描出來的原始資料。
+- **EnTifGr**:專門處理 TIFF 影像格式。銀行業愛用 TIFF 是因為它支援「多頁」且黑白壓縮率極高 (Group 4 Fax Compression)。
+- **EnImgScr**:提供 TImageScrollBox 視覺元件,用來平滑顯示並縮放超大尺寸的掃描圖檔。
+- **EnMisc**:提供影像處理所需的底層輔助數學或資料轉換函式。
+
+### **2. SecureBlackbox (前綴 SB)**
+
+由 EldoS (後被 /n software 收購) 開發的強大安全通訊與加密套件。由於早期 Delphi (D7~D2007) 內建網路庫缺乏完善的 SSL/TLS 支援,此套件被廣泛用於補強安全性。
+
+- **SBHTTPSClient / SBSimpleSSL**:實作了完整的 HTTPS 用戶端通訊協定,用來安全地上傳檔案或呼叫 Servlet API。
+- **SBSimpleFTPS**:支援 FTP over SSL (FTPS) 的安全檔案傳輸。
+- **SBWinCertStorage / SBX509**:處理 Windows 系統內的憑證儲存區,以及 X.509 數位憑證的驗證(例如確認銀行伺服器的 HTTPS 憑證是否合法)。
+
+### **3. MPS Barcode & BarcodesFinder**
+
+- **功能**:這是一套條碼識別引擎。
+- **專案應用**:在掃描過程中(如 PageDone 或 OnAcquire 階段),它會掃描圖片特定區域尋找一維或二維條碼。讀取到的條碼值會被用來決定這張影像屬於哪一種「文件表單」(FormCode),進而實現自動分類歸檔。
+
+### **4. VCLZip (VCLZip, VCLUnZip)**
+
+- **功能**:老牌的 Delphi ZIP 壓縮元件。
+- **專案應用**:為了節省網路頻寬與減少伺服器連線次數,掃描完成的多張 TIFF/JPG 檔案會被打包成一個 .zip 檔後,再一次性上傳至伺服器。
+
+### **5. Indy Components (前綴 Id)**
+
+- **IdHashMessageDigest / idHash**:Delphi 內建的 Internet Direct (Indy) 函式庫。
+- **專案應用**:在此專案中被用來計算檔案或字串的 **MD5 Hash (雜湊值)**。通常用於確保檔案上傳過程沒有損壞,伺服器比對 MD5 一致才算上傳成功。
+
+### **6. 其他工具 (Tools & Utils)**
+
+- **Xmltool**:負責讀寫 XML 檔案。銀行經常將表單的 OMR (光學標記辨識) 檢核座標或參數寫成 XML 設定檔,透過此工具讀入系統。
+- **Encryp**:這可能是開發商自訂或第三方的輕量級加密單元,用來加密本機設定檔 (.ini) 內的敏感資訊或混淆網頁傳入的參數。
diff --git a/doc/curtis/Image_Processer_Analysis.md b/doc/curtis/Image_Processer_Analysis.md
new file mode 100644
index 0000000..41e6b3a
--- /dev/null
+++ b/doc/curtis/Image_Processer_Analysis.md
@@ -0,0 +1,69 @@
+# 影像處理與轉換模組 (Image Processor) 深度分析
+
+在 `CB_IMGPSScanImp.pas` 中,「影像處理與轉換模組」負責在硬體掃描取得原始影像後,以及上傳/顯示之前,對影像進行一系列的強化、分析與格式轉換。這個模組是決定影像品質、檔案大小與後續 OMR 辨識準確率的關鍵。
+
+若要將此模組進一步細拆,其內部組成可分為以下四大子分類:
+
+---
+
+## 1. 影像幾何與物理變換引擎 (Image Geometric Transformation Engine)
+
+**職責**:專責處理影像的空間座標轉換、旋轉、去斜以及裁切,確保最終儲存的影像端正且符合業務規定的尺寸。
+**核心實作特性**:
+*   **影像去斜與轉正**:
+    *   `DeskewImg`:透過演算法自動偵測影像傾斜角度並將其校正。
+    *   `Rotate`:依據條碼辨識出的角度 (`MpsBarcodeinf.r180`) 或使用者手動點擊按鈕 (`SpeedButton14Click` 等),進行 90、180、270 度的旋轉。
+*   **影像裁切與分割**:
+    *   `CheckNeedCrop`:根據影像寬高比與偵測到的條碼數量,判斷是否為需要分割的 A3 雙頁合併影像。
+    *   `CropImg`:給定 `TRect` 座標,將 A3 影像精準裁切為兩張 A4 (`iGraphic_First`, `iGraphic_sec`)。
+*   **影像縮放 (Resize)**:
+    *   `ImageReSize_FormID` / `ImageReSize_tmp`:依據表單定義檔 (`FORM_INF`) 中的長寬設定與尋找到的十字定位點,強制將影像縮放變形至標準尺寸,以利後續的 OMR 座標對位。
+    *   `DpiResize`:調整影像的 DPI 解析度參數。
+
+## 2. 色彩處理與編碼轉換器 (Color & Format Converter)
+
+**職責**:處理影像的色彩深度 (位元深度) 轉換,以及針對不同色彩模式套用最適合的檔案壓縮演算法,以達到最佳的畫質與檔案大小平衡。
+**核心實作特性**:
+*   **色彩空間轉換**:
+    *   `ConvertToBW`:將彩色或灰階影像強制二值化 (Binarization) 轉為黑白影像,這不僅能大幅縮小檔案,也是條碼與 OMR 辨識的必要前置步驟 (系統通常會保留一個隱藏的 `ISB_BW` 物件專做辨識用)。
+    *   `ConvertToGray`:將彩色轉換為灰階 (`ifGray256`)。
+    *   `Image_Smooth` / `NegativeImg` / `CleanupBorder`:影像平滑化、反相處理與清除黑邊。
+*   **格式與壓縮決策**:
+    *   針對黑白影像 (`ifBlackWhite`):使用 `tcGroup4` (CCITT Group 4 Fax Compression) 或 `tcPackBits` 壓縮,並儲存為 `.tif`。
+    *   針對彩色/灰階影像 (`ifTrueColor`, `ifGray256`, `ifColor256`):轉換為 `TJpegGraphic`,套用 `tcJpeg` 壓縮與指定的壓縮率 (`FJpgCompression` / `SaveQuality`),並儲存為 `.jpg`。
+
+## 3. 條碼識別與解析器 (Barcode Recognizer)
+
+**職責**:獨立負責掃描與解析影像上的一維或二維條碼,這是系統實現「文件自動歸類」的核心依賴。
+**核心實作特性**:
+*   **條碼引擎呼叫**:
+    *   `MpsGetBarcode`:呼叫底層的 MPS Barcode 引擎,傳入二值化的影像 (`ISB_BW.Graphic`)。
+    *   回傳 `TMpsBarcodeinf` 結構,包含條碼內容字串陣列 (`Text`) 與每個條碼的方向資訊 (`r180`)。
+*   **應用與邏輯綁定**:
+    *   透過條碼字串找出對應的 `FormID` 與 `DocNo`。
+    *   檢查條碼長度是否符合規範 (`FormIDLength`),過濾雜訊或誤判的條碼。
+
+## 4. OMR 與十字定位點分析器 (OMR & Anchor Analyzer)
+
+**職責**:專門為「光學標記辨識 (OMR)」服務,負責找出影像上的基準定位點,並計算特定區域內的黑白像素分佈。
+**核心實作特性**:
+*   **基準點尋找 (Anchor Finding)**:
+    *   `FindPoint`:根據 XML 定義的模式 (`ANCHOR` 或 `FRAME`),在影像四個角落尋找定位基準點 (`UpLPoint`, `UpRPoint`, `DownLPoint`, `DownRPoint`)。
+    *   `CheckSize`:比對找到的定位點距離與標準長寬是否有巨大落差,若找不到則記錄至 `AnchorError.dat`。
+*   **像素計算與標記判定 (Pixel Calculation)**:
+    *   `GetSiteOMR`:根據 XML 傳入的相對座標字串 (`Site`),將其換算為實際的 `TRect`。
+    *   `Get_OMR`:計算該區域內黑色像素的數量。
+    *   結合雜訊過濾 (`ClearLine`) 與容差值 (`SafePixel`, `bt`),最終判定該 OMR 欄位是否「有畫記」。
+
+---
+
+## 💡 未來重構與微服務化建議
+
+若要對此影像處理模組進行重構,建議方向如下:
+
+1.  **抽離為獨立的 Pipeline 模式 (管線模式)**:
+    目前這些功能散落在 `OnAcquire` 與各個事件中。應將其重構為一條清晰的影像處理管線:`Image -> Deskew -> Crop -> ConvertBW -> BarcodeRead -> Resize -> Compress -> Save`。每個步驟 (Step) 應該是獨立的類別,方便抽換或開關。
+2.  **解耦 UI 與影像處理**:
+    目前大量依賴畫面上隱藏的 `ISB_BW` (TImageScrollBox) 來進行二值化和條碼辨識。這違反了 MVC 原則且耗費額外的 GDI 資源。應改用純記憶體物件 (如獨立的 `TDibGraphic` 或 `TBitmap`) 在背景執行緒中進行這些運算,不要綁定可見的 UI 元件。
+3.  **引入更現代的影像引擎 (如 OpenCV)**:
+    早期依賴的 Envision SDK 在尋找十字定位點 (FindPoint) 和去斜 (DeskewImg) 的演算法可能較為老舊。若未來轉型為微服務架構,可將這部分邏輯移植為 Python/C++ 並使用 OpenCV 來達成更精準的高速運算。
diff --git "a/doc/curtis/Local_IO_\346\212\275\345\203\217\346\226\271\346\263\225\345\210\227\350\241\250.md" "b/doc/curtis/Local_IO_\346\212\275\345\203\217\346\226\271\346\263\225\345\210\227\350\241\250.md"
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ "b/doc/curtis/Local_IO_\346\212\275\345\203\217\346\226\271\346\263\225\345\210\227\350\241\250.md"
diff --git "a/doc/curtis/Local_IO_\350\267\257\345\276\221\350\210\207\346\252\224\346\241\210\346\223\215\344\275\234\345\210\206\346\236\220.md" "b/doc/curtis/Local_IO_\350\267\257\345\276\221\350\210\207\346\252\224\346\241\210\346\223\215\344\275\234\345\210\206\346\236\220.md"
new file mode 100644
index 0000000..51ca802
--- /dev/null
+++ "b/doc/curtis/Local_IO_\350\267\257\345\276\221\350\210\207\346\252\224\346\241\210\346\223\215\344\275\234\345\210\206\346\236\220.md"
@@ -0,0 +1,233 @@
+# **IO 路徑與檔案操作分析**
+
+本報告詳列了 CB_IMGPSScanImp.pas 檔案中定義的所有 IO 相關變數,以及執行目錄與檔案管理的關鍵方法,並定義了抽像化所需的介面原型。
+
+## **壹、 關鍵路徑與檔案變數 (Variables)**
+
+程式中定義了多個全域或私有欄位,用來追蹤檔案在硬碟上的實體位置。
+
+### **1. 核心路徑變數與動態組合邏輯**
+
+| **變數名稱** | **類型** | **組合邏輯 (Combination Logic)** | **用途說明** |
+| --- | --- | --- | --- |
+| **ImagePath** | String | WORK_INF 的 LOCAL_PATH 參數值 | **本機基礎根路徑**。所有暫存資料的起點。 |
+| **ScaniniPath** | String | ImagePath + FWork_No + '\' + FUserUnit + '\' | **設定檔存放區**。區分作業別與單位。 |
+| **ImageSavePath** | String | 同 ImagePath (初期) 或隨 FMode 變動 | **影像儲存基準路徑**。 |
+| **ScanPath** | String | ImageSavePath + ScanCaseno + '\' + ScanDocdir + '\' | **當前掃描實體目錄**。指向最末層的影像資料夾。 |
+| **TransPath** | String | ImageSavePath + CaseID + '\Upload\' | **準備上傳區**。在傳送前將檔案結構扁平化組合於此。 |
+| **DisplayPath** | String | ImageSavePath + NowCaseNo + '\' | **預覽基準目錄**。用於 UI 點選樹狀圖時讀取特定案件資料。 |
+| **LngPath** | String | GetLocalAppDir(Handle) + 'MPS\CB_IMGPS\' | **應用程式資源路徑**。存放在使用者設定檔目錄以避開權限問題。 |
+| **CheckXmlPath** | String | ImagePath + 'OMRSITE\' | **OMR 規則暫存區**。存放從伺服器同步下來的 XML 定義。 |
+| **SamplePath** | String | ImagePath + 'Sample\' + FWork_No + '\' | **範本影像存放區**。按作業別區分。 |
+| **SitePath** | String | ImagePath + 'Site\' | **登打定位存放區**。 |
+| **FFtpRootPath** | String | 透過伺服器回傳值動態設定 | **FTP 伺服器根路徑**。指定在遠端 FTP 伺育器上存放影像檔的起始位址。 |
+
+### **2. 檔案名稱變數 (Filenames)**
+
+| **變數名稱** | **類型** | **用途說明** |
+| --- | --- | --- |
+| **ScanSaveFilename** | String | 下一張掃描影像預定的檔名(通常包含 FormID)。 |
+| **PEFileName** | String | 在 PageEnd 階段確定的最終完整檔案路徑。 |
+| **AttName** | String | **附件目錄名稱**。根據 FIs_In_Wh 決定為 Attach 或 S_Attach。 |
+| **Ext** | String | 副檔名。預設為 .tif,彩色/灰階模式下可能切換為 .jpg。 |
+
+## **貳、 關鍵 IO 操作方法 (Methods)**
+
+以下為需要進行抽像化設計的核心 IO 方法。
+
+### **1. 目錄管理 (Directory Management)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| _DelTree | 遞迴刪除整個目錄樹 | 上傳成功後清空暫存、模式切換初始化目錄 | RemoveDirRecursive(Path) |
+| Str2Dir / ForceDirectories | 確保路徑以 \ 結尾並建立路徑 | 初始化或掃描前建立資料夾 | EnsureDirExists(Path) |
+| GetNoNameCase | 搜尋尚未配號的臨時目錄 | 在本機搜尋如 未配號0001 到 9999 的可用路徑 | FindNextAvailablePath(Pattern) |
+| GetLocalAppDir | 取得 Windows %LocalAppData% 路徑 | 確保在現代 Windows 系統中有權限寫入語言檔與 Log | GetBaseStoragePath() |
+
+### **2. 存在性檢查與搜尋 (Existence & Search)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| FileExists | 檢查指定路徑檔案是否存在 | 在載入 .dat、.ini 或影像前進行安全檢查 | IsFilePresent(Path) |
+| DirectoryExists | 檢查指定路徑資料夾是否存在 | 在建立掃描目錄或上傳前確認結構完整性 | IsDirPresent(Path) |
+| FindFirst / FindNext | 搜尋符合特定格式的檔案 | 取得實體檔案大小 (FileRec.Size) 或遞迴搜尋檔案 | ListFiles(Path, Pattern) / GetFileInfo(Path) |
+
+### **3. 檔案生命週期與刪除 (File Lifecycle & Deletion)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| ReSortFileName | 影像重新編序命名 | 刪除或插入影像後,修正 001_xxx 等序號連續性 | RenameFile(Old, New) |
+| DeleteImageFile | 刪除實體影像檔 | 單張影像刪除並觸發 .dat 內容同步更新 | DeleteFile(Path) |
+| DeleteDocNoFile | 刪除特定文件代號下所有影像 | 整批文件(DocNo)的物理刪除與序號重整 | DeleteFilesByPattern(Pattern) |
+| DeleteShowFile | 刪除 UI 顯示中的影像清單 | 根據介面選取狀態進行批次物理刪除 | DeleteFileList(List<Path>) |
+| RenameFile / MoveFile | 檔案搬移或更名 | 用於「分案」、「移動頁數」或「變更歸類」 | MoveFile(Src, Dest) |
+| CopyFile | 複製實體檔案 | 影像搬移至上傳區或引用舊案件影像 | CopyFile(Src, Dest) |
+
+### **4. 資料紀錄與序列化 (Metadata IO)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| DeleteCustomDocDir | 移除自訂文件定義 | 從 CustomDocNo.ini 中移除特定自訂文件的節點 | Storage.IniDeleteSection(Section) |
+
+### **5. 網路傳輸 IO 方法 (Network Retrieval - dnFile_Get)**
+
+專案中使用 `dnFile_Get` 從伺服器端同步必要的環境檔案或規則定義。
+
+| **抓取對象 (目標路徑)** | **遠端請求 Action** | **用途說明** |  |
+| --- | --- | --- | --- |
+| **CheckXmlPath + filename** | `GetCheckXml` | **下載 OMR 檢核定義檔**。同步伺服器端最新的 XML 座標規則,用於自動判斷影像區域。 | https |
+| **SamplePath + filename** | `GetSampleImg` | **下載範本影像**。用於在 UI 介面上提供給操作員對照的標準範例圖檔。 | https |
+| **SitePath + filename** | `GetSiteImg` | **下載定位定義圖**。下載與登打、校對位置相關的輔助影像。 | https |
+| **LngPath + 'Language.ini'** | `GetLanguage` | **同步多國語言檔**。確保用戶端介面文字(繁體、英文、越南語等)與伺服器同步。 | https |
+
+## **參、 資料紀錄與序列化 (Metadata IO)**
+
+專案中使用了大量的 .dat 與 .ini 檔案來記錄目錄內的結構資訊與使用者偏好。
+
+### **1. .dat 檔案 (結構紀錄)**
+
+| **檔案名稱** | **組合路徑邏輯 (Path Logic)** | **內容與用途** |
+| --- | --- | --- |
+| **Context.dat** | ImageSavePath + CaseID + '\' + DocDir + '\Context.dat' | **影像清單**。紀錄該資料夾內所有影像檔名的正確順序。 |
+| **DocDir.dat** | ImageSavePath + CaseID + '\Upload\DocDir.dat' | **目錄對應表**。紀錄 Upload 下每個檔名所屬的原始 DocDir |
+| **CaseDocNo.dat** | ImageSavePath + CaseID + '\CaseDocNo.dat' | **文件目錄索引**。紀錄案件內已建立的實體資料夾名稱。 |
+| **CaseDocNo_Copies.dat** | ImageSavePath + CaseID + '\CaseDocNo_Copies.dat' | **份數紀錄**。對應 CaseDocNo.dat 中的資料夾分別有多少份。 |
+| **CaseIndex.dat** | ImageSavePath + CaseID + '\CaseIndex.dat' | **案件屬性**。如是否為「授信卷」(Case_loandoc)。 |
+| **EditedDocDir.dat** | ImageSavePath + CaseID + '\EditedDocDir.dat' | **異動清單**。紀錄當次操作中被修改過的文件目錄。 |
+| **Scan_Memo.dat** | DisplayPath + 'Scan_Memo.dat' | **使用者註記**。紀錄操作員手動輸入的備註內容。 |
+| **CaseList.dat** | ImageSavePath + 'CaseList.dat' | **案件總表**。紀錄目前本機快取中存在的所有 CaseID。 |
+
+### **2. .ini 檔案 (設定與偏好)**
+
+| **檔案名稱** | **路徑邏輯** | **回寫 (Write-back)** | **內容與用途** | 寫入關聯 |
+| --- | --- | --- | --- | --- |
+| **Scan.ini** | ScaniniPath + 'Scan.ini' | **是 (頻繁)** | **掃描器硬體設定**。儲存最後一次選取的 DPI、雙面、色彩模式、亮度、對比等參數。 |  |
+| **CustomDocNo.ini** | ScaniniPath + 'CustomDocNo.ini' | **是 (中等)** | **自訂文件代號**。儲存操作員定義的文件分類名稱與內部 ID 映射。 | DeleteCustomDocDir |
+| **CB_IMGPSScan.ini** | LngPath + 'CB_IMGPSScan.ini' | **是 (低頻)** | **環境配置**。儲存伺服器 IP、Port、自動更新版本資訊等全域參數。 |  |
+| **Language.ini** | LngPath + 'Language.ini' | **否 (唯讀同步)** | **多國語言包**。僅透過 `dnFile_Get` 從伺服器抓取更新,OCX 不自行修改。 |  |
+
+## **肆、 串流與讀寫操作 (Stream & File I/O)**
+
+源碼中頻繁使用 .LoadFromFile 與 .SaveToFile 來實現資料的持久化。
+
+### **1. 使用 TStringList 讀寫 .dat 結構**
+
+| **操作對象** | **讀取場景 (Load)** | **寫入場景 (Save)** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| **結構清單 (.dat)** | LoadImgFile 載入以重建樹狀結構 | PageEnd 掃描完成或結構增刪後即時存檔 | ReadTextFile(Path) / WriteTextFile(Path, Content) |
+| **備註文件 (Memo)** | 進入備註編輯器時載入舊有內容 | WNoteBtnClick 完成編輯後儲存內容 | ReadTextFile(Path) / WriteTextFile(Path, Content) |
+| **上傳包定義** | N/A | CreateFormID_FormName 產生上傳包所需的定義檔 | WriteTextFile(Path, Content) |
+|  |  |  |  |
+|  |  |  |  |
+
+### **2. 使用 TImageScrollBox / TDibGraphic 讀寫影像**
+
+| **操作對象** | **讀取場景 (Load)** | **寫入場景 (Save)** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| **掃描影像原始檔** | view_image_... 載入顯示於預覽窗 | OnAcquire 將記憶體影像 (Dib) 持久化至磁碟 | ReadBinaryFile(Path) / WriteBinaryFile(Path, Blob) |
+| **影像處理覆蓋** | ImageReSize_FormID 讀取進行定位縮放 | 處理完成後覆蓋原始影像檔 | ReadBinaryFile(Path) / WriteBinaryFile(Path, Blob) |
+| **旋轉/後製處理** | 點擊旋轉按鈕後從磁碟重新讀取 | 旋轉完成後保存更新內容回實體檔案 | ReadBinaryFile(Path) / WriteBinaryFile(Path, Blob) |
+
+## **伍、 檔案路徑構造邏輯示例**
+
+程式中典型的路徑構造方式如下(以 PageEnd 為例):
+
+// 1. 基礎路徑
+
+ScanPath := ImageSavePath + ScanCaseno + '\';
+
+// 2. 進入特定文件目錄 (DocDir)
+
+ScanPath := ScanPath + ScanDocdir + '\';
+
+// 3. 確保實體目錄存在
+
+Str2Dir(ScanPath);
+
+// 4. 構造最終影像路徑
+
+PEFileName := ScanPath + Add_Zoo(PageCount, 3) + '_' + FormID + ext;
+
+## **陸、 IO 方法具體實作邏輯細部說明 (Detailed Implementation Logic)**
+
+本節針對 CB_IMGPSScanImp.pas 內部如何透過 Windows API 實作這些 IO 操作進行細部解說。
+
+### **1. Str2Dir(Path: string) 的運作機制**
+
+這個方法的主要作用是 **「路徑標準化與實體資料夾建立」**。
+
+- **字串處理**:它會先檢查傳入的 Path 字串最後一個字元是否為 \。如果不是,會自動補上。
+- **建立資料夾**:**是的,它會在內部建立資料夾**。它會呼叫 Delphi 的 ForceDirectories(Path) 函式。
+- **ForceDirectories 的特性**:與一般的 CreateDir 不同,ForceDirectories 會「遞迴」建立路徑中所有不存在的父目錄(例如若路徑為 C:\A\B\C,即使 A 和 B 都不存在,它也會一併建立)。
+
+### **2. _DelTree(DirName: string) 的遞迴邏輯**
+
+由於 Delphi 早期版本沒有提供單一函式來刪除包含檔案的資料夾,此方法透過 Windows 的搜尋機制實現:
+
+- **遍歷搜尋**:使用 FindFirst 和 FindNext 找出資料夾內的所有物件。
+- **檔案處理**:若搜尋到的是一般檔案,直接呼叫 DeleteFile。
+- **遞迴處理**:若搜尋到的是子資料夾,則「自己呼叫自己」 (_DelTree) 先清空該子資料夾。
+- **物理移除**:當資料夾內的所有內容都清空後,呼叫 RemoveDir 將空的資料夾從磁碟移除。
+
+### **3. FindFirst 與 FindNext 的搜尋與疊代邏輯**
+
+這兩個方法是 Delphi 處理「集合式 IO 操作」(如掃描目錄、批次刪除)的基礎,通常搭配 TSearchRec 結構使用。
+
+- **FindFirst(Path, Attr, SearchRec)**:
+- **動作**:啟動搜尋任務,將找到的第一個檔案資訊填入 SearchRec。
+- **應用例**:在 PM104Click (匯入影像) 時,程式會先執行 FindFirst(FName, faAnyfile, FileRec) 來確認使用者選取的實體檔案是否存在,並藉由 FileRec.Size 取得位元組大小,用以判斷是否超過系統設定的匯入限制(例如 5MB)。
+- **FindNext(SearchRec)**:
+- **動作**:繼續尋找下一個符合條件的檔案。
+- **疊代模式**:通常包裹在 repeat ... until FindNext(SR) <> 0 迴圈中。
+- **應用例**:在 _DelTree 實作中,程式利用此疊代邏輯將資料夾內「所有的」子目錄與檔案清空,直到 FindNext 回傳非零值(代表搜尋結束)。
+- **FindClose(SearchRec)**:
+- **重要性**:釋放搜尋控制代碼(Handle)。若未呼叫,頻繁搜尋會導致系統資源洩漏。
+
+### **4. GetNoNameCase(Path: string) 的搜尋邏輯**
+
+這是一個典型的 **「可用名稱查表」** 實作:
+
+- **迴圈範圍**:從 1 迭代到 9999。
+- **格式組合**:使用 Add_Zoo 函式將數字轉為四位數(如 0001),並加上前綴字「未配號」。
+- **磁碟檢查**:呼叫 DirectoryExists 檢查 Path + '未配號000x'。
+- **結果回傳**:第一個回傳 False(代表該資料夾尚不存在)的名稱即為結果,程式會立即跳出迴圈並選定此名稱。
+
+### **5. ReSortFileName(Path: string) 的連續性維護**
+
+為了保證 UI 上顯示的頁碼順序與磁碟檔名一致,此方法採用「先暫存、後改名」的策略:
+
+- **防止衝突**:先將目錄內所有符合格式的影像更名為帶有臨時前綴(如 @)的檔名。
+- **按序更名**:讀取 Context.dat 內的清單,依照目前的順序,將檔案逐一更名為 001_..., 002_... 等格式。
+- **同步索引**:最後將更名後的結果重新寫入 Context.dat。
+
+### **6. GetLocalAppDir(Handle: HWND) 的權限繞過**
+
+這是一個系統級別的 IO 位置定位方法:
+
+- **API 呼叫**:呼叫 SHGetSpecialFolderPath (Windows Shell API)。
+- **定位 CSIDL_LOCAL_APPDATA**:指向 C:\Users\使用者名稱\AppData\Local\。
+- **必要性**:這能解決 OCX 程式被安裝在 Program Files 下時,因為 UAC 權限無法在安裝目錄寫入 Log 或語言檔的問題。
+
+### **🎯 移植至 Web 平台的建議**
+
+當您將這些邏輯移植到 Web 時:
+
+- Str2Dir 應對應到 **IndexedDB** 的 Object Store 建立或 **File System Access API** 的 getDirectoryHandle(搭配 create: true)。
+- FindFirst / FindNext 在 Web 端應對應到 Directory Handle 的 entries() 異步疊代器。
+- .dat 序列化文件在 Web 端建議直接轉為 **JSON** 格式存儲於瀏覽器的 localStorage 或 IndexedDB 中。
+
+## **柒、 設定檔回寫邏輯 (Write-back Logic)**
+
+本節說明專案中哪些 .ini 檔案會由 OCX 主動更新資料及其觸發時機。
+
+| **檔案名稱** | **回寫內容 (Content)** | **觸發時機 (Trigger)** |
+| --- | --- | --- |
+| **Scan.ini** | DPI、Duplex、亮度、對比、影像模式 | 掃描前設定變更或啟動掃描時(SaveScanPara)。 |
+| **CustomDocNo.ini** | 自訂文件名稱與 ID 映射 | 操作員新增自訂分類或呼叫 `DeleteCustomDocDir` 時。 |
+| **CB_IMGPSScan.ini** | 版本號、伺服器 IP/Port | 自動更新完成後更新版號,或手動修改伺服器設定時。 |
+|  |  |  |
+
+## **捌、 注意事項**
+
+- **硬編碼路徑**:ActiveFormCreate 中存在寫死的 C:\Temp\IMGPSScan,適合作為最終保險。
+- **權限問題**:作為 ActiveX,這些 IO 操作強烈依賴瀏覽器的「安全站台設定」或 IE 的「保護模式」。使用 GetLocalAppDir 是現代化重構中解決 UAC 權限問題的重要手段。
diff --git "a/doc/curtis/OCX_\346\272\235\351\200\232\350\210\207_\346\212\275\350\261\241\345\261\244\346\212\275\346\217\233.md" "b/doc/curtis/OCX_\346\272\235\351\200\232\350\210\207_\346\212\275\350\261\241\345\261\244\346\212\275\346\217\233.md"
new file mode 100644
index 0000000..65dba92
--- /dev/null
+++ "b/doc/curtis/OCX_\346\272\235\351\200\232\350\210\207_\346\212\275\350\261\241\345\261\244\346\212\275\346\217\233.md"
@@ -0,0 +1,249 @@
+# **TCB_IMGPSScanX OCX 通訊介面與溝通機制分析**
+
+本表條列了 Delphi 宿主環境(ActiveX[ocx]) 與 TCB_IMGPSScanX 元件之間主要的溝通管道、對應方法及其在系統架構中的作用。
+
+## **壹、 指令與資料交換介面表**
+
+| **通訊方法 (Method)** | **通訊方向** | **溝通內容 (Data Payload)** | **具體作用與目的** |
+| --- | --- | --- | --- |
+| **SetSQLData** | **宿主 -> OCX** | 以 ` | 或,` 分隔的長字串(如:IP, CaseID, DPI) |
+| **GetSQLData** | **宿主 <-> OCX** | 指定 Key (如 'PARA_NO') 取得對應 Value | **資料查詢通道**。宿主可詢問 OCX 目前快取清單中的特定數值,用於介面同步或邏輯判斷。 |
+| **GetSetInf1 ~ 7** | **宿主 <- OCX** | 單一字串值 (如 CaseID, 總張數, 成功標記 'Y') | **狀態出口 (Outlets)**。提供標準化的 7 個出口,讓 JavaScript 或宿主 App 輪詢(Polling)目前的執行結果或掃描統計。 |
+| **StatrTwainScan** | **宿主 -> OCX** | 無參數 (觸發動作) | **硬體啟動指令**。宿主程式按下「開始掃描」按鈕後呼叫此方法,通知 OCX 喚起 TWAIN 驅動程式。 |
+| **GetCurrentVersionNo** | **宿主 <- OCX** | 版本字串 (如 '1.0.3.5') | **版本識別**。宿主程式載入 OCX 後第一步通常會呼叫此處,用以比對伺服器版本並決定是否強制更新。 |
+| **upFile** | **宿主 -> OCX** | 無或部分參數 (觸發網路 IO) | **輸出指令**。通知 OCX 將本機暫存區的檔案(如 ZIP 包)依照先前設定好的路徑與權限上傳至伺服器。 |
+| **dnFile_Get** | **宿主 -> OCX** | 遠端 Action 關鍵字與本地檔名 | **同步指令**。通知 OCX 向伺服器抓取特定資源(如 XML 規則或語言檔)並存放到指定 IO 路徑。 |
+| **ActiveFormCreate** | **系統 -> OCX** | 視窗建立事件 | **環境初始化**。當宿主程式實體化 OCX 時,自動觸發此處執行 GetDefScanIni,確保掃描環境就緒。 |
+| **Property CaseID** | **宿主 <-> OCX** | WideString | **屬性直連**。透過 COM 屬性機制直接設定或讀取案件編號。 |
+| **Property ScreenSnap** | **宿主 -> OCX** | Boolean | **功能切換**。控制 OCX 是否要在特定時機執行螢幕截圖稽核。 |
+
+## **貳、 溝通機制細部說明**
+
+### **1. 參數化配置 (Config-by-String)**
+
+本專案大量使用 SetSQLData 這種「一條字串走天下」的設計,這在早期 ActiveX 開發中非常流行,優點是規避了 COM 介面頻繁修改 _TLB.pas 的麻煩。您在轉換 TypeScript UI 時,可以將其封裝為一個 JSON 物件,最後再組合成字串傳給這個方法。
+
+### **2. 狀態回饋 (The Inf1~7 Pattern)**
+
+由於 ActiveX 事件 (Events) 的回傳有時在網頁端不夠穩定,開發者選擇了 GetSetInf 系列。宿主程式通常會在執行完某個長耗時動作(如 upFile)後,連續呼叫 GetSetInf3 (成功標記) 與 GetSetInf6 (錯誤訊息) 來決定下一步 UI 流程。
+
+### **3. 雙向同步 (Bidirectional Sync)**
+
+- **同步設定**:宿主透過 GetDefScanIni 觸發,OCX 內部完成硬體設定。
+- **同步資料**:宿主透過 dnFile_Get 觸發,OCX 完成本機與伺服器的檔案 IO 同步。
+
+# **參、描服務抽象層實作**
+
+採用 **「抽象介面層 (Abstraction Layer)」** 配合 **「適配器模式 (Adapter Pattern)」**,處理遺留系統(Legacy System)過渡到現代化架構
+
+```tsx
+/**
+ * 掃描服務資料模型定義
+ * 將原本 OCX 雜亂的字串溝通 (SetSQLData) 結構化
+ */
+export interface ScanConfig {
+  serverIp: string;
+  caseId: string;
+  dpi: number;
+  isColor: boolean;
+  isDuplex: boolean;
+  // ... 其他來自 GetDefScanIni 的參數
+}
+
+export interface ScanStatus {
+  caseId: string;
+  totalPageCount: number;
+  isUploadSuccess: boolean;
+  lastBarcode: string;
+  errorMessage: string;
+}
+
+/**
+ * 掃描服務抽象介面 (IScanService)
+ * UI 層僅與此介面溝通,不直接操作底層實作
+ */
+export interface IScanService {
+  initialize(config: ScanConfig): Promise<void>;
+  startScan(): Promise<boolean>;
+  uploadFiles(): Promise<boolean>;
+  getStatus(): Promise<ScanStatus>;
+  getVersion(): Promise<string>;
+  downloadResource(action: string, fileName: string): Promise<void>;
+}
+
+/**
+ * 實作 A: ActiveX 適配器 (Legacy Adapter)
+ * 用於目前環境:UI (TS) -> Delphi Browser -> ActiveX (OCX)
+ */
+export class ActiveXScanAdapter implements IScanService {
+  private ocx: any;
+
+  constructor() {
+    // 透過 window.external 或 Delphi Bridge 取得 OCX 實例
+    this.ocx = (window as any).OCX_INSTANCE;
+  }
+
+  async initialize(config: ScanConfig): Promise<void> {
+    // 將 JSON 轉回 OCX 慣用的管道分隔字串 (SetSQLData 邏輯)
+    const sqlDataStr = `${config.serverIp}|${config.caseId}|${config.dpi}|${config.isColor ? 'C' : 'G'}`;
+    this.ocx.SetSQLData(sqlDataStr);
+  }
+
+  async startScan(): Promise<boolean> {
+    this.ocx.StatrTwainScan();
+    return true; // 實際狀態需透過 GetSetInf 輪詢
+  }
+
+  async getStatus(): Promise<ScanStatus> {
+    return {
+      caseId: this.ocx.GetSetInf1(),
+      totalPageCount: parseInt(this.ocx.GetSetInf2()),
+      isUploadSuccess: this.ocx.GetSetInf3() === 'Y',
+      lastBarcode: this.ocx.GetSetInf5(),
+      errorMessage: this.ocx.GetSetInf6()
+    };
+  }
+
+  async uploadFiles(): Promise<boolean> {
+    this.ocx.upFile();
+    return true;
+  }
+
+  async getVersion(): Promise<string> {
+    return this.ocx.GetCurrentVersionNo();
+  }
+
+  async downloadResource(action: string, fileName: string): Promise<void> {
+    this.ocx.dnFile_Get(action, fileName);
+  }
+}
+
+/**
+ * 實作 B: Backend Server 適配器 (Future Adapter)
+ * 用於未來環境:UI (TS) -> REST API / WebSocket -> Rust/Go Backend
+ */
+export class BackendServerAdapter implements IScanService {
+  private apiUrl = "http://localhost:8080/api/scanner";
+
+  async initialize(config: ScanConfig): Promise<void> {
+    await fetch(`${this.apiUrl}/config`, {
+      method: 'POST',
+      body: JSON.stringify(config)
+    });
+  }
+
+  async startScan(): Promise<boolean> {
+    const res = await fetch(`${this.apiUrl}/scan`, { method: 'POST' });
+    return res.ok;
+  }
+
+  async getStatus(): Promise<ScanStatus> {
+    const res = await fetch(`${this.apiUrl}/status`);
+    return await res.json();
+  }
+
+  async uploadFiles(): Promise<boolean> {
+    const res = await fetch(`${this.apiUrl}/upload`, { method: 'POST' });
+    return res.ok;
+  }
+
+  async getVersion(): Promise<string> {
+    const res = await fetch(`${this.apiUrl}/version`);
+    const data = await res.json();
+    return data.version;
+  }
+
+  async downloadResource(action: string, fileName: string): Promise<void> {
+    // 未來可能直接由後端處理,前端僅發送同步指令
+    await fetch(`${this.apiUrl}/sync?action=${action}&file=${fileName}`);
+  }
+}
+
+/**
+ * 服務工廠 (Scanner Factory)
+ * 根據環境自動切換實作
+ */
+export class ScannerFactory {
+  static getService(): IScanService {
+    if ((window as any).OCX_INSTANCE) {
+      console.log("偵測到 ActiveX 環境,啟用 ActiveX 適配器");
+      return new ActiveXScanAdapter();
+    } else {
+      console.log("現代瀏覽器環境,啟用後端 API 適配器");
+      return new BackendServerAdapter();
+    }
+  }
+}
+```
+
+### **1. 介面標準化(JSON 化)**
+
+原先 OCX 使用 SetSQLData 的「長字串」溝通是非常脆弱的(一項參數順序錯了就全毀)。在 TypeScript 抽象層中,請務必將其轉換為 **強型別的 JSON 物件**(如 ScanConfig 介面)。這樣你的 UI 邏輯在處理設定時會非常直覺。
+
+### **2. 非同步處理(Promise/Async)**
+
+ActiveX 的方法通常是同步阻塞的,而後端 API 是非同步的。
+
+- **建議**:在抽象介面(IScanService)中,所有方法都回傳 Promise。
+- **原因**:這樣當你未來切換到後端伺服器(fetch API)時,UI 的調用邏輯(await service.startScan())不需要做任何修改。
+
+### **3. 實作「心跳」或「狀態輪詢」**
+
+原本 GetSetInf1~7 主要是靠宿主程式主動去「問」OCX。
+
+- **抽象層建議**:在 IScanService 中實作一個 subscribeStatus(callback) 的觀察者模式。
+- **ActiveX 模式下**:在適配器內部啟動一個 setInterval 去輪詢 GetSetInf。
+- **未來後端模式下**:適配器改用 **WebSocket** 接收後端主動推播的掃描事件。
+- **UI 層感受**:UI 只需要處理 onStatusUpdate 事件,根本不用管底層是用輪詢還是 WebSocket。
+
+### **4. 資源路徑的轉義(The Bridge Proxy)**
+
+這是我之前提到的關鍵:由於 iframe 裡的 TypeScript 無法存取 C:\Temp,但 ActiveX 依舊會把檔案掃到那裡。
+
+- **策略**:你的 Delphi Browser 需要實作一個簡單的本地 Proxy。
+- **實作**:當 TypeScript 需要顯示圖檔時,它請求 http://local.bridge/view/001.tif,Delphi Browser 攔截此請求並從實體路徑讀取檔案回傳。
+- **好處**:未來改為 Backend Server 時,Server 也可以提供同樣的 URL 格式,UI 完全無縫接軌。
+
+## **肆、 Delphi 與 JavaScript 通訊橋樑 (Bridge) 實作說明**
+
+當您在 Delphi 宿主程式中使用內嵌瀏覽器時,JavaScript 取得 `OCX_INSTANCE` 的方式取決於底層的瀏覽器引擎:
+
+### **1. 舊版 IE 核心 (TWebBrowser / window.external)**
+
+這是最傳統的方式,Delphi 會透過實作 `IDocHostUIHandler` 介面,將一個自訂的 `IDispatch` 物件掛載到 `window.external` 上。
+
+- **Delphi 端**:將 `TCB_IMGPSScanX` 實例或其包裝類別指派給瀏覽器的 `External` 屬性。
+- **JS 端**:直接使用 `window.external.StatrTwainScan()` 呼叫。
+
+### **2. 新版 Edge 核心 (TEdgeBrowser / WebView2 Host Objects)**
+
+這是現代化的做法。Delphi 透過 WebView2 的 API 將物件直接「注入」到 JS 的命名空間中。
+
+- **Delphi 端執行**:
+
+    ```pascal
+    // 將 OCX 物件以 'OCX_INSTANCE' 名稱注入
+    EdgeBrowser.AddHostObjectToScript('OCX_INSTANCE', MyOcxWrapperObject);
+    ```
+
+- **JS 端取得**: WebView2 會將物件放置在 `window.chrome.webview.hostObjects` 底下。
+
+    ```jsx
+    const ocx = window.chrome.webview.hostObjects.OCX_INSTANCE;
+    ```
+
+
+### **3. 為什麼需要 Wrapper (包裝類別)?**
+
+通常我們**不建議**直接將 `TCB_IMGPSScanX` 注入,原因如下:
+
+1. **安全性**:直接暴露 COM 元件可能會有安全漏洞。
+2. **相容性**:OCX 的某些方法回傳型別(如 Delphi 的自訂 Enum)JavaScript 無法識別。
+3. **執行緒優化**:Delphi 可以在 Wrapper 中使用 `TThread.Queue` 確保掃描指令在正確的執行緒執行,避免瀏覽器 UI 凍結。
+
+### **4. 溝通路徑總結**
+
+1. **Delphi 宿主程式** 啟動並實體化 **OCX 控制項**。
+2. **Delphi 宿主程式** 建立 **Browser 物件** 並載入 **TypeScript UI (HTML)**。
+3. **Delphi 宿主程式** 呼叫瀏覽器 API(如 `AddHostObjectToScript`),將 OCX 的操作介面「注入」到該網頁的 `window` 物件中。
+4. **TypeScript** 透過抽象層 (Adapter) 取得該物件,實現「網頁點按鈕,掃描機開動」的效果。
diff --git "a/doc/curtis/ScanImp_\346\272\220\347\242\274\345\210\206\346\236\220.md" "b/doc/curtis/ScanImp_\346\272\220\347\242\274\345\210\206\346\236\220.md"
new file mode 100644
index 0000000..8781c3c
--- /dev/null
+++ "b/doc/curtis/ScanImp_\346\272\220\347\242\274\345\210\206\346\236\220.md"
@@ -0,0 +1,242 @@
+# **核心源碼與物件實作解析**
+
+本文件針對 CB_IMGPSScanImp.pas 中的核心方法與隱藏物件進行原始碼級別的邏輯拆解與推導。
+
+## **壹、 核心方法源碼說明**
+
+### **1) TCB_IMGPSScanX.GetCurrentVersionNo**
+
+- **功能描述**:取得目前 OCX 元件的版本號。這通常提供給網頁端的 JavaScript 呼叫,用來判斷客戶端的 OCX 是否需要觸發更新下載。
+- **實作推導與底層 API 說明**:
+
+  在 Delphi 中,若要動態讀取編譯進 OCX 的 VS_VERSION_INFO 資源,標準作法是呼叫一系列的 Windows API。這段實作通常包含以下三個關鍵概念:
+
+1. **HInstance (實體句柄)**:
+- 這是 Delphi 提供的一個全域變數,代表目前載入記憶體中的模組(即這個 OCX 檔)的「實體句柄 (Instance Handle)」。
+- 在 Windows 作業系統中,當一個執行檔 (EXE) 或動態連結檔 (DLL/OCX) 被載入記憶體時,會獲得一個記憶體基底位址,HInstance 就是指向這個位址的指標。Windows 需要這個值來識別「你要操作的是哪一個載入的模組」。
+1. **GetModuleFileName 的作用**:
+- 這是一個 Windows API。它的作用是利用前面提到的 HInstance,向作業系統反查出這個模組在硬碟上的**「完整實體檔案路徑」**(例如:C:\Windows\Downloaded Program Files\CB_IMGPSScan.ocx)。
+- 因為我們需要讀取檔案本身的版本資訊,程式必須先知道「我自己到底存放在硬碟的哪裡」。
+1. **後半段 VerQueryValue 的運作邏輯**:
+
+   取得檔案路徑後,讀取版本資訊會經過三部曲,而 VerQueryValue 是最後負責「解析」的關鍵:
+
+- **Step 1 (GetFileVersionInfoSize)**:先問 Windows 這個檔案的版本資訊區塊有多大。
+- **Step 2 (GetFileVersionInfo)**:把整塊版本資訊的二進位原始資料 (Raw Data) 完整讀進一段記憶體緩衝區中。
+- **Step 3 (VerQueryValue)**:因為剛剛讀進來的是一包無法直接閱讀的二進位資料,VerQueryValue 的作用就是**「在這包資料中進行精準查詢」**。透過傳入特定的查詢路徑(例如傳入 \ 可以取得包含主版號、次版號的 VS_FIXEDFILEINFO 結構體;或是傳入特定語系代碼如 \StringFileInfo\040404E4\FileVersion),作業系統會幫你把二進位資料解析成我們需要的字串或數字版本號(如 1.0.3.5)。
+
+### **2) TCB_IMGPSScanX.ActiveFormCreate**
+
+- **功能描述**:這是 ActiveX 視覺化窗體 (Form) 的生命週期起點。當 IE 瀏覽器或應用程式載入這個 OCX 時,首先觸發的初始化事件。
+- **實作推導**:
+
+  它會負責初始化全域變數、設定第三方元件的預設值、並建立暫存資料夾。
+
+    ```pascal
+     procedure TCB_IMGPSScanX.ActiveFormCreate(Sender: TObject);
+      begin
+        // 1. 預設變數初始化
+        Def_DeviceDelete := True;
+        Def_ScannerReverse := False;
+    
+        // 2. 建立本機暫存目錄
+        ForceDirectories('C:\Temp\IMGPSScan');
+    
+        // 3. UI 語系初始化
+        InitialLanguage;
+      end;
+    ```
+
+
+### **3) TCB_IMGPSScanX.StatrTwainScan**
+
+- **功能描述**:啟動掃描機的 TWAIN 介面,開始進紙或掃描。(註:Statr 應為 Start 的早期拼字錯誤,這在舊專案中很常見)。
+- **實作推導**:
+
+  這個方法會讀取網頁傳進來的參數(如 DPI、色彩),設定給 Scanner 物件,然後發出擷取指令。
+
+    ```pascal
+      procedure TCB_IMGPSScanX.StatrTwainScan;
+      begin
+        // 設定解析度與顏色
+        Scanner.Resolution := StrToIntDef(Fimgdpi, 200);
+        if Fscancolor = 'C' then
+          Scanner.PixelType := ptColor
+        else
+          Scanner.PixelType := ptGray;
+    
+        // 啟動掃描 (會喚起實體掃描機)
+        Scanner.Acquire; 
+      end;
+    ```
+
+
+### **4) TCB_IMGPSScanX.OnAcquire 與資料流物件**
+
+- **功能描述**:這是 Scanner (EnScan) 最核心的事件。當掃描機成功掃完「一張」影像並傳入電腦記憶體時,會觸發此事件。
+- **源碼邏輯推導**:
+
+    ```pascal
+    procedure TCB_IMGPSScanX.ScannerAcquire(Sender: TObject; DibHandle: THandle; var Handled: Boolean);
+      var
+        MyStream: TMemoryStream;
+        MyGraphic: TDibGraphic;
+      begin
+        // 1. 將 DibHandle 轉換為 Delphi 影像物件
+        MyGraphic := TDibGraphic.Create;
+        MyGraphic.Handle := DibHandle;
+    
+        // 2. 影像處理 (如去斜、黑白轉換)
+    
+        // 3. 存入記憶體串流或實體檔案
+        // ...
+      end;
+    ```
+
+- **三大核心資料物件解釋**:
+1. **DibHandle**:這是 Windows 底層的「全域記憶體句柄 (Global Memory Handle)」。掃描機驅動把圖片放在記憶體裡,給你這個代號。你必須透過 TDibGraphic 來「解讀」這塊記憶體。
+2. **TMemoryStream**:**記憶體串流**。它的作用像是一塊存在 RAM 裡的虛擬硬碟。掃描後的圖檔在還沒存到實體硬碟前,會先放在這裡進行格式轉換 (如轉成 JPEG) 或進行 MD5 計算,因為在記憶體中操作速度最快。
+    - **DeleteStm : TMemoryStream 的逐行操作說明**:
+      在 `OnAcquire` 事件中,`DeleteStm` 主要用於「空白頁判定」。其源碼邏輯如下:
+
+    ```pascal
+    // 判定是否啟動空白頁刪除功能
+    if Def_DeviceDelete then
+    begin
+      // 1. 在 Heap 記憶體中建立一個暫存串流物件
+      DeleteStm := TMemoryStream.Create;
+      try
+        // 2. 將當前掃描到的影像物件 (MyGraphic) 寫入記憶體串流
+        // 這會根據 TIFF G4 等格式進行壓縮,產生實際的檔案位元組資料
+        MyGraphic.SaveToStream(DeleteStm);
+    
+        // 3. 核心判定:檢查該影像在記憶體中所佔用的位元組大小 (Size)
+        // 若小於預設門檻值 (Def_DeviceDeleteSize, 如 3072 Bytes)
+        if DeleteStm.Size < Def_DeviceDeleteSize then
+        begin
+          // 4. 若符合空白頁特徵,則不進行存檔動作,直接跳出此 Procedure
+          // 並告知掃描控制項此頁已處理完畢 (Handled := True)
+          Handled := True;
+          Exit;
+        end;
+      finally
+        // 5. 無論是否為空白頁,操作結束後必須釋放記憶體,避免 Memory Leak
+        DeleteStm.Free;
+      end;
+    end;
+    ```
+    
+   - 
+3. **TFileStream**:**檔案串流**。用來直接對硬碟讀寫資料。當確認影像無誤後,會透過 TFileStream 將 TMemoryStream 的內容真實地寫入 C:\Temp\...\001.tif 中。
+
+### **5) TCB_IMGPSScanX.FindISB2View**
+
+- **功能描述**:用來在畫面上尋找並更新用來預覽圖片的元件。
+- **名詞解釋**:**ISB 代表 ImageScrollBox**。
+
+  這對應到 uses 區段中的 EnImgScr 套件。TImageScrollBox 是 Envision 提供的一個 UI 元件,專門用來顯示超出螢幕大小的掃描圖檔,支援平滑拖曳與縮放。這個方法通常用來把剛掃描完的 DibHandle 餵給畫面上的 ISB 元件顯示。
+
+
+### **6) TCB_IMGPSScanX.GetNoNameCase**
+
+- **功能描述**:處理「無案號」或「未知歸屬」的掃描件。
+- **源碼實作逐行說明**:
+
+  此方法透過迴圈尋找一個尚未被使用的目錄名稱(格式為「未配號 + 四位數字」)。
+
+
+```pascal
+Function TCB_IMGPSScanX.GetNoNameCase(Path:String):String; // 取未配號XXXX
+var
+  i : Integer; // 宣告迴圈計數器
+begin
+  // 1. 啟動一個從 1 到 9999 的迴圈,尋找可用的索引值
+  for i := 1 to 9999 do
+  begin
+    // 2. 檢查特定路徑下的目錄是否已存在
+    // _Msg('未配號'):取得「未配號」字串(可能具備多國語言處理)
+    // Add_Zoo(i, 4):將數字 i 補齊為 4 位數(例如 1 變為 0001)
+    if Not DirectoryExists(Path + _Msg('未配號') + Add_Zoo(i, 4)) then
+    begin
+      // 3. 若該目錄不存在,代表此名稱可用,設定 Result 並跳出迴圈
+      Result := _Msg('未配號') + Add_Zoo(i, 4);
+      Break; // 找到第一個可用的名稱後立即停止搜尋
+    end;
+  end;
+end;
+```
+
+### **7) TCB_IMGPSScanX.SetSQLData 與 8) GetSQLData**
+
+這兩個方法是 OCX 與網頁 (JS) 溝通的雙向橋樑。
+
+- **SetSQLData (網頁 -> OCX)**:接收由網頁傳來的設定字串(通常用 | 或 , 分隔,例如 192.168.1.1|L12345678|200|C),在內部將字串切開 (Split),並分別賦值給 ServerIP, FCaseID, Fimgdpi, Fscancolor 等內部變數。
+- **GetSQLData (OCX -> 網頁)**:將 OCX 內部的處理結果(例如:UploadSuccess|3|0 代表上傳成功、共 3 頁、0 錯誤),組合成一個長字串後回傳給網頁端的 JS 進行後續的頁面跳轉或提示。
+
+### **8) TCB_IMGPSScanX.GetDefScanIni**
+
+- **功能描述**:取得並套用掃瞄參數的預設值與自訂設定。
+- **源碼實作解析**:
+    - **硬編碼預設值 (Hardcoded Defaults)**:
+
+      程式一開始會先寫死一組標準值,例如 Def_ScanDpi := 300 (預設 300 DPI)、Def_DeviceDeleteSize := 3072 (空白頁判定門檻為 3KB)。
+
+    - **動態配置覆蓋 (Dynamic Overriding)**:
+
+      透過 for i := 0 to WORK_INF_List.Count - 1 do 迴圈遍歷設定檔清單。使用 GetSQLData 取得參數代號 (PARA_NO) 與內容 (PARA_CONTENT)。
+
+- **屬性設定對照表**:
+
+  下表整理了此方法中設定的所有關鍵屬性、其對應的參數代號及功能說明。
+
+  | **屬性名稱 (內部變數)** | **對應 PARA_NO** | **PARA_CONTENT 處理方式(GetSQLData)** | **功能說明** |
+      | --- | --- | --- | --- |
+  | **Def_DeviceDelete** | SCAN_BLANKDEL_USE | 'Y' -> True, Else -> False | 空白頁自動刪除開關。 |
+  | **Def_DeviceDeleteSize** | SCAN_BLANKDEL_SIZE | StrToInt (若空則 0) | 空白頁判定門檻 (Bytes)。 |
+  | **Def_ScannerReverse** | SCAN_REVERSE | 'Y' -> True, Else -> False | 影像是否反相。 |
+  | **Def_BoardClear** | SCAN_BOARDCLEAR | 'Y' -> True, Else -> False | 是否清除影像黑邊。 |
+  | **Def_ScanDpi** | SCAN_DPI | StrToInt (若空則 300) | 掃描解析度。 |
+  | **Def_ScanDuplex** | SCAN_DUPLEX | 'Y' -> True, Else -> False | 是否啟用雙面掃描。 |
+  | **Def_ScanRotate** | SCAN_ROTATE_MODE | '0'->0, '1'->270, '2'->180, '3'->90 | 掃描旋轉角度映射。 |
+  | **Def_ScanDeskew** | SCAN_DESKEW | 'Y' -> True, Else -> False | 是否自動矯正傾斜。 |
+  | **Def_ScanImgSetUse** | SCAN_IMGSET_USE | 'Y' -> True, Else -> False | 是否使用亮度/對比設定。 |
+  | **Def_ScanBright** | SCAN_BRIGHT | StrToInt (限制 -255~255) | 亮度數值。 |
+  | **Def_ScanContrast** | SCAN_CONTRAST | StrToInt (限制 -255~255) | 對比數值。 |
+  | **Def_ScanImgShowMode** | SCAN_SHOW_MODE | '0','1','2' 對應模式 | 影像顯示/縮放模式。 |
+  | **ScanDenialTime** | CASE_IN_TIME | 直接存為 String | 進件截止時間限制。 |
+  | **ScanDenialHint** | SCAN_HINT | 直接存為 String | 掃描畫面提示字串。 |
+  | **NoSaveBarCodeList** | NO_SAVE_FORM_ID | CommaText := Value | 不存檔之表單代號清單。 |
+  | **ImagePath** | LOCAL_PATH | 直接存為 String | 本機端暫存路徑。 |
+  | **GuideFormIDList** | GUIDEFORMID | CommaText := Value | 導引頁表單 ID 清單。 |
+  | **DivPageFormIDList** | DIVPAGEFORMID | CommaText := Value | 分案頁表單 ID 清單。 |
+  | **FJpgCompression** | FILE_COMPRESSION | StrToInt | JPG 轉 TIF 壓縮比。 |
+  | **FMaxUploadSize** | MAX_UPLOAD_SIZE | 直接存為 String | 上傳大小限制 (MB)。 |
+
+## **貳、 記憶體直接操作實作清單**
+
+以下條列專案中直接涉及記憶體操作的程式區段:
+
+### **記憶體操作對應位置表**
+
+| **記憶體操作對象** | **所屬 Function / Procedure** | **關鍵操作關鍵字 / 代碼** | **記憶體特性說明** | 註記 |
+| --- | --- | --- | --- | --- |
+| **HInstance** | GetCurrentVersionNo | GetModuleFileName(HInstance, ...) | 模組載入位址。 | 增API版本號 |
+| **資源緩衝區** | GetCurrentVersionNo | VerQueryValue, GetFileVersionInfo | 透過 Pointer 進行二進位搜尋。 | 增API版本號 |
+| **DibHandle** | onAcquire | MyGraphic.Handle := DibHandle; | Windows 全域記憶體句柄轉移。 | 改套件實作/Rust |
+| **TMemoryStream** | onAcquire | MemoryStream.Write, .Read | Heap Memory 內部二進位操作。 |  |
+
+## **參、 遺失物件反推與說明**
+
+你提到在原始碼中找不到 _DelTree 和 Scanner 的實作,這是因為它們屬於以下兩種情況:
+
+### **1) TCB_IMGPSScanX._DelTree**
+
+- **這是一個自訂的私有輔助函式 (Private Helper)**。
+- **功能**:它的名稱源自 DOS 時代的指令 deltree(刪除整個目錄樹)。在 ActiveX 中,當上傳伺服器成功後,必須清空 C:\Temp\案件編號\ 裡的所有暫存圖檔與資料夾以釋放空間,並防止資料外洩。
+- **實作原理**:由於早期的 Delphi 沒有內建遞迴刪除目錄的單一指令,開發者通常會自己寫一個 _DelTree,裡面使用 FindFirst, FindNext 找出所有檔案並用 DeleteFile 刪除,最後用 RemoveDir 砍掉資料夾。
+
+### **2) Scanner**
+
+- **這是一個視覺化/非視覺化的第三方元件實例 (Component Instance)**。
+- **為何找不到宣告?** 因為在 Delphi 中,如果你是透過 IDE 的工具箱 (Tool Palette) 將 TEnScan 元件直接拖拉到窗體 (Form) 上,IDE 會自動把它寫在 .dfm 檔裡,並在 TCB_IMGPSScanX 類別的 published 區段自動產生一行 Scanner: TEnScan;。
+- **功能**:它就是 **Envision SDK** 裡用來與 TWAIN 硬體溝通的靈魂核心。所有的掃描屬性 (Scanner.Resolution) 與方法 (Scanner.Acquire) 都是對這個物件進行操作。
diff --git a/doc/curtis/Scanner_Controller_Analysis.md b/doc/curtis/Scanner_Controller_Analysis.md
new file mode 100644
index 0000000..964c8d8
--- /dev/null
+++ b/doc/curtis/Scanner_Controller_Analysis.md
@@ -0,0 +1,62 @@
+# 硬體掃描控制模組 (Scanner Controller) 深度分析
+
+在 `CB_IMGPSScanImp.pas` 中,「硬體掃描控制模組」是系統與實體掃描設備溝通的唯一橋樑。它深度依賴 TWAIN 協定(透過第三方元件 `EnScan` 封裝),負責控制硬體行為並將紙本文件轉換為記憶體中的數位影像資料。
+
+若要將此模組進一步細拆,其內部組成可分為以下三大子分類:
+
+---
+
+## 1. TWAIN 介面封裝與控制 (TWAIN Interface Wrapper)
+
+**職責**:負責管理實體掃描機的連線狀態、開啟/關閉資料來源 (Data Source),以及觸發掃描動作。
+**核心實作特性**:
+*   **掃描機選擇與初始化**:
+    *   `SelectScanner` (`scanner.SelectScanner`):呼叫 TWAIN 介面讓使用者選擇預設的掃描機硬體。
+    *   `initkscan` / `CheckScannerConfig`:在系統啟動時檢查掃描機是否已正確配置並支援特定功能(例如檢查 `Scanner.DuplexCap > 0` 確認是否支援雙面掃描)。
+*   **掃描生命週期管理** (`StatrTwainScan`):
+    *   負責設定 `Scanner.OpenSource`(開啟驅動)。
+    *   呼叫 `Scanner.AcquireWithSourceOpen` 開始非同步擷取,並傳入回呼函式 (Callback) 的指標與自訂的狀態結構 (`LongInt(@ScanInfo)`)。
+    *   確保無論掃描成功、失敗或中斷,最終都會安全地執行 `Scanner.CloseSource`。
+
+## 2. 掃描參數與設定管理器 (Scanner Profile Manager)
+
+**職責**:負責載入、維護及套用掃描時所需的各項硬體與前處理參數。這些參數通常從資料庫 (`WORK_INF`) 或是本機的 `FBScan.ini` 中讀取。
+**核心實作特性**:
+*   **硬體基本參數 (Hardware Params)**:
+    *   `ScanDpi`:解析度設定,對應 `RequestedXDpi` 與 `RequestedYDpi`。
+    *   `ScanColor` (`TImageFormat`):影像色彩模式(黑白 `ifBlackWhite`、灰階 `ifGray256`、彩色 `ifTrueColor`)。
+    *   `ScanDuplex`:控制硬體是否開啟雙面進紙 (`Scanner.Duplex`)。
+    *   `TwainShowUI`:是否顯示掃描機原廠的 TWAIN 設定畫面 (`Scanner.ShowUI`)。
+*   **硬體增強參數 (Enhancement Params)**:
+    *   `ScanBright` (亮度) 與 `ScanContrast` (對比度):當啟用 `ScanImgSetUse` 時,將這些參數直接送入掃描硬體。
+*   **前置處理規則 (Pre-processing Rules)**:
+    *   `DeviceDelete` 與 `DeviceDeleteSize`:定義是否開啟「空白頁自動刪除」以及刪除的位元組閥值。
+    *   `ScannerReverse` (反相)、`ScanDeskew` (硬體/初階去斜)、`BoardClear` (清除黑邊)。
+
+## 3. 非同步影像接收與初始轉換器 (Acquisition Event Handler)
+
+**職責**:做為掃描機與應用程式記憶體的交界點,負責攔截驅動程式傳回的原始記憶體區塊 (`DibHandle`),並進行最基礎的安全轉換與前置判斷。
+**核心實作特性** (`OnAcquire` 回呼事件):
+*   **記憶體接管 (Memory Handover)**:
+    *   接收來自 TWAIN 驅動的 `DibHandle`(Device Independent Bitmap 記憶體指標)。
+    *   利用 `pScanInfo^.Graphic.AssignFromDibHandle(DibHandle)` 將非管理的記憶體轉換為 Delphi VCL 的 `TTiffGraphic` 物件。
+*   **早階條碼快篩與方向校正 (Early Barcode Detection & Rotation)**:
+    *   為確保後續處理正確,系統會在剛拿到記憶體影像時,立刻進行一次快速的條碼掃描 (`MpsGetBarcode`)。
+    *   讀取條碼所帶的方向資訊 (`MpsBarcodeinf.r180`),並在記憶體中立刻進行 `Rotate` 旋轉,將顛倒或橫放的文件轉正。
+*   **基礎裁切與壓縮決策 (Format & Crop Decision)**:
+    *   **A3 裁 A4**:呼叫 `CheckNeedCrop` 判斷長寬比例與特定條碼數量,若確認為 A3 合併頁,則立刻在記憶體中將其拆分為 `iGraphic_First` 與 `iGraphic_Sec` 兩張獨立影像。
+    *   **格式與壓縮決策**:針對色彩屬性 (`ifBlackWhite`, `ifTrueColor`, `ifGray256`),決定應該套用哪種壓縮演算法(如黑白套用 `tcGroup4` 或 `tcPackBits`,彩色則轉換為 `tcJpeg` 並套用指定的 `FJpgCompression` 壓縮率)。
+
+---
+
+## 💡 未來重構與微服務化建議
+
+若要將此「硬體掃描控制模組」進行現代化升級或跨平台轉型,建議考量以下方向:
+
+1.  **與 UI 徹底解耦**:
+    目前的 `OnAcquire` 回呼函式中混雜了大量 UI 操作(如 `ImageScrollBox1.Graphic.Assign(...)`)。應改用「發佈-訂閱模式 (Pub-Sub)」,讓 Scanner Controller 收到影像後只觸發事件,由外部的 UI 層去訂閱並更新畫面。
+2.  **Web/雲端化架構 (Web TWAIN / WebSockets)**:
+    若未來系統要走向純 Web 化(捨棄 ActiveX),由於瀏覽器無法直接呼叫 Windows 底層的 TWAIN API,此模組必須被改寫為一隻安裝於 Client 端的 **背景常駐服務 (Local Windows Service / Daemon)**。
+    該服務可以透過 **WebSocket** 或 **Local REST API** 接收來自網頁端的掃描指令,控制 TWAIN 掃描機,並將接收到的影像轉為 Base64 或二進位流回傳給網頁前端。
+3.  **單一職責分離 (Separation of Concerns)**:
+    應將 `OnAcquire` 中厚重的「條碼辨識」、「A3 裁切」與「黑邊處理」移出此模組。Scanner Controller 的唯一職責應該只有:**「將紙本轉為電腦中的 Bitmap」**。後續的處理應交給 `Image Processor` (影像處理模組) 透過管線 (Pipeline) 的方式接手處理。
diff --git a/doc/curtis/Transport_Manager_Analysis.md b/doc/curtis/Transport_Manager_Analysis.md
new file mode 100644
index 0000000..330fca5
--- /dev/null
+++ b/doc/curtis/Transport_Manager_Analysis.md
@@ -0,0 +1,69 @@
+# 安全傳輸與 API 通訊模組 (Transport Manager) 深度分析
+
+在 `CB_IMGPSScanImp.pas` 中,「安全傳輸與 API 通訊模組」負責處理 ActiveX 客戶端與後端伺服器 (如 Java Servlet 平台) 之間的所有資料交換與檔案傳輸。由於涉及機敏的金融/保險文件,此模組高度依賴加密與安全通訊協定。
+
+若要將此模組進一步細拆,其內部組成可分為以下四大子分類:
+
+---
+
+## 1. HTTP/HTTPS API 請求管理器 (RESTful / Servlet Client Wrapper)
+
+**職責**:專責透過 HTTP(S) 協定,向後端的 Java Servlet 端點發送 GET/POST 請求,用於同步時間、下載設定檔或回報案件狀態。
+**核心實作特性**:
+*   **套件依賴**:底層依賴 SecureBlackbox 的 `TElHTTPSClient` (在變數宣告為 `HTTPSClient`) 處理 SSL/TLS 連線。
+*   **字串/表單資料交換**:
+    *   `ProcessServlet_Get`:使用 HTTP GET 方式,將加密過的參數 (`SendData`) 送至伺服器,並將伺服器回傳的結果寫入 `FReWrite` 或 `Memo1` 中。
+    *   `ProcessServlet` / `ProcessServlet_FormData`:使用 HTTP POST 或 `multipart/form-data` 方式提交較大的資料集(如 OMR 檢核結果、案件完成通知等)。
+*   **狀態與錯誤攔截**:檢查伺服器回傳的代碼(例如回傳 `0` 代表成功,`1` 代表錯誤,或攔截回傳 HTML 中包含 `login.js` 來判斷 Session 是否逾時登出)。
+
+## 2. 雙協定檔案上傳/下載引擎 (Dual-Protocol File Transfer Engine)
+
+**職責**:處理實體影像檔案(通常是打包後的 ZIP 檔)或系統授權檔的實體傳輸,並根據系統設定動態切換 HTTP 或 FTP 協定。
+**核心實作特性**:
+*   **HTTP 檔案傳輸**:
+    *   `upFile`:透過 HTTP POST (`multipart/form-data`) 將本地端的檔案 (如 `Img.zip` 或 `.lic` 檔) 上傳至伺服器指定的 Servlet 接收端。
+    *   `dnFile_Get` / `dnFile`:透過 HTTP 協定從伺服器下載檔案 (如 `OMRSet.zip`, `KeyinSet.zip` 或舊案影像),並提供下載狀態監控。
+*   **FTPS 檔案傳輸 (高頻寬/大檔專用)**:
+    *   `GetftpInfo`:先透過 HTTP 向伺服器查詢該案件是否應使用 FTP 傳輸,並取回加密的 FTP 登入資訊。
+    *   依賴 SecureBlackbox 的 `TElSimpleFTPSClient` 建立 FTP over SSL 連線。
+    *   `SetFtpInfo`、`IIS_Ftp.FtpsConnect`、`IIS_Ftp.FtpsToMain`、`IIS_Ftp.FtpsDownloadFile`:負責實際的 FTP 登入、切換目錄、上傳與下載操作,完成後呼叫 `FtpCaseComplete` 透過 HTTP 通知伺服器傳檔結束。
+
+## 3. 安全加密與雜湊模組 (Security, Crypto & Hashing Utils)
+
+**職責**:負責資料傳輸前後的加解密運算,以及檔案完整性的 MD5 校驗,確保通訊過程不被竄改。
+**核心實作特性**:
+*   **字串加解密 (String Encryption)**:
+    *   利用 `En_DecryptionStr_Base64` 函式(可能來自自訂或第三方的 `Encryp` 單元),對 URL 參數 (如 `checktime`, `col` 欄位清單) 進行加解密,避免敏感資訊在 URL 明文中裸奔。
+    *   解析加密過的 FTP 登入資訊字串。
+*   **檔案 MD5 雜湊校驗 (File Hashing)**:
+    *   使用 Indy 的 `TIdHashMessageDigest5` 元件。
+    *   `LoadFileGetMD5`:讀取本機影像檔並計算其 MD5 值,用於比對「異動件 (ESCAN)」模式下,檔案是否與伺服器原有的版本一致,防止誤刪或重複傳輸。
+*   **憑證管理 (Certificate Management)**:
+    *   `HTTPSClientCertificateValidate`:處理 X.509 憑證驗證事件,通常設定為 `Validate := True` 以略過嚴格的自簽憑證檢查(在內部封閉網路中常見的做法)。
+
+## 4. 傳輸前置準備與封裝器 (Payload Archiver & Preparer)
+
+**職責**:在真正啟動傳輸前,將硬碟上散落的 TIFF/JPG 檔案、`.dat` 索引檔以及 `.ini` 設定檔,打包成單一的封裝檔以利傳輸。
+**核心實作特性**:
+*   **ZIP 壓縮封裝**:
+    *   依賴 `TVCLZip` (VCLZip 模組)。
+    *   `ZipMainFile`:讀取 `Context.dat` 等清單,將案件目錄下的所有影像與關聯的索引文字檔打包成 `Img.zip`。
+    *   包含檔案大小檢核邏輯:在打包完成後,檢查 ZIP 檔是否超過伺服器允許的上限 (`FMaxUploadSize`),若超過則阻擋上傳。
+*   **ZIP 解壓縮處理**:
+    *   依賴 `VCLUnZip` 模組。
+    *   `ExecuteUnZip` / `ExecuteUnZip_Pwd`:將從伺服器下載回來的 `OMRSet.zip`、`KeyinSet.zip` 或舊案件影像壓縮檔解壓縮至指定的工作目錄中,並支援帶密碼的解壓縮。
+
+---
+
+## 💡 未來重構與微服務化建議
+
+針對「安全傳輸與 API 通訊模組」,若未來系統架構演進,建議考量以下重構方向:
+
+1.  **統一且標準化的 HTTP Client (捨棄舊版第三方庫)**:
+    早期的 SecureBlackbox 雖然強大,但現代的開發環境 (如新版 Delphi 或 C#/Java/Node.js) 均已內建完善且高效的 `HttpClient`。建議將所有的 API 呼叫標準化為 RESTful API (JSON 格式),並使用原生的網路庫。
+2.  **廢除 FTP,全面改用 HTTP(S) 分塊上傳 (Chunked Upload)**:
+    目前系統需動態切換 HTTP 與 FTPS,增加了防火牆設定 (Port 21, Passive Ports) 與除錯的困難度。現代系統處理大檔上傳,主流做法是透過 HTTP/HTTPS 的 **分塊上傳 (Chunked Upload / Multipart)** 搭配斷點續傳機制,建議未來可逐步汰除 FTP 傳輸路徑。
+3.  **非同步與背景傳輸 (Asynchronous Transfer)**:
+    目前上傳時會透過 `DataLoading` 鎖死整個 UI (`Screen.Cursor := -11`),使用者必須枯等上傳完成。重構時應將 Transport Manager 放入獨立的 Thread 或背景 Service 中執行,並透過回呼 (Callback) 或事件 (Event) 更新進度條,提升使用者體驗。
+4.  **Token-based 授權取代自訂加密**:
+    目前依賴自訂的 `En_DecryptionStr_Base64` 在 URL 傳遞加密字串作為安全驗證。建議未來升級為標準的 **OAuth 2.0 (JWT Token)** 放在 HTTP Header 中進行授權,更加安全且符合現代 Web 規範。
diff --git a/doc/curtis/UI_View_Analysis.md b/doc/curtis/UI_View_Analysis.md
new file mode 100644
index 0000000..f6b4f93
--- /dev/null
+++ b/doc/curtis/UI_View_Analysis.md
@@ -0,0 +1,86 @@
+# UI 視圖與介面呈現模組 (UI View) 深度分析
+
+在 `CB_IMGPSScanImp.pas` 中,「UI 與介面呈現模組」主要負責與使用者的視覺互動,這是作為 ActiveX 控制項的核心表現形式。它管理了表單的佈局、多國語言切換、快捷鍵操作以及各種滑鼠拖拉 (Drag and Drop) 與捲動行為。
+
+以下是針對 UI View 模組的深度組成與分類分析:
+
+---
+
+## 1. 核心版面與容器管理 (Layout & Container Management)
+
+**職責**:定義整個 ActiveX 控制項的視覺區塊,並透過階層式的 Panel 進行排版管理,確保在不同解析度下能正確顯示。
+**核心實作特性**:
+*   **ActiveX 窗體繼承**:`TCB_IMGPSScanX` 繼承自 `TActiveForm`,並實作 `ICB_IMGPSScanX` 介面,是所有 UI 元件的根容器。
+*   **Panel 排版系統**:使用大量的 `TPanel` (如 `Panel1`, `Panel2`, `Panel9` 等) 與 `TSplitter` (如 `Splitter1`, `Splitter2`) 來分割畫面:
+    *   **頂部/底部工具列**:放置各種操作按鈕 (`TBitBtn`, `TButton`)。
+    *   **左側樹狀區**:放置文件結構清單 (`TreeView1`)。
+    *   **右側工作區**:通常包含影像預覽或細節設定面板 (`Panel9`, `ScrollBox1`)。
+*   **動態模式切換**:透過 `DisplayMode` 與 `GoViewMode` 根據不同的視圖模式 (VMode) 動態調整右側影像預覽區塊的排列方式 (如 1x1, 1x2, 2x2 等),並控制各 `imgp` (Panel) 的顯示與隱藏。
+
+## 2. 影像預覽與互動視窗 (Image Viewer & Interaction)
+
+**職責**:提供高效能的影像顯示功能,支援大圖縮放、拖曳平移、局部放大以及多頁縮圖並排顯示。
+**核心實作特性**:
+*   **Envision 影像元件**:深度依賴 `EnImgScr` (TImageScrollBox) 來處理大型 TIFF/JPEG 影像的渲染與捲動。
+*   **多圖預覽管理**:
+    *   主影像 (`ISB1`) 與縮圖陣列 (`ISB2` ~ `ISB8`)。
+    *   背景生成黑白影像 (`ISB_BW`) 供內部條碼辨識或影像處理使用,而不影響前端彩色顯示。
+    *   動態建立/釋放:`CreatePreViewISB` 與 `FreePreViewISB` 負責根據案件頁數動態產生縮圖物件。
+*   **滑鼠行為模式 (Mouse Mode)**:
+    *   透過 `ViewMouseMode` 函式切換 `TImageScrollBox` 的狀態,例如:放大鏡 (`mmAmplifier`)、框選縮放 (`mmZoom`)、手形拖曳 (`mmDrag`)、旋轉 (`mmR90`, `mmR180`, `mmR270`) 或刪除 (`mmDelete`)。
+    *   對應工具列按鈕 (`FC0` ~ `FC6`) 的點擊事件 (`FC0Click` ~ `FC6Click`) 來切換這些游標模式。
+*   **滑鼠與滾輪事件**:
+    *   處理自定義的滾輪捲動 (`WMMOUSEWHEEL`),同步捲動 `ScrollBox1` 或放大縮小影像 (`ZoomPercent`)。
+    *   處理影像上的點擊 (`ISBClick`) 與拖拉排序 (`ISBDragDrop`, `ISBDragOver`)。
+    *   在影像上繪製選取框 (`PaintShape`, `FreeShapeobj`)。
+
+## 3. 案件與文件樹狀檢視 (Case & Document TreeView)
+
+**職責**:以階層式樹狀結構呈現當前掃描或下載的「案件 -> 文件 -> 頁面」,並提供豐富的右鍵選單功能以管理這些節點。
+**核心實作特性**:
+*   **TTreeView 結構維護**:
+    *   `NewTreeNode`:頂層節點(如:新件、異動件)。
+    *   `MyTreeNode1`:案件層級 (CaseID)。
+    *   `MyTreeNode2`:文件層級 (DocNo/DocDir)。
+    *   `MyTreeNode3`:表單/頁面層級 (FormID)。
+*   **視覺狀態回饋**:依據節點的狀態改變圖示 (`ImageIndex`),例如:未配號、檢核失敗、完成檢核、或標記為被引用 (`GetUseCase`) 的文件。
+*   **節點資料綁定與更新**:
+    *   利用 `DrawDocItem2` 根據實體的 `.dat` 設定檔重新長出整棵樹。
+    *   利用 `NewTreeNodeRefresh`, `MyTreeNode1Refresh` 等更新節點後方的筆數或頁數統計。
+*   **右鍵選單與節點操作**:
+    *   根據選中的節點層級,動態顯示/隱藏 `PopupMenu1` 的選項 (`PopupMenu1Popup`)。
+    *   支援在樹狀圖上的拖拉移動 (`TreeView1DragDrop`) 以改變影像歸屬。
+
+## 4. 多國語言與本地化引擎 (I18N & Localization)
+
+**職責**:將 UI 介面上的所有寫死字串抽離,透過外部設定檔實現多國語言的動態切換。
+**核心實作特性**:
+*   **語言檔載入**:在初始化時透過 HTTP/FTP 下載最新的語言包 (`Language.Lng` 至 `LngPath`)。
+*   **動態介面翻譯**:`InitialLanguage` 函式。
+    *   利用 `TMemIniFile` 讀取語言檔。
+    *   遍歷表單上的所有元件 (`Components`),判斷其類型 (`TButton`, `TBitBtn`, `TMenuItem`, `TLabel`, `TListView`, `TRadioGroup` 等)。
+    *   將元件的 `Name` 作為 Key 去 Ini 檔中尋找對應的翻譯字串,並替換其 `Caption` 或 `Hint`。
+
+## 5. 系統狀態與進度回饋 (Status & Progress Feedback)
+
+**職責**:在進行耗時的網路傳輸、影像處理或資料庫比對時,鎖定 UI 並給予使用者明確的等待提示,避免重複操作。
+**核心實作特性**:
+*   **全域 UI 鎖定 (`DataLoading`)**:
+    *   當執行耗時任務時,將滑鼠游標改為漏斗 (`crHourGlass`)。
+    *   停用主要的控制面板 (`Panel1.Enabled := False`, `Panel2.Enabled := False`)。
+    *   顯示中央的進度提示面板 (`Panel22` 或 `Panel8`)。
+*   **動態文字更新**:透過 `Timer2` 定期在進度提示文字 (`ShowText`) 後方加上點號 (`...`),營造系統正在運作的視覺效果。
+*   **狀態列 (`StatusBar1`)**:顯示當前版本號 (`GetCurrentVersionNo`)、登入使用者名稱、引用狀態,以及浮動授權 (License) 的剩餘額度。
+
+---
+
+## 💡 未來重構與微服務化建議
+
+若要將此「UI View 模組」進行現代化重構 (例如轉向 Web 介面或更清晰的架構),建議考量以下方向:
+
+1.  **MVC / MVVM 架構解耦**:目前的程式碼將按鈕點擊事件 (Controller)、資料讀取 (Model) 與畫面更新 (View) 混雜在同一個 Pas 檔中。應將邏輯抽離,讓 UI 只負責「顯示資料」與「轉發命令」。
+2.  **TreeView 虛擬化 (Virtualization)**:若案件內包含極多頁面,頻繁的 `DrawDocItem2` 清空並重建樹狀節點會導致效能低落。建議改用 Virtual TreeView 或資料綁定 (Data Binding) 的方式,只渲染可見節點。
+3.  **分離多國語言引擎**:將 `InitialLanguage` 的邏輯獨立為一個全局的 `Translator` 服務,避免每個 Form 或 Frame 都需要自己實作載入邏輯。
+4.  **Web 相容性評估**:
+    *   由於深切依賴 `TImageScrollBox` 的 Windows GDI 渲染與特定的滑鼠狀態 (`TMouseMode`),若要轉為 Web (HTML5/Canvas),需尋找或實作對應的 Web Image Viewer 套件。
+    *   ActiveX 特有的 COM 介面 (`TActiveForm`, `safecall`) 將被淘汰,改以 WebSocket 或 REST API 提供狀態更新,前端由 React/Vue 等框架接手渲染。
diff --git a/doc/curtis/delphi_conventions.md b/doc/curtis/delphi_conventions.md
new file mode 100644
index 0000000..e068b7f
--- /dev/null
+++ b/doc/curtis/delphi_conventions.md
@@ -0,0 +1,249 @@
+# **Delphi 命名規範與風格指南 (Naming Conventions)**
+
+## **1. 大小寫敏感度 (Case Sensitivity)**
+
+在探討具體規範前,我們必須先釐清 Delphi 編譯器的特性:
+
+- **Delphi 是「大小寫不敏感」的 (Case-Insensitive):**
+
+  對 Delphi 編譯器而言,CaseID、caseid、CASEID 甚至 cAsEiD 都是**完全相同**的變數。這與 C++, C#, Java, JavaScript (這些是 Case-sensitive) 有著根本上的不同。
+
+- **為什麼還需要規範?**
+
+  既然編譯器不在乎,為什麼大家還是很嚴格遵守大小寫?因為**「人」在乎**。統一的大小寫規範(通常是 PascalCase)能極大提升程式碼的可讀性。
+
+- **何時大小寫「絕對」重要?**
+
+  當 Delphi 與外部世界溝通時!例如:
+
+1. 呼叫 C/C++ 寫的 DLL 函數(如 Windows API)。
+2. 處理 JSON/XML 資料解析時。
+3. 將 ActiveX/OCX 元件提供給網頁端的 JavaScript 呼叫時(這也是為什麼你在 _TLB.pas 裡會看到像 caseno 這種全小寫的屬性,因為它是為了迎合 JS/Web 的習慣)。
+
+## **2. 常見的程式命名風格 (Casing Styles)**
+
+了解以下三種風格,有助於我們理解 Delphi 的選擇:
+
+1. **PascalCase (帕斯卡命名法)**:每個單字的首字母都大寫。
+- *範例*:CalculateTotal, UserName, CaseID
+- **Delphi 的最愛**:Delphi 絕大多數的命名都基於這個風格。
+1. **camelCase (駱駝命名法)**:第一個單字全小寫,後續單字首字母大寫。
+- *範例*:calculateTotal, userName, caseId
+- **Delphi 的應用**:偶爾用於區域變數(Local Variables),但在傳統 Delphi 中不如 Java/C# 常見。
+1. **snake_case (蛇形命名法)**:全小寫,單字間用底線 _ 分隔。
+- *範例*:calculate_total, user_name, case_id
+- **Delphi 的應用**:**極少使用**。通常只出現在早期的舊程式碼,或是為了與 C 語言庫(如 SQLite, LibVLC)保持一致時才會使用。
+
+## **3. Delphi 核心命名規範 (前綴字慣例)**
+
+Delphi 最具特色的就是使用**單一字母前綴**來標示該元素的「種類」或「作用域」。
+
+| **元素類型 (Type)** | **前綴** | **命名風格** | **範例與說明** |
+| --- | --- | --- | --- |
+| **類別 (Class/Type)** | **T** | PascalCase | TForm, TCustomer
+*(T 代表 Type,所有類別與自訂型別皆以此開頭)* |
+| **介面 (Interface)** | **I** | PascalCase | IUnknown, IScanner
+*(I 代表 Interface)* |
+| **例外 (Exception)** | **E** | PascalCase | EOutOfMemory, EFileNotFound
+*(E 代表 Exception)* |
+| **指標 (Pointer)** | **P** | PascalCase | PChar, PInteger
+*(P 代表 Pointer)* |
+| **私有欄位 (Field)** | **F** | PascalCase | FCaseID, FWidth
+*(F 代表 Field,僅存在於類別的 private/protected 區段)* |
+| **屬性 (Property)** | **無** | PascalCase | CaseID, Width
+*(對外公開的屬性,通常用來讀寫對應的 F 變數)* |
+| **方法參數 (Parameter)** | **A** | PascalCase | AOwner, ACaseID
+*(A 代表 Argument,用以避免與內部 Field 撞名)* |
+
+## **4. 變數與常數命名**
+
+- **區域變數 (Local Variables)**:
+- 通常使用 **PascalCase**,不加前綴。例如:ImageStream, TotalCount。
+- 迴圈計數器習慣使用大寫字母:I, J, K。
+- **全域變數 (Global Variables)**:
+- 盡量避免使用。若必須使用,部分開發者會加上 G 前綴(如 GSystemStatus)。
+- **常數 (Constants)**:
+- 現代 Delphi 傾向直接使用 PascalCase 配合列舉。部分開發者使用 c 前綴(如 cMaxRetries)。
+
+## **5. 列舉型別 (Enumerations) 的特殊規範**
+
+Delphi 對列舉型別有非常優雅的規範:**型別以 T 開頭,列舉值以該型別的 2~3 個字母縮寫作為小寫前綴。**
+
+- *範例*:
+
+  type
+
+  TTransMode = (tsHttp, tsFtp, tsNone);
+
+  TFormAlign = (alNone, alTop, alBottom, alLeft, alRight, alClient);
+
+
+## **6. 檔案與單元 (File & Unit) 命名**
+
+在 Delphi 中,檔案名稱(.pas)與程式碼內宣告的單元名稱(unit XXX;)**必須完全一致**。
+
+- **基本規則**:使用 **PascalCase**,避免使用空白與特殊字元。
+- **視覺化窗體 (Forms)**:單元檔名通常結尾加上 Frm、Form 或 UI。
+- **資料模組 (DataModules)**:單元檔名通常結尾加上 DM。
+
+## **7. 檔案命名後綴與副檔名解析 (File Extensions & Suffixes)**
+
+在 Delphi 的專案架構中,除了單元名稱外,副檔名與特定的檔名後綴也承載了重要的架構意義。
+
+### **7.1 檔名後綴 _TLB**
+
+當你開發或匯入 COM、ActiveX 或 Automation Server 時,Delphi IDE 會自動生成以 _TLB 結尾的檔案(例如 CB_IMGPSScan_TLB.pas)。
+
+- **意義**:TLB 是 **Type Library (類型庫)** 的縮寫。
+- **作用**:Type Library 本身是一個二進位檔案,用來跨語言描述 COM 元件的介面。Delphi 為了讓 Object Pascal 能呼叫這些介面,會將其反編譯成 .pas 程式碼,並自動加上 _TLB 後綴。
+- **⚠️ 核心規範**:**絕對不要手動修改 _TLB.pas 檔案的內容!** 只要你在 IDE 中重新整理 Type Library,這個檔案就會被完全覆蓋重寫。若要實作功能,應寫在對應的 _Imp.pas 或其他單元中。
+
+### **7.2 常見的 Delphi 副檔名**
+
+以下是 Delphi 專案中常見的副檔名及其具體用途:
+
+| **副檔名** | **類型** | **說明** |
+| --- | --- | --- |
+| **.pas** | 原始碼 (Source) | **Pascal Source File**。最常見的程式碼檔案(單元/Unit),包含介面宣告 (interface) 與實作邏輯 (implementation)。 |
+| **.dpr** | 專案檔 (Project) | **Delphi Project**。專案的主進入點,定義這是一個執行檔 (program) 還是程式庫 (library),並包含專案的啟動邏輯與引入單元列表。 |
+| **.dfm** | 介面檔 (Form) | **Delphi Form**。儲存視覺化窗體 (Form) 或資料模組 (DataModule) 上所有元件的屬性與佈局設定。一定與同名的 .pas 檔成對出現。 |
+| **.dcu** | 編譯檔 (Compiled) | **Delphi Compiled Unit**。.pas 檔案成功編譯後產生的二進位結果。最終連結器 (Linker) 會將這些 .dcu 打包成 EXE 或 DLL。 |
+| **.res** | 資源檔 (Resource) | **Compiled Resource File**。二進位資源檔,包含應用程式圖示 (Icon)、版本資訊或夾帶的檔案。通常在 .dpr 中用 {$R *.res} 編譯指令引入。 |
+| **.tlb** | 類型庫 (Type Lib) | **Type Library**。微軟 COM 標準的二進位檔案,用來描述 ActiveX 元件對外公開的介面、方法與屬性,供其他語言(如 C++, JS)參考呼叫。 |
+| **.ridl** | 介面定義 (RIDL) | **Restricted Interface Definition Language**。較新版 Delphi 用來取代舊式二進位 .tlb 的純文字介面定義檔。開發者可以透過文字或 IDE 編輯它,編譯時會自動生成對應的 .tlb 與 _TLB.pas。 |
+| **.ocx** | 控件擴充檔 | **OLE Control Extension**。本質上是一個特殊格式的 DLL(動態連結函式庫),內部包含了 ActiveX 控件。Windows 系統可以透過 regsvr32 註冊它,讓 IE 瀏覽器或其他應用程式嵌入使用。 |
+
+## **8. Delphi 架構與現代語言概念對應 (Architecture Mapping)**
+
+對於習慣 C#、Java、Python 或 JavaScript 的開發者,了解 Delphi 專屬的結構名詞如何對應到現代語言是非常重要的。
+
+### **8.1 Namespace (命名空間)**
+
+- **現代語言對應**:等同於 C# 的 namespace、Java 的 package,或是 C++ 的 namespace,用來組織程式碼並避免名稱衝突。
+- **Delphi 的對應**:
+- **早期 Delphi (如 Delphi 7/2007)**:沒有明確的 Namespace 關鍵字,**unit (單元) 本身就充當了扁平化的命名空間**。為避免撞名,開發者強烈依賴「前綴字」(例如 Indy 網路套件都以 Id 開頭,如 IdHTTP;Envision 影像套件以 En 開頭,如 EnScan)。
+- **現代 Delphi (XE2 以後)**:正式引入了 **Dotted Unit Names (點綴命名)** 作為 Namespace 的支援。例如原先的 SysUtils.pas 變成了 System.SysUtils.pas,Forms.pas 變成了 Vcl.Forms.pas。
+
+### **8.2 Class (類別)**
+
+- **現代語言對應**:等同於 C# / Java / TS 的 class。
+- **Delphi 的對應**:同樣使用 class 關鍵字,但在 Delphi 中必須宣告於 type 區塊之下。如前文所述,類別名稱慣例上**必須以大寫 T 開頭**(例如 TMainForm)。實體化時,Delphi 是呼叫建構子方法(如 TMyClass.Create),而不是使用 new 關鍵字。
+
+### **8.3 Unit (單元, .pas)**
+
+- **現代語言對應**:等同於 ES6 的 **Module (.js/.ts)**、Python 的 **Module (.py)**,或是 C/C++ 中 .h (標頭檔) 與 .cpp (原始檔) 的綜合體。
+- **Delphi 的對應**:unit 是 Delphi 程式碼封裝的最核心基礎。一個完整的 unit 會被劃分為兩個主要區塊:
+- **interface (介面區)**:等同於對外輸出的 API 或 Header,這裡宣告的型別與函式可透過 uses 關鍵字被其他檔案呼叫。
+- **implementation (實作區)**:等同於內部的私有邏輯實作。在這裡宣告的變數或函式,對外部檔案是完全隱藏的。
+
+### **8.4 Library (程式庫, .dpr)**
+
+- **現代語言對應**:等同於 C# 的 **Class Library 專案**、Node.js 的原生 C++ 附加元件,或 C/C++ 的 **Shared Library / 動態連結檔**。
+- **Delphi 的對應**:在專案原始檔中(.dpr),如果開頭宣告為 library(而非一般視窗程式的 program),代表它的編譯目標是一個不具獨立執行程序的主體,通常會編譯為 **.dll** 或 **.ocx**。這類專案主要透過 exports 關鍵字,將內部的函式暴露給作業系統或其他語言的程式(如 C++ 或網頁瀏覽器)來呼叫。
+
+
+## **9 Compiler Directive**
+
+在 Delphi (Object Pascal) 中,`{ }` 符號的意義取決於緊跟在 `{` 後面的第一個字元。這是一個非常基礎但關鍵的語法,讓我們來拆解你的疑問:
+
+---
+
+### 9.1 `{ }` 符號的基本意義:註解 (Comments)
+
+在最基本的情況下,`{ }` 是 **「區塊註解」**。編譯器會完全忽略裡面的內容。
+
+* **`{ TCB_IMGPSScanX }`**:這是一段 **註解**。
+    * **作用**:通常開發者寫這行是為了告訴讀程式碼的人:「接下來這一段程式碼是屬於 `TCB_IMGPSScanX` 類別的實作」。它對程式執行**沒有任何影響**。
+* **`TCB_IMGPSScanX`**:這是一段 **程式碼 (識別碼)**。
+    * **作用**:編譯器會去尋找名為 `TCB_IMGPSScanX` 的類別、型別或變數。如果沒定義,編譯就會報錯。
+
+---
+
+### 9.2 `{$ }` 符號的進階意義:編譯指令 (Compiler Directives)
+
+當 `{` 後面緊跟著 **`$`** 字元時,它就從「註解」變成了 **「編譯指令」**。這不是給人看的,而是**給編譯器下的指令**。
+
+#### 關於 `{$I filename}` (Include 指令)
+你看到的 `{$I ...}` 是 **Include Directive**。
+
+* **作用**:它的功能就像是編譯器的「複製貼上」工具。它告訴編譯器:「在編譯這行時,請先去把 `CB_IMGPSScanImp_UI.pas` 檔案裡的文字**原封不動地抓過來,塞到這個位置**,然後再繼續往下編譯」。
+* **目的**:這通常用來處理非常巨大的程式碼檔案。就像你之前的 `CB_IMGPSScanImp.pas` 檔案太長了,開發者把它拆成小檔案,最後用這種方式在主檔「匯合」。
+
+---
+
+### 9.3 解析你的範例語法
+
+你提到的這一段:
+`{$I CB_IMGPSScanImp_UI.pas}{$I CB_IMGPSScanImp_Scan.pas}...initialization`
+
+#### 這是在做什麼?
+這既不是定義,也不是宣告,更不是字串。它是一種 **「程式碼組合行為」**。
+
+1.  **組合實作內容**:編譯器會依序讀入 `UI.pas`、`Scan.pas`、`Data.pas`、`Utils.pas`。這四個檔案裡放的通常是 `TCB_IMGPSScanX` 的各種 `procedure` 和 `function` 實作。
+2.  **銜接初始化區段**:當上述所有檔案的內容都被「貼進來」後,程式碼剛好接到了 `initialization` 關鍵字。
+
+#### 語法邏輯如下:
+```pascal
+implementation
+
+// 編譯器開始貼上檔案
+[貼上 UI.pas 的內容]
+[貼上 Scan.pas 的內容]
+[貼上 Data.pas 的內容]
+[貼上 Utils.pas 的內容]
+
+// 貼完後,剛好銜接這支單元的初始化邏輯 (AxCtrl)
+initialization
+  TActiveFormFactory.Create(...);
+  SetLicenseKey(...);
+end.
+```
+
+### 總結
+* **`{ ... }`** = 註解(編譯器不看)。
+* **`{$I ...}`** = 編譯器指令(叫編譯器去別的檔案搬程式碼過來貼上)。
+* **為什麼這樣寫?** 這是為了讓主檔保持簡潔。主檔只負責「宣告結構」和「啟動初始化」,而「具體的細節邏輯」則被藏在那些被 Include 的檔案裡。
+
+
+## 10. 註解語法與風格慣例 (Comments Style)
+
+Delphi 提供三種主要的註解方式,以及一些開發者社群常用的視覺化風格:
+
+### 10.1 單行註解 (`//`)
+
+- **用法**:從 `//` 開始到該行結束。
+- **視覺強調 (`////`)**:
+    - 你在源碼中看到的 `////` 語法上等同於 `//`。
+    - **開發者意圖**:通常用於**「標題化」**或**「強力分隔」**。多個斜線能在視覺上形成橫條效果,幫助開發者在快速捲動程式碼時一眼認出關鍵區塊(例如:`//// ***** 預設區 ***** ////`)。
+
+### 10.2 區塊註解 (`{ }`)
+
+- **用法**:被 `{ }` 包圍的所有文字。
+- **特點**:常用於長篇說明的標註,或是在調試時暫時關閉一整段程式碼。
+- **編譯指令**:若開頭為 `{$`(如 `{$R *.DFM}`),則代表它是給編譯器的指令,而非一般註解。
+
+### 10.3 替代區塊註解 (`(* *)`)
+
+- **用法**:由 `(*` 開始到 `)` 結束。
+- **主要用途 (註解嵌套)**:當你想要註解掉一段已經包含 `{ }` 註解的程式碼時,Delphi 規定 `{ }` 不能包在另一對 `{ }` 裡面,此時必須改用 `(* ... *)` 來包裹,才能正確註解。
+
+### 10.4 文件化註解 (`///` XML Documentation)
+
+- **用法**:在方法上方使用連續三個斜線。
+- **作用**:現代 Delphi IDE (XE 以後) 會解析這類註解,並在鼠標懸停於方法名上時顯示提示說明(類似 JavaDoc 或 C# XML Doc)。
+
+### 10.5 分隔線風格示例
+
+在大型檔案(如 `CB_IMGPSScanImp.pas`)中,常用註解來劃分功能界線:
+
+```
+// ********************************************************************* //
+// 這是區塊分隔線風格,常用於自動生成的 TLB 檔
+// ********************************************************************* //
+
+{-----------------------------------------------------------------------}
+{  這是另一種常見的手寫分隔線風格                                          }
+{-----------------------------------------------------------------------}
+```
+
+
diff --git a/doc/curtis/index.md b/doc/curtis/index.md
new file mode 100644
index 0000000..6bb2376
--- /dev/null
+++ b/doc/curtis/index.md
@@ -0,0 +1,15 @@
+
+## TableOfContent
+- [IO_說明.md](IO_%E8%AA%AA%E6%98%8E.md)
+- [ScanImp_分析.md](ScanImp_%E5%88%86%E6%9E%90.md)
+- [介面實作.md](%E4%BB%8B%E9%9D%A2%E5%AF%A6%E4%BD%9C.md)
+- [delphi_專案必讀.md](delphi_%E5%B0%88%E6%A1%88%E5%BF%85%E8%AE%80.md)
+- [EnScan_拆解.md](EnScan_%E6%8B%86%E8%A7%A3.md)
+
+
+
+- 各生命周期 or diagram
+- Remote/Local IO 方法
+- Remote/Local IO 抽象介面
+- OCX 抽像介面
+- 
diff --git "a/doc/curtis/remote_\347\233\270\351\227\234\346\226\271\346\263\225.md" "b/doc/curtis/remote_\347\233\270\351\227\234\346\226\271\346\263\225.md"
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ "b/doc/curtis/remote_\347\233\270\351\227\234\346\226\271\346\263\225.md"
diff --git "a/doc/curtis/\345\210\206\346\236\220_\345\260\232\351\200\262\350\241\214\344\270\255.md" "b/doc/curtis/\345\210\206\346\236\220_\345\260\232\351\200\262\350\241\214\344\270\255.md"
new file mode 100644
index 0000000..a454c84
--- /dev/null
+++ "b/doc/curtis/\345\210\206\346\236\220_\345\260\232\351\200\262\350\241\214\344\270\255.md"
@@ -0,0 +1,830 @@
+
+
+# **相依套件分析報告**
+
+本報告針對 ActiveX 元件核心實作檔 CB_IMGPSScanImp.pas 進行功能解構,並分析其與第三方套件的綁定關係,以作為後續維護或現代化升級之參考。
+
+## **壹、 依功能拆分模組與第三方套件綁定分析**
+
+根據原始碼結構,CB_IMGPSScanImp.pas 是一個將介面、硬體、網路與業務邏輯高度耦合的「上帝物件 (God Object)」。若要進行重構或拆件,建議依據以下五個核心模組進行解耦:
+
+### **1. 硬體掃描控制模組 (Scanner Controller)**
+
+- **功能描述**:負責與實體掃描機溝通,處理 TWAIN 介面初始化、設定掃描參數(DPI、色彩、雙面)、觸發掃描指令,以及接收掃描完成的記憶體影像 (DibHandle)。
+- **關鍵方法**:initkscan、StatrTwainScan、OnAcquire、PageEnd、PageDone。
+- **第三方套件綁定 (強綁定)**:
+- 依賴 **Envision Imaging SDK** (EnScan) 進行 TWAIN 驅動控制。
+- 依賴 EnMisc 處理底層記憶體或雜項運算。
+
+### **2. 影像處理與轉換模組 (Image Processor)**
+
+- **功能描述**:負責對擷取到的原始影像進行後製處理,包括:裁切(如 A3 裁 A4)、去斜 (Deskew)、旋轉、二值化 (轉黑白)、格式轉換 (轉 TIFF/JPEG),以及讀取影像上的條碼。
+- **關鍵方法**:ImageReSize_FormID、CheckNeedCrop、DeskewImg、ConvertToBW。
+- **第三方套件綁定 (強綁定)**:
+- 依賴 **Envision Imaging SDK** (EnTifGr, EnDiGrph) 進行 TIFF (CCITT Group 4) 壓縮與 DIB 物件封裝。
+- 依賴 **MPS Barcode** (mpsBarco, BarcodesFinder) 進行影像條碼掃描與解析。
+
+### **3. 安全傳輸與 API 通訊模組 (Transport Manager)**
+
+- **功能描述**:負責將掃描並壓縮後的檔案上傳至伺服器,或從伺服器下載檔案。同時處理與後端 Java Servlet 的參數交換(如校時、取得 FTP 資訊、更新案件狀態)。
+- **關鍵方法**:upFile、dnFile_Get、ProcessServlet_Get、GetServerDate、GetftpInfo。
+- **第三方套件綁定 (強綁定)**:
+- 依賴 **SecureBlackbox** (SBSimpleSSL, SBHTTPSClient, SBSimpleFTPS 等) 處理 HTTPS/FTPS 安全加密通訊。
+- 依賴 **Indy** (IdHashMessageDigest) 產生檔案的 MD5 檢核碼。
+- 依賴自訂/第三方加密庫 (Encryp) 處理字串加解密。
+
+### **4. 業務邏輯與資料解析模組 (Business Logic & Parser)**
+
+- **功能描述**:專案核心的領域邏輯,包含接收網頁端傳入的參數字串進行解析、定義文件歸類邏輯(由條碼推導文件類型)、OMR (光學標記辨識) 檢核定義等。
+- **關鍵方法**:SetSQLData (負責解析傳入的長字串至 TStringList)、GetSQLData、FormCode2DocNo、OMRCheckCase。
+- **第三方套件綁定 (中度綁定)**:
+- 依賴 **Xmltool** 解析 XML 格式的 OMR 座標定義。
+- 依賴 **VCLZip** (VCLZip, VCLUnZip) 將多個影像檔打包成 ZIP 進行單一傳輸。
+
+### **5. UI 與介面呈現模組 (UI View)**
+
+- **功能描述**:負責 ActiveX 控制項的視覺化介面,包含左側的樹狀文件清單 (TreeView)、右側的影像預覽區 (ScrollBox),以及按鈕與多國語言切換。
+- **關鍵方法**:InitialLanguage、各類 OnClick 事件。
+- **第三方套件綁定 (輕度綁定)**:
+- 依賴 **Envision Imaging** (EnImgScr) 作為支援大影像拖曳的滾動視窗。
+- 依賴 PJMenuSpeedButtons 作為自訂外觀的按鈕元件。
+
+## **貳、 第三方套件功能總覽**
+
+為達成上述複雜的業務需求,本專案引入了多個 Delphi 著名的第三方套件。以下為各套件的大致功能說明:
+
+### **1. Envision Imaging SDK (前綴 En)**
+
+這是一套專為 Delphi 設計的高效能影像與 TWAIN 處理套件,在金融與保險業的文件電子化系統中非常常見。
+
+- **EnScan**:封裝了 TWAIN 協定,讓程式能直接控制實體掃描機,控制進紙、解析度與雙面掃描。
+- **EnDiGrph (TDibGraphic)**:封裝 Windows 底層的 DIB (Device Independent Bitmap) 記憶體句柄,讓開發者能像操作一般圖片一樣操作掃描出來的原始資料。
+- **EnTifGr**:專門處理 TIFF 影像格式。銀行業愛用 TIFF 是因為它支援「多頁」且黑白壓縮率極高 (Group 4 Fax Compression)。
+- **EnImgScr**:提供 TImageScrollBox 視覺元件,用來平滑顯示並縮放超大尺寸的掃描圖檔。
+- **EnMisc**:提供影像處理所需的底層輔助數學或資料轉換函式。
+
+### **2. SecureBlackbox (前綴 SB)**
+
+由 EldoS (後被 /n software 收購) 開發的強大安全通訊與加密套件。由於早期 Delphi (D7~D2007) 內建網路庫缺乏完善的 SSL/TLS 支援,此套件被廣泛用於補強安全性。
+
+- **SBHTTPSClient / SBSimpleSSL**:實作了完整的 HTTPS 用戶端通訊協定,用來安全地上傳檔案或呼叫 Servlet API。
+- **SBSimpleFTPS**:支援 FTP over SSL (FTPS) 的安全檔案傳輸。
+- **SBWinCertStorage / SBX509**:處理 Windows 系統內的憑證儲存區,以及 X.509 數位憑證的驗證(例如確認銀行伺服器的 HTTPS 憑證是否合法)。
+
+### **3. MPS Barcode & BarcodesFinder**
+
+- **功能**:這是一套條碼識別引擎。
+- **專案應用**:在掃描過程中(如 PageDone 或 OnAcquire 階段),它會掃描圖片特定區域尋找一維或二維條碼。讀取到的條碼值會被用來決定這張影像屬於哪一種「文件表單」(FormCode),進而實現自動分類歸檔。
+
+### **4. VCLZip (VCLZip, VCLUnZip)**
+
+- **功能**:老牌的 Delphi ZIP 壓縮元件。
+- **專案應用**:為了節省網路頻寬與減少伺服器連線次數,掃描完成的多張 TIFF/JPG 檔案會被打包成一個 .zip 檔後,再一次性上傳至伺服器。
+
+### **5. Indy Components (前綴 Id)**
+
+- **IdHashMessageDigest / idHash**:Delphi 內建的 Internet Direct (Indy) 函式庫。
+- **專案應用**:在此專案中被用來計算檔案或字串的 **MD5 Hash (雜湊值)**。通常用於確保檔案上傳過程沒有損壞,伺服器比對 MD5 一致才算上傳成功。
+
+### **6. 其他工具 (Tools & Utils)**
+
+- **Xmltool**:負責讀寫 XML 檔案。銀行經常將表單的 OMR (光學標記辨識) 檢核座標或參數寫成 XML 設定檔,透過此工具讀入系統。
+- **Encryp**:這可能是開發商自訂或第三方的輕量級加密單元,用來加密本機設定檔 (.ini) 內的敏感資訊或混淆網頁傳入的參數。
+
+# **核心源碼與物件實作解析**
+
+本文件針對 CB_IMGPSScanImp.pas 中的核心方法與隱藏物件進行原始碼級別的邏輯拆解與推導。
+
+## **壹、 核心方法源碼說明**
+
+### **1) TCB_IMGPSScanX.GetCurrentVersionNo**
+
+- **功能描述**:取得目前 OCX 元件的版本號。這通常提供給網頁端的 JavaScript 呼叫,用來判斷客戶端的 OCX 是否需要觸發更新下載。
+- **實作推導與底層 API 說明**:
+
+  在 Delphi 中,若要動態讀取編譯進 OCX 的 VS_VERSION_INFO 資源,標準作法是呼叫一系列的 Windows API。這段實作通常包含以下三個關鍵概念:
+
+1. **HInstance (實體句柄)**:
+- 這是 Delphi 提供的一個全域變數,代表目前載入記憶體中的模組(即這個 OCX 檔)的「實體句柄 (Instance Handle)」。
+- 在 Windows 作業系統中,當一個執行檔 (EXE) 或動態連結檔 (DLL/OCX) 被載入記憶體時,會獲得一個記憶體基底位址,HInstance 就是指向這個位址的指標。Windows 需要這個值來識別「你要操作的是哪一個載入的模組」。
+1. **GetModuleFileName 的作用**:
+- 這是一個 Windows API。它的作用是利用前面提到的 HInstance,向作業系統反查出這個模組在硬碟上的**「完整實體檔案路徑」**(例如:C:\Windows\Downloaded Program Files\CB_IMGPSScan.ocx)。
+- 因為我們需要讀取檔案本身的版本資訊,程式必須先知道「我自己到底存放在硬碟的哪裡」。
+1. **後半段 VerQueryValue 的運作邏輯**:
+
+   取得檔案路徑後,讀取版本資訊會經過三部曲,而 VerQueryValue 是最後負責「解析」的關鍵:
+
+- **Step 1 (GetFileVersionInfoSize)**:先問 Windows 這個檔案的版本資訊區塊有多大。
+- **Step 2 (GetFileVersionInfo)**:把整塊版本資訊的二進位原始資料 (Raw Data) 完整讀進一段記憶體緩衝區中。
+- **Step 3 (VerQueryValue)**:因為剛剛讀進來的是一包無法直接閱讀的二進位資料,VerQueryValue 的作用就是**「在這包資料中進行精準查詢」**。透過傳入特定的查詢路徑(例如傳入 \ 可以取得包含主版號、次版號的 VS_FIXEDFILEINFO 結構體;或是傳入特定語系代碼如 \StringFileInfo\040404E4\FileVersion),作業系統會幫你把二進位資料解析成我們需要的字串或數字版本號(如 1.0.3.5)。
+
+### **2) TCB_IMGPSScanX.ActiveFormCreate**
+
+- **功能描述**:這是 ActiveX 視覺化窗體 (Form) 的生命週期起點。當 IE 瀏覽器或應用程式載入這個 OCX 時,首先觸發的初始化事件。
+- **實作推導**:
+
+  它會負責初始化全域變數、設定第三方元件的預設值、並建立暫存資料夾。
+
+    ```pascal
+     procedure TCB_IMGPSScanX.ActiveFormCreate(Sender: TObject);
+      begin
+        // 1. 預設變數初始化
+        Def_DeviceDelete := True;
+        Def_ScannerReverse := False;
+    
+        // 2. 建立本機暫存目錄
+        ForceDirectories('C:\Temp\IMGPSScan');
+    
+        // 3. UI 語系初始化
+        InitialLanguage;
+      end;
+    ```
+
+
+### **3) TCB_IMGPSScanX.StatrTwainScan**
+
+- **功能描述**:啟動掃描機的 TWAIN 介面,開始進紙或掃描。(註:Statr 應為 Start 的早期拼字錯誤,這在舊專案中很常見)。
+- **實作推導**:
+
+  這個方法會讀取網頁傳進來的參數(如 DPI、色彩),設定給 Scanner 物件,然後發出擷取指令。
+
+    ```pascal
+      procedure TCB_IMGPSScanX.StatrTwainScan;
+      begin
+        // 設定解析度與顏色
+        Scanner.Resolution := StrToIntDef(Fimgdpi, 200);
+        if Fscancolor = 'C' then
+          Scanner.PixelType := ptColor
+        else
+          Scanner.PixelType := ptGray;
+    
+        // 啟動掃描 (會喚起實體掃描機)
+        Scanner.Acquire; 
+      end;
+    ```
+
+
+### **4) TCB_IMGPSScanX.OnAcquire 與資料流物件**
+
+- **功能描述**:這是 Scanner (EnScan) 最核心的事件。當掃描機成功掃完「一張」影像並傳入電腦記憶體時,會觸發此事件。
+- **源碼邏輯推導**:
+
+    ```pascal
+    procedure TCB_IMGPSScanX.ScannerAcquire(Sender: TObject; DibHandle: THandle; var Handled: Boolean);
+      var
+        MyStream: TMemoryStream;
+        MyGraphic: TDibGraphic;
+      begin
+        // 1. 將 DibHandle 轉換為 Delphi 影像物件
+        MyGraphic := TDibGraphic.Create;
+        MyGraphic.Handle := DibHandle;
+    
+        // 2. 影像處理 (如去斜、黑白轉換)
+    
+        // 3. 存入記憶體串流或實體檔案
+        // ...
+      end;
+    ```
+
+- **三大核心資料物件解釋**:
+1. **DibHandle**:這是 Windows 底層的「全域記憶體句柄 (Global Memory Handle)」。掃描機驅動把圖片放在記憶體裡,給你這個代號。你必須透過 TDibGraphic 來「解讀」這塊記憶體。
+2. **TMemoryStream**:**記憶體串流**。它的作用像是一塊存在 RAM 裡的虛擬硬碟。掃描後的圖檔在還沒存到實體硬碟前,會先放在這裡進行格式轉換 (如轉成 JPEG) 或進行 MD5 計算,因為在記憶體中操作速度最快。
+    - **DeleteStm : TMemoryStream 的逐行操作說明**:
+      在 `OnAcquire` 事件中,`DeleteStm` 主要用於「空白頁判定」。其源碼邏輯如下:
+
+    ```pascal
+    // 判定是否啟動空白頁刪除功能
+    if Def_DeviceDelete then
+    begin
+      // 1. 在 Heap 記憶體中建立一個暫存串流物件
+      DeleteStm := TMemoryStream.Create;
+      try
+        // 2. 將當前掃描到的影像物件 (MyGraphic) 寫入記憶體串流
+        // 這會根據 TIFF G4 等格式進行壓縮,產生實際的檔案位元組資料
+        MyGraphic.SaveToStream(DeleteStm);
+    
+        // 3. 核心判定:檢查該影像在記憶體中所佔用的位元組大小 (Size)
+        // 若小於預設門檻值 (Def_DeviceDeleteSize, 如 3072 Bytes)
+        if DeleteStm.Size < Def_DeviceDeleteSize then
+        begin
+          // 4. 若符合空白頁特徵,則不進行存檔動作,直接跳出此 Procedure
+          // 並告知掃描控制項此頁已處理完畢 (Handled := True)
+          Handled := True;
+          Exit;
+        end;
+      finally
+        // 5. 無論是否為空白頁,操作結束後必須釋放記憶體,避免 Memory Leak
+        DeleteStm.Free;
+      end;
+    end;
+    ```
+    
+   - 
+3. **TFileStream**:**檔案串流**。用來直接對硬碟讀寫資料。當確認影像無誤後,會透過 TFileStream 將 TMemoryStream 的內容真實地寫入 C:\Temp\...\001.tif 中。
+
+### **5) TCB_IMGPSScanX.FindISB2View**
+
+- **功能描述**:用來在畫面上尋找並更新用來預覽圖片的元件。
+- **名詞解釋**:**ISB 代表 ImageScrollBox**。
+
+  這對應到 uses 區段中的 EnImgScr 套件。TImageScrollBox 是 Envision 提供的一個 UI 元件,專門用來顯示超出螢幕大小的掃描圖檔,支援平滑拖曳與縮放。這個方法通常用來把剛掃描完的 DibHandle 餵給畫面上的 ISB 元件顯示。
+
+
+### **6) TCB_IMGPSScanX.GetNoNameCase**
+
+- **功能描述**:處理「無案號」或「未知歸屬」的掃描件。
+- **源碼實作逐行說明**:
+
+  此方法透過迴圈尋找一個尚未被使用的目錄名稱(格式為「未配號 + 四位數字」)。
+
+
+```pascal
+Function TCB_IMGPSScanX.GetNoNameCase(Path:String):String; // 取未配號XXXX
+var
+  i : Integer; // 宣告迴圈計數器
+begin
+  // 1. 啟動一個從 1 到 9999 的迴圈,尋找可用的索引值
+  for i := 1 to 9999 do
+  begin
+    // 2. 檢查特定路徑下的目錄是否已存在
+    // _Msg('未配號'):取得「未配號」字串(可能具備多國語言處理)
+    // Add_Zoo(i, 4):將數字 i 補齊為 4 位數(例如 1 變為 0001)
+    if Not DirectoryExists(Path + _Msg('未配號') + Add_Zoo(i, 4)) then
+    begin
+      // 3. 若該目錄不存在,代表此名稱可用,設定 Result 並跳出迴圈
+      Result := _Msg('未配號') + Add_Zoo(i, 4);
+      Break; // 找到第一個可用的名稱後立即停止搜尋
+    end;
+  end;
+end;
+```
+
+### **7) TCB_IMGPSScanX.SetSQLData 與 8) GetSQLData**
+
+這兩個方法是 OCX 與網頁 (JS) 溝通的雙向橋樑。
+
+- **SetSQLData (網頁 -> OCX)**:接收由網頁傳來的設定字串(通常用 | 或 , 分隔,例如 192.168.1.1|L12345678|200|C),在內部將字串切開 (Split),並分別賦值給 ServerIP, FCaseID, Fimgdpi, Fscancolor 等內部變數。
+- **GetSQLData (OCX -> 網頁)**:將 OCX 內部的處理結果(例如:UploadSuccess|3|0 代表上傳成功、共 3 頁、0 錯誤),組合成一個長字串後回傳給網頁端的 JS 進行後續的頁面跳轉或提示。
+
+### **8) TCB_IMGPSScanX.GetDefScanIni**
+
+- **功能描述**:取得並套用掃瞄參數的預設值與自訂設定。
+- **源碼實作解析**:
+    - **硬編碼預設值 (Hardcoded Defaults)**:
+
+      程式一開始會先寫死一組標準值,例如 Def_ScanDpi := 300 (預設 300 DPI)、Def_DeviceDeleteSize := 3072 (空白頁判定門檻為 3KB)。
+
+    - **動態配置覆蓋 (Dynamic Overriding)**:
+
+      透過 for i := 0 to WORK_INF_List.Count - 1 do 迴圈遍歷設定檔清單。使用 GetSQLData 取得參數代號 (PARA_NO) 與內容 (PARA_CONTENT)。
+
+- **屬性設定對照表**:
+
+  下表整理了此方法中設定的所有關鍵屬性、其對應的參數代號及功能說明。
+
+  | **屬性名稱 (內部變數)** | **對應 PARA_NO** | **PARA_CONTENT 處理方式(GetSQLData)** | **功能說明** |
+      | --- | --- | --- | --- |
+  | **Def_DeviceDelete** | SCAN_BLANKDEL_USE | 'Y' -> True, Else -> False | 空白頁自動刪除開關。 |
+  | **Def_DeviceDeleteSize** | SCAN_BLANKDEL_SIZE | StrToInt (若空則 0) | 空白頁判定門檻 (Bytes)。 |
+  | **Def_ScannerReverse** | SCAN_REVERSE | 'Y' -> True, Else -> False | 影像是否反相。 |
+  | **Def_BoardClear** | SCAN_BOARDCLEAR | 'Y' -> True, Else -> False | 是否清除影像黑邊。 |
+  | **Def_ScanDpi** | SCAN_DPI | StrToInt (若空則 300) | 掃描解析度。 |
+  | **Def_ScanDuplex** | SCAN_DUPLEX | 'Y' -> True, Else -> False | 是否啟用雙面掃描。 |
+  | **Def_ScanRotate** | SCAN_ROTATE_MODE | '0'->0, '1'->270, '2'->180, '3'->90 | 掃描旋轉角度映射。 |
+  | **Def_ScanDeskew** | SCAN_DESKEW | 'Y' -> True, Else -> False | 是否自動矯正傾斜。 |
+  | **Def_ScanImgSetUse** | SCAN_IMGSET_USE | 'Y' -> True, Else -> False | 是否使用亮度/對比設定。 |
+  | **Def_ScanBright** | SCAN_BRIGHT | StrToInt (限制 -255~255) | 亮度數值。 |
+  | **Def_ScanContrast** | SCAN_CONTRAST | StrToInt (限制 -255~255) | 對比數值。 |
+  | **Def_ScanImgShowMode** | SCAN_SHOW_MODE | '0','1','2' 對應模式 | 影像顯示/縮放模式。 |
+  | **ScanDenialTime** | CASE_IN_TIME | 直接存為 String | 進件截止時間限制。 |
+  | **ScanDenialHint** | SCAN_HINT | 直接存為 String | 掃描畫面提示字串。 |
+  | **NoSaveBarCodeList** | NO_SAVE_FORM_ID | CommaText := Value | 不存檔之表單代號清單。 |
+  | **ImagePath** | LOCAL_PATH | 直接存為 String | 本機端暫存路徑。 |
+  | **GuideFormIDList** | GUIDEFORMID | CommaText := Value | 導引頁表單 ID 清單。 |
+  | **DivPageFormIDList** | DIVPAGEFORMID | CommaText := Value | 分案頁表單 ID 清單。 |
+  | **FJpgCompression** | FILE_COMPRESSION | StrToInt | JPG 轉 TIF 壓縮比。 |
+  | **FMaxUploadSize** | MAX_UPLOAD_SIZE | 直接存為 String | 上傳大小限制 (MB)。 |
+
+## **貳、 記憶體直接操作實作清單**
+
+以下條列專案中直接涉及記憶體操作的程式區段:
+
+### **記憶體操作對應位置表**
+
+| **記憶體操作對象** | **所屬 Function / Procedure** | **關鍵操作關鍵字 / 代碼** | **記憶體特性說明** | 註記 |
+| --- | --- | --- | --- | --- |
+| **HInstance** | GetCurrentVersionNo | GetModuleFileName(HInstance, ...) | 模組載入位址。 | 增API版本號 |
+| **資源緩衝區** | GetCurrentVersionNo | VerQueryValue, GetFileVersionInfo | 透過 Pointer 進行二進位搜尋。 | 增API版本號 |
+| **DibHandle** | onAcquire | MyGraphic.Handle := DibHandle; | Windows 全域記憶體句柄轉移。 | 改套件實作/Rust |
+| **TMemoryStream** | onAcquire | MemoryStream.Write, .Read | Heap Memory 內部二進位操作。 |  |
+
+## **參、 遺失物件反推與說明**
+
+你提到在原始碼中找不到 _DelTree 和 Scanner 的實作,這是因為它們屬於以下兩種情況:
+
+### **1) TCB_IMGPSScanX._DelTree**
+
+- **這是一個自訂的私有輔助函式 (Private Helper)**。
+- **功能**:它的名稱源自 DOS 時代的指令 deltree(刪除整個目錄樹)。在 ActiveX 中,當上傳伺服器成功後,必須清空 C:\Temp\案件編號\ 裡的所有暫存圖檔與資料夾以釋放空間,並防止資料外洩。
+- **實作原理**:由於早期的 Delphi 沒有內建遞迴刪除目錄的單一指令,開發者通常會自己寫一個 _DelTree,裡面使用 FindFirst, FindNext 找出所有檔案並用 DeleteFile 刪除,最後用 RemoveDir 砍掉資料夾。
+
+### **2) Scanner**
+
+- **這是一個視覺化/非視覺化的第三方元件實例 (Component Instance)**。
+- **為何找不到宣告?** 因為在 Delphi 中,如果你是透過 IDE 的工具箱 (Tool Palette) 將 TEnScan 元件直接拖拉到窗體 (Form) 上,IDE 會自動把它寫在 .dfm 檔裡,並在 TCB_IMGPSScanX 類別的 published 區段自動產生一行 Scanner: TEnScan;。
+- **功能**:它就是 **Envision SDK** 裡用來與 TWAIN 硬體溝通的靈魂核心。所有的掃描屬性 (Scanner.Resolution) 與方法 (Scanner.Acquire) 都是對這個物件進行操作。
+
+---
+
+# **IO 路徑與檔案操作分析**
+
+本報告詳列了 CB_IMGPSScanImp.pas 檔案中定義的所有 IO 相關變數,以及執行目錄與檔案管理的關鍵方法,並定義了抽像化所需的介面原型。
+
+## **壹、 關鍵路徑與檔案變數 (Variables)**
+
+程式中定義了多個全域或私有欄位,用來追蹤檔案在硬碟上的實體位置。
+
+### **1. 核心路徑變數與動態組合邏輯**
+
+| **變數名稱** | **類型** | **組合邏輯 (Combination Logic)** | **用途說明** |
+| --- | --- | --- | --- |
+| **ImagePath** | String | WORK_INF 的 LOCAL_PATH 參數值 | **本機基礎根路徑**。所有暫存資料的起點。 |
+| **ScaniniPath** | String | ImagePath + FWork_No + '\' + FUserUnit + '\' | **設定檔存放區**。區分作業別與單位。 |
+| **ImageSavePath** | String | 同 ImagePath (初期) 或隨 FMode 變動 | **影像儲存基準路徑**。 |
+| **ScanPath** | String | ImageSavePath + ScanCaseno + '\' + ScanDocdir + '\' | **當前掃描實體目錄**。指向最末層的影像資料夾。 |
+| **TransPath** | String | ImageSavePath + CaseID + '\Upload\' | **準備上傳區**。在傳送前將檔案結構扁平化組合於此。 |
+| **DisplayPath** | String | ImageSavePath + NowCaseNo + '\' | **預覽基準目錄**。用於 UI 點選樹狀圖時讀取特定案件資料。 |
+| **LngPath** | String | GetLocalAppDir(Handle) + 'MPS\CB_IMGPS\' | **應用程式資源路徑**。存放在使用者設定檔目錄以避開權限問題。 |
+| **CheckXmlPath** | String | ImagePath + 'OMRSITE\' | **OMR 規則暫存區**。存放從伺服器同步下來的 XML 定義。 |
+| **SamplePath** | String | ImagePath + 'Sample\' + FWork_No + '\' | **範本影像存放區**。按作業別區分。 |
+| **SitePath** | String | ImagePath + 'Site\' | **登打定位存放區**。 |
+| **FFtpRootPath** | String | 透過伺服器回傳值動態設定 | **FTP 伺服器根路徑**。指定在遠端 FTP 伺育器上存放影像檔的起始位址。 |
+
+### **2. 檔案名稱變數 (Filenames)**
+
+| **變數名稱** | **類型** | **用途說明** |
+| --- | --- | --- |
+| **ScanSaveFilename** | String | 下一張掃描影像預定的檔名(通常包含 FormID)。 |
+| **PEFileName** | String | 在 PageEnd 階段確定的最終完整檔案路徑。 |
+| **AttName** | String | **附件目錄名稱**。根據 FIs_In_Wh 決定為 Attach 或 S_Attach。 |
+| **Ext** | String | 副檔名。預設為 .tif,彩色/灰階模式下可能切換為 .jpg。 |
+
+## **貳、 關鍵 IO 操作方法 (Methods)**
+
+以下為需要進行抽像化設計的核心 IO 方法。
+
+### **1. 目錄管理 (Directory Management)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| _DelTree | 遞迴刪除整個目錄樹 | 上傳成功後清空暫存、模式切換初始化目錄 | RemoveDirRecursive(Path) |
+| Str2Dir / ForceDirectories | 確保路徑以 \ 結尾並建立路徑 | 初始化或掃描前建立資料夾 | EnsureDirExists(Path) |
+| GetNoNameCase | 搜尋尚未配號的臨時目錄 | 在本機搜尋如 未配號0001 到 9999 的可用路徑 | FindNextAvailablePath(Pattern) |
+| GetLocalAppDir | 取得 Windows %LocalAppData% 路徑 | 確保在現代 Windows 系統中有權限寫入語言檔與 Log | GetBaseStoragePath() |
+
+### **2. 存在性檢查與搜尋 (Existence & Search)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| FileExists | 檢查指定路徑檔案是否存在 | 在載入 .dat、.ini 或影像前進行安全檢查 | IsFilePresent(Path) |
+| DirectoryExists | 檢查指定路徑資料夾是否存在 | 在建立掃描目錄或上傳前確認結構完整性 | IsDirPresent(Path) |
+| FindFirst / FindNext | 搜尋符合特定格式的檔案 | 取得實體檔案大小 (FileRec.Size) 或遞迴搜尋檔案 | ListFiles(Path, Pattern) / GetFileInfo(Path) |
+
+### **3. 檔案生命週期與刪除 (File Lifecycle & Deletion)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| ReSortFileName | 影像重新編序命名 | 刪除或插入影像後,修正 001_xxx 等序號連續性 | RenameFile(Old, New) |
+| DeleteImageFile | 刪除實體影像檔 | 單張影像刪除並觸發 .dat 內容同步更新 | DeleteFile(Path) |
+| DeleteDocNoFile | 刪除特定文件代號下所有影像 | 整批文件(DocNo)的物理刪除與序號重整 | DeleteFilesByPattern(Pattern) |
+| DeleteShowFile | 刪除 UI 顯示中的影像清單 | 根據介面選取狀態進行批次物理刪除 | DeleteFileList(List<Path>) |
+| RenameFile / MoveFile | 檔案搬移或更名 | 用於「分案」、「移動頁數」或「變更歸類」 | MoveFile(Src, Dest) |
+| CopyFile | 複製實體檔案 | 影像搬移至上傳區或引用舊案件影像 | CopyFile(Src, Dest) |
+
+### **4. 資料紀錄與序列化 (Metadata IO)**
+
+| **方法名稱** | **作用** | **應用場景** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| DeleteCustomDocDir | 移除自訂文件定義 | 從 CustomDocNo.ini 中移除特定自訂文件的節點 | Storage.IniDeleteSection(Section) |
+
+### **5. 網路傳輸 IO 方法 (Network Retrieval - dnFile_Get)**
+
+專案中使用 `dnFile_Get` 從伺服器端同步必要的環境檔案或規則定義。
+
+| **抓取對象 (目標路徑)** | **遠端請求 Action** | **用途說明** |  |
+| --- | --- | --- | --- |
+| **CheckXmlPath + filename** | `GetCheckXml` | **下載 OMR 檢核定義檔**。同步伺服器端最新的 XML 座標規則,用於自動判斷影像區域。 | https |
+| **SamplePath + filename** | `GetSampleImg` | **下載範本影像**。用於在 UI 介面上提供給操作員對照的標準範例圖檔。 | https |
+| **SitePath + filename** | `GetSiteImg` | **下載定位定義圖**。下載與登打、校對位置相關的輔助影像。 | https |
+| **LngPath + 'Language.ini'** | `GetLanguage` | **同步多國語言檔**。確保用戶端介面文字(繁體、英文、越南語等)與伺服器同步。 | https |
+
+## **參、 資料紀錄與序列化 (Metadata IO)**
+
+專案中使用了大量的 .dat 與 .ini 檔案來記錄目錄內的結構資訊與使用者偏好。
+
+### **1. .dat 檔案 (結構紀錄)**
+
+| **檔案名稱** | **組合路徑邏輯 (Path Logic)** | **內容與用途** |
+| --- | --- | --- |
+| **Context.dat** | ImageSavePath + CaseID + '\' + DocDir + '\Context.dat' | **影像清單**。紀錄該資料夾內所有影像檔名的正確順序。 |
+| **DocDir.dat** | ImageSavePath + CaseID + '\Upload\DocDir.dat' | **目錄對應表**。紀錄 Upload 下每個檔名所屬的原始 DocDir |
+| **CaseDocNo.dat** | ImageSavePath + CaseID + '\CaseDocNo.dat' | **文件目錄索引**。紀錄案件內已建立的實體資料夾名稱。 |
+| **CaseDocNo_Copies.dat** | ImageSavePath + CaseID + '\CaseDocNo_Copies.dat' | **份數紀錄**。對應 CaseDocNo.dat 中的資料夾分別有多少份。 |
+| **CaseIndex.dat** | ImageSavePath + CaseID + '\CaseIndex.dat' | **案件屬性**。如是否為「授信卷」(Case_loandoc)。 |
+| **EditedDocDir.dat** | ImageSavePath + CaseID + '\EditedDocDir.dat' | **異動清單**。紀錄當次操作中被修改過的文件目錄。 |
+| **Scan_Memo.dat** | DisplayPath + 'Scan_Memo.dat' | **使用者註記**。紀錄操作員手動輸入的備註內容。 |
+| **CaseList.dat** | ImageSavePath + 'CaseList.dat' | **案件總表**。紀錄目前本機快取中存在的所有 CaseID。 |
+
+### **2. .ini 檔案 (設定與偏好)**
+
+| **檔案名稱** | **路徑邏輯** | **回寫 (Write-back)** | **內容與用途** | 寫入關聯 |
+| --- | --- | --- | --- | --- |
+| **Scan.ini** | ScaniniPath + 'Scan.ini' | **是 (頻繁)** | **掃描器硬體設定**。儲存最後一次選取的 DPI、雙面、色彩模式、亮度、對比等參數。 |  |
+| **CustomDocNo.ini** | ScaniniPath + 'CustomDocNo.ini' | **是 (中等)** | **自訂文件代號**。儲存操作員定義的文件分類名稱與內部 ID 映射。 | DeleteCustomDocDir |
+| **CB_IMGPSScan.ini** | LngPath + 'CB_IMGPSScan.ini' | **是 (低頻)** | **環境配置**。儲存伺服器 IP、Port、自動更新版本資訊等全域參數。 |  |
+| **Language.ini** | LngPath + 'Language.ini' | **否 (唯讀同步)** | **多國語言包**。僅透過 `dnFile_Get` 從伺服器抓取更新,OCX 不自行修改。 |  |
+
+## **肆、 串流與讀寫操作 (Stream & File I/O)**
+
+源碼中頻繁使用 .LoadFromFile 與 .SaveToFile 來實現資料的持久化。
+
+### **1. 使用 TStringList 讀寫 .dat 結構**
+
+| **操作對象** | **讀取場景 (Load)** | **寫入場景 (Save)** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| **結構清單 (.dat)** | LoadImgFile 載入以重建樹狀結構 | PageEnd 掃描完成或結構增刪後即時存檔 | ReadTextFile(Path) / WriteTextFile(Path, Content) |
+| **備註文件 (Memo)** | 進入備註編輯器時載入舊有內容 | WNoteBtnClick 完成編輯後儲存內容 | ReadTextFile(Path) / WriteTextFile(Path, Content) |
+| **上傳包定義** | N/A | CreateFormID_FormName 產生上傳包所需的定義檔 | WriteTextFile(Path, Content) |
+|  |  |  |  |
+
+### **2. 使用 TImageScrollBox / TDibGraphic 讀寫影像**
+
+| **操作對象** | **讀取場景 (Load)** | **寫入場景 (Save)** | **建議抽象 IO 介面** |
+| --- | --- | --- | --- |
+| **掃描影像原始檔** | view_image_... 載入顯示於預覽窗 | OnAcquire 將記憶體影像 (Dib) 持久化至磁碟 | ReadBinaryFile(Path) / WriteBinaryFile(Path, Blob) |
+| **影像處理覆蓋** | ImageReSize_FormID 讀取進行定位縮放 | 處理完成後覆蓋原始影像檔 | ReadBinaryFile(Path) / WriteBinaryFile(Path, Blob) |
+| **旋轉/後製處理** | 點擊旋轉按鈕後從磁碟重新讀取 | 旋轉完成後保存更新內容回實體檔案 | ReadBinaryFile(Path) / WriteBinaryFile(Path, Blob) |
+
+## **伍、 檔案路徑構造邏輯示例**
+
+程式中典型的路徑構造方式如下(以 PageEnd 為例):
+
+// 1. 基礎路徑
+
+ScanPath := ImageSavePath + ScanCaseno + '\';
+
+// 2. 進入特定文件目錄 (DocDir)
+
+ScanPath := ScanPath + ScanDocdir + '\';
+
+// 3. 確保實體目錄存在
+
+Str2Dir(ScanPath);
+
+// 4. 構造最終影像路徑
+
+PEFileName := ScanPath + Add_Zoo(PageCount, 3) + '_' + FormID + ext;
+
+## **陸、 IO 方法具體實作邏輯細部說明 (Detailed Implementation Logic)**
+
+本節針對 CB_IMGPSScanImp.pas 內部如何透過 Windows API 實作這些 IO 操作進行細部解說。
+
+### **1. Str2Dir(Path: string) 的運作機制**
+
+這個方法的主要作用是 **「路徑標準化與實體資料夾建立」**。
+
+- **字串處理**:它會先檢查傳入的 Path 字串最後一個字元是否為 \。如果不是,會自動補上。
+- **建立資料夾**:**是的,它會在內部建立資料夾**。它會呼叫 Delphi 的 ForceDirectories(Path) 函式。
+- **ForceDirectories 的特性**:與一般的 CreateDir 不同,ForceDirectories 會「遞迴」建立路徑中所有不存在的父目錄(例如若路徑為 C:\A\B\C,即使 A 和 B 都不存在,它也會一併建立)。
+
+### **2. _DelTree(DirName: string) 的遞迴邏輯**
+
+由於 Delphi 早期版本沒有提供單一函式來刪除包含檔案的資料夾,此方法透過 Windows 的搜尋機制實現:
+
+- **遍歷搜尋**:使用 FindFirst 和 FindNext 找出資料夾內的所有物件。
+- **檔案處理**:若搜尋到的是一般檔案,直接呼叫 DeleteFile。
+- **遞迴處理**:若搜尋到的是子資料夾,則「自己呼叫自己」 (_DelTree) 先清空該子資料夾。
+- **物理移除**:當資料夾內的所有內容都清空後,呼叫 RemoveDir 將空的資料夾從磁碟移除。
+
+### **3. FindFirst 與 FindNext 的搜尋與疊代邏輯**
+
+這兩個方法是 Delphi 處理「集合式 IO 操作」(如掃描目錄、批次刪除)的基礎,通常搭配 TSearchRec 結構使用。
+
+- **FindFirst(Path, Attr, SearchRec)**:
+- **動作**:啟動搜尋任務,將找到的第一個檔案資訊填入 SearchRec。
+- **應用例**:在 PM104Click (匯入影像) 時,程式會先執行 FindFirst(FName, faAnyfile, FileRec) 來確認使用者選取的實體檔案是否存在,並藉由 FileRec.Size 取得位元組大小,用以判斷是否超過系統設定的匯入限制(例如 5MB)。
+- **FindNext(SearchRec)**:
+- **動作**:繼續尋找下一個符合條件的檔案。
+- **疊代模式**:通常包裹在 repeat ... until FindNext(SR) <> 0 迴圈中。
+- **應用例**:在 _DelTree 實作中,程式利用此疊代邏輯將資料夾內「所有的」子目錄與檔案清空,直到 FindNext 回傳非零值(代表搜尋結束)。
+- **FindClose(SearchRec)**:
+- **重要性**:釋放搜尋控制代碼(Handle)。若未呼叫,頻繁搜尋會導致系統資源洩漏。
+
+### **4. GetNoNameCase(Path: string) 的搜尋邏輯**
+
+這是一個典型的 **「可用名稱查表」** 實作:
+
+- **迴圈範圍**:從 1 迭代到 9999。
+- **格式組合**:使用 Add_Zoo 函式將數字轉為四位數(如 0001),並加上前綴字「未配號」。
+- **磁碟檢查**:呼叫 DirectoryExists 檢查 Path + '未配號000x'。
+- **結果回傳**:第一個回傳 False(代表該資料夾尚不存在)的名稱即為結果,程式會立即跳出迴圈並選定此名稱。
+
+### **5. ReSortFileName(Path: string) 的連續性維護**
+
+為了保證 UI 上顯示的頁碼順序與磁碟檔名一致,此方法採用「先暫存、後改名」的策略:
+
+- **防止衝突**:先將目錄內所有符合格式的影像更名為帶有臨時前綴(如 @)的檔名。
+- **按序更名**:讀取 Context.dat 內的清單,依照目前的順序,將檔案逐一更名為 001_..., 002_... 等格式。
+- **同步索引**:最後將更名後的結果重新寫入 Context.dat。
+
+### **6. GetLocalAppDir(Handle: HWND) 的權限繞過**
+
+這是一個系統級別的 IO 位置定位方法:
+
+- **API 呼叫**:呼叫 SHGetSpecialFolderPath (Windows Shell API)。
+- **定位 CSIDL_LOCAL_APPDATA**:指向 C:\Users\使用者名稱\AppData\Local\。
+- **必要性**:這能解決 OCX 程式被安裝在 Program Files 下時,因為 UAC 權限無法在安裝目錄寫入 Log 或語言檔的問題。
+
+### **🎯 移植至 Web 平台的建議**
+
+當您將這些邏輯移植到 Web 時:
+
+- Str2Dir 應對應到 **IndexedDB** 的 Object Store 建立或 **File System Access API** 的 getDirectoryHandle(搭配 create: true)。
+- FindFirst / FindNext 在 Web 端應對應到 Directory Handle 的 entries() 異步疊代器。
+- .dat 序列化文件在 Web 端建議直接轉為 **JSON** 格式存儲於瀏覽器的 localStorage 或 IndexedDB 中。
+
+## **柒、 設定檔回寫邏輯 (Write-back Logic)**
+
+本節說明專案中哪些 .ini 檔案會由 OCX 主動更新資料及其觸發時機。
+
+| **檔案名稱** | **回寫內容 (Content)** | **觸發時機 (Trigger)** |
+| --- | --- | --- |
+| **Scan.ini** | DPI、Duplex、亮度、對比、影像模式 | 掃描前設定變更或啟動掃描時(SaveScanPara)。 |
+| **CustomDocNo.ini** | 自訂文件名稱與 ID 映射 | 操作員新增自訂分類或呼叫 `DeleteCustomDocDir` 時。 |
+| **CB_IMGPSScan.ini** | 版本號、伺服器 IP/Port | 自動更新完成後更新版號,或手動修改伺服器設定時。 |
+
+## **捌、 注意事項**
+
+- **硬編碼路徑**:ActiveFormCreate 中存在寫死的 C:\Temp\IMGPSScan,適合作為最終保險。
+- **權限問題**:作為 ActiveX,這些 IO 操作強烈依賴瀏覽器的「安全站台設定」或 IE 的「保護模式」。使用 GetLocalAppDir 是現代化重構中解決 UAC 權限問題的重要手段。
+
+---
+
+# **TCB_IMGPSScanX OCX 通訊介面與溝通機制分析**
+
+本表條列了 Delphi 宿主環境(ActiveX[ocx]) 與 TCB_IMGPSScanX 元件之間主要的溝通管道、對應方法及其在系統架構中的作用。
+
+## **壹、 指令與資料交換介面表**
+
+| **通訊方法 (Method)** | **通訊方向** | **溝通內容 (Data Payload)** | **具體作用與目的** |
+| --- | --- | --- | --- |
+| **SetSQLData** | **宿主 -> OCX** | 以 ` | 或,` 分隔的長字串(如:IP, CaseID, DPI) |
+| **GetSQLData** | **宿主 <-> OCX** | 指定 Key (如 'PARA_NO') 取得對應 Value | **資料查詢通道**。宿主可詢問 OCX 目前快取清單中的特定數值,用於介面同步或邏輯判斷。 |
+| **GetSetInf1 ~ 7** | **宿主 <- OCX** | 單一字串值 (如 CaseID, 總張數, 成功標記 'Y') | **狀態出口 (Outlets)**。提供標準化的 7 個出口,讓 JavaScript 或宿主 App 輪詢(Polling)目前的執行結果或掃描統計。 |
+| **StatrTwainScan** | **宿主 -> OCX** | 無參數 (觸發動作) | **硬體啟動指令**。宿主程式按下「開始掃描」按鈕後呼叫此方法,通知 OCX 喚起 TWAIN 驅動程式。 |
+| **GetCurrentVersionNo** | **宿主 <- OCX** | 版本字串 (如 '1.0.3.5') | **版本識別**。宿主程式載入 OCX 後第一步通常會呼叫此處,用以比對伺服器版本並決定是否強制更新。 |
+| **upFile** | **宿主 -> OCX** | 無或部分參數 (觸發網路 IO) | **輸出指令**。通知 OCX 將本機暫存區的檔案(如 ZIP 包)依照先前設定好的路徑與權限上傳至伺服器。 |
+| **dnFile_Get** | **宿主 -> OCX** | 遠端 Action 關鍵字與本地檔名 | **同步指令**。通知 OCX 向伺服器抓取特定資源(如 XML 規則或語言檔)並存放到指定 IO 路徑。 |
+| **ActiveFormCreate** | **系統 -> OCX** | 視窗建立事件 | **環境初始化**。當宿主程式實體化 OCX 時,自動觸發此處執行 GetDefScanIni,確保掃描環境就緒。 |
+| **Property CaseID** | **宿主 <-> OCX** | WideString | **屬性直連**。透過 COM 屬性機制直接設定或讀取案件編號。 |
+| **Property ScreenSnap** | **宿主 -> OCX** | Boolean | **功能切換**。控制 OCX 是否要在特定時機執行螢幕截圖稽核。 |
+
+## **貳、 溝通機制細部說明**
+
+### **1. 參數化配置 (Config-by-String)**
+
+本專案大量使用 SetSQLData 這種「一條字串走天下」的設計,這在早期 ActiveX 開發中非常流行,優點是規避了 COM 介面頻繁修改 _TLB.pas 的麻煩。您在轉換 TypeScript UI 時,可以將其封裝為一個 JSON 物件,最後再組合成字串傳給這個方法。
+
+### **2. 狀態回饋 (The Inf1~7 Pattern)**
+
+由於 ActiveX 事件 (Events) 的回傳有時在網頁端不夠穩定,開發者選擇了 GetSetInf 系列。宿主程式通常會在執行完某個長耗時動作(如 upFile)後,連續呼叫 GetSetInf3 (成功標記) 與 GetSetInf6 (錯誤訊息) 來決定下一步 UI 流程。
+
+### **3. 雙向同步 (Bidirectional Sync)**
+
+- **同步設定**:宿主透過 GetDefScanIni 觸發,OCX 內部完成硬體設定。
+- **同步資料**:宿主透過 dnFile_Get 觸發,OCX 完成本機與伺服器的檔案 IO 同步。
+
+# **參、描服務抽象層實作**
+
+採用 **「抽象介面層 (Abstraction Layer)」** 配合 **「適配器模式 (Adapter Pattern)」**,處理遺留系統(Legacy System)過渡到現代化架構
+
+```tsx
+/**
+ * 掃描服務資料模型定義
+ * 將原本 OCX 雜亂的字串溝通 (SetSQLData) 結構化
+ */
+export interface ScanConfig {
+  serverIp: string;
+  caseId: string;
+  dpi: number;
+  isColor: boolean;
+  isDuplex: boolean;
+  // ... 其他來自 GetDefScanIni 的參數
+}
+
+export interface ScanStatus {
+  caseId: string;
+  totalPageCount: number;
+  isUploadSuccess: boolean;
+  lastBarcode: string;
+  errorMessage: string;
+}
+
+/**
+ * 掃描服務抽象介面 (IScanService)
+ * UI 層僅與此介面溝通,不直接操作底層實作
+ */
+export interface IScanService {
+  initialize(config: ScanConfig): Promise<void>;
+  startScan(): Promise<boolean>;
+  uploadFiles(): Promise<boolean>;
+  getStatus(): Promise<ScanStatus>;
+  getVersion(): Promise<string>;
+  downloadResource(action: string, fileName: string): Promise<void>;
+}
+
+/**
+ * 實作 A: ActiveX 適配器 (Legacy Adapter)
+ * 用於目前環境:UI (TS) -> Delphi Browser -> ActiveX (OCX)
+ */
+export class ActiveXScanAdapter implements IScanService {
+  private ocx: any;
+
+  constructor() {
+    // 透過 window.external 或 Delphi Bridge 取得 OCX 實例
+    this.ocx = (window as any).OCX_INSTANCE;
+  }
+
+  async initialize(config: ScanConfig): Promise<void> {
+    // 將 JSON 轉回 OCX 慣用的管道分隔字串 (SetSQLData 邏輯)
+    const sqlDataStr = `${config.serverIp}|${config.caseId}|${config.dpi}|${config.isColor ? 'C' : 'G'}`;
+    this.ocx.SetSQLData(sqlDataStr);
+  }
+
+  async startScan(): Promise<boolean> {
+    this.ocx.StatrTwainScan();
+    return true; // 實際狀態需透過 GetSetInf 輪詢
+  }
+
+  async getStatus(): Promise<ScanStatus> {
+    return {
+      caseId: this.ocx.GetSetInf1(),
+      totalPageCount: parseInt(this.ocx.GetSetInf2()),
+      isUploadSuccess: this.ocx.GetSetInf3() === 'Y',
+      lastBarcode: this.ocx.GetSetInf5(),
+      errorMessage: this.ocx.GetSetInf6()
+    };
+  }
+
+  async uploadFiles(): Promise<boolean> {
+    this.ocx.upFile();
+    return true;
+  }
+
+  async getVersion(): Promise<string> {
+    return this.ocx.GetCurrentVersionNo();
+  }
+
+  async downloadResource(action: string, fileName: string): Promise<void> {
+    this.ocx.dnFile_Get(action, fileName);
+  }
+}
+
+/**
+ * 實作 B: Backend Server 適配器 (Future Adapter)
+ * 用於未來環境:UI (TS) -> REST API / WebSocket -> Rust/Go Backend
+ */
+export class BackendServerAdapter implements IScanService {
+  private apiUrl = "http://localhost:8080/api/scanner";
+
+  async initialize(config: ScanConfig): Promise<void> {
+    await fetch(`${this.apiUrl}/config`, {
+      method: 'POST',
+      body: JSON.stringify(config)
+    });
+  }
+
+  async startScan(): Promise<boolean> {
+    const res = await fetch(`${this.apiUrl}/scan`, { method: 'POST' });
+    return res.ok;
+  }
+
+  async getStatus(): Promise<ScanStatus> {
+    const res = await fetch(`${this.apiUrl}/status`);
+    return await res.json();
+  }
+
+  async uploadFiles(): Promise<boolean> {
+    const res = await fetch(`${this.apiUrl}/upload`, { method: 'POST' });
+    return res.ok;
+  }
+
+  async getVersion(): Promise<string> {
+    const res = await fetch(`${this.apiUrl}/version`);
+    const data = await res.json();
+    return data.version;
+  }
+
+  async downloadResource(action: string, fileName: string): Promise<void> {
+    // 未來可能直接由後端處理,前端僅發送同步指令
+    await fetch(`${this.apiUrl}/sync?action=${action}&file=${fileName}`);
+  }
+}
+
+/**
+ * 服務工廠 (Scanner Factory)
+ * 根據環境自動切換實作
+ */
+export class ScannerFactory {
+  static getService(): IScanService {
+    if ((window as any).OCX_INSTANCE) {
+      console.log("偵測到 ActiveX 環境,啟用 ActiveX 適配器");
+      return new ActiveXScanAdapter();
+    } else {
+      console.log("現代瀏覽器環境,啟用後端 API 適配器");
+      return new BackendServerAdapter();
+    }
+  }
+}
+```
+
+### **1. 介面標準化(JSON 化)**
+
+原先 OCX 使用 SetSQLData 的「長字串」溝通是非常脆弱的(一項參數順序錯了就全毀)。在 TypeScript 抽象層中,請務必將其轉換為 **強型別的 JSON 物件**(如 ScanConfig 介面)。這樣你的 UI 邏輯在處理設定時會非常直覺。
+
+### **2. 非同步處理(Promise/Async)**
+
+ActiveX 的方法通常是同步阻塞的,而後端 API 是非同步的。
+
+- **建議**:在抽象介面(IScanService)中,所有方法都回傳 Promise。
+- **原因**:這樣當你未來切換到後端伺服器(fetch API)時,UI 的調用邏輯(await service.startScan())不需要做任何修改。
+
+### **3. 實作「心跳」或「狀態輪詢」**
+
+原本 GetSetInf1~7 主要是靠宿主程式主動去「問」OCX。
+
+- **抽象層建議**:在 IScanService 中實作一個 subscribeStatus(callback) 的觀察者模式。
+- **ActiveX 模式下**:在適配器內部啟動一個 setInterval 去輪詢 GetSetInf。
+- **未來後端模式下**:適配器改用 **WebSocket** 接收後端主動推播的掃描事件。
+- **UI 層感受**:UI 只需要處理 onStatusUpdate 事件,根本不用管底層是用輪詢還是 WebSocket。
+
+### **4. 資源路徑的轉義(The Bridge Proxy)**
+
+這是我之前提到的關鍵:由於 iframe 裡的 TypeScript 無法存取 C:\Temp,但 ActiveX 依舊會把檔案掃到那裡。
+
+- **策略**:你的 Delphi Browser 需要實作一個簡單的本地 Proxy。
+- **實作**:當 TypeScript 需要顯示圖檔時,它請求 http://local.bridge/view/001.tif,Delphi Browser 攔截此請求並從實體路徑讀取檔案回傳。
+- **好處**:未來改為 Backend Server 時,Server 也可以提供同樣的 URL 格式,UI 完全無縫接軌。
+
+## **肆、 Delphi 與 JavaScript 通訊橋樑 (Bridge) 實作說明**
+
+當您在 Delphi 宿主程式中使用內嵌瀏覽器時,JavaScript 取得 `OCX_INSTANCE` 的方式取決於底層的瀏覽器引擎:
+
+### **1. 舊版 IE 核心 (TWebBrowser / window.external)**
+
+這是最傳統的方式,Delphi 會透過實作 `IDocHostUIHandler` 介面,將一個自訂的 `IDispatch` 物件掛載到 `window.external` 上。
+
+- **Delphi 端**:將 `TCB_IMGPSScanX` 實例或其包裝類別指派給瀏覽器的 `External` 屬性。
+- **JS 端**:直接使用 `window.external.StatrTwainScan()` 呼叫。
+
+### **2. 新版 Edge 核心 (TEdgeBrowser / WebView2 Host Objects)**
+
+這是現代化的做法。Delphi 透過 WebView2 的 API 將物件直接「注入」到 JS 的命名空間中。
+
+- **Delphi 端執行**:
+
+    ```pascal
+    // 將 OCX 物件以 'OCX_INSTANCE' 名稱注入
+    EdgeBrowser.AddHostObjectToScript('OCX_INSTANCE', MyOcxWrapperObject);
+    ```
+
+- **JS 端取得**: WebView2 會將物件放置在 `window.chrome.webview.hostObjects` 底下。
+
+    ```jsx
+    const ocx = window.chrome.webview.hostObjects.OCX_INSTANCE;
+    ```
+
+
+### **3. 為什麼需要 Wrapper (包裝類別)?**
+
+通常我們**不建議**直接將 `TCB_IMGPSScanX` 注入,原因如下:
+
+1. **安全性**:直接暴露 COM 元件可能會有安全漏洞。
+2. **相容性**:OCX 的某些方法回傳型別(如 Delphi 的自訂 Enum)JavaScript 無法識別。
+3. **執行緒優化**:Delphi 可以在 Wrapper 中使用 `TThread.Queue` 確保掃描指令在正確的執行緒執行,避免瀏覽器 UI 凍結。
+
+### **4. 溝通路徑總結**
+
+1. **Delphi 宿主程式** 啟動並實體化 **OCX 控制項**。
+2. **Delphi 宿主程式** 建立 **Browser 物件** 並載入 **TypeScript UI (HTML)**。
+3. **Delphi 宿主程式** 呼叫瀏覽器 API(如 `AddHostObjectToScript`),將 OCX 的操作介面「注入」到該網頁的 `window` 物件中。
+4. **TypeScript** 透過抽象層 (Adapter) 取得該物件,實現「網頁點按鈕,掃描機開動」的效果。
+
+---
+
+
+# Transport 相關套件分析
+
+---
+
+# Image Processor 相關套件分析
diff --git a/separate/scanImp/CB_IMGPSScanImp_Data.pas b/separate/scanImp/CB_IMGPSScanImp_Data.pas
new file mode 100644
index 0000000..7a7a89a
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Data.pas
@@ -0,0 +1,5178 @@
+function TCB_IMGPSScanX.Get_HelpFile: WideString;
+begin
+  Result := WideString(HelpFile);
+end;
+
+procedure TCB_IMGPSScanX.Set_HelpFile(const Value: WideString);
+begin
+  HelpFile := string(Value);
+end;
+
+function TCB_IMGPSScanX.DocNoIsExistImg(DocNopath:String):boolean;
+var
+  i:integer;
+  ST:TStringList;
+begin
+  Result:=False;
+  ST:=TStringList.Create;
+  if FileExists(DocNopath+'\Context.dat') then   /////20190319 Hong 當有空的Docno目錄時會掛掉,增加這行
+    ST.loadFromfile(DocNopath+'\Context.dat');
+  for I := 0 to ST.Count - 1 do
+  begin
+    if ISExistImg(DocNopath+ST.Strings[i]) then
+    begin
+
+      Result:=False;
+      Exit;
+      Break;
+    end;
+  end;
+  Result:=True;
+
+
+end;
+
+procedure TCB_IMGPSScanX.HTTPSClientCertificateValidate(Sender: TObject;
+  X509Certificate: TElX509Certificate; var Validate: Boolean);
+begin
+  Validate := True;
+end;
+
+procedure TCB_IMGPSScanX.HTTPSClientRedirection(Sender: TObject;
+  const OldURL: string; var NewURL: string; var AllowRedirection: Boolean);
+begin
+  AllowRedirection := True;
+end;
+
+Function TCB_IMGPSScanX.GetServerDate : Boolean;
+begin
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/servertimeforocx','',FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    ServerDate := memo1.Lines.Strings[1];
+    ServerTime := Copy(ServerDate,9,6);
+    ServerDate := Copy(ServerDate,1,8);
+    Balance := GetBalance(ServerTime); //Server 跟Local的時間差
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.GetSetInf1 : Boolean; //取系統設定資訊Mode1 DOC_INF
+Var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT %s FROM DOC_INF WHERE WORK_NO = '%s' ORDER BY DOC_TYPE, DOC_NO, DOC_VERSION"
+
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+
+  ColumeStr := 'WORK_NO,DOC_NO,DOC_U_DESC,DOC_TYPE,DOC_VERSION,FORM_PAGES,START_DATE,STOP_DATE,IS_DOC_DIV,IS_IN_WH';
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=1&col='+Doc_Inf_Colume+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=1&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,Doc_Inf_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetSetInf2 : Boolean; //取系統設定資訊Mode2  DM_FORM_INF
+var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT %s FROM DM_FORM_INF
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  ColumeStr := 'WORK_NO,MAIN_FORM_ID,DOC_VERSION,DEPE_FORM_ID,MUTEX_FORM_ID';
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=2&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+   If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=2&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,DM_FORM_INF_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetSetInf3 : Boolean; //取系統設定資訊mode3  FORM_INF
+var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT distinct %s FROM FORM_INF T1 LEFT JOIN DOC_INF T2 ON T2.DOC_NO = T1.DOC_NO AND T1.DOC_VERSION = T2.DOC_VERSION AND T1.WORK_NO = T2.WORK_NO WHERE T2.IS_USE = 'Y' AND T2.WORK_NO = %s
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  //ColumeStr := 'T1.WORK_NO,T1.FORM_ID,T1.DOC_KIND,T1.DOC_NO,T1.DOC_VERSION,T1.FORM_NAME,T1.FORM_DESC,T1.DIVISION,T1.ANCHOR,T1.MAX_PAGE,T1.FORM_HEIGHT,T1.FORM_WIDTH,T1.MERGE_IMAGE,T1.CC_FORM_ID,T1.CC_MERGE_FORMID,T2.DOC_TYPE'; {T1.CC_FORM_ID,T1.CC_MERGE_FORMID,}
+  ColumeStr := 'T1.WORK_NO,T1.FORM_ID,T1.DOC_NO,T1.DOC_VERSION,T1.FORM_NAME,T1.FORM_DESC,T1.DIVISION,T1.ANCHOR,T1.MAX_PAGE,T1.FORM_HEIGHT,T1.FORM_WIDTH,T1.IS_PRINT,T2.DOC_TYPE'; {T1.CC_FORM_ID,T1.CC_MERGE_FORMID,}
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=3&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=3&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,FORM_INF_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetSetInf4 : Boolean; //取系統設定資訊mode4  CHECK_RULE_INF
+var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT %s FROM CHECK_RULE_INF WHERE CHECK_TYPE = 'S'
+
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  ColumeStr := 'WORK_NO,CHECK_NO,CHECK_RULE_DESC,MESG_SHOW_TYPE,MESG_DISP_TYPE,CHECK_MESG,SCAN_MODE';
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=4&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=4&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,CHECK_RULE_INF_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+  CheckRule2OMRErrInfo;
+end;
+
+Function TCB_IMGPSScanX.GetSetInf5 : Boolean; //取系統設定資訊mode5  MEMO_INF
+  var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT %s FROM MEMO_INF T1 LEFT JOIN MEMO_TYPE_INF T2 ON T2.MEMO_TYPE_NO = T1.MEMO_TYPE WHERE T1.MEMO_SOURCE = '01'
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  ColumeStr := 'T1.WORK_NO,T1.MEMO_TYPE,T1.MEMO_CONTENT,T2.MEMO_TYPE_NAME';
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=5&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=5&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,MEMO_INF_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetSetInf6 : Boolean; //取系統設定資訊mode5  WORK_INF
+var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT %s FROM WORK_INF
+
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  ColumeStr := 'WORK_NO,PARA_NO,PARA_CONTENT';
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=5&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=6&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,WORK_INF_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetSetInf7 : Boolean; //取系統設定資訊mode5  LASTEST_FORM_INF
+var
+  ColumeStr : String;
+  S : TStringlist;
+  EnCodeDateTime : String;
+begin
+  //SELECT FORM_ID,DOC_NO,DOC_VERSION FROM FORM_INF WHERE (DOC_NO,DOC_VERSION) in (SELECT DOC_NO, MAX(DOC_VERSION) FROM FORM_INF GROUP BY DOC_NO) ORDER BY DOC_NO
+
+  Result := False;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  ColumeStr := 'FORM_ID,DOC_NO';
+  //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=5&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/tables','checktime='+EnCodeDateTime+'&mode=7&col='+En_DecryptionStr_Base64('E',ColumeStr,Mpskey)+'&work_no='+FWork_No,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    S := TStringlist.Create;
+    S.Text := Memo1.Lines.Text;
+    SetSQLData(ColumeStr,S,LASTEST_FORM_INF_List);
+    S.Free;
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetIn_WH_DocNo; //將要入庫的DocNo抽出來另存入list裡
+var
+  i : Integer;
+begin
+  for i := 1 to Doc_Inf_List.Count - 1 do
+  begin
+
+    if GetSQLData(Doc_Inf_List,'IS_IN_WH',i) = 'Y' then
+      IN_WH_DocNoList.Add(GetSQLData(Doc_Inf_List,'DOC_NO',i));
+  end;
+  {Showmessage(IN_WH_DocNoList.Text);
+  StringtoFile(IN_WH_DocNoList.Text,'D:\121.txt');}
+end;
+
+Function TCB_IMGPSScanX.DeleteDocNoFile(Path,DocNo:String):Boolean;  //刪除指定DocNo文件
+var
+  i: Integer;
+  FName : String;
+begin
+  Result := False;
+  for i := ContextList.Count - 1 downto 0 do
+  begin
+    FName := ContextList.Strings[i];
+    If DocNo = FormCode2DocNo(FileName2FormCode(FName)) then
+    begin
+      DeleteFile(Path+FName);
+      ContextList.Delete(i);
+      Context_DocnoList.Delete(i);
+      Result := True; //有刪到指定文件
+    end;
+  end;
+  ContextList.SaveToFile(Path+'Context.dat');
+  Context_DocnoList.SaveToFile(Path+'Context_DocNo.dat');
+  ReSortFileName(Path);
+  ContextList.LoadFromFile(Path+'Context.dat');
+  Context_DocnoList.LoadFromFile(Path+'Context_DocNo.dat');
+  if FileExists(Path+'CustomDocNo.dat') then
+    Cust_DocNoList.LoadFromFile(Path+'CustomDocNo.dat');
+end;
+
+Procedure TCB_IMGPSScanX.DeleteShowFile(Path:String); //刪除顯示中的影像
+var
+  i : Integer;
+  DelFile : String;
+begin
+  for i := 0 to NowShowFileList.Count - 1 do
+  begin
+    DelFile := NowShowFileList.Strings[i];
+    DeleteFile(Path+DelFile);
+    SetContextList('D',-1,NowCaseno,NowDocNo,DelFile);
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.GetDataDocNoPage(MainDocNo,MainVersion:String):Integer;  //取記錄的文件_版本頁數
+var
+  P : String;
+begin
+  Result := 0;
+  If FindSQLData(Doc_Inf_List,'FORM_PAGES','DOC_NO,DOC_VERSION',MainDocNo+','+MainVersion,0,FindResult) Then
+  begin
+    P := GetFindResult('FORM_PAGES');
+    if P <> '' then
+      Result := strtoint(P)
+    else
+      Result := 0;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckCaseDocNoPage(CaseID,DocNo,Version:String;Pages:Integer):Integer; //取案件裡的文件_版本頁數
+var
+  i,n,Count : integer;
+  S, S2 : TStringlist;
+  FormCode,iPage : String;
+  docInt,tempInt:integer;
+  v,v2:integer;
+begin
+  Count := 0;
+  docInt:=0;
+  tempInt:=0;
+  S := TStringlist.Create;
+  S2 := TStringlist.Create;
+//ShowMessage('page='+IntToStr(Pages));
+  try
+    S.LoadFromFile(ImageSavePath+CaseID+'\upload\Context.dat');
+    S2.LoadFromFile(ImageSavePath+CaseID+'\upload\DocDir.dat'); //2017 1220 改成只承認第一份的
+
+    for I := 1 to pages do //從0到pages-1  改成 1到pages 20170316 這樣可以修改檢核的頁數問題
+    begin
+      iPage := Add_Zoo(i,2);
+      for n := 0 to S.Count - 1 do
+      begin
+        if (FWH_category='N') and (FIs_In_Wh='Y') then
+        begin
+          if ISExistImg(ImageSavePath+CaseID+'\upload\'+S.Strings[n]) then
+          begin
+            Continue;
+          end;
+        end;
+
+        if (Length(S2.Strings[n])>8) and (Pos(DocNo,S2.Strings[n])<>0) then //2017 1220 改成只承認第一份的
+        begin
+//LogFile1.LogToFile(logTimeString+'有進'+docno+','+S2.Strings[n]+IntToStr(Pos(DocNo,S2.Strings[n])));
+          v:=Pos('(',S2.Strings[n]);
+          v2:=Pos(')',S2.Strings[n]);
+          tempInt:=StrToInt(Copy(S2.Strings[n],v+1,v2-v-1));
+
+          if docInt=0 then
+          begin
+            docInt:=tempInt;
+          end;
+          if docInt<>tempInt then
+          begin
+//LogFile1.LogToFile(logTimeString+'docInt='+IntToStr(docInt)+',tempInt='+IntToStr(tempInt));
+            Result := Count;
+            Break;
+          end;
+        end;
+
+        FormCode := FileName2FormCode(S.Strings[n]);
+//LogFile1.LogToFile(logTimeString+'S.Strings[n]='+S.Strings[n]);
+//Showmessage('1:'+version+','+FormCode2Version(FormCode)+','+DocNo+','+FormCode2DocNo(FormCode)+','+iPage+','+FormCode2Page(FormCode));
+//LogFile1.LogToFile(logTimeString+'FormCode='+FormCode);
+LogFile1.LogToFile(logTimeString+'CheckCaseDocNoPage caseno='+CaseID+','+version+','+FormCode2Version(FormCode)+','+DocNo+','+FormCode2DocNo(FormCode)+','+iPage+','+FormCode2Page(FormCode));
+//ShowMessage(DocNo+','+IntToStr(docInt)+','+IntToStr(tempInt));
+//LogFile1.LogToFile(logTimeString+'FormCode='+FormCode);
+        if (version = FormCode2Version(FormCode)) and (DocNo = FormCode2DocNo(FormCode)) and (ipage = FormCode2Page(FormCode)) then
+        begin
+LogFile1.LogToFile(logTimeString+'CheckCaseDocNoPage caseno='+CaseID+','+version+','+FormCode2Version(FormCode)+','+DocNo+','+FormCode2DocNo(FormCode)+','+iPage+','+FormCode2Page(FormCode));
+//Showmessage(version+','+DocNo+',iPage='+iPage);
+//Showmessage(inttostr(Count+1));
+          Inc(Count);
+          Break;   //找到了...離開
+        end;
+      end;
+    end;
+  finally
+  S.Free;
+  S2.free;
+  end;
+  Result := Count;
+end;
+
+Function TCB_IMGPSScanX.TransCaseID(Path,CaseID:String;MainCase:Boolean):Boolean; //傳送案件
+Var
+  i,n,v: Integer;
+  ZipFileList : TStringlist;
+  UpFormID:String;
+  pages : Integer;
+  TransName : String;
+  MaskPath : String;
+  HaveMask : Boolean;
+  S : String;
+  SendData:String;
+  Doc_Data,Doc_Data1 : String;
+  In_Doc1,In_Doc2 : String;
+  AttachYN : String; //是否有附件 Y:有 N:沒有
+
+  ST1,ST2,ST3:TStringList;
+  str1,str2:String;
+  must_formidStr :string;
+  last_add_formidstr :string;
+  ScanListStr:String;
+  casepath:String;
+  filesizeInt:integer;
+  case_page:string;
+  Fname:String;
+  FileRec:TSearchrec;
+begin
+  Result := True;
+  TransName := CaseID;
+  MaskPath := Path+'MaskImg\';
+  if fileExists(Path+'Context.dat') then
+  begin
+    ContextList.LoadFromFile(Path+'Context.dat');
+    Context_DocnoList.LoadFromFile(Path+'Context_DocNo.dat');
+  end;
+
+  if FileExists(Path+'CustomDocNo.dat') then
+    Cust_DocNoList.LoadFromFile(Path+'CustomDocNo.dat');
+
+  Pages := ContextList.Count;
+  case_page:=IntToStr(pages);
+  if (FMode = 'NSCAN') or (FMode = 'ESCAN') or (FMode = 'ASCAN') or (FMode = 'DSCAN') or (FMode = 'SSCAN') or (FMode = 'MSCAN') or (FMode = 'RI_SCAN') or (FMode = 'RSCAN')  then
+  begin
+    //Showmessage('1');
+    UpformID := GetCaseFormID(Path);
+    {if UpformID = '' then             //20131213  yuu說不管主form
+    begin
+      Showmessage(_msg('取不到主FormID!!'));
+      Result := False;
+      DataLoading(False,False);
+      Exit;
+    end;}
+  end;
+
+  CaseResort2Scanlist(Path); //檔名照設定排序產生scanlist.dat
+  //CaseResort(Path);  //檔名照設定排序
+  CreateFormID_FormName(Path,CaseID);  //產生FormID_FormName.dat
+  CreateDocNo_DocName(Path,CaseID); //產生DocNo_Name.dat
+  Doc_Data := CreateDocNo_Info(CaseID);  //產生保管袋文件 Docno,份數,頁數;Docno,份數,頁數 的回傳字串
+  Doc_Data1 := CreateCustDocNo_Info(CaseID);  //產生自定文件 Docname,份數,頁數;Docno,份數,頁數 的回傳字串
+  In_Doc1 := CreateDocnoFrom_Info(CaseID); //產生被引進的保管袋文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+  In_Doc2 := CreateCustDocNoFrom_Info(CaseID);   //產生被引進的自定文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+  AttachYN := CreateAttach_Info(CaseID); //是否還有附件 Y:有 N:沒有
+  ReadCaseIndex(Path);
+  //LoanDoc := 'Y';
+  //產生遮罩影像
+//  if FWork_No = 'CW' then
+//    HaveMask := Case2Mask(Path,MaskPath);
+  //產生遮罩影像
+ // S := S +#13+'5-->'+ Timetostr(now);
+
+  ///////必要formid 20170315 start  //////////////////////////////
+  must_formidStr:='';
+  last_add_formidstr:='';
+  ST1:=TStringList.Create;
+  ST1.LoadFromFile(path+'FormCode_Name.dat');
+//ShowMessage(ST1.Text);
+//ShowMessage(LastInitFormidList.Text);
+  ST2:=TStringList.Create;
+  ST3:=TStringlist.Create;
+
+  for I := 0 to ST1.Count - 1 do
+  begin
+    if (Pos('_',St1.Strings[i])<>1) and (Pos('_',St1.Strings[i])<>-1) then
+    begin
+      str1:=Copy(ST1.Strings[i],1,Pos('_',St1.Strings[i])-1);
+      ST2.Add(str1);
+      must_formidStr:= must_formidStr+str1+'@#,';
+    end;
+  end;
+  must_formidStr:=Copy(must_formidStr,1,Length(must_formidStr)-3) ;
+//ShowMessage('must_formidStr='+must_formidStr);
+//ShowMessage('AST2='+ST2.Text);
+
+
+  for I := 0 to LastInitFormidList.Count - 1 do
+  begin
+    if ST2.IndexOf(LastInitFormidList.Strings[i]) <> -1 then
+    begin
+      ST2.Delete(ST2.IndexOf(LastInitFormidList.Strings[i]));
+    end;
+  end;
+//ShowMessage('BST2='+ST2.Text);
+  for I := 0 to ST2.Count - 1 do
+  begin
+      last_add_formidstr:=last_add_formidstr+ST2.Strings[i]+'@#,';
+  end;
+  last_add_formidstr:=Copy(last_add_formidstr,1,Length(last_add_formidstr)-3) ;
+
+  ST3.LoadFromFile(path+'scanlist.dat');
+  for I := 0 to ST3.Count - 1 do
+  begin
+    if ScanListStr = '' then
+      ScanListStr := FileName2FormCode(ST3.Strings[i])
+    else
+      ScanListStr := Format('%s,%s',[ScanListStr,FileName2FormCode(ST3.Strings[i])]);
+  end;
+
+  ST1.Free;
+  ST2.Free;
+  ST3.Free;
+//ShowMessage('last_add_formidstr='+last_add_formidstr);
+  ///////必要formid 20170315 end //////////////////////////
+
+  ///保留外部影像  start///////////////////////////////
+  casepath:= Copy(Path,1,pos('Upload',path)-1);
+//ShowMessage('casepath='+casepath);
+//FIsExternal:='Y';
+  if (FMode='ESCAN') and (FIsExternal='Y') then
+  begin
+    if FileExists(casepath+'Download\FirstImg.zip') then
+    begin
+      CopyFile(PWChar(casepath+'Download\FirstImg.zip'),PWChar(path+'FirstImg.zip'),false);
+    end
+    else
+    begin
+      CopyFile(PWChar(casepath+'Download\'+CaseID+'.zip'),PWChar(path+'FirstImg.zip'),false);
+    end;
+  end;
+  ///保留外部影像  end///////////////////////////////
+
+  //file_size 計算  就先不做 20170316
+  filesizeInt:=0;
+
+
+  //////壓檔/////
+  ZipMainFile(Path,Path,'Img.zip');
+  if HaveMask then
+    ZipMaskFile(Path,MaskPath,Path,'MaskImg.zip');  //有遮罩設定的才產生
+  /////壓檔////
+  ///檢查上傳的zip大小////
+   FName :=Path+ 'Img.zip';
+
+    FindFirst(FName, faAnyfile, FileRec);
+
+    //FMaxUploadSize
+//ShowMessage(IntToStr(FileRec.Size));
+//Result:=False;
+//exit;           //目前上傳檔案大小為xxMB,已超過50MB,無法上傳    %.3f  ,[FileRec.Size / 1048576]
+    If FileRec.Size > StrtoInt(FMaxUploadSize) * 1048576 Then // 檢查檔案大小
+    Begin
+      ShowMessage(Format(_Msg('%s目前上傳檔案大小為%.3fMB,已超過%sMB,無法上傳'),[caseid,FileRec.Size / 1048576,FMaxUploadSize]));
+      //ShowMessage(Format('%s目前上傳檔案大小為%.3fMB,已超過'+FMaxUploadSize+'MB,無法上傳',[caseid,FileRec.Size / 1048576]) );
+      FindClose(FileRec);
+      Result := False;
+      Exit;
+    End;
+    FindClose(FileRec);
+  ///檢查上傳的zip大小////
+//ShowMessage('last_add_formidstr='+last_add_formidstr);
+  if not GetftpInfo(CaseID,'upload') then   //取案件上傳方式
+  begin
+    //Showmessage(_Msg()Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+'.');
+    DownFileErrStr := _Msg('取案件上傳資訊失敗!!')+HttpErrStr;
+    Result := False;
+    Exit;
+  end;
+  SendData:='data='+HTTPEncode(UTF8Encode(FData))
+      +'&verify='+FVerify
+      +'&form_id='+UpformID
+      +'&loan_doc='+Case_loandoc
+      +'&case_no='+TransName
+      +'&doc_data='+HTTPEncode(UTF8Encode(Doc_Data))
+      +'&doc_data1='+HTTPEncode(UTF8Encode(Doc_Data1))
+      +'&attach='+AttachYN
+      +'&case_page='+case_page
+      +'&file_size='+IntToStr(filesizeInt)
+      +'&must_formid='+must_formidStr  //擁有的 formid
+      +'&last_add_formid='+last_add_formidstr   //當次新加的 formid
+      +'&form_code='+ScanListStr      //scanlist.dat 表單代號
+      +'&ftp_image_path='+FFtpExtraPath   //加傳FTP目錄  HTTP上傳時會是空白
+      +'&in_doc1='+HTTPEncode(UTF8Encode(In_Doc1))
+      +'&in_doc2='+HTTPEncode(UTF8Encode(In_Doc2));
+
+  case TransMode of
+    tsHttp :
+    begin
+      ////上傳/////
+      ShowText := CaseID+_Msg('資料上傳中(Http),請稍候');
+      DataLoading(True,True);
+      if not upFile(HTTPSClient,FUrl,'service/imgpsc/IMGPSC02/caseupload',SendData,'file',Path+'Img.zip',FReWrite,Memo1,False) then
+      begin
+        Showmessage(Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+'.');
+        Result := False;
+        Exit;
+      end;
+      if memo1.Lines.Strings[0] = '1' then
+      begin
+        Showmessage(Format(_Msg('')+_Msg(''),[CaseID])+memo1.Lines.Strings[1]+'。');
+        Result := False;
+        Exit;
+      end
+      Else if Pos('<script type="text/javascript" src="scripts/IMGPS00/login.js"></script>',Memo1.Lines.Text) > 0 then
+      begin
+        Showmessage(Format(_Msg('')+_Msg('')+_Msg('閒置過久或被登出,請重新登入'),[CaseID]));
+        Result := False;
+        Exit;
+      end;
+      ////上傳////
+    end;
+    tsFtp :
+    begin
+       ShowText := CaseID+_Msg('資料上傳中(Ftp),請稍候');
+       DataLoading(True,True);
+       SetFtpInfo;
+       try
+         if not IIS_Ftp.FtpsConnect then
+         begin
+           Showmessage(Format('無法連上Ftp主機,錯誤原因:%s',[FtpErrReason]));
+           Result := False;
+           Exit;
+         end;
+         if not IIS_Ftp.FtpsToMain(FFtpExtraPath,CaseID+'.zip',Path+'Img.zip',display1) then
+         begin
+           Showmessage(Format(_msg('上傳案件(%s)時,發生錯誤,錯誤原因:%s'),[CaseID,FtpErrStr]));
+           Result := False;
+           Exit;
+         end;
+
+         if not FtpCaseComplete(SendData) then    //Ftp上傳後通知完成
+         begin
+           Showmessage(Format(_Msg('通知案件(%s)Ftp上傳完成時,發生錯誤!!'),[CaseID])+HttpErrStr);
+           Result := False;
+           Exit;
+         end;
+       finally
+       IIS_Ftp.FtpsClose;
+       end;
+    end;
+
+  end;
+
+
+  if FMode = 'ESCAN' then    //上傳舊件引入檔案      //20140616 原本先搬舊件再搬新件,改為先搬新件再搬舊件
+  begin
+    if not TransOldCaseFile(ImageSavePath+CaseID+'\') then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  // 呼叫Server完成 /////
+  {If not CaseComplete(Path,CaseID,MainCase) Then
+  begin
+    Showmessage(_Msg('通知案件傳送完成時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Result := False;
+    Exit;
+  end;  }
+  /// 呼叫Server完成////
+
+  ////刪檔////
+  //_DelTree(Path);  //會只刪TransPath
+//ShowMessage('STOP');
+  _DelTree(ImageSavePath+CaseID);
+  SetCaseList('D',-1,CaseID);
+  ////刪檔////
+end;
+
+Function TCB_IMGPSScanX.GetNoNameCase(Path:String):String; //取未配號XXXX
+var
+  i : Integer;
+begin
+  for i := 1 to 9999 do
+  begin
+    if Not DirectoryExists(Path+_Msg('未配號')+Add_Zoo(i,4)) then
+    begin
+      Result := _Msg('未配號')+Add_Zoo(i,4);
+      Break;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.CaseResort(Path:String); //案件的檔案重新排序(次文件依Docno排)
+var
+  i,n,v,v1 : Integer;
+  S,S1 : TStringlist;
+  FormID,OldName,NewName,DocNo,Doc_Type:String;
+  x : Integer;
+begin
+  S := TStringlist.Create;
+  S1 := TStringlist.Create;
+  try
+  S.LoadFromFile(Path+'Context.dat');
+  X := 0;
+  {for I := 1 to FORM_INF_List.Count - 1 do    //在FormID有設定的   //主文件 照SQL排   20101028改
+  begin
+    FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+    if FormCode2FileName(FormID,S) = '' then
+       Continue;
+    Doc_Type := GetSQLData(FORM_INF_List,'T2.DOC_TYPE',i);
+    for n := 0 to S.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FileName2FormCode(S.Strings[n]) = FormID) and (Doc_Type='1') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;}
+
+  {for I := 0 to FORM_INF_List.Count - 1 do  //次文件 照FormID 1~8碼+掃瞄順序排   20110512為了某個文件要先打的原因要求改
+  begin
+    for n := 0 to S.Count - 1 do
+    begin
+      FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+      Doc_Type := GetSQLData(FORM_INF_List,'T2.DOC_TYPE',i);
+      if (S.Strings[n][1] <> '*') and (Copy(FileName2FormCode(S.Strings[n]),1,8) = Copy(FormID,1,8)) and (Doc_Type='2') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;}
+  for I := 0 to Doc_Inf_List.Count - 1 do  //主文件 照文件代碼+掃瞄順序排   20101101改   20110512晚上又說改回來
+  begin
+    DocNo := GetSQLData(Doc_Inf_List,'DOC_NO',i);
+    if DocNo2FileName(DocNo,S) = '' then
+      Continue;
+    Doc_Type := GetSQLData(Doc_Inf_List,'DOC_TYPE',i);
+    for n := 0 to S.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FormCode2DocNo(FileName2FormCode(S.Strings[n])) = DocNo) and (Doc_Type='1') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;
+
+
+  for I := 0 to Doc_Inf_List.Count - 1 do  //次文件 照文件代碼+掃瞄順序排   20101101改   20110512晚上又說改回來
+  begin
+    DocNo := GetSQLData(Doc_Inf_List,'DOC_NO',i);
+    if DocNo2FileName(DocNo,S) = '' then
+      Continue;
+    Doc_Type := GetSQLData(Doc_Inf_List,'DOC_TYPE',i);
+    for n := 0 to S.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FormCode2DocNo(FileName2FormCode(S.Strings[n])) = DocNo) and (Doc_Type='2') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;
+
+  {for n := 0 to S.Count - 1 do    //次文件 照掃瞄順序排   20101028改
+  begin
+    FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+    Doc_Type := GetSQLData(FORM_INF_List,'T2.DOC_TYPE',i);
+    for i := 0 to FORM_INF_List.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FileName2FormCode(S.Strings[n]) = FormID) and (Doc_Type='2') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;}
+  for i := 0 to S.Count - 1 do   //FormID沒設定的或附件
+  begin
+    if S.Strings[i][1] <> '*' then
+    begin
+      Inc(X);
+      OldName := S.Strings[i];
+      //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3);
+      NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName);
+      S.Strings[i] := '*'+S.Strings[i];
+      S1.Add(OldName+','+NewName);
+    end;
+  end;
+  S.Clear;
+  for i := 0 to S1.Count - 1 do  //開始轉換檔名
+  begin
+    v := Pos(',',S1.Strings[i]);
+    v1 := length(S1.Strings[i]);
+    OldName := copy(S1.Strings[i],1,v-1);
+    NewName := copy(S1.Strings[i],v+1,v1-v);
+    if FileExists(Path+OldName) then
+    begin
+      ReNameFile(Path+OldName,Path+NewName);
+      S.Add(NewName);
+      S.SaveToFile(Path+'Context.dat');
+    end;
+  end;
+  ReSortFileName(Path);
+  finally
+  S.Free;
+  S1.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.DistinctDocinCase(Path:String); //列出案件裡的Docno_版本
+var
+  i,n,v : Integer;
+  S : TStringlist;
+  FormCode,DocNo,Ver : String;
+  Doc_Ver : String;
+  Exists : Boolean;
+begin
+  S := TSTringlist.Create;
+  try
+    DocNo_VerinCase.Clear;
+    S.LoadFromFile(Path+'Context.dat');
+    for I := 0 to S.Count - 1 do
+    begin
+      if FWH_category='N' then
+      begin
+        if (ISExistImg(Path+S.Strings[i])) or (reSizeExistImgList.IndexOf(LoadFileGetMD5(Path+S.Strings[i]))<>-1)  then
+        begin
+          Continue;
+        end;
+      end;
+      FormCode := FileName2FormCode(S.Strings[i]);
+      DocNo := FormCode2DocNo(FormCode);
+      Ver := FormCode2Version(FormCode);
+      if (Docno <> '') and (Ver <> '') then
+      begin
+        Doc_Ver := DocNo+'_'+Ver;
+        Exists := False;
+        for n := 0 to DocNo_VerinCase.Count-1 do
+        begin
+          if Doc_Ver = DocNo_VerinCase.Strings[n] then
+          begin
+            Exists := True;
+            Break;
+          end;
+        end;
+        if not Exists then
+          DocNo_VerinCase.Add(Doc_Ver);
+      end;
+    end;
+  finally
+  S.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.DistinctDocNoinCase(Path:String); //列出案件裡的Docno
+var
+  i,n,v : Integer;
+  S : TStringlist;
+  FormCode,DocNo,Ver : String;
+  Exists : Boolean;
+begin
+  S := TSTringlist.Create;
+  try
+    CaseDocNoList.Clear;
+    S.LoadFromFile(Path+'Context.dat');
+    for I := 0 to S.Count - 1 do
+    begin
+      FormCode := FileName2FormCode(S.Strings[i]);
+      DocNo := FormCode2DocNo(FormCode);
+      if (Docno <> '') then
+      begin
+        Exists := False;
+        for n := 0 to CaseDocNoList.Count-1 do
+        begin
+          if DocNo = CaseDocNoList.Strings[n] then
+          begin
+            Exists := True;
+            Break;
+          end;
+        end;
+        if not Exists then
+          CaseDocNoList.Add(DocNo);
+      end;
+    end;
+  finally
+  S.Free;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.SetCaseList(Mode:Char;Index:Integer;text:String);  //'A:加入,I:插入,D:刪除,E:修改'
+var
+  i : Integer;
+begin
+  CaseList.Clear;
+  if FileExists(ImageSavePath + 'CaseList.dat') then
+    CaseList.LoadFromFile(ImageSavePath + 'CaseList.dat');
+  case Mode of
+    'A':begin
+          CaseList.Add(Text);
+        end;
+    'I':begin
+          CaseList.Insert(Index,Text);
+        end;
+    'E':begin
+          CaseList.Strings[Index] := Text;
+        end;
+    'D':begin
+          if Index <> -1 then
+            CaseList.Delete(Index)
+          Else if (text <> '') then
+          begin
+            for i := 0 to CaseList.Count - 1 do
+            begin
+              if Text = CaseList.Strings[i] then
+              begin
+                CaseList.Delete(i);
+                Break;
+              end;
+            end;
+          end;
+          if CaseList.Count = 0 then
+              DeleteFile(ImageSavePath + 'CaseList.dat');
+        end;
+  end;
+  if CaseList.Count > 0 then
+    CaseList.SaveToFile(ImageSavePath+'CaseList.dat');
+end;
+
+Procedure TCB_IMGPSScanX.SetDocNoList(Mode:Char;Index:Integer;CaseNo,DocDir,Copies:String);  //'A:加入,I:插入,D:刪除,E:修改'
+var
+  i : Integer;
+  CaseDocNoList : TStringlist;
+  CaseDocNo_copiesList : TStringlist;
+begin
+  CaseDocNoList := TStringlist.Create;
+  CaseDocNo_CopiesList := TStringlist.Create;
+  try
+    CaseDocNoList.Clear;
+    if FileExists(ImageSavePath+CaseNo+'\CaseDocNo.dat') then
+      CaseDocNoList.LoadFromFile(ImageSavePath+CaseNo+'\CaseDocNo.dat');
+    if FileExists(ImageSavePath+CaseNo+'\CaseDocNo_Copies.dat') then
+      CaseDocNo_CopiesList.LoadFromFile(ImageSavePath+CaseNo+'\CaseDocNo_Copies.dat');
+    case Mode of
+      'A':begin
+            CaseDocNoList.Add(DocDir);
+            CaseDocNo_CopiesList.Add(Copies);
+            SetRecordEditedDocDir('A',CaseNo,DocDir);
+          end;
+      'I':begin
+            CaseDocNoList.Insert(Index,DocDir);
+            CaseDocNo_CopiesList.Insert(Index,Copies);
+          end;
+      'E':begin
+            CaseDocNoList.Strings[Index] := DocDir;
+            CaseDocNo_CopiesList.Strings[Index] := Copies;
+          end;
+      'D':begin
+            if Index <> -1 then
+            begin
+              //SetRecordEditedDocDir('D',CaseNo,CaseDocNoList.Strings[Index]);  //20140624 修改刪除文件時也記一筆異動,刪掉會無法通知前端網頁有異動
+              SetRecordEditedDocDir('A',CaseNo,CaseDocNoList.Strings[Index]);  //20170912 要刪除  不然我寫不下去
+
+              CaseDocNoList.Delete(Index);
+              CaseDocNo_CopiesList.Delete(Index);
+
+            end
+            Else if (DocDir <> '') then
+            begin
+              for i := 0 to CaseDocNoList.Count - 1 do
+              begin
+                if DocDir = CaseDocNoList.Strings[i] then
+                begin
+                  //SetRecordEditedDocDir('D',CaseNo,CaseDocNoList.Strings[i]);  //20140624 修改刪除文件時也記一筆異動,刪掉會無法通知前端網頁有異動
+                  SetRecordEditedDocDir('A',CaseNo,CaseDocNoList.Strings[i]);  //20170912 要刪除  不然我寫不下去
+                  CaseDocNoList.Delete(i);
+                  CaseDocNo_CopiesList.Delete(i);
+                  Break;
+                end;
+              end;
+            end;
+            if ContextList.Count = 0 then
+            begin
+              DeleteFile(ImageSavePath+CaseNo+'\CaseDocNo.dat');
+            end;
+          end;
+    end;
+    //Showmessage('abc'+#13+ImageSavePath+CaseNo+'\CaseDocNo.dat'+#13+inttostr(CaseDocNoList.Count)+#13+CaseDocNoList.Text);
+    if CaseDocNoList.Count >= 0 then
+    begin
+      CaseDocNoList.SaveToFile(ImageSavePath+CaseNo+'\CaseDocNo.dat');
+      CaseDocNo_CopiesList.SaveToFile(ImageSavePath+CaseNo+'\CaseDocNo_Copies.dat');
+      //Showmessage('存了');
+    end;
+  finally
+  CaseDocNoList.Free;
+  CaseDocNo_CopiesList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.checkCaseOMRDone:Boolean;  //檢查案件是否完成OMR檢核
+var
+  i : Integer;
+begin
+  Result := True;
+  for I := 0 to NewTreeNode.Count - 1 do
+  begin
+    if NewTreeNode.Item[i].ImageIndex <> 7 then
+    begin
+      Result := False;
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckCaseID_OK:Boolean;  //檢查是否有未配號的案件
+var
+  i,n : Integer;
+begin
+  Result := True;
+  for i := 0 to NewTreeNode.Count - 1 do
+  begin
+    if Pos(_msg('未配號'),NewTreeNode.Item[i].Text) > 0 then
+    begin
+      Result := False;
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckCaseAttach_OK:Boolean;  //檢查是否有未歸類的案件
+var
+  i,j : Integer;
+begin
+  Result := True;
+  for i := 0 to NewTreeNode.Count - 1 do
+  begin
+    for j := 0 to NewTreeNode.Item[i].Count - 1 do
+    begin
+      if Pos(_msg('未歸類'),NewTreeNode.Item[i].Item[j].Text) > 0 then
+      begin
+        Result := False;
+        Break;
+      end;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.CreateEmptyCase(Path,CaseID:String);  //產生空白案號(重掃件用)
+var
+  S : TStringlist;
+begin
+  S := TStringlist.Create;
+  try
+    S.SaveToFile(Path+CaseID+'\Context.dat');
+    S.Add(FCaseID);
+    S.SaveToFile(Path+'CaseList.dat')
+  finally
+  S.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ShowFileReplace(Path,NewFormID:String);//顯示的影像換成新的FormID
+var
+  i,n : Integer;
+  OldFile,NewFile:String;
+  Ext : String;
+begin
+  for i := 0 to NowShowFileList.Count - 1 do
+  begin
+    OldFile := NowShowFileList.Strings[i];
+    Ext := ExtractFileExt(OldFile);
+    NewFile := Add_Zoo(FileName2ScanPage(OldFile),3)+'_'+NewFormID+Ext;
+    ReNameFile(Path+OldFile,Path+NewFile);
+    SetContextList('E',FileName2Index(OldFile),NowCaseno,NowDocNo,NewFile);
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetCasePage(Path,CaseID:String):Integer;
+var
+  DocDirList,FileList,ST1 :TStringlist;
+  iDocDir,iDocNo : String;
+  i,n,Count : Integer;
+begin
+  Count := 0;
+  DocDirList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  ST1:=TStringList.Create;
+  try
+    if FileExists(Path+CaseID+'\CaseDocNo.dat') then
+      DocDirList.LoadFromFile(Path+CaseID+'\CaseDocNo.dat');
+    //Showmessage(DocDirList.Text);
+    for i := 0 to DocDirList.Count - 1 do
+    begin
+      iDocDir := DocDirList.Strings[i];
+      iDocno := DocNoDir2DocNo(iDocDir);
+      {if (((FIs_In_Wh  = 'Y') and (not DocNoIs_In_WH(iDocNo))) or   //入庫掃描不看非入庫文件
+         ((FIs_In_Wh  = 'N') and (DocNoIs_In_WH(iDocNo)))) and
+         ((iDocNo <> 'Attach') and (Copy(iDocNo,1,5)<>'ZZZZZ')) then     //非入庫掃描不看入庫文件
+      begin
+        Continue;
+      end;}
+      //if not DocNoAppear(iDocNo) then Continue; //20170817 先註解
+
+      FileList.Clear;
+      if FileExists(Path+CaseID+'\'+iDocDir+'\Context.dat') then
+      begin
+        FileList.LoadFromFile(Path+CaseID+'\'+iDocDir+'\Context.dat');
+
+        if (FWH_category='N') and (FIs_In_Wh='Y') then
+        begin
+          ST1.Clear;
+          for n := 0 to FileList.Count - 1 do
+          begin
+            if ISExistImg(Path+CaseID+'\'+iDocDir+'\'+FileList.Strings[n]) then
+            begin
+              ST1.Add(FileList.Strings[n]);
+            end;
+          end;
+
+          for n := 0 to ST1.Count - 1 do
+          begin
+            if (FileList.IndexOf(ST1.Strings[n])<>-1) and (not DocNoIs_In_WH(iDocNo)) then
+            begin
+              FileList.Delete(FileList.IndexOf(ST1.Strings[n]));
+            end;
+          end;
+        end
+        Else
+          if not DocNoAppear(iDocNo) then Continue; //20180925 Hong覺得應該要加這段
+      end;
+
+
+      Count := Count+ FileList.Count;
+    end;
+    if FileExists(Path+CaseID+'\'+AttName+'\Context.dat') then
+    begin
+      FileList.LoadFromFile(Path+CaseID+'\'+AttName+'\Context.dat');
+      Count := Count+ FileList.Count;
+    end;
+
+    Result := Count;
+  finally
+  DocDirList.Free;
+  FileList.Free;
+  ST1.free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetFile2Case(CaseID,FileName:String);
+var
+  S :TStringlist;
+begin
+  S := TStringlist.Create;
+  try
+    S.LoadFromFile(ImageSavePath+CaseID+'\Context.dat');
+    S.Add(FileName);
+    S.SaveToFile(ImageSavePath+CaseID+'\Context.dat');
+  finally
+  S.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetCase_PageCount(var CaseCount,PageCount:Integer):Boolean; //取出案件的數量及頁數
+var
+  i,n,k: Integer;
+  CaseList,DocList,FileList,ST1 : TStringlist;
+begin
+  Result := False;
+  CaseCount := 0;
+  PageCount := 0;
+  CaseList := TStringlist.Create;
+  DocList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  ST1:= TStringlist.Create;
+  try
+    ImageSavePath := ImagePath;
+    CaseList.Clear;
+    if FileExists(ImageSavePath + 'CaseList.dat') then
+      CaseList.LoadFromFile(ImageSavePath + 'CaseList.dat');
+    CaseCount :=  CaseCount+CaseList.Count;
+//ShowMessage('ImageSavePath='+ImageSavePath+#10#13+'CaseList.Count='+IntToStr(CaseList.Count));
+    for i := 0 to CaseList.Count - 1 do
+    begin
+      DocList.Clear;
+      If FileExists(ImageSavePath+CaseList.Strings[i]+'\CaseDocNo.dat') Then
+        DocList.LoadFromFile(ImageSavePath+CaseList.Strings[i]+'\CaseDocNo.dat');
+//ShowMessage('DocList='+DocList.Text);
+      for n := 0 to DocList.Count - 1 do
+      begin
+//ShowMessage(DocList.Strings[n]+','+BoolToStr(DocNoAppear(DocNoDir2DocNo(DocList.Strings[n])),true));
+        if not DocNoAppear(DocNoDir2DocNo(DocList.Strings[n])) then Continue;
+        FileList.Clear;
+        If FileExists(ImageSavePath+CaseList.Strings[i]+'\'+DocList.Strings[n]+'\Context.dat') Then
+          FileList.LoadFromFile(ImageSavePath+CaseList.Strings[i]+'\'+DocList.Strings[n]+'\Context.dat');
+        PageCount := PageCount+FileList.Count;
+      end;
+      //Showmessage(inttostr(PageCount));
+      FileList.Clear;
+      If FileExists(ImageSavePath+CaseList.Strings[i]+'\'+Attname+'\Context.dat') Then
+          FileList.LoadFromFile(ImageSavePath+CaseList.Strings[i]+'\'+Attname+'\Context.dat');
+      //Showmessage(ImageSavePath+CaseList.Strings[i]+'\'+Attname+'\Context.dat');
+//Showmessage('FileList='+FileList.Text);
+      PageCount := PageCount+FileList.Count;
+//Showmessage('PageCount='+inttostr(PageCount));
+      if (FWH_category='N') and (FIs_In_Wh='Y') then  //20170912 針對非入庫並當次掃描做頁數計算
+      begin
+        if FileExists(ImageSavePath+NowCaseno+'\EditedDocDir.dat') then
+        begin
+          ST1.LoadFromFile(ImageSavePath+NowCaseno+'\EditedDocDir.dat');
+          for n := 0 to ST1.Count - 1 do
+          begin
+            if ST1.Strings[n]=AttName then  Continue;
+//ShowMessage(ST1.Strings[n]+','+BoolToStr(DocNoIs_In_WH(DocNoDir2DocNo(ST1.Strings[n])),true));
+            if not DocNoIs_In_WH(DocNoDir2DocNo(ST1.Strings[n])) then
+            begin
+
+              FileList.Clear;
+              if FileExists(ImageSavePath+CaseList.Strings[i]+'\'+ST1.Strings[n]+'\Context.dat') then
+              begin
+                FileList.LoadFromFile(ImageSavePath+CaseList.Strings[i]+'\'+ST1.Strings[n]+'\Context.dat');
+                for k := 0 to FileList.Count - 1 do
+                begin
+                  if not ISExistImg(ImageSavePath+CaseList.Strings[i]+'\'+ST1.Strings[n]+'\'+FileList.Strings[k]) then
+                    PageCount := PageCount+1;
+                end;
+              end;
+            end;
+          end;
+        end;
+      end;
+    end;
+  Finally
+  CaseList.Free;
+  DocList.Free;
+  FileList.Free;
+  ST1.Free
+  end;
+  Result := True;
+end;
+
+Function TCB_IMGPSScanX.BarCode2CaseID : String; //Barcode依規則轉成CaseID
+var
+  i : Integer;
+  iCaseID : String;
+begin
+  Result := ''; //沒找到
+  iCaseID := '';
+  for i := 1 to MpsBarcodeinf.Count  do    //20180920 拿掉-1
+  begin
+    if (Length(MpsBarcodeinf.text[i]) = CaseIDLength) then
+    begin
+      iCaseID := MpsBarcodeinf.text[i];
+      Result := iCaseID;
+      Break;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.WriteCaseIndex(Path:String);
+Var
+  S : TStringlist;
+begin
+  if Path = '' then Exit;
+  S := TStringlist.Create;
+  try
+    try
+      S.Add(Case_loandoc);
+      S.SaveToFile(Path+'CaseIndex.dat');
+    except on E: Exception do
+    end;
+
+  finally
+  S.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ReadCaseIndex(Path:String);
+Var
+  S : TStringlist;
+begin
+  AddCredit1RG.ItemIndex := -1;
+  S := TStringlist.Create;
+  try
+    if FileExists(Path+'CaseIndex.dat') then
+    begin
+      S.LoadFromFile(Path+'CaseIndex.dat');
+      Case_loandoc := S.Strings[0];
+    end;
+    if (Case_loandoc = '') and (FLoanDoc_Value <> '') then
+    begin
+      Case_loandoc := FLoanDoc_Value;
+      WriteCaseIndex(Path);
+    end;
+    if Case_loandoc = 'Y' then
+      AddCredit1RG.ItemIndex := 0
+    Else if Case_loandoc = 'N' then
+      AddCredit1RG.ItemIndex := 1;
+
+  finally
+  S.Free;
+  end;
+
+end;
+
+
+procedure TCB_IMGPSScanX.ReduceLogFile; //20171011 必免log檔掌太大
+var
+  ST1:TStringlist;
+  I:integer;
+begin
+  ST1:=TStringList.Create;
+  if FileExists(LngPath+'IMGPSCheck.log') then
+  begin
+    ST1.LoadFromFile(LngPath+'IMGPSCheck.log');
+    if ST1.count>100000 then
+    begin
+      for I := 0 to 10000 do
+      begin
+        ST1.Delete(0);
+      end;
+      ST1.SaveToFile(LngPath+'IMGPSCheck.log');
+    end;
+  end;
+  ST1.Free;
+end;
+
+Procedure TCB_IMGPSScanX.ClearCaseIndex;
+begin
+  AddCredit1RG.Enabled := False;
+  AddCredit1RG.ItemIndex := -1;
+end;
+
+Function TCB_IMGPSScanX.GetDocNoDir(Path,DocNo:String):String; //取出目前DocNo的份數
+var
+  i : Integer;
+  iDocNo : String;
+begin
+  if (DocNo <> '') then
+  begin
+    i := 0;
+    Repeat
+    begin
+      inc(i);
+      iDocNo := Format('%s_%d',[DocNo,i]);
+    end;
+    until not DirectoryExists(Path+iDocNo);
+    Result := iDocNo;
+  end
+  Else
+  begin
+    Result := AttName;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNo2DocNoDir(Path,DocNo:String):String;    //DocNo轉成DocNo(份數)目錄
+var
+  i : Integer;
+  iDocNo : String;
+begin
+  if (DocNo <> '') then
+  begin
+    i := 0;
+    Repeat
+    begin
+      inc(i);
+      iDocNo := Format('%s(%d)',[DocNo,i]);
+    end;
+    until not DirectoryExists(Path+iDocNo);
+    Result := iDocNo;
+  end
+  Else
+  begin
+    Result := AttName;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNoDir2DocNo(DocNoDir:String):String; //DocNo(份數)目錄轉成DocNo
+var
+  v,ln : Integer;
+begin
+  if (DocNoDir <> 'Attach') and (DocNoDir <> 'S_Attach') then
+  begin
+    v := Pos('(',DocNoDir);
+    if v > 0 then
+      Result := Copy(DocNoDir,1,v-1)
+    else
+      Result := DocNoDir;
+  end
+  Else
+    Result := DocNoDir
+end;
+
+Function TCB_IMGPSScanX.DocNoDir2Index(Path,DocNoDir:String):Integer; //DocNo(份數)目錄轉成index
+var
+  i : Integer;
+  CaseNo_List : TStringlist;
+begin
+  Result := -1;
+  CaseNo_List := TStringlist.Create;
+  try
+    CaseNo_List.LoadFromFile(Path+'CaseDocNo.dat');
+    for i := 0 to CaseNo_List.Count - 1 do
+    begin
+      if DocNoDir = CaseNo_List.Strings[i] then
+      begin
+        Result := i;
+        Break;
+      end;
+    end;
+  finally
+  CaseNo_List.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ZipMainFile(SoPath,DePath,ZipName:String);
+var
+  ZipFileList : TStringlist;
+  n : Integer;
+begin
+  ZipFileList := TStringlist.Create;
+  try
+    if fileExists(DePath+ZipName) then
+      DeleteFile(DePath+ZipName);
+    {if FileExists(SoPath+'ReSize.dat') then
+      DeleteFile(SoPath+'ReSize.dat');}
+    //Showmessage(SoPath+#13+ContextList.Text);
+    for n := 0 to ContextList.Count - 1 do
+    begin
+      {WriteResize(SoPath+ContextList.Strings[n],SoPath+'ReSize.dat');}
+      ZipFileList.Add(SoPath+ContextList.Strings[n]);
+      if FileExists(SoPath+'@'+ContextList.Strings[n]) then
+        ZipFileList.Add(SoPath+'@'+ContextList.Strings[n]);
+    end;
+    if FileExists(SoPath+'Context.dat') then
+      ZipFileList.Add(SoPath+'Context.dat');
+
+    AttContextList.Clear;
+    if FileExists(SoPath+'ATTContext.dat') then
+      AttContextList.LoadFromFile(SoPath+'ATTContext.dat');
+    for n := 0 to AttContextList.Count - 1 do
+    begin
+      ZipFileList.Add(SoPath+AttContextList.Strings[n]);
+    end;
+    if FileExists(SoPath+'ATTContext.dat') then
+      ZipFileList.Add(SoPath+'ATTContext.dat');
+
+
+    if FileExists(SoPath+'Context_DocNo.dat') then
+      ZipFileList.Add(SoPath+'Context_DocNo.dat');
+    if FileExists(SoPath+'scanlist.dat') then
+      ZipFileList.Add(SoPath+'scanlist.dat');
+    if FileExists(SoPath+'FormCode_Name.dat') then
+      ZipfileList.Add(SoPath+'FormCode_Name.dat');
+    if FileExists(SoPath+'DocNo_Name.dat') then
+      ZipfileList.Add(SoPath+'DocNo_Name.dat');
+    if FileExists(SoPath+'ReSize.dat') then
+      ZipfileList.Add(SoPath+'ReSize.dat');
+    if FileExists(SoPath+'FormIDReplace.dat') then
+      ZipfileList.Add(SoPath+'FormIDReplace.dat');
+    if FileExists(SoPath+'AnchorError.dat') then
+      ZipfileList.Add(SoPath+'AnchorError.dat');
+    if FileExists(SoPath+'CaseDocNo.dat') then
+      ZipfileList.Add(SoPath+'CaseDocNo.dat');
+    if FileExists(SoPath+'CaseDocNo_Copies.dat') then
+      ZipfileList.Add(SoPath+'CaseDocNo_Copies.dat');
+    if FileExists(SoPath+'CustomDocNo.ini') then
+      ZipfileList.Add(SoPath+'CustomDocNo.ini');
+    if FileExists(SoPath+'DocDir.dat') then
+      ZipfileList.Add(SoPath+'DocDir.dat');
+    if FileExists(SoPath+'In_Wh.dat') then
+      ZipfileList.Add(SoPath+'In_Wh.dat');
+    if FileExists(SoPath+'UseCase.ini') then
+      ZipfileList.Add(SoPath+'UseCase.ini');
+
+    if FileExists(SoPath+'FirstImg.zip') then//20170315 加的
+    begin
+      ZipfileList.Add(SoPath+'FirstImg.zip');
+    end;
+
+
+    ExeCuteZip(DePath+ZipName,SoPath,ZipFileList,False,False);
+    //Showmessage('111');
+  finally
+  ZipFileList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ZipMaskFile(SoPath,MarkPath,DePath,ZipName:String); //壓縮遮罩影像檔
+var
+  ZipFileList : TStringlist;
+  n : Integer;
+begin
+  ZipFileList := TStringlist.Create;
+  try
+    if fileExists(DePath+ZipName) then
+      DeleteFile(DePath+ZipName);
+
+    for n := 0 to ContextList.Count - 1 do
+    begin
+      ZipFileList.Add(MarkPath+ContextList.Strings[n]);
+    end;
+    if FileExists(SoPath+'Context.dat') then
+      ZipFileList.Add(SoPath+'Context.dat');
+    if FileExists(SoPath+'scanlist.dat') then
+      ZipFileList.Add(SoPath+'scanlist.dat');
+    if FileExists(SoPath+'FormCode_Name.dat') then
+      ZipfileList.Add(SoPath+'FormCode_Name.dat');
+    if FileExists(SoPath+'DocNo_Name.dat') then
+      ZipfileList.Add(SoPath+'DocNo_Name.dat');
+    if FileExists(SoPath+'ReSize.dat') then
+      ZipfileList.Add(SoPath+'ReSize.dat');
+    if FileExists(SoPath+'Err.jpg') then
+      ZipfileList.Add(SoPath+'Err.jpg');
+    if FileExists(SoPath+'auth.jpg') then
+      ZipfileList.Add(SoPath+'auth.jpg');
+    ExeCuteZip(DePath+ZipName,SoPath,ZipFileList,False,False);
+  finally
+  ZipFileList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.MemoInfoTransfer(Mode,Str:String;ID_S,Name_S:TStringlist):String;  //註記代碼註記類別轉換  Mode 'ID':代碼轉名稱;'NAME':名稱轉代碼
+var
+  i : Integer;
+begin
+  if Mode = 'ID' then
+  begin
+    Result := _Msg('自行輸入');
+    for i := 0 to ID_S.Count - 1 do
+    begin
+      if Str = ID_S.Strings[i] then
+      begin
+        Result := Name_S.Strings[i];
+        Break;
+      end;
+    end;
+  end
+  else if Mode = 'NAME' then
+  begin
+    Result := '00';
+    for i := 0 to Name_S.Count - 1 do
+    begin
+      if Str = Name_S.Strings[i] then
+      begin
+        Result := ID_S.Strings[i];
+        Break;
+      end;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetSQLData(ColumeStr:String;FromList,ToList:TStringlist); //把SQL值塞入
+var
+  i : Integer;
+begin
+  ToList.Clear;
+  ToList.Add(ColumeStr);
+  For i := 1 to FromList.Count -1 do
+  begin
+    ToList.Add(FromList.Strings[i]);
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetSQLData(TableList:TStringlist;Colname:String;colNo:Integer):String; //依欄位及索引取值
+var
+  i,col,v,v1 : Integer;
+  ColStr,DataStr: TStringList;
+  TmpStr : String;
+  P1,p2 : Integer;
+begin
+  Result := '';
+  ColStr := TStringList.Create;
+  DataStr := TSTringList.Create;
+  ColStr.CommaText := TableList.Strings[0];
+  TmpStr := TableList.Strings[ColNo];
+  //DataStr.Text:=StringReplace(TmpStr,'!@!',#13,[rfReplaceAll]);
+
+  While Length(Tmpstr) > 0 do
+  begin
+    v:= Pos('!@!',TmpStr);
+    v1 := Length(TmpStr);
+    If v > 0 Then
+    begin
+      DataStr.Add(Copy(TmpStr,1,v-1));
+      TmpStr := Copy(TmpStr,v+3,V1-(V-2));
+    end
+    Else
+    begin
+      DataStr.Add(TmpStr);
+      TmpStr := '';
+    end;
+  end;
+  For i := 0 to ColStr.Count-1 do
+  begin
+    IF ColStr.Strings[i] = ColName Then
+    begin
+      Result := '';
+      If (DataStr.Count > 0) and (i<=DataStr.Count-1) Then
+        Result := DataStr.Strings[i];
+      //If (DataStr.Count > 0) and (i<=DataStr.Count-1) Then
+      //begin
+        {if i = 0 then
+        begin
+          P1 := 1;
+          p2 := PosN('!@!',TmpStr,1)-1;
+        end
+        else
+        begin
+          P1 := PosN('!@!',TmpStr,i)+3;
+          p2 := PosN('!@!',TmpStr,i+1)-p1;
+        end;
+
+
+        Result :=Copy(tmpstr,p1,p2);}
+      //end;
+        //Result := DataStr.Strings[i];
+
+      Break;
+    end;
+  end;
+  ColStr.Free;
+  DataStr.Free;
+end;
+
+Function TCB_IMGPSScanX.FindSQLData(TableList:TStringlist;ColumeStr,KeyColumeStr,KeyStr:String;ColNo:Integer;Var ResultList:TStringlist):Boolean; //找指定的資料
+Var i,n,Findindex : Integer;
+    ColList,KeyColList,KeyList : TStringlist;
+    Cols,Keycols,keys :String;
+    Find:Boolean;
+begin
+  ResultList.Clear;
+  if (KeyStr = '') or (TableList.Count <= 1) then
+  begin
+    Result := False;
+    Exit;
+  end;
+
+  ColList := TStringlist.Create;
+  KeyColList := TStringlist.Create;
+  KeyList := TStringlist.Create;
+  try
+    ColList.CommaText := ColumeStr;
+    KeyColList.CommaText := KeyColumeStr;
+    KeyList.CommaText := KeyStr;
+    if ColNo = 0 then
+    begin
+      for i := 1 to TableList.Count -1 do  //找key對不對
+      begin
+        Findindex := i;
+        for n := 0 to KeyColList.Count - 1 do
+        begin
+          Find := True;
+          Keycols := KeyColList.Strings[n];
+          keys := KeyList.Strings[n];
+          //Showmessage(keys);
+          //Showmessage(TableList.Strings[i]);
+          if GetSQLData(TableList,Keycols,i) = keys then //對.繼續
+          //if Pos('!@!'+keys+'!@!','!@!'+TableList.Strings[i]+'!@!') >0 then  //在資料列前後加!@! 用pos的方式來改善速度  //20130521發現找資料會有問題
+            Continue
+          Else   //不對.離開
+          begin
+            Find := False;
+            Break;
+          end;
+        end;
+        if Find then Break;  // 找到了離開
+      end;
+    end
+    Else
+    begin
+      i := ColNo;
+      Findindex := i;
+      for n := 0 to KeyColList.Count - 1 do
+      begin
+        Find := True;
+        Keycols := KeyColList.Strings[n];
+        keys := KeyList.Strings[n];
+        //if GetSQLData(TableList,Keycols,i) = keys then //對.繼續
+        if Pos('!@!'+keys+'!@!','!@!'+TableList.Strings[i]+'!@!') >0 then  //在資料列前後加!@! 用pos的方式來改善速度
+            Continue
+        Else   //不對.離開
+        begin
+          Find := False;
+          Break;
+        end;
+      end;
+    end;
+    if Find then //有找到key
+    begin
+      for n := 0 to ColList.Count -1 do
+      begin
+        Cols := ColList.Strings[n];
+        ResultList.Add(Cols+','+GetSQLData(TableList,Cols,Findindex));
+      end;
+    end;
+  finally
+  Result := Find;
+  ColList.Free;
+  KeyColList.Free;
+  KeyList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.DataLoading(Loading:Boolean;UseTimer:Boolean);  //資料載入中要停止點選的動作
+begin
+  If Loading Then
+  begin
+    Screen.Cursor := -11;
+    if UseTimer then
+    begin
+      Panel22.Caption := ShowText;
+      Panel22.Left := (Panel9.Width div 2) - (Panel22.Width div 2);
+      Panel22.Top := (Panel9.Height div 2) - (Panel22.Height div 2);
+      Panel22.Visible := True;
+      Timer2.Enabled := True;
+    end
+    Else
+    begin
+      Panel8.Left := (Panel9.Width div 2) - (Panel8.Width div 2);
+      Panel8.Top := (Panel9.Height div 2) - (Panel8.Height div 2);
+      Panel8.Visible := True;
+    end;
+    Application.ProcessMessages;
+    Panel1.Enabled := False;
+    Panel2.Enabled := False;
+  end
+  Else
+  begin
+    Panel22.Visible := False;
+    Panel8.Visible := False;
+    Timer2.Enabled := False;
+    Panel1.Enabled := True;
+    Panel2.Enabled := True;
+    Screen.Cursor := 0;
+  end;
+
+end;
+
+function TCB_IMGPSScanX.LoadFileGetMD5(const filename: string): string;
+var
+  Stream: TFileStream;
+  //Buffer: array[0..1023] of AnsiChar;
+  Buffer: array[0..1023] of AnsiChar;
+  TempStr: string;
+  i: Integer;
+  idmd5:TIdHashMessageDigest5;  //import IdHashMessageDigest, idHash
+
+begin
+  idmd5 := TIdHashMessageDigest5.Create;
+
+  try
+    Stream := TFileStream.Create(filename, fmOpenRead);
+    Stream.Read(Buffer[0], SizeOf(Buffer));
+
+    result := idmd5.HashStreamAsHex(Stream) ;
+  finally
+    idmd5.Free;
+    Stream.Free;
+
+  end;
+end;
+
+procedure TCB_IMGPSScanX.LoadImgFile;  //載入新件及替換件
+Var
+  i,v,v1,m : Integer;
+  CasePage : integer;
+  TempName : String;
+  BarName : String;
+  DocName : String;
+  //S : String;
+begin
+  ClearView(1);
+  PageLV.Clear;
+  AttListBox.Items.Clear;
+  AddAttFileLB.Enabled := False;
+  DelAttFileLB.Enabled := False;
+  DisplayPath := '';
+  ClearCaseIndex;
+  CaseHelpBtn.Visible := False;
+  //Del_Sub_NothingPath(ImageSavePath);  //清掉案件目錄是空的
+  TreeView1.Items.Clear;
+  NewTreeNode := nil;
+  MyTreenode1 := nil;
+  MyTreenode2 := nil;
+  MyTreenode3 := nil;
+  NewTreeNode := TreeView1.Items.Add(nil,Format(_Msg('%s-共%d筆共%d頁'),[FModeName,0,0]));
+  NewTreenode.ImageIndex := 0;
+  NewTreenode.SelectedIndex := 0;
+  Del_Sub_NothingPath(ImageSavePath);  //清掉案件目錄是空的
+  GetCase_PageCount(CaseCount,PageCount);
+  CaseList.Clear;
+  if FileExists(ImageSavePath + 'CaseList.dat') then
+    CaseList.LoadFromFile(ImageSavePath + 'CaseList.dat');
+  for i := 0 to CaseList.Count - 1 do
+  begin
+    CaseDocNoList.Clear;
+    if FileExists(ImageSavePath+CaseList.Strings[i]+'\CaseDocNo.dat') then
+      CaseDocNoList.LoadFromFile(ImageSavePath+CaseList.Strings[i]+'\CaseDocNo.dat');
+    if not FileExists(ImageSavePath+CaseList.Strings[i]+'\CaseDocNo_Copies.dat') then
+    begin
+      CaseDocNo_CopiesList.Clear;
+      for m := 0 to CaseDocNoList.Count - 1 do
+      begin
+        CaseDocNo_CopiesList.Add('1');
+        CaseDocNo_CopiesList.SaveToFile(ImageSavePath+CaseList.Strings[i]+'\CaseDocNo_Copies.dat');
+      end;
+    end;
+
+    CasePage := GetCasePage(ImageSavePath,CaseList.Strings[i]);
+//ShowMessage('CasePage='+IntToStr(CasePage));
+    MytreeNode1 := TreeView1.Items.AddChild(NewTreeNode,Format(_Msg('%s-%d頁'),[CaseList.Strings[i],CasePage]));
+    MytreeNode1.ImageIndex := 1;
+    MytreeNode1.SelectedIndex := 1;
+    DrawDocItem2(MytreeNode1,CaseList.Strings[i]); //長出文件名稱的樹並傳回是否有申請書的影像
+    if Pos(_Msg('未配號'),CaseList.Strings[i]) > 0 then
+    begin
+      MytreeNode1.ImageIndex := 5;
+      MytreeNode1.SelectedIndex := 5;
+    end;
+    If FileExists(ImageSavePath+CaseList.Strings[i]+'\OMRCheckOk.dat') Then
+    begin
+      MytreeNode1.ImageIndex := 7;
+      MytreeNode1.SelectedIndex := 7;
+      CaseHelpBtn.Visible := False;
+    end
+    Else IF FileExists(ImageSavePath+CaseList.Strings[i]+'\Checkerr.ini') Then
+    begin
+      MyTreenode1.ImageIndex := 5;
+      MyTreenode1.SelectedIndex := 5;
+
+      //AllEnforceLb.Visible := True; //全部強迫送件
+    end;
+  end;
+  MyTreenode1 := nil;
+  MyTreenode2 := nil;
+  If NewTreeNode <> nil Then
+  begin
+    TreeView1.Selected := NewTreeNode;
+    NewTreeNode.Expand(False);
+  end;
+  IF (NewTreeNode <> nil) and (NewTreeNode.Count > 0) Then
+  begin
+    GetCase_PageCount(CaseCount,PageCount);
+    v := Pos('-',NewTreeNode.Text);
+    NewTreeNode.Text := Format(_Msg('%s-共%d筆共%d頁'),[Copy(NewTreeNode.Text,1,v-1),CaseCount,PageCount]);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.LoadImgFile1;  //載入新件及替換件
+Var
+  i,n,v,v1,m : Integer;
+  p : integer;
+  iCaseNo,iDocNo : String;
+  TempName : String;
+  BarName : String;
+  DocName : String;
+  //S : String;
+begin
+  ClearView(1);
+  PageLV.Clear;
+  DisplayPath := '';
+  ClearCaseIndex;
+  CaseHelpBtn.Visible := False;
+  //Del_Sub_NothingPath(ImageSavePath);  //清掉案件目錄是空的
+  TreeView1.Items.Clear;
+  NewTreeNode := nil;
+  MyTreenode1 := nil;
+  MyTreenode2 := nil;
+  MyTreenode3 := nil;
+  NewTreeNode := TreeView1.Items.Add(nil,Format(_Msg('%s-共%d筆共%d頁'),[FModeName,0,0]));
+  NewTreenode.ImageIndex := 0;
+  NewTreenode.SelectedIndex := 0;
+
+  Del_Sub_NothingPath(ImageSavePath);  //清掉案件目錄是空的
+  GetCase_PageCount(CaseCount,PageCount);
+  CaseList.Clear;
+  if FileExists(ImageSavePath + 'CaseList.dat') then
+    CaseList.LoadFromFile(ImageSavePath + 'CaseList.dat');
+  for n := 0 to CaseList.Count - 1 do
+  begin
+    iCaseNo := CaseList.Strings[n];
+    CaseDocNoList.Clear;
+    if FileExists(ImageSavePath+CaseList.Strings[n]+'\DocNoList.dat') then
+      CaseDocNoList.LoadFromFile(ImageSavePath+CaseList.Strings[n]+'\DocNoList.dat');
+
+    for m := 0 to CaseDocNoList.Count - 1 do
+    begin
+      iDocNo := CaseDocNoList.Strings[i];
+      MytreeNode1 := TreeView1.Items.AddChild(NewTreeNode,Format(_Msg('%s-%d頁'),[CaseList.Strings[n],p]));
+      MytreeNode1.ImageIndex := 1;
+      MytreeNode1.SelectedIndex := 1;
+    end;
+
+
+    ContextList.Clear;
+    Context_DocnoList.Clear;
+    If FileExists(ImageSavePath+CaseList.Strings[n]+'\Context.dat') Then
+    begin
+      ContextList.LoadFromFile(ImageSavePath+CaseList.Strings[n]+'\Context.dat');
+      if FileExists(ImageSavePath+CaseList.Strings[n]+'\Context_DocNo.dat') then
+        Context_DocnoList.LoadFromFile(ImageSavePath+CaseList.Strings[n]+'\Context_DocNo.dat')
+      else
+      begin
+        for m := 0 to ContextList.Count - 1 do
+        begin
+          Context_DocnoList.Add(FormCode2DocNo(FileName2FormCode(ContextList.Strings[m])));
+        end;
+        Context_DocnoList.SaveToFile(ImageSavePath+CaseList.Strings[n]+'\Context_DocNo.dat');
+      end;
+      Cust_DocNoList.Clear;
+      if FileExists(ImageSavePath+CaseList.Strings[n]+'\CustomDocNo.dat') then
+        Cust_DocNoList.LoadFromFile(ImageSavePath+CaseList.Strings[n]+'\CustomDocNo.dat');
+
+      P := ContextList.Count;
+      MytreeNode1 := TreeView1.Items.AddChild(NewTreeNode,Format(_Msg('%s-%d頁'),[CaseList.Strings[n],p]));
+      MytreeNode1.ImageIndex := 1;
+      MytreeNode1.SelectedIndex := 1;
+      //DrawDocItem1(MytreeNode1,Doc_Inf_List,CaseList.Strings[n]); //長出文件名稱的樹並傳回是否有申請書的影像
+      DrawDocItem2(MytreeNode1,CaseList.Strings[n]); //長出文件名稱的樹並傳回是否有申請書的影像  20140820改
+
+      if Pos(_Msg('未配號'),CaseList.Strings[n]) > 0 then
+      begin
+        MytreeNode1.ImageIndex := 5;
+        MytreeNode1.SelectedIndex := 5;
+      end;
+      If FileExists(ImageSavePath+CaseList.Strings[n]+'\OMRCheckOk.dat') Then
+      begin
+        MytreeNode1.ImageIndex := 7;
+        MytreeNode1.SelectedIndex := 7;
+        CaseHelpBtn.Visible := False;
+      end
+      Else IF FileExists(ImageSavePath+CaseList.Strings[n]+'\Checkerr.ini') Then
+      begin
+        MyTreenode1.ImageIndex := 5;
+        MyTreenode1.SelectedIndex := 5;
+
+        //AllEnforceLb.Visible := True; //全部強迫送件
+      end;
+    end;
+  end;
+
+
+  MyTreenode1 := nil;
+  MyTreenode2 := nil;
+  If NewTreeNode <> nil Then
+  begin
+    TreeView1.Selected := NewTreeNode;
+    NewTreeNode.Expand(False);
+  end;
+  ContextList.Clear;
+  IF (NewTreeNode <> nil) and (NewTreeNode.Count > 0) Then
+  begin
+    GetCase_PageCount(CaseCount,PageCount);
+    v := Pos('-',NewTreeNode.Text);
+    NewTreeNode.Text := Format(_Msg('%s-共%d筆共%d頁'),[Copy(NewTreeNode.Text,1,v-1),CaseCount,PageCount]);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.LoadAttFile(CaseID:String); //載入附加檔案
+var
+  AttContextList : TStringlist;
+  i : Integer;
+begin
+  AttListBox.Clear;
+  AttContextList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\AttContext.dat') then
+    begin
+      AttContextList.LoadFromFile(ImageSavePath+CaseID+'\AttContext.dat');
+    end;
+    for i := 0 to AttContextList.Count - 1 do
+    begin
+      AttListBox.Items.Add(UTF8Decode(HTTPDEcode(AttContextList.Strings[i])));
+    end;
+  finally
+  AttContextList.Free;
+  end;
+end;
+
+function TCB_IMGPSScanX.logTimeString: String;
+begin
+Result:=FormatDateTime('yyyymmdd hh:mm:ss',now) +'  caseNo='+NowCaseno+'  ';
+end;
+
+Function TCB_IMGPSScanX.Case2Mask(SoPath,DePath:String):Boolean;//產生遮罩影像  20170639 發現沒用到
+var
+  XT : TXMLTool;
+  i : Integer;
+  S : TStringlist;
+  SiteList : TStringlist;
+  FormID : String;
+  ColEName : String;
+  FileName : String;
+  nodename : String;
+  Site : String;
+  Anchor : String;
+begin
+  Result := False;
+  if DirectoryExists(DePath) then
+    _DelTree(DePath);
+  Str2Dir(DePath);
+  DeleteFile(SoPath+'MaskImg.zip');
+  SiteList := TStringlist.Create;
+  S := TStringlist.Create;
+  XT := TXMLTool.Create;
+  try
+    S.LoadFromFile(SoPath+'Context.dat');
+    for I := 0 to S.Count - 1 do
+    begin
+      SiteList.Clear;
+      ImageScrollBox1.LoadFromFile(SoPath+S.Strings[i],1);
+
+      FormID := FileName2FormCode(S.Strings[i]);
+      Anchor := FormID2Anchor(FormID);
+      //ParserPoint(CropMpsV.FindPoint(Anchor));
+      FindPoint(ImageScrollBox1.Graphic,UpLPoint,UpRPoint,DownLPoint,Anchor);
+      if FileExists(CheckXmlPath+FWork_no+'\'+FormID+'.xml') then  //沒有Xml就不用遮罩
+      begin
+        XT.LoadFromFile(CheckXmlPath+FWork_no+'\'+FormID+'.xml');
+        if XT.SubNodes['/form/settype10/'].First then
+        Repeat
+          ColEName := XT.SubNodes['/form/settype10/'].NodeName;
+          if XT.SubNodes['/form/settype10/'+ColEName+'/'].First then
+          Repeat
+            nodename := XT.SubNodes['/form/settype10/'+ColEName+'/'].NodeName;
+            If nodename <> '@coldesc' then
+            begin
+              Site := XT.Node['/form/settype10/'+ColEName+'/'+nodename+'/'].Attributes['colxy'];
+              SiteList.Add(Site);
+              Result := True;  //有設定
+            end
+            Else
+            begin
+              //ColCName := XT['/form/settype1/'+ColEName+'/'+nodename+'/'];
+            end;
+          Until not XT.SubNodes['/form/settype10/'+ColEName+'/'].Next;
+        Until not XT.SubNodes['/form/settype10/'].Next ;
+        FieldMask(ImageScrollBox1,SiteList.Text,'Mask',UpLPoint);
+      end;
+      SaveAnnotation(ImageScrollBox1,DePath+S.Strings[i]);
+    end;
+  finally
+  SiteList.Free;
+  S.Free;
+  XT.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetNewCustomDocNo(Path,DocName:String):String; //取出未使用的自訂文件代號
+var
+  ini : Tinifile;
+  Ct:Integer;
+  DocNo,FormID : String;
+
+  {i,n,v,ln : Integer;
+  C_No,C_Name : String;
+  CNo : Integer;
+  S : TStringlist;
+  NewDocNo : String;}
+begin
+  ini := Tinifile.Create(Path+'CustomDocNo.ini');
+  try
+    Ct := ini.ReadInteger('CustomCount','Count',0);
+    inc(Ct);
+    DocNo := 'ZZZZZ'+Add_Zoo(Ct,3);
+    if FIs_In_Wh <> 'Y' then //不是入庫文件
+      DocNo := 'YYYYY'+Add_Zoo(Ct,3);
+
+    if (FMode='ESCAN') and (FWH_category='N')  then //20170914 補件下改成非入庫的自定文件
+    begin
+      DocNo := 'YYYYY'+Add_Zoo(Ct,3);
+    end;
+
+    FormID := DocNo+'010101A';
+    ini.WriteInteger('CustomCount','Count',Ct);
+    ini.WriteString(DocNo,'FormID',FormID);
+    ini.WriteString(DocNo,'Name',DocName);
+    Result := DocNo;
+  finally
+  ini.Free;
+  end;
+
+  {S := TStringlist.Create;
+  try
+  NewDocNo :='ZZZZZ001';
+  if FileExists(Path+'CustomDocNo.dat') then
+  begin
+    ///   ZZZZZ001_自定文件名稱  001_自定文件名稱
+    S.LoadFromFile(Path+'CustomDocNo.dat');
+    for i := 0 to S.Count - 1 do
+    begin
+      v := Pos('_',S.Strings[i]);
+      ln := Length(S.Strings[i]);
+      C_No := Copy(S.Strings[i],1,v-1);
+      C_Name := Copy(S.Strings[i],v+1,ln-v);
+      if DocName = C_Name then
+      begin
+        Showmessage('文件名稱已存在');
+        Result := '';
+        Exit;
+      end;
+    end;
+    CNo := strtoint(Copy(C_No,6,3))+1;
+    NewDocNo := 'ZZZZZ'+Add_Zoo(CNo,3);
+  end;
+  S.Add(NewDocNo+'_'+DocName);
+  S.SaveToFile(Path+'CustomDocNo.dat');
+  Result := NewDocNo;
+  finally
+  S.Free;
+  end; }
+end;
+
+Function TCB_IMGPSScanX.GetCustomDocDir(Path,DocName:String):String; //取出自定文件DocDir
+var
+  i,ct:integer;
+  ini : Tinifile;
+begin
+  Result := '';
+  ini := Tinifile.Create(Path+'CustomDocNo.ini');
+  try
+    ct := ini.ReadInteger('CustomCount','Count',0);
+    for i := 1 to ct do
+    begin
+      if ini.ReadString('ZZZZZ'+Add_Zoo(i,3),'Name','') = DocName then
+      begin
+        Result := 'ZZZZZ'+Add_Zoo(i,3);
+        Break;
+      end;
+      if ini.ReadString('YYYYY'+Add_Zoo(i,3),'Name','') = DocName then
+      begin
+        Result := 'YYYYY'+Add_Zoo(i,3);
+        Break;
+      end;
+    end;
+  finally
+  ini.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.DeleteCustomDocDir(Path,DocNo:String); //刪除自定文件DocNo
+var
+  ini : Tinifile;
+begin
+  ini := Tinifile.Create(Path+'CustomDocNo.ini');
+  try
+    ini.EraseSection(DocNo);
+  finally
+  ini.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FindLastestDocDir(CaseID,DocNo:String):String; //找出最新的DocDir
+var
+  i : Integer;
+  DocNoList,FileList : TStringlist;
+begin
+  Result := '';
+  DocNoList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  try
+  if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+    DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+  for i := DocNoList.Count-1 downto 0 do
+  begin
+    if Copy(DocNoList.Strings[i],1,length(DocNo)) = DocNo then
+    begin
+      Result := DocNoList.Strings[i];
+      Break;
+    end;
+  end;
+  finally
+  DocNoList.Free;
+  FileList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FindLastestDocDirForPage(CaseID,DocNo,formid:String):String; //找出最新的DocDir  20180207  排除隱藏的資料夾
+var
+  i,j:integer;
+  DocNoList,FileList : TStringlist;
+  Imglist: TStringlist;
+  DirIsHide:Boolean;
+begin
+  Result := '';
+  DocNoList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  imglist := TStringlist.Create;
+  try
+  if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+    DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+
+  for i := DocNoList.Count-1 downto 0 do
+  begin
+    if Copy(DocNoList.Strings[i],1,length(DocNo)) = DocNo then
+    begin
+//ShowMessage(ImageSavePath+CaseID+'\'+DocNoList.Strings[i]);
+      if not DocNoIsExistImg(ImageSavePath+CaseID+'\'+DocNoList.Strings[i]+'\') then
+      begin
+//ShowMessage('DDDDD');
+        Result := '';
+        Break;
+      end
+      else
+      begin
+        Result := DocNoList.Strings[i];
+        Break;
+      end;
+    end;
+  end;
+  finally
+    DocNoList.Free;
+    FileList.Free;
+    imglist.Free;
+  end;
+
+end;
+
+
+Procedure TCB_IMGPSScanX.Create_Cust_DocDir(CaseID:String); //產生外面傳入的文件代號及自定文件
+var
+  i,n : Integer;
+  C_DocNoList,C_DocNameList : TStringlist;
+  DocNo,DocName,DocDir : String;
+  DocNo_Ct,NowDocNo_Ct :integer;
+  DocName_Ct : Integer;
+  inx : Integer;
+begin
+  C_DocNoList := TStringlist.Create;
+  C_DocNameList := TStringlist.Create;
+  try
+
+    if FC_DocNoList <> '' then
+    begin
+      C_DocNoList.StrictDelimiter := True;
+      C_DocNoList.Delimiter := #9;
+      C_DocNoList.DelimitedText := FC_DocNoList;
+      //Showmessage(C_DocNoList.Text);
+      for i := 0 to C_DocNoList.Count - 1 do
+      begin
+        DocNo := C_DocNoList.Strings[i];
+        //舊件不長出錯誤的文件出來
+        if (FIs_OldCase = 'Y') and (FWork_no='HLN') and (DocNo = FormCode2DocNo('10000001011112A')) then
+          Continue;
+        NowDocNo_Ct := GetDocNoCount(CaseID,DocNo);
+        if DocNoNeedDiv(DocNo) then
+        begin
+          DocNo_Ct := 0;
+          for n := 0 to i do
+          begin
+            if C_DocNoList.Strings[n] = DocNo then
+              inc(DocNo_Ct);
+          end;
+          if DocNo_CT <= NowDocNo_Ct then
+            Continue;
+          if DirectoryExists(ImageSavePath+CaseID+'\'+DocNo+'('+inttostr(DocNo_Ct)+')') then  //存在了
+            Continue;
+          if (DocNo_Ct = 1) and DirectoryExists(ImageSavePath+CaseID+'\'+DocNo) then  //存在了  20140327加
+            Continue;
+          DocDir := DocNo2DocNoDir(ImageSavePath+CaseID+'\',DocNo)
+
+        end
+        else
+        begin
+          DocDir := DocNo;
+        end;
+        if not DirectoryExists(ImageSavePath+CaseID+'\'+DocDir) then
+        begin
+          MkDir(ImageSavePath+CaseID+'\'+DocDir);
+          SetDocNoList('A',-1,CaseID,DocDir,'1');
+        end;
+        if not DocNoNeedDiv(DocNo) then   //不分份的秀數
+          SetDocDirCopies(CaseID,DocNo,GetCustomDocNoCount(DocNo));
+
+      end;
+    end;
+    if FC_DocNameList <> '' then
+    begin
+      C_DocNameList.StrictDelimiter := True;
+      C_DocNameList.Delimiter := #9;
+      C_DocNameList.DelimitedText := FC_DocNameList;
+      //Showmessage(C_DocNameList.Text);
+      for i := 0 to C_DocNameList.Count - 1 do
+      begin
+        DocName := C_DocNameList.Strings[i];
+        DocName_Ct := GetCustomNameCount(DocName);
+        if not FindCustomDocName(ImageSavePath+CaseID+'\',DocName) then
+        begin
+          DocDir := GetNewCustomDocNo(ImageSavePath+CaseID+'\',DocName);
+          if not DirectoryExists(ImageSavePath+CaseID+'\'+DocDir) then
+          begin
+            MkDir(ImageSavePath+CaseID+'\'+DocDir);
+            SetDocNoList('A',-1,CaseID,DocDir,inttostr(DocName_Ct));
+          end;
+        end
+        Else
+        begin
+          DocDir := GetCustomDocDir(ImageSavePath+CaseID+'\',DocName);
+          //inx := DocNoDir2Index(ImageSavePath+CaseID+'\',DocDir);
+          SetDocDirCopies(CaseID,DocDir,DocName_Ct);
+        end;
+      end;
+    end;
+
+  finally
+  C_DocNoList.Free;
+  C_DocNameList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.OldCasetoNewCase(CaseID:String); //將舊案份數轉成新規則
+var
+  i,n : Integer;
+  C_DocNoList,C_DocNameList : TStringlist;
+  DocNoList,DocNo_CopiesList : TStringlist;
+  DocNo,DocName,DocDir : String;
+  DocNo_Ct :integer;
+begin
+  C_DocNoList := TStringlist.Create;
+  C_DocNameList := TStringlist.Create;
+  DocNoList := TStringlist.Create;
+  DocNo_CopiesList := TStringlist.Create;
+  try
+    DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+    for i := 0 to DocNoList.Count - 1 do
+    begin
+      DocNo_CopiesList.Add('0');
+    end;
+    //Showmessage(FC_DocNoList);
+    if FC_DocNoList <> '' then
+    begin
+      C_DocNoList.StrictDelimiter := True;
+      C_DocNoList.Delimiter := #9;
+      C_DocNoList.DelimitedText := FC_DocNoList;
+      //showmessage(C_DocNoList.Text+#13+#13+DocNoList.Text);
+      for i := 0 to DocNoList.Count - 1 do
+      begin
+        //DocNo := DocNoList.Strings[i];
+        DocNo := DocNoDir2DocNo(DocNoList.Strings[i]);  //20140812 因轉舊案錯誤件會出現DocnoDir
+        DocNo_Ct := 0;
+        for n := 0 to C_DocNoList.Count - 1 do
+        begin
+          if DocNo = C_DocNoList.Strings[n] then
+            inc(DocNo_Ct);
+        end;
+        if DocNo_CT > 0 Then
+          DocNo_CopiesList.Strings[i] := inttostr(DocNo_CT);
+      end;
+      DocNo_CopiesList.SaveToFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+    end;
+    if FC_DocNameList <> '' then
+    begin
+      C_DocNameList.StrictDelimiter := True;
+      C_DocNameList.Delimiter := #9;
+      C_DocNameList.DelimitedText := FC_DocNameList;
+      for i := 0 to DocNoList.Count - 1 do
+      begin
+        DocNo := DocNoList.Strings[i];
+        DocNo_Ct := 0;
+        for n := 0 to C_DocNameList.Count - 1 do
+        begin
+          if GetCustomDocName(ImageSavePath+CaseID+'\',DocNo) = C_DocNameList.Strings[n] then
+            inc(DocNo_Ct);
+        end;
+
+        if DocNo_CT > 0 Then
+          DocNo_CopiesList.Strings[i] :=inttostr(DocNo_CT);
+      end;
+    end;
+    DocNo_CopiesList.SaveToFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+  finally
+  C_DocNoList.Free;
+  C_DocNameList.Free;
+  DocNoList.Free;
+  DocNo_CopiesList.Free;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.SetRecordEditedDocDir(Mode:Char;CaseID,DocDir:String);  //記錄被異動的文件目錄  'A:加入D:刪掉'
+var
+  i : Integer;
+  Exists : Boolean;
+  EditedDocDirList : TStringlist;
+begin
+  EditedDocDirList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\EditedDocDir.dat') then
+      EditedDocDirList.LoadFromFile(ImageSavePath+CaseID+'\EditedDocDir.dat');
+    case Mode of
+      'A':begin
+            Exists := False;
+            for i := 0 to EditedDocDirList.Count - 1 do
+            begin
+              if EditedDocDirList.Strings[i]=DocDir then
+              begin
+                Exists := True;
+                Break;
+              end;
+            end;
+            if not Exists then
+            begin
+              EditedDocDirList.Add(DocDir);
+              EditedDocDirList.SaveToFile(ImageSavePath+CaseID+'\EditedDocDir.dat');
+            end;
+          end;
+      'D':begin
+            for i := 0 to EditedDocDirList.Count - 1 do
+            begin
+              if EditedDocDirList.Strings[i] = DocDir then
+              begin
+                EditedDocDirList.Delete(i);
+                if EditedDocDirList.Count > 0 then
+                  EditedDocDirList.SaveToFile(ImageSavePath+CaseID+'\EditedDocDir.dat')
+                else
+                  DeleteFile(ImageSavePath+CaseID+'\EditedDocDir.dat');
+                Break;
+              end;
+            end;
+          end;
+    end;
+
+  finally
+  EditedDocDirList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetDocDir_Page(CaseID,DocDir:String):Integer;
+var
+  FileList : TStringlist;
+begin
+  Result := 0;
+  FileList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat') then
+    begin
+      FileList.LoadFromFile(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat');
+      Result := FileList.Count;
+    end;
+  finally
+  FileList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.Path2DocDir(Path,CaseID:String):String;
+var
+  i : Integer;
+  DocnoList : TStringlist;
+begin
+  Result := '';
+  DocNoList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+      DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+    if Path[length(Path)]<>'\' then
+      path := path+'\';
+    for i := 0 to DocNoList.Count - 1 do
+    begin
+      if (path=ImageSavePath+CaseID+'\'+DocNoList.Strings[i]+'\') then
+      begin
+        Result := DocNoList.Strings[i];
+        Break;
+      end;
+    end;
+  finally
+  DocNoList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetDocNo_IS_WH(DocNo:String):Boolean; //DocNo是否為入庫文件
+var
+  i :Integer;
+begin
+  Result := False;
+  for i := 0 to IN_WH_DocNoList.Count - 1 do
+  begin
+    if DocNo = IN_WH_DocNoList.Strings[i] then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNoIs_In_WH(DocNo:String):Boolean; //DocNo是否為入庫文件
+var
+  i : Integer;
+begin
+  Result := False;
+  if (Copy(DocNo,1,5)='ZZZZZ') then //20140728 yuu 說自訂文件也是入庫文件
+  begin
+    Result := True;
+    Exit;
+  end;
+  for i := 0 to IN_WH_DocNoList.Count -1 do
+  begin
+    if DocNo = IN_WH_DocNoList.Strings[i] then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+Procedure  TCB_IMGPSScanX.CreateCaseNeedData(Path:String);
+var
+  FileList,DocNoList,CaseDocNoList,CaseDocNo_CopiesList : TStringlist;
+  i,n : Integer;
+  Docno : String;
+  Exists : Boolean;
+begin
+  FileList := TStringlist.Create;
+  DocNoList := TStringlist.Create;
+  CaseDocNoList := TStringlist.Create;
+  CaseDocNo_CopiesList := TStringlist.Create;
+  try
+    if FileExists(Path+'Context.dat') then
+    begin
+      FileList.LoadFromFile(Path+'Context.dat');
+      for i := 0 to FileList.Count - 1 do
+      begin
+        Docno := FormCode2DocNo(FileName2FormCode(FileList.Strings[i]));
+//ShowMessage('Docno='+Docno);
+        DocNoList.Add(DocNo);
+        Exists := False;
+        for n := 0 to CaseDocNoList.Count - 1 do
+        begin
+          if Docno = CaseDocNoList.Strings[n] then
+            Exists := True;
+        end;
+        if not Exists then
+        begin
+          CaseDocNoList.Add(DocNo);
+          CaseDocNo_CopiesList.Add('1');
+        end;
+      end;
+//ShowMessage('CreateCaseNeedData  DocNoList='+DocNoList.Text);
+      DocNoList.SaveToFile(Path+'DocDir.dat');
+      CaseDocNoList.SaveToFile(Path+'CaseDocNo.dat');
+      CaseDocNo_CopiesList.SaveToFile(Path+'CaseDocNo_Copies.dat')
+    end;
+
+  finally 
+  FileList.Free;
+  DocNoList.Free;
+  CaseDocNoList.Free;
+  CaseDocNo_CopiesList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetDocDirtoSelected(CaseNode:TTreeNode;DocDir:String);
+var
+  i : Integer;
+begin
+  for i := 0 to CaseNode.Count - 1 do
+  begin
+    if Pos(DocDir+'{',CaseNode.Item[i].Text) > 0 then
+    begin
+      TreeView1.Selected := CaseNode.Item[i];
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckSelectImg_UseCase(Path,CaseID:String):Boolean; //檢查選擇的影像是否有包含被引用的影像
+var
+  i : Integer;
+  iISBName : String;
+  iISB : TImageScrollBox;
+  ImgPath,DocDir : String;
+begin
+  Result := False;
+  for i := 0 to ComponentCount -1 do
+  begin
+    if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+    begin
+      //Showmessage(Components[i].Name);
+      iISBName := ShapeName2PreViewISBName(TShape(Components[i]));
+      iISB := TImageScrollBox(FindComponent(iISBName));
+      ImgPath := ExtractFilePath(iISB.FileName);
+      DocDir := Path2DocDir(ImgPath,CaseID);
+      if GetUseCase('T',Path,DocDir) <> '' then
+        Result := True;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.TransOldCaseFile(Path:String):Boolean;
+var
+  i : Integer;
+  OldCaseID,Year,Data,Verify:String;
+  SendData : String;
+  OldCaseInfoList,Caseinfolist : TStringlist;
+  OldCasePath : String;
+begin
+  Result := True;
+  OldCaseInfoList := TStringlist.Create;
+  Caseinfolist := TStringlist.Create;
+  try
+    OldCaseInfoList.StrictDelimiter := True;
+    OldCaseInfoList.Delimiter := #9;
+    OldCaseInfoList.DelimitedText := FOldCaseInfo;
+    for i := 0 to OldCaseInfoList.Count - 1 do
+    begin
+      Caseinfolist := SplitString('@#,',OldCaseInfoList.Strings[i]);
+      //Caseinfolist.Delimiter := '_';
+      //Caseinfolist.DelimitedText := OldCaseInfoList.Strings[i];
+      OldCaseID := Caseinfolist.Strings[0];
+      Year := Caseinfolist.Strings[1];
+      Data := Caseinfolist.Strings[4];
+      Verify := Caseinfolist.Strings[5];
+      OldCasePath := Path+OldCaseID+'\';
+      if FileExists(OldCasePath+'UseCase.dat') and FileExists(OldCasePath+'UseCase.ini') then
+      begin
+        //////壓檔/////
+        //ZipMainFile(Path,Path,'Img.zip');
+
+        ////上傳/////
+        SendData:='data='+HTTPEncode(UTF8Encode(Data))+'&verify='+Verify+'&other_case_no='+OldCaseID;
+        //Showmessage(FUrl+'service/slic/SLIC02/useOther?'+senddata);
+        if not upFile(HTTPSClient,FUrl,'service/imgpsc/IMGPSC02/useOther',SendData,'file',OldCasePath+'UseCase.ini',FReWrite,Memo1,False) then
+        begin
+          Showmessage(Format(_Msg('傳送舊件編號(%s)檔案時,網路發生錯誤!!'),[OldCaseID])+_Msg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason);
+          Result := False;
+          Exit;
+        end;
+        if memo1.Lines.Strings[0] = '1' then
+        begin
+          Showmessage(Format(_Msg('傳送舊件編號(%s)檔案時,網路發生錯誤!!'),[OldCaseID])+_Msg('錯誤原因:')+memo1.Lines.Strings[1]);
+          Result := False;
+          Exit;
+        end
+        Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+        begin
+          Showmessage(Format(_Msg('傳送舊件編號(%s)檔案時,網路發生錯誤!!'),[OldCaseID])+_Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入'));
+          Result := False;
+          Exit;
+        end;
+      end;
+
+  ////上傳////
+    end;
+  finally
+  OldCaseInfoList.Free;
+  Caseinfolist.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.Writelog(CaseID : String):Boolean;
+var
+  SendData : String;
+begin
+  Result := True;
+  SendData:='data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&case_no='+CaseID;
+  If not ProcessServlet(HTTPSClient,FURL+'service/imgpsc/IMGPSC06/printlog',SendData,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetFtpinfo(CaseID,Action:String):Boolean;
+var
+  SendData : String;
+
+  Procedure DecodeFtpInfo(EncryStr:String);
+  var
+    FtpStr : String;
+    ftpinfoList : TStringlist;
+  begin
+    if EncryStr = '' then Exit;
+    ftpinfoList := TStringlist.Create;
+    try
+      FtpStr := En_DecryptionStr_Base64('D',EncryStr,MpsKey);
+      SplitString('!@!',FtpStr,ftpinfoList);
+      if ftpinfoList[0] = 'ftps' then
+        FFtpProtocol := fpftps
+      else if ftpinfoList[0] = 'ftp' then
+        FFtpProtocol := fpftp;
+      FFtpIP := ftpinfoList[1];
+      FFtpPort := strtoint(ftpinfoList[2]);
+      FFtpID := ftpinfoList[3];
+      FFtpPwd := ftpinfoList[4];
+
+    finally
+    ftpinfoList.Free;
+    end;
+  end;
+begin
+  Result := True;
+  SendData:='product='+FWork_no+'&case_no='+CaseID+'&department='+FUserUnit+'&action='+Action;
+  If not ProcessServlet_FormData(HTTPSClient,FURL+'service/imgpsc/IMGPSC02/ftps',SendData,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF (memo1.Lines.Strings[0] = '1') Then
+  begin
+    if memo1.Lines.Strings[1]='nodata' then   //nodata 為正常可繼續的判斷
+    begin
+      TransMode := tsNone;
+      Result := True;
+      Exit;
+    end
+    else
+    begin
+      HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+      Result := False;
+      Exit;
+    end;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end
+  else if (memo1.Lines.Strings[0] <> '0') then//不認識的字串
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[0];
+    Result := False;
+    Exit;
+  end;
+  TransMode := tsHttp;
+  FFtpExtraPath := '';
+
+  if memo1.Lines.Strings[0] = '0' then
+  begin
+    if memo1.Lines.Strings[2] = 'Y' then   //要使用FTP
+      TransMode := tsFtp;
+    if memo1.Lines.Count > 3 then
+    begin
+      FFtpExtraPath := memo1.Lines.Strings[3];
+      DecodeFtpInfo(memo1.Lines.Strings[4]);
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetFtpInfo;     //餵入FTP資訊
+begin
+  IIS_Ftp.Display1 := Display1;
+  IIS_Ftp.FTPSClient1 := FTPSClient1;
+  IIS_Ftp.ElMemoryCertStorage := ElMemoryCertStorage;
+  IIS_Ftp.Display1 := Display1;
+  IIS_Ftp.Ftpip := FFtpIP;
+  IIS_Ftp.Ftpuserid := FFtpID;
+  IIS_Ftp.FtpPwd := FFtpPwd;
+  IIS_Ftp.FtpPath := FFtpRootPath;
+  IIS_Ftp.FtpPort := FFtpPort;
+  IIS_Ftp.FtpSSL := True;
+  IIS_Ftp.FtpPassive := True;
+  if FFtpProtocol = fpftp then
+     IIS_Ftp.FtpSSL := False;
+  IIS_Ftp.FtpEncryptDataChannel := true;
+  FTPSClient1.OnControlReceiveAsString := IIS_Ftp.EventHandlers.ControlReceiveAsString;
+  FTPSClient1.OnControlSendAsString := IIS_Ftp.EventHandlers.ControlSendAsString;
+  FTPSClient1.OnSSLError := IIS_Ftp.EventHandlers.SSLError;
+  FTPSClient1.OnCertificateValidate := IIS_Ftp.EventHandlers.CertificateValidate;
+  FTPSClient1.OnTextDataLine := IIS_Ftp.EventHandlers.TextDataLine;
+
+  {Showmessage(Format('Ftpip:%s'+#13
+              +'Ftpid:%s'+#13
+              +'Ftppwd:%s'+#13
+              +'Ftppath:%s'+#13
+              +'Ftpport:%s'+#13
+              ,[FFtpIP,FFtpid,FFtpPwd,Ftppath,inttostr(Ftpport)]));}
+end;
+
+Function TCB_IMGPSScanX.FtpCaseComplete(SendData:String):Boolean;
+begin
+  Result := True;
+  If not ProcessServlet_FormData(HTTPSClient,FURL+'service/imgpsc/IMGPSC02/caseupload',SendData,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF (memo1.Lines.Strings[0] = '1') or (memo1.Lines.Strings[0] <> '0') Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNoAppear(DocNo:String):Boolean;   //DocNo是否可出現
+begin
+  Result := True;
+
+  {if (((FIs_In_Wh  = 'Y') and (not DocNoIs_In_WH(DocNo)) or (DocNo ='S_Attach')) or   //入庫掃描不看非入庫文件
+     ((FIs_In_Wh  = 'N') and (DocNoIs_In_WH(DocNo)) or (DocNo ='Attach') )) {and      //非入庫掃描不看入庫文件
+     (Copy(DocNo,1,5)<>'ZZZZZ')} {then
+       {Result := False;}
+  //20181031 應該要換成下面的判斷比較對,FIs_In_Wh傳空的話才會出全部
+  if (((FIs_In_Wh  = 'Y') and ((not DocNoIs_In_WH(DocNo)) or (DocNo ='S_Attach'))) or   //入庫掃描不看非入庫文件
+     ((FIs_In_Wh  = 'N') and ((DocNoIs_In_WH(DocNo)) or (DocNo ='Attach') ))) {and      //非入庫掃描不看入庫文件
+     (Copy(DocNo,1,5)<>'ZZZZZ')} then
+       Result := False;
+
+
+end;
+
+Function TCB_IMGPSScanX.GetDocNoCount(CaseID,DocNo:String):Integer; //取DocNo數量
+var
+  i : Integer;
+  Doc_Ct:Integer;
+  iDocNo : String;
+  DocNoList,DocNo_CopiesList : TStringlist;
+begin
+  DocNoList := TStringlist.Create;
+  DocNo_CopiesList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+    begin
+      DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+      DocNo_CopiesList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+    end;
+    Doc_Ct := 0;
+    for i := 0 to DocNoList.Count - 1 do
+    begin
+      iDocNo := DocNoDir2DocNo(DocNoList.Strings[i]);
+      if iDocNo = DocNo then
+        Doc_Ct := Doc_Ct + strtoint(DocNo_CopiesList.Strings[i]);
+    end;
+    Result := Doc_Ct;
+   // Showmessage(DocNo+#13+inttostr(Doc_Ct));
+  finally
+  DocNoList.Free;
+  DocNo_CopiesList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetDocDirCopies(CaseID,DocDir:String):Integer; //取DocDir數量
+var
+  i : Integer;
+  DocNoList,DocNo_CopiesList : TStringlist;
+begin
+  Result := 1;  //預設回傳1  //20140521 由0改成1
+  DocNoList := TStringlist.Create;
+  DocNo_CopiesList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+      DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat') then
+    begin
+      DocNo_CopiesList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+      for i := 0 to DocNoList.Count - 1 do
+      begin
+        if (DocDir = DocNoList.Strings[i]) and (i <= DocNo_CopiesList.Count-1) then
+        begin
+          Result := strtoint(DocNo_CopiesList.Strings[i]);
+          Break;
+        end;
+      end;
+    end;
+  finally
+  DocNoList.Free;
+  DocNo_CopiesList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetDocDirCopies(CaseID,DocDir:String;NewCopies:Integer); //修改DocDir份數
+var
+  i : Integer;
+  DocNoList,DocNo_CopiesList : TStringlist;
+begin
+  DocNoList := TStringlist.Create;
+  DocNo_CopiesList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+    begin
+      DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+      DocNo_CopiesList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+    end;
+    for i := 0 to DocNoList.Count - 1 do
+    begin
+      if DocDir = DocNoList.Strings[i] then
+      begin
+        DocNo_CopiesList.Strings[i] := inttostr(NewCopies);
+        DocNo_CopiesList.SaveToFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+        Break;
+      end;
+    end;
+  finally
+  DocNoList.Free;
+  DocNo_CopiesList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetDocDirCopies_Rec(Path,CaseID,DocDir:String):Integer; //取記錄裡的DocDir份數
+var
+  i,n,v,v1 : Integer;
+  OldCaseInfoList,Caseinfolist : TStringlist;
+  iCaseID,Year,iBS_No,iIS_Old,iDocNo,iCopies:String;
+begin
+  Result := 1;
+  OldCaseInfoList := TStringlist.Create;
+  Caseinfolist := TStringlist.Create;
+  try
+    //OldCaseInfoList 案件編號@#,年度@#,業務別@#,是否舊件@#,Data@#,Verify@#,文件編號[份數]@#,文件編號[份數] tab 案件編號@#,年度@#,業務別@#,是否舊件@#,Data@#,Verify@#,文件編號[份數]@#,文件編號[份數]
+    OldCaseInfoList.StrictDelimiter := true;
+    OldCaseInfoList.Delimiter := #9;
+    OldCaseInfoList.DelimitedText := FOldCaseInfo;
+
+    for i := 0 to OldCaseInfoList.Count - 1 do
+    begin
+      Caseinfolist:=SplitString('@#,',OldCaseInfoList.Strings[i]);
+      //Caseinfolist.Delimiter := '_';
+      //Caseinfolist.DelimitedText := OldCaseInfoList.Strings[i];
+      iCaseID := Caseinfolist.Strings[0];
+      Year := Caseinfolist.Strings[1];
+      iBS_No := Caseinfolist.Strings[2];
+      iIS_Old := Caseinfolist.Strings[3];
+      if CaseID = iCaseID then
+      begin
+        for n := 6 to Caseinfolist.Count - 1 do
+        begin
+          v := Pos('[',Caseinfolist.Strings[n]);
+          v1 := Pos(']',Caseinfolist.Strings[n]);
+          iDocNo := Copy(Caseinfolist.Strings[n],1,v-1);
+          iCopies := Copy(Caseinfolist.Strings[n],v+1,v1-v-1);
+          if Copy(DocDir,1,5) = 'ZZZZZ' then
+          begin
+            if iDocNo = GetCustomDocName(Path,DocDir) then
+              Result := strtoint(iCopies);
+          end
+          else
+          begin
+            if iDocNo = DocNoDir2DocNo(DocDir) then
+              Result := strtoint(iCopies);
+          end;
+        end;
+
+      end;
+    end;
+  finally
+  OldCaseInfoList.Free;
+  Caseinfolist.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetCustomDocNoCount(Docno:String):Integer;   //取外傳的DocNo數量
+var
+  i,ct : Integer;
+  C_DocNoList : TStringlist;
+begin
+  C_DocNoList := TStringlist.Create;
+  try
+    C_DocNoList.StrictDelimiter := True;
+    C_DocNoList.Delimiter := #9;
+    C_DocNoList.DelimitedText := FC_DocNoList;
+    ct := 0;
+    for i := 0 to C_DocNoList.Count - 1 do
+    begin
+      if C_DocNoList.Strings[i] = Docno then
+      begin
+        inc(ct);
+      end;
+    end;
+    Result := ct;
+  finally
+  C_DocNoList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CaseDelete_Enable(CaseID:String):Boolean;  //案件可否被刪除
+var
+  i : Integer;
+  CaseDocNoList : TStringlist;
+begin
+  Result := True;
+  CaseDocNoList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+      CaseDocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+    for i := 0 to CaseDocNoList.Count - 1 do
+    begin
+      if GetUseCase('T',DisplayPath,CaseDocNoList.Strings[i]) <> '' then   //有被引用走的
+        Result := False;
+    end;
+
+  finally
+  CaseDocNoList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetUseCase(Mode:Char;Path,DocDir,FormCaseID,ToCaseID:String);   //記錄引用其他案件 A:加入 D:刪掉
+var
+  ini : Tinifile;
+begin
+  ini := Tinifile.Create(Path+'UseCase.ini');
+  try
+    case Mode of
+      'A':begin
+            ini.WriteString(DocDir,'FROM_CASEID',FormCaseID);
+            ini.WriteString(DocDir,'TO_CASEID',ToCaseID);
+          end;
+      'D':begin
+            ini.EraseSection(DocDir);
+          end;
+    end;
+
+  finally
+  ini.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetUseCase(Mode:Char;Path,DocDir:String):String;  //F:取被引用 To:引用
+var
+  ini : Tinifile;
+begin
+  ini := Tinifile.Create(Path+'UseCase.ini');
+  try
+    case Mode of
+      'F':begin
+            Result := ini.ReadString(DocDir,'FROM_CASEID','');
+          end;
+      'T':begin
+            Result := ini.ReadString(DocDir,'TO_CASEID','');
+          end;
+    end;
+  finally
+  ini.Free;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.Case2upload(CaseID:String);
+var
+  i,n:Integer;
+  OldPath,NewPath,DocDir : String;
+  OldFile,NewFile,AttFile : String;
+  DocNoList,FileList:TStringlist;
+  iFileList,iFile_DocNoList :TStringlist;
+  iDocDirList : TStringlist;
+  iAttFileList : TStringlist;
+begin
+  DocNoList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  iFileList := TStringlist.Create;
+  iFile_DocNoList := TStringlist.Create;
+  iDocDirList := TStringlist.Create;
+  iAttFileList := TStringlist.Create;
+  try
+    OldPath := ImageSavePath+CaseID+'\';
+    NewPath := ImageSavePath+CaseID+'\Upload\';
+    if DirectoryExists(NewPath) then
+      _DelTree(NewPath);
+    str2dir(NewPath);
+    CopyFile(PWideChar(OldPath+'CaseDocNo.dat'),PWideChar(NewPath+'CaseDocNo.dat'),False);
+    CopyFile(PWideChar(OldPath+'CaseDocNo_Copies.dat'),PWideChar(NewPath+'CaseDocNo_Copies.dat'),False);
+    CopyFile(PWideChar(OldPath+'CustomDocNo.ini'),PWideChar(NewPath+'CustomDocNo.ini'),False);
+    CopyFile(PWideChar(OldPath+'CaseIndex.dat'),PWideChar(NewPath+'CaseIndex.dat'),False);
+    CopyFile(PWideChar(OldPath+'In_Wh.dat'),PWideChar(NewPath+'In_Wh.dat'),False);
+    CopyFile(PWideChar(OldPath+'UseCase.ini'),PWideChar(NewPath+'UseCase.ini'),False);
+
+    if FileExists(OldPath+'CaseDocNo.dat') then
+    begin
+      DocNoList.LoadFromFile(OldPath+'CaseDocNo.dat');
+    end
+    else
+    begin
+      DocNoList.SaveToFile(OldPath+'CaseDocNo.dat');
+      CopyFile(PWideChar(OldPath+'CaseDocNo.dat'),PWideChar(NewPath+'CaseDocNo.dat'),False);
+    end;
+
+    for i := 0 to DocNoList.Count-1 do
+    begin
+      DocDir := DocNoList.Strings[i];
+      OldPath := ImageSavePath+CaseID+'\'+ DocDir+'\';
+
+      FileList.Clear;
+      if FileExists(OldPath+'Context.dat') then
+      begin
+        FileList.LoadFromFile(OldPath+'Context.dat');
+        for n := 0 to FileList.Count - 1 do
+        begin
+          OldFile := FileList.Strings[n];
+          NewFile := Add_Zoo(iFileList.Count+1,3)+FileName2NoQuene_Filename(OldFile);
+          CopyFile(PWideChar(OldPath+OldFile),PWideChar(NewPath+NewFile),False);
+          iFileList.Add(NewFile);
+          iFile_DocNoList.Add(DocNoDir2DocNo(DocDir));
+          iDocDirList.Add(DocDir);
+        end;
+      end;
+    end;
+    if DirectoryExists(ImageSavePath+CaseID+'\Attach') then
+    begin
+      DocDir := 'Attach';
+      OldPath := ImageSavePath+CaseID+'\'+ DocDir+'\';
+
+      FileList.Clear;
+      if FileExists(OldPath+'Context.dat') then
+      begin
+        FileList.LoadFromFile(OldPath+'Context.dat');
+        for n := 0 to FileList.Count - 1 do
+        begin
+          OldFile := FileList.Strings[n];
+          NewFile := Add_Zoo(iFileList.Count+1,3)+FileName2NoQuene_Filename(OldFile);
+          CopyFile(PWideChar(OldPath+OldFile),PWideChar(NewPath+NewFile),False);
+          iFileList.Add(NewFile);
+          iFile_DocNoList.Add(DocNoDir2DocNo(DocDir));
+          iDocDirList.Add(DocDir);
+        end;
+      end;
+    end;
+
+    if DirectoryExists(ImageSavePath+CaseID+'\S_Attach') then
+    begin
+      DocDir := 'S_Attach';
+      OldPath := ImageSavePath+CaseID+'\'+ DocDir+'\';
+
+      FileList.Clear;
+      if FileExists(OldPath+'Context.dat') then
+      begin
+        FileList.LoadFromFile(OldPath+'Context.dat');
+        for n := 0 to FileList.Count - 1 do
+        begin
+          OldFile := FileList.Strings[n];
+          NewFile := Add_Zoo(iFileList.Count+1,3)+FileName2NoQuene_Filename(OldFile);
+          CopyFile(PWideChar(OldPath+OldFile),PWideChar(NewPath+NewFile),False);
+          iFileList.Add(NewFile);
+          iFile_DocNoList.Add(DocNoDir2DocNo(DocDir));
+          iDocDirList.Add(DocDir);
+        end;
+      end;
+    end;
+    OldPath := ImageSavePath+CaseID+'\';
+    if FileExists(OldPath+'AttContext.dat') then
+    begin
+      iAttFileList.LoadFromFile(OldPath+'AttContext.dat');
+      for n := 0 to iAttFileList.Count - 1 do
+      begin
+        AttFile := iAttFileList.Strings[n];
+        CopyFile(PWideChar(OldPath+AttFile),PWideChar(NewPath+AttFile),False);
+      end;
+      iAttFileList.SaveToFile(NewPath+'AttContext.dat');
+    end;
+
+
+    iFileList.SaveToFile(NewPath+'Context.dat');
+    iFile_DocNoList.SaveToFile(NewPath+'Context_DocNo.dat');
+    iDocDirList.SaveToFile(NewPath+'DocDir.dat');
+
+  finally
+  iFileList.Free;
+  iAttFileList.Free;
+  iFile_DocNoList.Free;
+  DocNoList.Free;
+  FileList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.Download2Case(SoDir,DeDir:String);
+var
+  i,n : Integer;
+  DocDir:String;
+  OldFile,NewFile,AttFile:String;
+  DocNoList,FileList : TStringlist;
+  iFileList,iFile_DocDirList :TStringlist;
+  iAttFileList :TStringlist;
+  AA,AA2,AA3,AA4:Boolean;
+begin
+
+  if (not FileExists(SoDir+'CaseDocNo.dat')) or (not FileExists(SoDir+'DocDir.dat')) then   //截畫面會沒這些檔
+  begin
+//ShowMessage('產生必要的文字檔');
+    CreateCaseNeedData(SoDir);   //產生必要的文字檔
+  end;
+
+  AA:=CopyFile(PWideChar(SoDir+'CaseDocNo.dat'),PWideChar(DeDir+'CaseDocNo.dat'),False);
+  AA2:=CopyFile(PWideChar(SoDir+'CaseDocNo_Copies.dat'),PWideChar(DeDir+'CaseDocNo_Copies.dat'),False);
+  AA3:=CopyFile(PWideChar(SoDir+'CustomDocNo.ini'),PWideChar(DeDir+'CustomDocNo.ini'),False);
+  AA4:=CopyFile(PWideChar(SoDir+'UseCase.ini'),PWideChar(DeDir+'UseCase.ini'),False);
+//ShowMessage(BoolToStr(AA)+#10#13+BoolToStr(AA2)+#10#13+BoolToStr(AA3)+#10#13+BoolToStr(AA4));
+  if FileExists(SoDir+'DocDir.dat') then     //20170222 新加
+  begin
+    CopyFile(PWideChar(SoDir+'DocDir.dat'),PWideChar(DeDir+'DocDir.dat'),False);
+  end;
+
+
+  DocNoList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  iFileList := TStringlist.Create;
+  iFile_DocDirList := TStringlist.Create;
+  iAttFileList := TStringlist.Create;
+  try
+    //if Not FileExists(SoDir+'Context.dat') then  Exit;
+    //iFileList.LoadFromFile(SoDir+'Context.dat');
+    //if iFileList.Count = 0 then Exit;
+    if FileExists(SoDir+'Context.dat') then
+      iFileList.LoadFromFile(SoDir+'Context.dat');
+    if FileExists(SoDir+'DocDir.dat') then
+      iFile_DocDirList.LoadFromFile(SoDir+'DocDir.dat');
+    if iFileList.Count <> iFile_DocDirList.Count then
+    begin
+      for i := 0 to iFileList.Count - 1 do
+      begin
+        if i > iFile_DocDirList.Count -1 then
+        begin
+          iFile_DocDirList.Add(FormCode2DocNo(FileName2FormCode(iFileList.Strings[i])));
+        end;
+      end;
+    end;
+    if FileExists(SoDir+'CaseDocNo.dat') then
+      DocNoList.LoadFromFile(SoDir+'CaseDocNo.dat');
+    if FileExists(DeDir+'CaseDocNo_Copies.dat') then
+      CaseDocNo_CopiesList.LoadFromFile(DeDir+'CaseDocNo_Copies.dat');
+    {for i := 0 to DocNoList.Count - 1 do
+    begin
+      DocDir := DocNoList.Strings[i];
+      MkDir(DeDir+DocDir);
+    end;}
+//ShowMessage('DocNoList='+DocNoList.Text);
+
+    for i := DocNoList.Count - 1 downto 0 do
+    begin
+      DocDir := DocNoList.Strings[i];
+      if not DirectoryExists(DeDir+DocDir) then
+      begin
+        MkDir(DeDir+DocDir);
+        if not FileExists(DeDir+DocDir+'\Context.dat') then
+          StringtoFile('',DeDir+DocDir+'\Context.dat');
+      end
+      else
+      begin
+//ShowMessage('GGG');
+        DocNoList.Delete(i);
+        DocNoList.SaveToFile(DeDir+'CaseDocNo.dat');
+        if i <= CaseDocNo_CopiesList.Count-1  then
+        begin
+//ShowMessage('KKKK');
+          CaseDocNo_CopiesList.Delete(i);
+          CaseDocNo_CopiesList.SaveToFile(DeDir+'CaseDocNo_Copies.dat');
+        end;
+      end;
+    end;
+  //20170221 先註解起來  因為他在補充掃瞄時好像會有顯示的問題
+
+    for i := 0 to iFileList.Count - 1 do
+    begin
+      OldFile := iFileList.Strings[i];
+      DocDir := iFile_DocDirList.Strings[i];
+      if (DocDir = 'Attach') or (DocDir = 'S_Attach') then
+      begin
+        if not DirectoryExists(DeDir+DocDir) then
+          MkDir(DeDir+DocDir);
+      end;
+
+      FileList.Clear;
+      if FileExists(DeDir+DocDir+'\Context.dat') then
+      begin
+        FileList.LoadFromFile(DeDir+DocDir+'\Context.dat');
+      end;
+      NewFile := Add_Zoo(FileList.Count+1,3)+FileName2NoQuene_Filename(OldFile);
+      CopyFile(PWideChar(SoDir+OldFile),PWideChar(DeDir+DocDir+'\'+NewFile),False);
+      FileList.Add(NewFile);
+      FileList.SaveToFile(DeDir+DocDir+'\Context.dat');
+    end;
+
+    for i := DocNoList.Count -1 downto 0 do
+    begin
+      if (DocNoList.Strings[i] = 'Attach') or (DocNoList.Strings[i] = 'S_Attach') then
+      begin
+        DocNoList.Delete(i);
+        DocNoList.SaveToFile(DeDir+'CaseDocNo.dat');
+      end;
+    end;
+
+    {if (DocNoList.Count > 0) and ((DocNoList.Strings[DocNoList.Count-1] = 'Attach') or (DocNoList.Strings[DocNoList.Count-1] = 'S_Attach')) then
+    begin
+      DocNoList.Delete(DocNoList.Count-1);
+      DocNoList.SaveToFile(DeDir+'CaseDocNo.dat');
+    end; }
+    CaseDocNo_CopiesList.Clear;
+
+    if FileExists(DeDir+'CaseDocNo_Copies.dat') then
+      CaseDocNo_CopiesList.LoadFromFile(DeDir+'CaseDocNo_Copies.dat');
+    if DocNoList.Count > CaseDocNo_CopiesList.Count then
+    begin
+      for i := 0 to DocNoList.Count - 1 do
+      begin
+        if i > CaseDocNo_CopiesList.Count-1 then
+        begin
+          CaseDocNo_CopiesList.Add('1');
+          //CaseDocNo_CopiesList.SaveToFile(DeDir+'CaseDocNo_Copies.dat');
+        end;
+      end;
+    end;
+    CaseDocNo_CopiesList.SaveToFile(DeDir+'CaseDocNo_Copies.dat');
+    {if (not FileExists(DeDir+'CaseDocNo_Copies.dat') then
+    begin
+      CaseDocNo_CopiesList.Free;
+      for i := 0 to DocNoList.Count - 1 do
+      begin
+        CaseDocNo_CopiesList.Add('1');
+        CaseDocNo_CopiesList.SaveToFile(DeDir+'CaseDocNo_Copies.dat');
+      end;
+    end;}
+    if FileExists(SoDir+'AttContext.dat') then
+    begin
+      iAttFileList.LoadFromFile(SoDir+'AttContext.dat');
+      for i := 0 to iAttFileList.Count - 1 do
+      begin
+        AttFile := iAttFileList.Strings[i];
+        CopyFile(PWideChar(SoDir+AttFile),PWideChar(DeDir+AttFile),False);
+      end;
+      iAttFileList.SaveToFile(DeDir+'AttContext.dat');
+    end;
+
+
+    if FMode='ESCAN' then
+    begin
+      InitExistImgList(DeDir);
+    end;
+
+
+  finally
+  iFileList.Free;
+  FileList.Free;
+  DocNoList.Free;
+  iFile_DocDirList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FileName2NoQuene_Filename(FileName:String):String; //取出沒有序號的檔名
+var
+  v,v1 : Integer;
+  FName : String;
+begin
+  FName := ExtractFileName(FileName);
+  v := Pos('_',FName);
+  if v = 0 then   //附件
+    v := pos('.',FName);
+  v1 := length(FName);
+  Result := Copy(FName,v,v1-v+1);
+end;
+
+Function TCB_IMGPSScanX.FileName2Index(FileName:String):Integer; //從檔名取出在ContextList的序號
+var
+  i : Integer;
+begin
+  for i := 0 to ContextList.Count - 1 do
+  begin
+    if FileName = ContextList.Strings[i] then
+    begin
+      Result := i;
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FileName2NowDcoNo(FileName:String;CtList,DNList:TStrings):String; //從檔名取出歸屬的文件代號
+var
+  i : Integer;
+begin
+  for I := 0 to CTList.Count -1 do
+  begin
+    if FileName = CTList.Strings[i] then
+    begin
+      Result := DNList.Strings[i];
+      break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNo2DocName(CaseID,DocNo:String):String; //Docno轉Doc名稱
+var
+  i,v,ln : Integer;
+  CusDocNo,CusDocName : String;
+begin
+  Result := '';
+  if DocNo = AttName then
+  begin
+    Result := _Msg('未歸類');
+  end
+  Else
+  begin
+    If FindSQLData(Doc_Inf_List,'DOC_U_DESC','DOC_NO',DocNo,0,FindResult) Then
+    begin
+//ShowMessage(FindResult.Text);
+      Result := GetFindResult('DOC_U_DESC');
+    end;
+  end;
+
+  if Result = '' then  //去自訂文件裡找
+  begin
+    Result := GetCustomDocName(ImageSavePath+CaseID+'\',DocNo);
+    {for i := 0 to Cust_DocNoList.Count - 1 do
+    begin
+      v := Pos('_',Cust_DocNoList.Strings[i]);
+      ln := length(Cust_DocNoList.Strings[i]);
+      CusDocNo := Copy(Cust_DocNoList.Strings[i],1,v-1);
+      CusDocName := Copy(Cust_DocNoList.Strings[i],v+1,ln-v);
+      if DocNo = CusDocNo then
+      begin
+        Result := CusDocName;
+        Break;
+      end;
+    end;}
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.DocNo2FileName(DocNo:String;List:TStrings):String; //用DocNo找出檔名(第一頁)
+var
+  i : Integer;
+begin
+  Result := '';
+  for i := 0 to List.Count - 1 do
+  begin
+    IF DocNo = FormCode2DocNo(FileName2FormCode(List.Strings[i])) then
+    begin
+      Result := List.Strings[i];
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNo2WorkNo(DocNo:String):String; //用DocNo取出作業別
+begin
+  Result := '';
+  If FindSQLData(Doc_Inf_List,'WORK_NO','DOC_NO',DocNo,0,FindResult) Then
+  begin
+    Result := GetFindResult('WORK_NO');
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNoNeedDiv(DocNo:String):Boolean; //是否是需分份數的文件代號
+var
+  NeedDiv : String;
+begin
+  Result := False;
+  If FindSQLData(Doc_Inf_List,'IS_DOC_DIV','DOC_NO',DocNo,0,FindResult) Then
+  begin
+    NeedDiv := GetFindResult('IS_DOC_DIV');
+    if NeedDiv = 'Y' then
+      Result := True;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocnoNeedGroup(DocNo:String):Boolean; //傳入的DocNo是否需分組
+begin
+  Result := False;
+  If FindSQLData(Doc_Inf_List,'IS_DOC_DIV','DOC_NO',DocNo,0,FindResult) Then
+  begin
+    if GetFindResult('IS_DOC_DIV') = 'Y' Then
+      Result := True;
+  end;
+end;
+
+Function TCB_IMGPSScanX.OMRCheckCase(CaseID:String):Boolean; //OMR檢核
+var
+  i,n,m,v,v1 : Integer;
+  XT,RelaXT,ValueXT : TXmltool;
+  OMRFormCode,OMRFile,OMRFormName,ColEName,ColCName,Site : String;
+  Pixel : Integer;
+  RelaFormCode,RelaFile,RelaFormName,RelaColEName,RelaColCName,RelaSite : String;
+  RelaDocNo,RelaDocName : string;
+  RelaPixel : Integer;
+  s : String;
+  nodename : String;
+  OMROK : Boolean;
+  CaseOk : Boolean;
+  ErrStr : String;
+  SiteRec,RelaSiteRec : String;  //多組位置記錄
+  OMRValue : String;
+  MainFormID,MainDocNo,MainVersion : String; //主FormID
+  MainFormPage,CaseFormPage : Integer;  //主要文件需要的頁數
+  NeedDocNoStr,NoDocNoStr : String; //相依 互斥文件字串
+  List : TStringlist;
+  FormCode : String;
+  FormDataPages : Integer;
+  NoSite : Boolean; //未定位
+  Anchor,Anchor1 : String;
+  OMROkCount : Integer;
+  //Casecheck : Boolean;  //是否要做檢核
+  //AllCheck : Boolean;  //是否要做完整檢核
+
+  ISB8W,ISB8H:integer;
+begin
+  ///OMRErrInfo  1: 必要文件  2:相依文件 3:互斥文件  4:必填 5:欄位有值附文件  6:欄位有值不附文件
+  ///            7: 欄位有值相關欄位也要有值  8:欄位有值要寫備註 9:停用日期 10:最大頁數
+  //Casecheck := True;
+  //Allcheck := True;
+  //if (FMode = 'ISCAN') then
+    //Allcheck := False;
+  CaseOk := True;
+  //if Casecheck then
+  //begin
+    DeleteFile(ImageSavePath+CaseID+'\upload\Checkerr.ini');
+    DeleteFile(ImageSavePath+CaseID+'\upload\CheckMemo.dat');
+    //DeleteFile(ImageSavePath+CaseID+'\upload\ReSize.dat');
+    DeleteFile(ImageSavePath+CaseID+'\upload\RemoveMemo.dat');
+    DeleteFile(ImageSavePath+CaseID+'\upload\OMRCheckOk.dat');
+    Memo1.Lines.Clear;
+    OMRFileList.Clear;
+
+    MainFormID := GetCaseFormID(ImageSavePath+CaseID+'\upload\');
+    List := TStringlist.Create;
+    try
+      //if AllCheck then
+      //begin
+        if GetCasePage(ImageSavePath,CaseID) =0 then
+        begin
+
+        end;
+//ShowMessage('MainFormID='+MainFormID);
+LogFile1.LogToFile(logTimeString+' '+FModeName+' '+CaseID+' '+'MainFormID='+MainFormID);
+        if MainFormID = ''then
+        begin
+          //20131203 yuu說不檢查這個,先拿掉   20170315 楷琳說未歸類要擋  20170726 因此有檢查必要FormID  所以 可以拿掉
+          {if FCheck_main_form='Y' then
+          begin
+            if (FMode <> 'SSCAN') AND (FMode<>'ESCAN') then  //簽署章件會換主FormID,先跳過 20170629 ESCAN 也不檢查
+            begin
+              ErrStr:=_Msg('找不到分案文件');   //找不到主文件
+              OMRErr2ini(CaseID,ErrStr,'','','','','','',False,False,True);
+              CaseOk := false;
+//ShowMessage('AAAAA');
+            end;
+          end;
+          }
+        end
+        Else
+        begin
+          //////主要非主要文件//////
+          DistinctDocinCase(ImageSavePath+CaseID+'\upload\');
+//ShowMessage(DocNo_VerinCase.Text);
+//DocNo_VerinCase.Add('31A00101_1706A');
+LogFile1.LogToFile(logTimeString+' '+CaseID+' '+'DocNo_VerinCase.Text='+DocNo_VerinCase.Text);
+          if ModeNeedCheck(OMRErrInfo[1].Mode,FMode) then //是否要檢核
+          begin
+            for i := 0 to DocNo_VerinCase.Count - 1 do
+            begin
+              v := Pos('_', DocNo_VerinCase.Strings[i]);
+              v1 := length(DocNo_VerinCase.Strings[i]);
+              MainDocNo := Copy(DocNo_VerinCase.Strings[i],1,v-1); //FormCode2DocNo(MainFormID);
+              MainVersion :=Copy(DocNo_VerinCase.Strings[i],v+1,v1-v); //FormCode2Version(MainFormID);
+              MainFormPage := GetDataDocNoPage(MainDocNo,MainVersion); //資料庫記錄主文件頁數
+              CaseFormPage := CheckCaseDocNoPage(CaseID,MainDocNo,MainVersion,MainFormPage); //案件主文件的頁數
+LogFile1.LogToFile(logTimeString+CaseID+',MainDocNo='+MainDocNo+',MainVersion='+MainVersion+',MainFormPage='+IntToStr(MainFormPage)+',CaseFormPage='+IntToStr(CaseFormPage));
+              //CheckFirstDocNoPage
+              IF (MainFormPage > 0) and (MainFormPage <> CaseFormPage) then
+              begin
+                ErrStr:=MainDocNo+Format(OMRErrInfo[1].Info,[Inttostr(MainFormPage),Inttostr(CaseFormPage)]); //主要文件需有XX頁僅附XX頁
+                OMRErr2ini(CaseID,ErrStr,'','','','','','',False,OMRErrInfo[1].Ignore,OMRErrInfo[1].Display);
+                if OMRErrInfo[1].Display then
+                  CaseOk := false;
+              end;
+            end;
+          end;
+          //////主要非主要文件/////
+//showmessage(MainFormID);
+          MainDocNo := FormCode2DocNo(MainFormID);
+          MainVersion := FormCode2Version(MainFormID);
+          if FindSQLData(DM_FORM_INF_List,'DEPE_FORM_ID,MUTEX_FORM_ID','MAIN_FORM_ID,DOC_VERSION',MainDocNo+','+MainVersion,0,FindResult) then
+          begin
+            NeedDocNoStr := GetFindResult('DEPE_FORM_ID');
+            NoDocNoStr := GetFindResult('MUTEX_FORM_ID');
+          end
+          Else if FindSQLData(DM_FORM_INF_List,'DEPE_FORM_ID,MUTEX_FORM_ID','MAIN_FORM_ID,DOC_VERSION',MainDocNo+','+MainVersion,0,FindResult) then
+          begin
+            NeedDocNoStr := GetFindResult('DEPE_FORM_ID');
+            NoDocNoStr := GetFindResult('MUTEX_FORM_ID');
+          end;
+
+          //////相依文件/////
+          if ModeNeedCheck(OMRErrInfo[2].Mode,FMode) then //是否要檢核
+          begin
+            List.CommaText := NeedDocNoStr;
+            for I := 0 to List.Count - 1 do
+            begin
+              if not Case_DocNoExists(CaseID,List.Strings[i]) then  //沒附相依文件
+              begin
+                if FWH_category='N' then
+                begin
+                  if ISExistImg(ImageSavePath+CaseID+'\upload\'+List.Strings[i]) then
+                  begin
+                    Continue;
+                  end;
+                end;
+                ErrStr:=Format(OMRErrInfo[2].Info,[DocNo2DocName(CaseID,List.Strings[i])]);   //沒附相依文件
+                OMRErr2ini(CaseID,ErrStr,'','','','','','',False,OMRErrInfo[2].Ignore,OMRErrInfo[2].Display);
+                if OMRErrInfo[2].Display then
+                  CaseOk := false;
+              end;
+            end;
+          end;
+          //////相依文件/////
+
+          //////互斥文件/////
+          if ModeNeedCheck(OMRErrInfo[3].Mode,FMode) then //是否要檢核
+          begin
+            List.CommaText := NoDocNoStr;
+            for I := 0 to List.Count - 1 do
+            begin
+              if Case_DocNoExists(CaseID,List.Strings[i]) then  //附了互斥文件
+              begin
+                if FWH_category='N' then
+                begin
+                  if ISExistImg(ImageSavePath+CaseID+'\upload\'+List.Strings[i]) then
+                  begin
+                    Continue;
+                  end;
+                end;
+                ErrStr:=Format(OMRErrInfo[3].Info,[DocNo2DocName(CaseID,List.Strings[i])]);   //有附互斥文件
+                OMRErr2ini(CaseID,ErrStr,'','','','','','',False,OMRErrInfo[3].Ignore,OMRErrInfo[3].Display);
+                if OMRErrInfo[3].Display then
+                  CaseOk := false;
+              end;
+            end;
+          end;
+          //////互斥文件/////
+        end; //MainFormID結束
+      //end;
+      List.LoadFromFile(ImageSavePath + CaseID+'\upload\Context.dat');
+      for i := 0 to List.Count - 1 do
+      begin
+        FormCode := FileName2FormCode(List.Strings[i]);
+        /////未歸類///
+        {IF FormCode = 'Attach' Then   //20140211 yuu說不檢查了
+        begin
+          ErrStr:=_Msg('尚有文件未歸類');
+          OMRErr2ini(CaseID,ErrStr,'','','','','','',False,False,True);
+          CaseOk := false;
+        end; }
+        /////未歸類//////
+
+        /////未註冊文件/////
+        {IF not FormIDExists(FormCode,False) then  //未註冊文件
+        begin
+          ErrStr:=FormCode+_Msg('不為此業務的表單代碼');
+          OMRErr2ini(CaseID,ErrStr,'','','','',False,False,True);
+          CaseOk := false;
+        end }
+        /////未註冊文件/////
+        //////停用文件//
+        {Else} IF ModeNeedCheck(OMRErrInfo[9].Mode,FMode) and (not FormIDExists(FormCode,True,0)) and (not checkFormCodeIsCustom(ImageSavePath + CaseID+'\upload\',FormCode)) then  //有停用的文件
+        begin
+//ShowMessage('AAAA');
+          ErrStr:=Format(OMRErrInfo[9].Info,[FormCode2FormName(CaseID,FormCode)]);   //有停用文件
+          OMRErr2ini(CaseID,ErrStr,'','','','','','',False,OMRErrInfo[9].Ignore,OMRErrInfo[9].Display);
+//ShowMessage('ErrStr='+ErrStr);
+          if OMRErrInfo[9].Display then
+            CaseOk := false;
+        end;
+        //////停用文件////
+      end;
+    finally
+      List.Free;
+    end;
+    //if AllCheck then
+    //begin
+      //////最大頁數///
+LogFile1.LogToFile(logTimeString+'最大頁數A段 '+CaseID+' '+'OMRFileList.Text='+OMRFileList.Text);
+      DistinctFormCode(CaseID);
+      if ModeNeedCheck(OMRErrInfo[10].Mode,FMode) then //是否要檢核
+      begin
+//ShowMessage('AAA'+OMRFileList.Text);
+LogFile1.LogToFile(logTimeString+'最大頁數B段 '+CaseID+' '+'OMRFileList.Text='+OMRFileList.Text);
+        For i := 0 to OMRFileList.Count - 1 do
+        begin
+          if FModeName=_Msg('異動件') then Continue;
+
+          if FWH_category='N' then
+          begin
+            if ISExistImg(ImageSavePath+CaseID+'\upload\'+OMRFileList.Strings[i]) then
+            begin
+              Continue;
+            end;
+          end;
+          FormCode := FileName2FormCode(OMRFileList.Strings[i]);
+          FormDataPages := GetDataFormCodePages(FormCode);
+
+          IF (FormCode <> '') and (FormDataPages > 0) and (FindFormCodePages(CaseID,FormCode) > FormDataPages) then  //有超過最大頁數的文件
+          begin
+            ErrStr:=Format(OMRErrInfo[10].Info,[FormCode2FormName(CaseID,FormCode),inttostr(FormDataPages)]);   //有超過最大頁數文件
+            OMRErr2ini(CaseID,ErrStr,'','','','','','',False,OMRErrInfo[10].Ignore,OMRErrInfo[10].Display);
+            if OMRErrInfo[10].Display then
+              CaseOk := false;
+          end;
+        end;
+      end;
+      /////最大頁數/////
+    //end;
+    ImageScrollBox1.FileName := '';
+    //if FWork_No = 'CW' then   //理賠就不做下面的檢核了
+    //begin
+      //////OMR檢核///////
+      ContextList.LoadFromFile(ImageSavePath+CaseID+'\upload\Context.dat');
+      DistinctFormCode(CaseID);
+      ValueXT := TXmltool.Create;
+      Try
+//ShowMessage('必填'+OMRFileList.Text);
+LogFile1.LogToFile(logTimeString+'必填 '+CaseID+' '+'OMRFileList.Text='+OMRFileList.Text);
+        For i := 0 to OMRFileList.Count - 1 do
+        begin
+//ShowMessage('OMRFileList.Strings['+IntToStr(i)+']'+OMRFileList.Strings[i]);
+          if CheckRequiredColumnValues(FWork_NO,CaseID) then Continue;
+
+          OMRFile := OMRFileList.Strings[i];
+          OMRFormCode := FileName2FormCode(OMRFileList.Strings[i]);
+          OMRFormName := FormCode2FormName(CaseID,OMRFormCode);
+          Anchor := FormID2Anchor(OMRFormCode);
+          ///依十字定位點縮放////
+          ImageReSize_FormID(CaseID,OMRFile);
+          ////依十字定位點縮放///
+//Display1.Lines.Add('OMRFile='+OMRFile+',OMRFormCode='+OMRFormCode+',OMRFormName='+OMRFormName);
+LogFile1.LogToFile(logTimeString+'OMRFile='+OMRFile+',OMRFormCode='+OMRFormCode+',OMRFormName='+OMRFormName);
+//ShowMessage('KKKKK');
+          if not FileExists(CheckXmlPath+FWork_no+'\'+OMRFormCode+'.xml') then  //沒有Xml就不用檢核
+            Continue;
+
+//ShowMessage('11638 OMRFileList.Strings['+IntToStr(i)+']'+OMRFileList.Strings[i]);
+          XT := TXmltool.Create(CheckXmlPath+FWork_no+'\'+OMRFormCode+'.xml');
+          RelaXT := TXmltool.Create;
+//ShowMessage('ModeNeedCheck='+BoolToStr(ModeNeedCheck(OMRErrInfo[4].Mode,FMode),true));
+          try
+            //*******必填********
+            if ModeNeedCheck(OMRErrInfo[4].Mode,FMode) then //是否要檢核
+            begin
+              if XT.SubNodes['/form/settype1/'].First then
+              Repeat
+                OMROK := False;
+                SiteRec := ''; //清掉
+                ColEName := XT.SubNodes['/form/settype1/'].NodeName;
+                ColCName := XT.Node['/form/settype1/'+ColEName+'/'].Attributes['coldesc'];
+                ColCName := Copy(ColCName,1,length(ColCName)-6);
+                if XT.SubNodes['/form/settype1/'+ColEName+'/'].First then
+                Repeat
+                  nodename := XT.SubNodes['/form/settype1/'+ColEName+'/'].NodeName;
+                  If nodename <> '@coldesc' then
+                  begin
+                    Pixel := Strtoint(XT.Node['/form/settype1/'+ColEName+'/'+nodename+'/'].Attributes['pixel']);
+                    Site := XT.Node['/form/settype1/'+ColEName+'/'+nodename+'/'].Attributes['colxy'];
+                    if SiteRec= '' then   //記錄位置
+                      SiteRec := Site
+                    else
+                      SiteRec := SiteRec+'@'+Site;
+                    //有填就ok
+                    //Showmessage(ColCName +','+ inttostr(OMRMpsV1.GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site))+','+inttostr(Pixel + SafePixel));
+//SafePixel:=90000;
+Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+//FindPoint(ISB_BW.Graphic,UpLPoint,UpRPoint,DownLPoint,ANCHOR);
+                    if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel)  then
+                    begin
+                      //Showmessage('oh');
+                      OMROK := True;
+                      Break;
+                    end;
+                  end
+                  Else
+                  begin
+                    //ColCName := XT['/form/settype1/'+ColEName+'/'+nodename+'/'];
+                  end;
+                Until not XT.SubNodes['/form/settype1/'+ColEName+'/'].Next;
+                if not OMROk then
+                begin
+                  ErrStr:=Format(OMRErrInfo[4].Info,[ColCName]);   //XX欄位未填寫
+                  OMRErr2ini(CaseID,ErrStr,ImageSavePath+CaseID+'\upload\'+OMRFile,SiteRec,'','',Anchor,Anchor1,False,OMRErrInfo[4].Ignore,OMRErrInfo[4].Display);
+                  if OMRErrInfo[4].Display then
+                    CaseOk := false;
+                end;
+              Until not XT.SubNodes['/form/settype1/'].Next ;
+            end;
+            //*******必填********
+//ShowMessage('11692 OMRFileList.Strings['+IntToStr(i)+']'+OMRFileList.Strings[i]);
+            //if AllCheck then
+            //begin
+            //*******有值相關文件的欄位也要有值*******
+            if ModeNeedCheck(OMRErrInfo[7].Mode,FMode) then //是否要檢核
+            begin
+              if XT.SubNodes['/form/settype3/'].First then
+              Repeat
+                SiteRec := '';
+                RelaSiteRec := '';
+                ColEName := XT.SubNodes['/form/settype3/'].NodeName;
+                ColCName := XT.Node['/form/settype3/'+ColEName+'/'].Attributes['coldesc'];
+                ColCName := Copy(ColCName,1,length(ColCName)-6);
+                Site := XT.Node['/form/settype3/'+ColEName+'/'].Attributes['colxy'];
+                if SiteRec= '' then   //記錄位置
+                  SiteRec := Site
+                else
+                  SiteRec := SiteRec+'@'+Site;
+                Pixel := XT.Node['/form/settype3/'+ColEName+'/'].Attributes['pixel'];
+Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+                if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel) then
+                begin
+                  ////有填寫////
+
+                  if XT.SubNodes['/form/settype3/'+ColEName+'/'].First then
+                  Repeat
+                    RelaSiteRec := '';
+                    nodename := XT.SubNodes['/form/settype3/'+ColEName+'/'].NodeName;
+                    If (nodename <> '@coldesc') and (not XT.SubNodes['/form/settype3/'+ColEName+'/'].NodeIsAttr) then
+                    begin
+                      RelaFormCode := XT.node['/form/settype3/'+ColEName+'/'+nodename+'/'].Attributes['relaformid'];
+                      RelaColEName := XT.node['/form/settype3/'+ColEName+'/'+nodename+'/'].Attributes['rela_col_name'];
+                      RelaColCName := XT.node['/form/settype3/'+ColEName+'/'+nodename+'/'].Attributes['relacoldesc'];
+                      RelaColCName := Copy(RelaColCName,1,length(RelaColCName)-6);
+                      RelaFile := FormCode2FileName(RelaFormCode,ContextList);
+                      RelaFormName := FormCode2FormName(CaseID,RelaFormCode);
+                      Anchor1 := FormID2Anchor(RelaFormCode);
+                      RelaXT.LoadFromFile(CheckXmlPath+FWork_no+'\'+RelaFormCode+'.xml');
+Display1.Lines.Add(RelaFile+','+RelaFormName);
+//ShowMessage(RelaFile);
+//ShowMessage(ImageSavePath+CaseID+'\upload\'+RelaFile);
+                      if RelaFile<>'' then
+                      begin
+                        ISB8.LoadFromFile(ImageSavePath+CaseID+'\upload\'+RelaFile,1); //20170815
+                        ISB8W:= ISB8.Graphic.Width;
+                        ISB8H:= ISB8.Graphic.Height;
+                        FindPoint(ISB8.Graphic,UpLPoint,UpRPoint,DownLPoint,ISB8W,ISB8H,ANCHOR);  //20170815  抓相關然欄位所在圖檔的定位
+                      end;
+
+                      OMROK := False;
+                      //OMROK := False;
+                      //if RelaXT.SubNodes['/form/settype2/'].First then
+                      //Repeat
+                        NoSite := True;
+                        if RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].Count >0 then
+                          NoSite := False;
+                        if RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].First then
+                        Repeat
+                          nodename := RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].NodeName;
+                          If nodename <> '@coldesc' then
+                          begin
+                            RelaPixel := Strtoint(RelaXT.Node['/form/settype2/'+RelaColEName+'/'+nodename+'/'].Attributes['pixel']);
+                            RelaSite := RelaXT.Node['/form/settype2/'+RelaColEName+'/'+nodename+'/'].Attributes['colxy'];
+                            if RelaSiteRec= '' then   //記錄位置
+                              RelaSiteRec := RelaSite
+                            else
+                              RelaSiteRec := RelaSiteRec+'@'+RelaSite;
+                            if  FileExists(ImageSavePath+CaseID+'\upload\'+RelaFile) then
+                            begin
+Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+                              if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+RelaFile,RelaSite,Bt) > (RelaPixel + SafePixel)  then
+                              begin
+                                OMROK := True;
+                                Break;
+                              end;
+                              ///依十字定位點縮放////
+                              ImageReSize_FormID(CaseID,OMRFile); //20170815 重新抓定位
+                              ////依十字定位點縮放////
+                            end;
+                          end;
+
+                        Until not RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].Next;
+                        if not OMROk then
+                        begin
+                          if not FileExists(ImageSavePath+CaseID+'\upload\'+RelaFile) then
+                            ErrStr:=Format(OMRErrInfo[7].Info,[ColCName,RelaColCName])+'('+_msg('未附')+RelaFormName+')'   //XX欄位填寫時,XX欄位未填寫
+                          Else if NoSite then
+                            ErrStr:=Format(OMRErrInfo[7].Info,[ColCName,RelaColCName])+'('+_msg('未定位')+')'
+                          Else
+                            ErrStr:=Format(OMRErrInfo[7].Info,[ColCName,RelaColCName]);   //XX欄位填寫時,XX欄位未填寫
+                          OMRErr2ini(CaseID,ErrStr,ImageSavePath+CaseID+'\upload\'+OMRFile,SiteRec,ImageSavePath+CaseID+'\upload\'+RelaFile,RelaSiteRec,Anchor,Anchor1,False,OMRErrInfo[7].Ignore,OMRErrInfo[7].Display);
+                          if OMRErrInfo[7].Display then
+                            CaseOk := false;
+                        end;
+                      //Until not RelaXT.SubNodes['/form/settype2/'].Next ;
+
+                    end;
+                  Until not XT.SubNodes['/form/settype3/'+ColEName+'/'].Next;
+                end;
+              Until not XT.SubNodes['/form/settype3/'].Next ;
+            end;
+            //*******有值相關文件的欄位也要有值*******
+//ShowMessage('11788 OMRFileList.Strings['+IntToStr(i)+']'+OMRFileList.Strings[i]);
+
+            //*******有值相關文件的欄位不能有值*******
+            if ModeNeedCheck(OMRErrInfo[11].Mode,FMode) then //是否要檢核
+            begin
+              if XT.SubNodes['/form/settype8/'].First then
+              Repeat
+                SiteRec := '';
+                RelaSiteRec := '';
+                OMROkCount := 0;
+                ColEName := XT.SubNodes['/form/settype8/'].NodeName;
+                ColCName := XT.Node['/form/settype8/'+ColEName+'/'].Attributes['coldesc'];
+                ColCName := Copy(ColCName,1,length(ColCName)-6);
+                Site := XT.Node['/form/settype8/'+ColEName+'/'].Attributes['colxy'];
+                if SiteRec= '' then   //記錄位置
+                  SiteRec := Site
+                else
+                  SiteRec := SiteRec+'@'+Site;
+                Pixel := XT.Node['/form/settype8/'+ColEName+'/'].Attributes['pixel'];
+Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+
+                if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel) then
+                begin
+                  ////有填寫// //
+                  inc(OMROkCount);
+                end;
+                if XT.SubNodes['/form/settype8/'+ColEName+'/'].First then
+                Repeat
+                  RelaSiteRec := '';
+                  nodename := XT.SubNodes['/form/settype8/'+ColEName+'/'].NodeName;
+                  If (nodename <> '@coldesc') and (not XT.SubNodes['/form/settype8/'+ColEName+'/'].NodeIsAttr) then
+                  begin
+                    RelaFormCode := XT.node['/form/settype8/'+ColEName+'/'+nodename+'/'].Attributes['relaformid'];
+                    RelaColEName := XT.node['/form/settype8/'+ColEName+'/'+nodename+'/'].Attributes['rela_col_name'];
+                    RelaColCName := XT.node['/form/settype8/'+ColEName+'/'+nodename+'/'].Attributes['relacoldesc'];
+                    RelaColCName := Copy(RelaColCName,1,length(RelaColCName)-6);
+                    RelaFile := FormCode2FileName(RelaFormCode,ContextList);
+                    RelaFormName := FormCode2FormName(CaseID,RelaFormCode);
+                    Anchor1 := FormID2Anchor(RelaFormCode);
+                    RelaXT.LoadFromFile(CheckXmlPath+FWork_no+'\'+RelaFormCode+'.xml');
+
+                    if RelaFile<>'' then
+                    begin
+                      ISB8.LoadFromFile(ImageSavePath+CaseID+'\upload\'+RelaFile,1); //20170815
+                      ISB8W:= ISB8.Graphic.Width;
+                      ISB8H:= ISB8.Graphic.Height;
+                      FindPoint(ISB8.Graphic,UpLPoint,UpRPoint,DownLPoint,ISB8W,ISB8H,ANCHOR);  //20170815  抓相關然欄位所在圖檔的定位
+                    end;
+
+                    OMROK := False;
+                    //OMROK := False;
+                    //if RelaXT.SubNodes['/form/settype2/'].First then
+                    //Repeat
+                      NoSite := True;
+                      if RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].Count >0 then
+                        NoSite := False;
+                      if RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].First then
+                      Repeat
+                        nodename := RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].NodeName;
+                        If nodename <> '@coldesc' then
+                        begin
+                          RelaPixel := Strtoint(RelaXT.Node['/form/settype2/'+RelaColEName+'/'+nodename+'/'].Attributes['pixel']);
+                          RelaSite := RelaXT.Node['/form/settype2/'+RelaColEName+'/'+nodename+'/'].Attributes['colxy'];
+                          if RelaSiteRec= '' then   //記錄位置
+                            RelaSiteRec := RelaSite
+                          else
+                            RelaSiteRec := RelaSiteRec+'@'+RelaSite;
+                          if  FileExists(ImageSavePath+CaseID+'\upload\'+RelaFile) then
+                          begin
+Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+                            if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+RelaFile,RelaSite,Bt) > (RelaPixel + SafePixel)  then
+                            begin
+                              inc(OMROkCount);
+                              //OMROK := True;
+                              //Break;
+                            end;
+                            ///依十字定位點縮放////
+                            ImageReSize_FormID(CaseID,OMRFile);
+                            ////依十字定位點縮放////
+                          end;
+                        end;
+                        //Else
+                        //begin
+                          //ColCName := XT['/form/settype1/'+ColEName+'/'+nodename+'/'];
+                        //end;
+                      Until not RelaXT.SubNodes['/form/settype2/'+RelaColEName+'/'].Next;
+                      if OMROkCount > 1  then
+                      begin
+                        if not FileExists(ImageSavePath+CaseID+'\upload\'+RelaFile) then
+                          ErrStr:=Format(OMRErrInfo[11].Info,[ColCName,RelaColCName])+'('+_msg('未附')+RelaFormName+')'   //XX欄位填寫時,XX欄位也填寫
+                        Else if NoSite then
+                          ErrStr:=Format(OMRErrInfo[11].Info,[ColCName,RelaColCName])+'('+_msg('未定位')+')'
+                        Else
+                          ErrStr:=Format(OMRErrInfo[11].Info,[ColCName,RelaColCName]);   //XX欄位填寫時,XX欄位也填寫
+                        OMRErr2ini(CaseID,ErrStr,ImageSavePath+CaseID+'\upload\'+OMRFile,SiteRec,ImageSavePath+CaseID+'\upload\'+RelaFile,RelaSiteRec,Anchor,Anchor1,False,OMRErrInfo[7].Ignore,OMRErrInfo[7].Display);
+                        if OMRErrInfo[11].Display then
+                          CaseOk := false;
+                      end;
+                    //Until not RelaXT.SubNodes['/form/settype2/'].Next ;
+
+                  end;
+                Until not XT.SubNodes['/form/settype8/'+ColEName+'/'].Next;
+              Until not XT.SubNodes['/form/settype8/'].Next ;
+            end;
+            //*******有值相關文件的欄位不能有值*******
+
+//ShowMessage('11889 OMRFileList.Strings['+IntToStr(i)+']'+OMRFileList.Strings[i]);
+
+              //*******有值相依文件*******
+            if ModeNeedCheck(OMRErrInfo[5].Mode,FMode) then //是否要檢核
+            begin
+              if XT.SubNodes['/form/settype4/'].First then
+              Repeat
+                SiteRec := '';
+                RelaSiteRec := '';
+                ColEName := XT.SubNodes['/form/settype4/'].NodeName;
+                ColCName := XT.Node['/form/settype4/'+ColEName+'/'].Attributes['coldesc'];
+                ColCName := Copy(ColCName,1,length(ColCName)-6);
+                Site := XT.Node['/form/settype4/'+ColEName+'/'].Attributes['colxy'];
+                if SiteRec= '' then   //記錄位置
+                  SiteRec := Site
+                else
+                  SiteRec := SiteRec+'@'+Site;
+                Pixel := XT.Node['/form/settype4/'+ColEName+'/'].Attributes['pixel'];
+ Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+
+                if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel) then
+                begin
+                  ////有填寫////
+                  if XT.SubNodes['/form/settype4/'+ColEName+'/'].First then
+                  Repeat
+                    nodename := XT.SubNodes['/form/settype4/'+ColEName+'/'].NodeName;
+                    If (nodename <> 'coldesc') and (not XT.SubNodes['/form/settype4/'+ColEName+'/'].NodeIsAttr) then
+                    begin
+                      {RelaFormCode := XT.Node['/form/settype4/'+ColEName+'/'+nodename+'/'].Attributes['relaformid'];
+                      RelaFile := FormCode2FileName(RelaFormCode);
+                      RelaFormName := FormCode2FormName(RelaFormCode); }
+                      RelaDocNo := XT.Node['/form/settype4/'+ColEName+'/'+nodename+'/'].Attributes['relaformid'];
+                      RelaFile := DocNo2FileName(RelaDocNo,ContextList);
+                      RelaDocName := XT.Node['/form/settype4/'+ColEName+'/'+nodename+'/'].Attributes['relaformname'];
+                      if RelaFile='' then
+                      begin
+                        ErrStr:=Format(OMRErrInfo[5].Info,[ColCName,RelaDocName]);   //XX文件XX欄位填寫時,需附XX文件
+                        OMRErr2ini(CaseID,ErrStr,ImageSavePath+CaseID+'\upload\'+OMRFile,SiteRec,'','',Anchor,Anchor1,False,OMRErrInfo[5].Ignore,OMRErrInfo[5].Display);
+                        if OMRErrInfo[5].Display then
+                          CaseOk := false;
+                      end;
+                    end;
+                  Until not XT.SubNodes['/form/settype4/'+ColEName+'/'].Next;
+                end;
+              Until not XT.SubNodes['/form/settype4/'].Next ;
+            end;
+              //*******有值相依文件*******
+
+              //*******有值互斥文件*******
+            if ModeNeedCheck(OMRErrInfo[6].Mode,FMode) then //是否要檢核
+            begin
+              if XT.SubNodes['/form/settype5/'].First then
+              Repeat
+                SiteRec := '';
+                RelaSiteRec := '';
+                ColEName := XT.SubNodes['/form/settype5/'].NodeName;
+                ColCName := XT.Node['/form/settype5/'+ColEName+'/'].Attributes['coldesc'];
+                ColCName := Copy(ColCName,1,length(ColCName)-6);
+                Site := XT.Node['/form/settype5/'+ColEName+'/'].Attributes['colxy'];
+                if SiteRec= '' then   //記錄位置
+                  SiteRec := Site
+                else
+                  SiteRec := SiteRec+'@'+Site;
+                Pixel := XT.Node['/form/settype5/'+ColEName+'/'].Attributes['pixel'];
+ Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+
+                if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel) then
+                begin
+                  ////有填寫////
+                  if XT.SubNodes['/form/settype5/'+ColEName+'/'].First then
+                  Repeat
+                    nodename := XT.SubNodes['/form/settype5/'+ColEName+'/'].NodeName;
+                    If (nodename <> 'coldesc') and (not XT.SubNodes['/form/settype5/'+ColEName+'/'].NodeIsAttr) then
+                    begin
+                      {RelaFormCode := XT.Node['/form/settype5/'+ColEName+'/'+nodename+'/'].Attributes['relaformid'];
+                      RelaFile := FormCode2FileName(RelaFormCode);
+                      RelaFormName := FormCode2FormName(RelaFormCode);}
+                      RelaDocNo := XT.Node['/form/settype5/'+ColEName+'/'+nodename+'/'].Attributes['relaformid'];
+                      RelaFile := DocNo2FileName(RelaDocNo,ContextList);
+                      RelaDocName := XT.Node['/form/settype5/'+ColEName+'/'+nodename+'/'].Attributes['relaformname'];
+                      if RelaFile<>'' then //有附   20130604看到(='')改的(未測)
+                      begin
+                        ErrStr:=Format(OMRErrInfo[6].Info,[ColCName,RelaDocName]);   //XX文件XX欄位填寫時,不能附XX文件
+                        OMRErr2ini(CaseID,ErrStr,ImageSavePath+CaseID+'\upload\'+OMRFile,SiteRec,'','',Anchor,Anchor1,False,OMRErrInfo[6].Ignore,OMRErrInfo[6].Display);
+                        if OMRErrInfo[6].Display then
+                          CaseOk := false;
+                      end;
+                    end;
+                  Until not XT.SubNodes['/form/settype5/'+ColEName+'/'].Next;
+                end;
+              Until not XT.SubNodes['/form/settype5/'].Next ;
+            end;
+              //*******有值互斥文件*******
+
+              //*******有值寫備註*******
+            if ModeNeedCheck(OMRErrInfo[8].Mode,FMode) then //是否要檢核
+            begin
+              if XT.SubNodes['/form/settype6/'].First then
+              Repeat
+                SiteRec := '';
+                ColEName := XT.SubNodes['/form/settype6/'].NodeName;
+                ColCName := XT.Node['/form/settype6/'+ColEName+'/'].Attributes['coldesc'];
+                ColCName := Copy(ColCName,1,length(ColCName)-6);
+                Site := XT.Node['/form/settype6/'+ColEName+'/'].Attributes['colxy'];
+                Pixel := XT.Node['/form/settype6/'+ColEName+'/'].Attributes['pixel'];
+
+                if SiteRec= '' then   //記錄位置
+                  SiteRec := Site
+                else
+                  SiteRec := SiteRec+'@'+Site;
+
+ Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+
+                if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel) then
+                begin
+                  ////有填寫////
+                  if not FileExists(ImageSavePath+CaseID+'ScanMemo.dat') then
+                  begin
+                    ErrStr:=Format(OMRErrInfo[8].Info,[ColCName]);   //XX文件XX欄位填寫時,需寫備註
+                    OMRErr2ini(CaseID,ErrStr,ImageSavePath+CaseID+'\upload\'+OMRFile,SiteRec,'','',Anchor,Anchor1,False,OMRErrInfo[8].Ignore,OMRErrInfo[8].Display);
+                    if OMRErrInfo[8].Display then
+                      CaseOk := false;
+                  end;
+                end;
+              Until not XT.SubNodes['/form/settype6/'].Next ;
+            end;
+              //*******有值寫備註*******
+
+              //*******OMR帶值********
+              if XT.SubNodes['/form/settype7/'].First then
+              Repeat
+                ColEName := XT.SubNodes['/form/settype7/'].NodeName;
+                ValueXT['/content/'+ColEName+'/@savevalue'] := '';  //先給預設空白
+                if XT.SubNodes['/form/settype7/'+ColEName+'/'].First then
+                Repeat
+                  nodename := XT.SubNodes['/form/settype7/'+ColEName+'/'].NodeName;
+                  If nodename <> '@coldesc' then
+                  begin
+                    Pixel := Strtoint(XT.Node['/form/settype7/'+ColEName+'/'+nodename+'/'].Attributes['pixel']);
+                    Site := XT.Node['/form/settype7/'+ColEName+'/'+nodename+'/'].Attributes['colxy'];
+                    OMRValue := XT.Node['/form/settype7/'+ColEName+'/'+nodename+'/'].Attributes['getvalue'];
+
+                    //有填就ok
+ Display1.Lines.Add(ColEName+' '+ColCName+'   圖像實際點數='+IntToStr(GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt))+' 設定點數='+IntToStr( (Pixel + SafePixel)));
+
+                    if GetSiteOMR(ImageSavePath+CaseID+'\upload\'+OMRFile,Site,Bt) > (Pixel + SafePixel)  then
+                    begin
+                      ValueXT['/content/'+ColEName+'/@savevalue'] := OMRValue;  //有填就換成設定的值
+                      Break;
+                    end;
+                  end;
+                Until not XT.SubNodes['/form/settype7/'+ColEName+'/'].Next;
+              Until not XT.SubNodes['/form/settype7/'].Next ;
+
+              //*******OMR帶值********
+            //end;
+          Finally
+          if (OMRValue <> '') then
+            ValueXT.SaveToFile(ImageSavePath+CaseID+'/GetValue.xml');
+          XT.Free;
+          RelaXT.Free;
+          end;
+        end;
+        //必填迴圈結束
+      Finally
+      ValueXT.Free;
+      end;
+    //end;
+  //end;
+  Result := CaseOk;
+end;
+
+function TCB_IMGPSScanX.OMRErrini2ListForLog(CaseID: String): String;
+var
+  ini : Tinifile;
+  Errcount : Integer;
+  Del : Boolean;
+  i,j : Integer;
+  ST,CaseList:TStringList;
+
+begin
+  Result:='';
+  //CaseList.dat
+  ST:=TStringList.Create;
+  CaseList:=TStringList.Create;
+  CaseList.LoadFromFile(ImageSavePath+'CaseList.dat');
+  for I := 0 to CaseList.Count - 1 do
+  begin
+    ini := Tinifile.Create(ImageSavePath + CaseList.Strings[i]+'\upload\Checkerr.ini');
+    try
+      Errcount := ini.ReadInteger('OMRCount','Count',0);
+
+      for j := 1 to ErrCount do
+      begin
+        Del := ini.ReadBool(inttostr(j),'Del',False); //是否被移除了
+        if Not Del then
+        begin
+          ST.Add(ini.ReadString(inttostr(j),'Reason','')) ;
+        end;
+      end;
+    finally
+    ini.Free;
+    end;
+  end;
+  Result:=ST.Text;
+  ST.Free;
+  CaseList.Free;
+end;
+
+
+Procedure TCB_IMGPSScanX.CreateDocNo_DocName(Path,CaseID:String);  //產生DocNo_DocName.dat
+var
+  i : Integer;
+  S : TStringlist;
+  Doc_Name : String;
+begin
+  S := TStringlist.Create;
+  try
+    DistinctDocNoinCase(Path);
+    for i := 0 to CaseDocNoList.Count - 1 do
+    begin
+      Doc_Name := CaseDocNoList.Strings[i]+'_'+DocNo2DocName(CaseID,CaseDocNoList.Strings[i]);
+      if not DocnoNeedGroup(CaseDocNoList.Strings[i]) Then  //不用分組的加*號給智豪
+        Doc_Name := '*'+Doc_Name;
+      S.Add(Doc_Name);
+    end;
+    S.SaveToFile(Path+'DocNo_Name.dat',TEnCoding.UTF8);
+  finally
+  S.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CreateDocNo_Info(CaseID:String):String; //產生 DocNo[tab]份數[tab]總頁數[tab]是否異動[換行]DocNo[tab]份數[tab]總頁數[tab]是否異動
+var
+  i,n : Integer;
+  DocDirList,DocDir_CopiesList,FileList,C_DocNoList : TStringlist;
+  DocNo,iDocDir,iDocNo,iEdit:String;
+  icopys,ipages : integer;
+  S,S1 : TStringlist;
+  Str : String;
+begin
+  DocDirList := TStringlist.Create;
+  DocDir_CopiesList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  C_DocNoList := TStringlist.Create;
+  try
+    Str := '';
+    if Not FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then Exit;
+
+    DocDirList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+
+    if DocDirList.Count =0 then exit;//20170222 新加
+
+
+    DocDir_CopiesList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+    while DocDirList.Count > 0 do
+    begin
+      iDocDir := DocDirList.Strings[0];
+      DocNo := DocNoDir2DocNo(iDocDir);
+      if Copy(iDocDir,1,5) <> 'ZZZZZ' then   //不為自定文件
+      begin
+        //icopys := 1;
+        icopys := GetDocNoCount(CaseID,DocNo);
+        ipages := GetDocDir_Page(CaseID,iDocDir);
+        iEdit := GetDocNoEdit(CaseID,DocNo,'');
+        for i := DocDirList.Count - 1 downto 1 do
+        begin
+          iDocDir := DocDirList.Strings[i];
+          iDocNo := DocNoDir2DocNo(iDocDir);
+          if iDocNo = DocNo then
+          begin
+            //inc(icopys);
+            ipages := ipages + GetDocDir_Page(CaseID,iDocDir);
+            DocDirList.Delete(i);
+          end;
+        end;
+        if str = '' then
+          Str := Format('%s'+#9+'%d'+#9+'%d'+#9+'%s',[DocNo,iCopys,iPages,iEdit])
+        else
+          Str := Str+#13#10+ Format('%s'+#9+'%d'+#9+'%d'+#9+'%s',[DocNo,iCopys,iPages,iEdit]);
+      end;
+      DocDirList.Delete(0);
+    end;
+
+
+  finally
+  DocDirList.Free;
+  DocDir_CopiesList.Free;
+  FileList.Free;
+  C_DocNoList.Free;
+  end;
+  Result := Str;
+
+  {S := TStringlist.Create;
+  S1 := TStringlist.Create;
+  try
+    S.LoadFromFile(Path+'Context.dat');
+    S1.LoadFromFile(Path+'Context_DocNo.dat');
+    for i := 0 to CaseDocNoList.Count - 1 do
+    begin
+      iDocNo := CaseDocNoList.Strings[i];
+      iCopys := GetDocNo_Count(Path,iDocNo);
+      iPages := GetDocNo_Page(Path,iDocNo);
+      if str = '' then
+        Str := Format('%s,%d,%d',[iDocNo,iCopys,iPages])
+      else
+        Str := Str+';'+ Format('%s,%d,%d',[iDocNo,iCopys,iPages]);
+    end;
+    Result := Str;
+
+  finally
+  S.Free;
+  S1.Free;
+  end; }
+end;
+
+Function TCB_IMGPSScanX.CreateCustDocNo_Info(CaseID:String):String; //產生自訂文件 DocName[tab]份數[tab]總頁數[tab]是否異動[#13#10]DocName[tab]份數[tab]總頁數[tab]是否異動
+var
+  i,n : Integer;
+  DocDirList,FileList : TStringlist;
+  DocNo,DocName,iDocDir,iDocNo,iEdit:String;
+  icopys,ipages : integer;
+  S,S1 : TStringlist;
+  Str : String;
+begin
+  DocDirList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  try
+    Str := '';
+    if Not FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then Exit;
+    DocDirList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+//ShowMessage(DocDirList.Text);
+    while DocDirList.Count > 0 do
+    begin
+      iDocDir := DocDirList.Strings[0];
+      DocNo := DocNoDir2DocNo(iDocDir);
+      if Copy(iDocDir,1,5) = 'ZZZZZ' then   //是自定文件
+      begin
+        //icopys := 1;
+        DocName := GetCustomDocName(ImageSavePath+CaseID+'\',DocNo);
+        icopys := GetDocNoCount(CaseID,DocNo);
+        ipages := GetDocDir_Page(CaseID,iDocDir);
+        iEdit := GetDocNoEdit(CaseID,DocNo,DocName);
+        for i := DocDirList.Count - 1 downto 1 do
+        begin
+          iDocDir := DocDirList.Strings[i];
+          iDocNo := DocNoDir2DocNo(iDocDir);
+          if iDocNo = DocNo then
+          begin
+            //inc(icopys);
+            ipages := ipages + GetDocDir_Page(CaseID,iDocDir);
+            DocDirList.Delete(i);
+          end;
+        end;
+        DocName := GetCustomDocName(ImageSavePath+CaseID+'\',DocNo);
+        if str = '' then
+          Str := Format('%s'+#9+'%d'+#9+'%d'+#9+'%s',[DocName,iCopys,iPages,iEdit])
+        else
+          Str := Str+#13#10+ Format('%s'+#9+'%d'+#9+'%d'+#9+'%s',[DocName,iCopys,iPages,iEdit]);
+      end;
+      DocDirList.Delete(0);
+    end;
+  finally
+  DocDirList.Free;
+  FileList.Free;
+  end;
+  Result := Str;
+end;
+
+Function TCB_IMGPSScanX.CreateDocnoFrom_Info(CaseID:String):String; //產生被引進的保管袋文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+var
+  i,n : Integer;
+  DocDirList,DocDir_CopiesList,FileList : TStringlist;
+  DocNo,iDocDir,iDocNo,iEdit:String;
+  FromCaseID : string;
+  icopys,ipages : integer;
+  S,S1 : TStringlist;
+  Str : String;
+begin
+  DocDirList := TStringlist.Create;
+  DocDir_CopiesList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  try
+    Str := '';
+    if Not FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then Exit;
+    DocDirList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+
+    if DocDirList.Count=0 then exit;//20170222 新加
+
+
+    DocDir_CopiesList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo_Copies.dat');
+    while DocDirList.Count > 0 do
+    begin
+      iDocDir := DocDirList.Strings[0];
+      DocNo := DocNoDir2DocNo(iDocDir);
+      if (Copy(iDocDir,1,5) <> 'ZZZZZ') then   //不為自定文件
+      begin
+        //icopys := 1;
+        //icopys := GetDocNoCount(CaseID,DocNo);
+        icopys := GetDocDirCopies(CaseID,iDocDir);
+        ipages := GetDocDir_Page(CaseID,iDocDir);
+        iEdit := GetDocNoEdit(CaseID,DocNo,'');
+        FromCaseID := GetUseCase('F',ImageSavePath+CaseID+'\',iDocDir);
+        if FromCaseID <> '' then
+        begin
+          for i := DocDirList.Count - 1 downto 1 do
+          begin
+            iDocDir := DocDirList.Strings[i];
+            iDocNo := DocNoDir2DocNo(iDocDir);
+            if (iDocNo = DocNo) and (GetUseCase('F',ImageSavePath+CaseID+'\',iDocDir)<>'') then
+            begin
+              FromCaseID := GetUseCase('F',ImageSavePath+CaseID+'\',iDocDir);
+              //inc(icopys);
+              icopys := icopys + GetDocDirCopies(CaseID,iDocDir);
+              ipages := ipages + GetDocDir_Page(CaseID,iDocDir);
+              DocDirList.Delete(i);
+            end;
+          end;
+          if str = '' then
+            Str := Format('%s'+#9+'%d'+#9+'%s',[DocNo,iCopys,FromCaseID])
+          else
+            Str := Str+#13#10+ Format('%s'+#9+'%d'+#9+'%s',[DocNo,iCopys,FromCaseID]);
+        end;
+      end;
+      DocDirList.Delete(0);
+    end;
+  finally
+  DocDirList.Free;
+  DocDir_CopiesList.Free;
+  FileList.Free;
+  end;
+  Result := Str;
+end;
+
+Function TCB_IMGPSScanX.CreateCustDocNoFrom_Info(CaseID:String):String; //產生被引進的自定文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+var
+  i,n : Integer;
+  DocDirList,FileList : TStringlist;
+  DocNo,DocName,iDocDir,iDocNo,iEdit:String;
+  FromCaseID : string;
+  icopys,ipages : integer;
+  S,S1 : TStringlist;
+  Str : String;
+begin
+  DocDirList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  try
+    Str := '';
+    if Not FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then Exit;
+    DocDirList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+    while DocDirList.Count > 0 do
+    begin
+      iDocDir := DocDirList.Strings[0];
+      DocNo := DocNoDir2DocNo(iDocDir);
+      if Copy(iDocDir,1,5) = 'ZZZZZ' then   //是自定文件
+      begin
+        //icopys := 1;
+        //icopys := GetDocNoCount(CaseID,DocNo);
+        icopys := GetDocDirCopies(CaseID,iDocDir);
+        ipages := GetDocDir_Page(CaseID,iDocDir);
+        iEdit := GetDocNoEdit(CaseID,DocNo,DocName);
+        FromCaseID := GetUseCase('F',ImageSavePath+CaseID+'\',iDocDir);
+        if FromCaseID <> '' then
+        begin
+          for i := DocDirList.Count - 1 downto 1 do
+          begin
+            iDocDir := DocDirList.Strings[i];
+            iDocNo := DocNoDir2DocNo(iDocDir);
+            if (iDocNo = DocNo) and (GetUseCase('F',ImageSavePath+CaseID+'\',iDocDir)<>'') then
+            begin
+              FromCaseID := GetUseCase('F',DisplayPath,iDocDir);
+              //inc(icopys);
+              ipages := ipages + GetDocDir_Page(CaseID,iDocDir);
+              DocDirList.Delete(i);
+            end;
+          end;
+          DocName := GetCustomDocName(ImageSavePath+CaseID+'\',DocNo);
+          if str = '' then
+            Str := Format('%s'+#9+'%d'+#9+'%s',[DocName,iCopys,FromCaseID])
+          else
+            Str := Str+#13#10+ Format('%s'+#9+'%d'+#9+'%s',[DocName,iCopys,FromCaseID]);
+        end;
+      end;
+      DocDirList.Delete(0);
+    end;
+  finally
+  DocDirList.Free;
+  FileList.Free;
+  end;
+  Result := Str;
+end;
+
+Function TCB_IMGPSScanX.GetDocNoEdit(CaseID,DocNo,DocName:String):String; //取出DocNo是否被異動 (Y/N)
+var
+  i : Integer;
+  EditedDocDirList : TStringlist;
+  C_DocNoList,C_DocNameList : TStringlist;
+begin
+  Result := 'N';
+  EditedDocDirList := TStringlist.Create;
+  C_DocNoList := TStringlist.Create;
+  C_DocNameList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\EditedDocDir.dat') then
+      EditedDocDirList.LoadFromFile(ImageSavePath+CaseID+'\EditedDocDir.dat');
+    C_DocNoList.StrictDelimiter := True;
+    C_DocNoList.Delimiter := #9;
+    C_DocNoList.DelimitedText := FC_DocNoList;
+    C_DocNameList.StrictDelimiter := True;
+    C_DocNameList.Delimiter := #9;
+    C_DocNameList.DelimitedText := FC_DocNameList;
+
+    //Showmessage(C_DocNoList.Text);
+    if (DocName = '') and (C_DocNoList.IndexOf(DocNo)=-1 ) then
+      Result := 'Y';
+    if (DocName <> '') and (C_DocNameList.IndexOf(DocName)=-1) then
+      Result := 'Y';
+    for i := 0 to EditedDocDirList.Count - 1 do
+    begin
+      if (DocNo = DocNoDir2DocNo(EditedDocDirList.Strings[i]))   then
+      begin
+        Result := 'Y';
+        Break;
+      end;
+    end;
+  finally
+  EditedDocDirList.Free;
+  C_DocNoList.Free;
+  C_DocNameList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetDocNo_Count(Path,DocNo:String):Integer;  //取出文件份數
+var
+  i : Integer;
+  iCopys : integer;
+  S,S1 : TStringlist;
+  iFormID : String;
+  DocFirst : Boolean;
+begin
+  Result := 0;
+  if not DocnoNeedGroup(DocNo) then
+  begin
+    Result := 1;
+    Exit;
+  end;
+
+  S := TStringlist.Create;
+  S1 := TStringlist.Create;
+  try
+    S.LoadFromFile(Path+'Context.dat');
+    S1.LoadFromFile(Path+'Context_DocNo.dat');
+    iCopys := 0;
+
+    for i := 0 to S.Count - 1 do
+    begin
+      iFormID := FileName2FormCode(S.Strings[i]);
+      DocFirst := False;
+      if FormCode2Page(iFormID) = '01' then
+        DocFirst := True;
+      if ((iCopys = 0) or DocFirst) and (Docno = S1.Strings[i])  then
+      begin
+        inc(iCopys);
+      end;
+    end;
+    Result := iCopys;
+  finally
+  S.Free;
+  S1.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetDocNo_Page(Path,DocNo:String):Integer;  //取出文件總頁數
+var
+  i : Integer;
+  ipages : integer;
+  S,S1 : TStringlist;
+begin
+  Result := 0;
+  S := TStringlist.Create;
+  S1 := TStringlist.Create;
+  try
+    S.LoadFromFile(Path+'Context.dat');
+    S1.LoadFromFile(Path+'Context_DocNo.dat');
+    iPages := 0;
+    for i := 0 to S.Count - 1 do
+    begin
+      if Docno = S1.Strings[i] then
+      begin
+        inc(iPages);
+      end;
+    end;
+    Result := ipages;
+  finally
+  S.Free;
+  S1.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.Case_DocNoExists(CaseID,Docno:String):Boolean; //Docno是否存在案件裡
+var
+  i : Integer;
+  S : TStringlist;
+  iDocNo : String;
+begin
+  Result := False;
+  S := TStringlist.Create;
+  try
+    S.LoadFromFile(ImageSavePath + CaseID+'\Context.dat');
+    for i := 0 to S.Count - 1 do
+    begin
+      iDocNo := FormCode2DocNo(FileName2FormCode(S.Strings[i]));
+      if Docno = iDocNo then
+      begin
+        Result := True;
+        Break;
+      end;
+    end;
+  finally
+  S.Free;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.ReSortFileName(Path:String); //檔名重新排序
+var
+  i : Integer;
+  OldName,NewName : String;
+  Filelist : TStringlist;
+begin
+  Filelist := TStringlist.Create;
+  try
+    if FileExists(Path+'Context.dat') then
+    begin
+      Filelist.LoadFromFile(Path+'Context.dat');
+      for i := 0 to Filelist.Count - 1 do
+      begin
+        OldName := Filelist.Strings[i];
+        //NewName := Add_Zoo(i+1,3)+Copy(OldName,4,length(OldName)-3);
+        NewName := Add_Zoo(i+1,3)+FileName2NoQuene_Filename(OldName);
+//ShowMessage(OldName+#10#13+NewName);
+        ReNameFile(Path+OldName,Path+NewName);
+        Filelist.Strings[i] := NewName;
+      end;
+      Filelist.SaveToFile(Path+'Context.dat');
+      ContextList.LoadFromFile(Path+'Context.dat');
+    end;
+  finally
+  Filelist.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ReSortFileName_New(Path:String); //檔名重新排序
+var
+  i : Integer;
+  OldName,NewName : String;
+  Filelist : TStringlist;
+begin
+  Filelist := TStringlist.Create;
+  try
+    if FileExists(Path+'Context.dat') then
+    begin
+      Filelist.LoadFromFile(Path+'Context.dat');
+      for i := Filelist.Count - 1 downto 0 do
+      begin
+        OldName := Filelist.Strings[i];
+        //NewName := Add_Zoo(i+1,3)+Copy(OldName,4,length(OldName)-3);
+        NewName := Add_Zoo(i+1,3)+FileName2NoQuene_Filename(OldName);
+        ReNameFile(Path+OldName,Path+NewName);
+        Filelist.Strings[i] := NewName;
+      end;
+      Filelist.SaveToFile(Path+'Context.dat');
+      ContextList.LoadFromFile(Path+'Context.dat');
+    end;
+  finally
+  Filelist.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CaseAsk(CaseID: string):Integer;
+var
+  SendData : String;
+begin
+//Memo1.Clear;
+  SendData := 'data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&case_no='+CaseID+'&work_no='+FWork_no;
+  if (FMode = 'NSCAN') or (FMode = 'DSCAN') then
+  begin
+//ShowMessage('JJJJJ');
+    If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC05/isnew',SendData,FReWrite,Memo1,False) Then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := -1;
+      Exit;
+    end;
+  end;
+//ShowMessage(SendData);
+
+  IF memo1.Lines.Strings[0] <> '0' Then
+  begin
+    HttpErrStr := _Msg('')+memo1.Lines.Strings[1]+'。';
+    Result := -1;
+    Exit;
+  end
+  Else
+  begin
+    if (memo1.Lines.Count < 2) then
+    begin
+      HttpErrStr := _Msg('')+'OCX:Index Count error';
+      Result := -1;
+      Exit;
+    end
+    Else
+    begin
+      if memo1.Lines.Strings[1] = '0' then
+      begin
+        Result := 0;
+      end
+      Else if memo1.Lines.Strings[1] = '1' then
+        Result := 1
+      Else
+      begin
+        HttpErrStr := _Msg('')+'OCX:Value error';
+        Result := -1;
+        Exit;
+      end;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CaseComplete(Path,CaseID:String;MainCase:Boolean):Boolean;  //通知傳送完成
+var
+  OMRValue,Batchnum,Usermemo,Checkmemo,UpformID,ReMoveMemo: String;
+  Case_type,Handle_no,Format_id,Cen_Uid,Cen_Cliname,Cen_Platno,Cen_Apolyno,Case_priority : String;
+  Pages : Integer;
+  EnCodeDateTime : String;
+  SendData : String;
+  S : TStringlist;
+  i,v,v1 : Integer;
+  UpSortID : String;
+begin
+  Result := True;
+  S := TStringlist.Create;
+  try
+    EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+
+    UpformID := GetCaseFormID(Path);
+
+
+    Case_type := '0';
+    if FileExists(Path+'Context.dat') then    //掃描頁數
+    begin
+      S.LoadFromFile(Path+'Context.dat');
+      Pages := S.Count;
+    end;
+    if not FileExists(ImageSavePath+CaseID+'\CaseIndex.dat') then //如果沒這個檔就重產生預設值
+    begin
+      ClearCaseIndex;
+      WriteCaseIndex(ImageSavePath+CaseID+'\');
+    end;
+    {if FileExists(ImageSavePath+CaseID+'\CaseIndex.dat') then
+    begin
+      S.LoadFromFile(ImageSavePath+CaseID+'\CaseIndex.dat');
+
+      Handle_No := S.Strings[0];    //經辦代號
+      Cen_Uid := S.Strings[1];      //被保人ID
+      Cen_Cliname := S.Strings[2];  //被保人姓名
+      Cen_Platno := S.Strings[3];   //車號
+      Case_Priority := S.Strings[4];//案件等級
+      if FMode = 'SSCAN' then  //簽署章件的時候一律傳Format_ID
+      begin
+        Format_ID := S.Strings[5];    //主鍵值 (報價單號or續保單號or保單號碼or保險證號)
+      end
+      Else
+      begin
+        if (Length(UpformID) = 12) and (UpformID[2] = '-') then
+          Format_ID := S.Strings[5]    //主鍵值 (報價單號or續保單號or保單號碼or保險證號)
+        else
+          Cen_Apolyno := S.Strings[5]; //強制證號
+      end;
+      if (FMode = 'MSCAN') and (length(Format_ID) = 16) and (Copy(Format_ID,1,2) = '05') then
+      begin
+        Format_ID := Copy(Format_ID,3,14);   //20130606 yuu說監理站件的主鍵值為16碼且開開為05的要去掉
+      end;
+
+    end; }
+    if FileExists(ImageSavePath+CaseID+'\GetValue.xml') then    //掃描帶值
+    begin
+      S.LoadFromFile(ImageSavePath+CaseID+'\GetValue.xml');
+      OMRValue := Trim(S.Text);
+    end;
+    if MainCase then    //雙主約的主要案件
+    begin
+      if FileExists(ImageSavePath+CaseID+'\Batchnum.dat') then
+      begin
+        S.LoadFromFile(ImageSavePath+CaseID+'\Batchnum.dat');
+        Batchnum := Trim(S.Text);
+      end;
+    end
+    Else    //雙主約的第二案件
+    begin
+      if FileExists(ImageSavePath+CaseID+'\SecBatchnum.dat') then
+      begin
+        S.LoadFromFile(ImageSavePath+CaseID+'\SecBatchnum.dat');
+        Batchnum := Trim(S.Text);
+      end;
+    end;
+    if FileExists(ImageSavePath+CaseID+'\Scan_Memo.dat') then
+    begin
+      S.LoadFromFile(ImageSavePath+CaseID+'\Scan_Memo.dat');
+      Usermemo := Trim(S.Text);
+    end;
+    if FileExists(ImageSavePath+CaseID+'\CheckMemo.dat') then
+    begin
+      S.LoadFromFile(ImageSavePath+CaseID+'\CheckMemo.dat');
+      Checkmemo := Trim(S.Text);
+    end;
+
+    if FileExists(ImageSavePath+CaseID+'\RemoveMemo.dat') then
+    begin
+      S.LoadFromFile(ImageSavePath+CaseID+'\RemoveMemo.dat');
+      ReMoveMemo := Trim(S.Text);
+    end;
+
+
+  finally
+  S.Free;
+  end;
+  case_priority:='0';
+  if (FMode = 'NSCAN') or (FMode = 'ASCAN') or (FMode = 'DSCAN') or (FMode = 'SSCAN') or (FMode = 'MSCAN') or (FMode = 'RI_SCAN') then
+  begin
+    SendData := 'checktime='+EnCodeDateTime
+                +'&work_no='+FWork_No                                  //作業別
+                +'&case_id='+CaseID                                    //受理編號
+                +'&form_id='+UpformID                                  //表單代號
+                +'&scan_page='+inttostr(pages)                         //掃描頁數
+                +'&scan_get_value='+HTTPEncode(UTF8Encode(OMRValue))   //掃描帶值
+                +'&case_priority='+case_priority                       //案件等級
+                +'&batch_no='+batchnum                                 //車隊批號
+                +'&user_memo='+HTTPEncode(UTF8Encode(usermemo))        //使用者註記
+                +'&check_memo='+HTTPEncode(UTF8Encode(checkmemo))      //檢核註記
+                +'&remove_memo='+HTTPEncode(UTF8Encode(ReMoveMemo))    //檢核移除註記
+                +'&case_type='+Case_type                               //進件種類    進件0 歸檔1
+                +'&handle_no='+Handle_no                               //經辦代號
+                +'&format_id='+Format_id                               //案件主鍵值
+                +'&cen_uid='+Cen_Uid                                   //被保人ID
+                +'&cen_cliname='+HTTPEncode(UTF8Encode(Cen_Cliname))   //被保人姓名
+                +'&cen_platno='+Cen_Platno                             //車牌
+                +'&cen_apolyno='+Cen_Apolyno                           //強制證號
+                +'&has_authorize='+Has_Authorize;                      //是否有授權書影像
+                Showmessage(SendData);
+    if not RejectCase then
+    begin
+      If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC05',SendData,FReWrite,Memo1,False) Then
+      begin
+        HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+        Result := False;
+        Exit;
+      end;
+    end
+    Else
+    begin
+      If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC06',SendData,FReWrite,Memo1,False) Then
+      begin
+        HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+        Result := False;
+        Exit;
+      end;
+    end;
+
+
+  end
+  Else if FMode = 'ISCAN' then
+  begin
+    SendData := 'checktime='+EnCodeDateTime
+                +'&work_no='+FWork_No
+                +'&case_id='+CaseID
+                +'&form_id='+UpformID
+                +'&format_id='+Format_id
+                +'&scan_page='+inttostr(pages)
+                +'&user_memo='+HTTPEncode(UTF8Encode(usermemo))
+                +'&check_memo='+HTTPEncode(UTF8Encode(checkmemo))
+                +'&remove_memo='+HTTPEncode(UTF8Encode(ReMoveMemo))
+                +'&has_authorize='+Has_Authorize;    //是否有授權書影像
+    //Showmessage(SendData);
+    If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC08',SendData,FReWrite,Memo1,False) Then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+  end
+  Else if FMode = 'FSCAN' then
+  begin
+    SendData := 'checktime='+EnCodeDateTime
+                +'&work_no='+FWork_No
+                +'&case_id='+CaseID
+                +'&scan_page='+inttostr(pages)
+                +'&user_memo='+HTTPEncode(UTF8Encode(usermemo))
+                +'&check_memo='+HTTPEncode(UTF8Encode(checkmemo))
+                +'&remove_memo='+HTTPEncode(UTF8Encode(ReMoveMemo))
+                +'&has_authorize='+Has_Authorize;     //是否有授權書影像
+    If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC09',SendData,FReWrite,Memo1,False) Then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+  end
+  Else if FMode = 'RSCAN' then
+  begin
+    SendData := 'checktime='+EnCodeDateTime
+                +'&act=rescan'
+                +'&workno='+FWork_No
+                +'&caseid='+CaseID
+                +'&formid='+UpformID
+                +'&scanpage='+inttostr(pages)
+               // +'&areano='+FUserArea
+                +'&scangetvalue='+HTTPEncode(UTF8Encode(OMRValue))
+                +'&usermemo='+HTTPEncode(UTF8Encode(usermemo))
+                +'&checkmemo='+HTTPEncode(UTF8Encode(checkmemo))
+                +'&removememo='+HTTPEncode(UTF8Encode(ReMoveMemo))
+                +'&has_authorize='+Has_Authorize;        //是否有授權書影像
+    If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC01',SendData,FReWrite,Memo1,False) Then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+  end
+  Else if FMode = 'ESCAN' then
+  begin
+    SendData := 'checktime='+EnCodeDateTime
+                    +'&act=escan'
+                    +'&workno='+FWork_No
+                    +'&caseid='+CaseID
+                    +'&formid='+UpformID
+                    +'&scanpage='+inttostr(pages)
+                    +'&batchnum='+batchnum
+                    +'&usermemo='+HTTPEncode(UTF8Encode(usermemo))
+                    +'&checkmemo='+HTTPEncode(UTF8Encode(checkmemo))
+                    +'&removememo='+HTTPEncode(UTF8Encode(ReMoveMemo))
+                    +'&has_authorize='+Has_Authorize;      //是否有授權書影像
+    If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC01',SendData,FReWrite,Memo1,False) Then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  if Memo1.Lines.Strings[0] <> '0'then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+Memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.Set_caseid(const Value: WideString);
+begin
+  FCaseID := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_data(const Value: WideString);
+begin
+  FData := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_c_docnolist(const Value: WideString);
+begin
+  FC_DocNoList := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_fixfilelist(const Value: WideString);
+begin
+  FFixFileList := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_oldcaseinfo(const Value: WideString);
+begin
+  FOldCaseInfo := Value;
+end;
+
+function TCB_IMGPSScanX.Get_c_docnolist: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_caseid: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_data: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_fixfilelist: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_oldcaseinfo: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_is_oldcase: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_is_oldcase(const Value: WideString);
+begin
+  FIs_OldCase := UpperCase(Value);
+end;
+
+function TCB_IMGPSScanX.Get_casenolength: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_filesizelimit: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_casenolength(const Value: WideString);
+begin
+  if Value ='' then
+  begin
+    FCaseNoLength := 0 ;
+    CaseIDLength := FCaseNoLength;
+  end
+  else
+  begin
+    FCaseNoLength := StrToInt(Value) ;
+    CaseIDLength := FCaseNoLength;
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.Set_filesizelimit(const Value: WideString);
+begin
+//ShowMessage(Value);
+  FFileSizeLimit:=0;
+  if Value ='' then
+  begin
+    FFileSizeLimit := 5*1024;
+  end
+  else
+  begin
+    FFileSizeLimit := StrToInt(Value);
+  end;
+
+end;
+
diff --git a/separate/scanImp/CB_IMGPSScanImp_Data.ts b/separate/scanImp/CB_IMGPSScanImp_Data.ts
new file mode 100644
index 0000000..6fbea50
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Data.ts
@@ -0,0 +1,819 @@
+import * as fs from 'fs';
+import * as path from 'path';
+
+export function applyDataMixins(cls: any) {
+
+    cls.prototype.Get_HelpFile = function(): string {
+        let Result = String(this.HelpFile);
+        return Result;
+    };
+
+    cls.prototype.Set_HelpFile = function(Value: string): void {
+        this.HelpFile = String(Value);
+    };
+
+    cls.prototype.DocNoIsExistImg = function(DocNopath: string): boolean {
+        let i: number;
+        let ST: any;
+        let Result = false;
+        ST = new this.TStringList();
+        if (fs.existsSync(DocNopath + '\\Context.dat')) {   /////20190319 Hong 當有空的Docno目錄時會掛掉,增加這行
+            ST.LoadFromFile(DocNopath + '\\Context.dat');
+        }
+        for (i = 0; i < ST.Count; i++) {
+            if (this.ISExistImg(DocNopath + ST.Strings[i])) {
+                Result = false;
+                return Result; // Exit;
+                // Break;
+            }
+        }
+        Result = true;
+        return Result;
+    };
+
+    cls.prototype.HTTPSClientCertificateValidate = function(Sender: any, X509Certificate: any, Validate: { val: boolean }): void {
+        Validate.val = true;
+    };
+
+    cls.prototype.HTTPSClientRedirection = function(Sender: any, OldURL: string, NewURL: { val: string }, AllowRedirection: { val: boolean }): void {
+        AllowRedirection.val = true;
+    };
+
+    cls.prototype.GetServerDate = function(): boolean {
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/servertimeforocx', '', this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            this.ServerDate = this.Memo1.Lines.Strings[1];
+            this.ServerTime = this.ServerDate.substring(8, 14); // Copy(ServerDate,9,6)
+            this.ServerDate = this.ServerDate.substring(0, 8); // Copy(ServerDate,1,8)
+            this.Balance = this.GetBalance(this.ServerTime); //Server 跟Local的時間差
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.GetSetInf1 = function(): boolean { //取系統設定資訊Mode1 DOC_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+
+        ColumeStr = 'WORK_NO,DOC_NO,DOC_U_DESC,DOC_TYPE,DOC_VERSION,FORM_PAGES,START_DATE,STOP_DATE,IS_DOC_DIV,IS_IN_WH';
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=1&col='+Doc_Inf_Colume+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=1&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.Doc_Inf_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.GetSetInf2 = function(): boolean { //取系統設定資訊Mode2  DM_FORM_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+        ColumeStr = 'WORK_NO,MAIN_FORM_ID,DOC_VERSION,DEPE_FORM_ID,MUTEX_FORM_ID';
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=2&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=2&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.DM_FORM_INF_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.GetSetInf3 = function(): boolean { //取系統設定資訊mode3  FORM_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+        //ColumeStr := 'T1.WORK_NO,T1.FORM_ID,T1.DOC_KIND,T1.DOC_NO,T1.DOC_VERSION,T1.FORM_NAME,T1.FORM_DESC,T1.DIVISION,T1.ANCHOR,T1.MAX_PAGE,T1.FORM_HEIGHT,T1.FORM_WIDTH,T1.MERGE_IMAGE,T1.CC_FORM_ID,T1.CC_MERGE_FORMID,T2.DOC_TYPE'; {T1.CC_FORM_ID,T1.CC_MERGE_FORMID,}
+        ColumeStr = 'T1.WORK_NO,T1.FORM_ID,T1.DOC_NO,T1.DOC_VERSION,T1.FORM_NAME,T1.FORM_DESC,T1.DIVISION,T1.ANCHOR,T1.MAX_PAGE,T1.FORM_HEIGHT,T1.FORM_WIDTH,T1.IS_PRINT,T2.DOC_TYPE'; //{T1.CC_FORM_ID,T1.CC_MERGE_FORMID,}
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=3&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=3&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.FORM_INF_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.GetSetInf4 = function(): boolean { //取系統設定資訊mode4  CHECK_RULE_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+        ColumeStr = 'WORK_NO,CHECK_NO,CHECK_RULE_DESC,MESG_SHOW_TYPE,MESG_DISP_TYPE,CHECK_MESG,SCAN_MODE';
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=4&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=4&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.CHECK_RULE_INF_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        this.CheckRule2OMRErrInfo();
+        return Result;
+    };
+
+    cls.prototype.GetSetInf5 = function(): boolean { //取系統設定資訊mode5  MEMO_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+        ColumeStr = 'T1.WORK_NO,T1.MEMO_TYPE,T1.MEMO_CONTENT,T2.MEMO_TYPE_NAME';
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=5&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=5&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.MEMO_INF_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.GetSetInf6 = function(): boolean { //取系統設定資訊mode5  WORK_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+        ColumeStr = 'WORK_NO,PARA_NO,PARA_CONTENT';
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=5&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=6&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.WORK_INF_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.GetSetInf7 = function(): boolean { //取系統設定資訊mode5  LASTEST_FORM_INF
+        let ColumeStr: string;
+        let S: any;
+        let EnCodeDateTime: string;
+        //SELECT FORM_ID,DOC_NO,DOC_VERSION FROM FORM_INF WHERE (DOC_NO,DOC_VERSION) in (SELECT DOC_NO, MAX(DOC_VERSION) FROM FORM_INF GROUP BY DOC_NO) ORDER BY DOC_NO
+
+        let Result = false;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+        EnCodeDateTime = this.En_DecryptionStr_Base64('E', this.ServerDate + this.GetBalance2Time(this.Balance), this.Mpskey);
+        ColumeStr = 'FORM_ID,DOC_NO';
+        //If not ProcessServlet(HTTPSClient,FURL+'servlet/CWC02 ','checktime='+EnCodeDateTime+'&mode=5&col='+ColumeStr+'&workno='+FWork_No,FReWrite.Text,Memo1) Then
+        if (!this.ProcessServlet_Get(this.HTTPSClient, this.FUrl + 'service/imgpsc/IMGPSC01/tables', 'checktime=' + EnCodeDateTime + '&mode=7&col=' + this.En_DecryptionStr_Base64('E', ColumeStr, this.Mpskey) + '&work_no=' + this.FWork_no, this.FReWrite, this.Memo1, false)) {
+            this.HttpErrStr = this._Msg('錯誤代碼:') + this.HttpError.HttpErrorCode.toString() + ',' + this.HttpError.HttpReason;
+            Result = false;
+            return Result; // Exit;
+        }
+        if (this.Memo1.Lines.Strings[0] === '1') {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this.Memo1.Lines.Strings[1];
+            Result = false;
+            return Result; // Exit;
+        }
+        else if (this.Memo1.Lines.Strings[0] === '0') {
+            S = new this.TStringList();
+            S.Text = this.Memo1.Lines.Text;
+            this.SetSQLData(ColumeStr, S, this.LASTEST_FORM_INF_List);
+            S.Free();
+            Result = true;
+        }
+        else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/CW00/login.js"></script>') >= 0) {
+            this.HttpErrStr = this._Msg('錯誤原因:') + this._Msg('閒置過久或被登出,請重新登入');
+            Result = false;
+            return Result; // Exit;
+        }
+        return Result;
+    };
+
+    cls.prototype.SetIn_WH_DocNo = function(): void { //將要入庫的DocNo抽出來另存入list裡
+        let i: number;
+        for (i = 1; i < this.Doc_Inf_List.Count; i++) {
+            if (this.GetSQLData(this.Doc_Inf_List, 'IS_IN_WH', i) === 'Y') {
+                this.IN_WH_DocNoList.Add(this.GetSQLData(this.Doc_Inf_List, 'DOC_NO', i));
+            }
+        }
+        // {Showmessage(IN_WH_DocNoList.Text);
+        // StringtoFile(IN_WH_DocNoList.Text,'D:\121.txt');}
+    };
+
+    cls.prototype.DeleteDocNoFile = function(Path: string, DocNo: string): boolean {  //刪除指定DocNo文件
+        let i: number;
+        let FName: string;
+        let Result = false;
+        for (i = this.ContextList.Count - 1; i >= 0; i--) {
+            FName = this.ContextList.Strings[i];
+            if (DocNo === this.FormCode2DocNo(this.FileName2FormCode(FName))) {
+                if (fs.existsSync(Path + FName)) fs.unlinkSync(Path + FName); // DeleteFile(Path+FName);
+                this.ContextList.Delete(i);
+                this.Context_DocnoList.Delete(i);
+                Result = true; //有刪到指定文件
+            }
+        }
+        this.ContextList.SaveToFile(Path + 'Context.dat');
+        this.Context_DocnoList.SaveToFile(Path + 'Context_DocNo.dat');
+        this.ReSortFileName(Path);
+        this.ContextList.LoadFromFile(Path + 'Context.dat');
+        this.Context_DocnoList.LoadFromFile(Path + 'Context_DocNo.dat');
+        if (fs.existsSync(Path + 'CustomDocNo.dat')) {
+            this.Cust_DocNoList.LoadFromFile(Path + 'CustomDocNo.dat');
+        }
+        return Result;
+    };
+
+    cls.prototype.DeleteShowFile = function(Path: string): void { //刪除顯示中的影像
+        let i: number;
+        let DelFile: string;
+        for (i = 0; i < this.NowShowFileList.Count; i++) {
+            DelFile = this.NowShowFileList.Strings[i];
+            if (fs.existsSync(Path + DelFile)) fs.unlinkSync(Path + DelFile); // DeleteFile(Path+DelFile);
+            this.SetContextList('D', -1, this.NowCaseno, this.NowDocNo, DelFile);
+        }
+    };
+
+    cls.prototype.GetDataDocNoPage = function(MainDocNo: string, MainVersion: string): number {  //取記錄的文件_版本頁數
+        let P: string;
+        let Result = 0;
+        if (this.FindSQLData(this.Doc_Inf_List, 'FORM_PAGES', 'DOC_NO,DOC_VERSION', MainDocNo + ',' + MainVersion, 0, this.FindResult)) {
+            P = this.GetFindResult('FORM_PAGES');
+            if (P !== '') {
+                Result = parseInt(P, 10);
+            } else {
+                Result = 0;
+            }
+        }
+        return Result;
+    };
+
+    cls.prototype.CheckCaseDocNoPage = function(CaseID: string, DocNo: string, Version: string, Pages: number): number { //取案件裡的文件_版本頁數
+        let i: number, n: number, Count: number;
+        let S: any, S2: any;
+        let FormCode: string, iPage: string;
+        let docInt = 0, tempInt = 0;
+        let v: number, v2: number;
+
+        Count = 0;
+        docInt = 0;
+        tempInt = 0;
+        S = new this.TStringList();
+        S2 = new this.TStringList();
+        //ShowMessage('page='+IntToStr(Pages));
+        try {
+            S.LoadFromFile(this.ImageSavePath + CaseID + '\\upload\\Context.dat');
+            S2.LoadFromFile(this.ImageSavePath + CaseID + '\\upload\\DocDir.dat'); //2017 1220 改成只承認第一份的
+
+            for (i = 1; i <= Pages; i++) { //從0到pages-1  改成 1到pages 20170316 這樣可以修改檢核的頁數問題
+                iPage = this.Add_Zoo(i, 2);
+                for (n = 0; n < S.Count; n++) {
+                    if (this.FWH_category === 'N' && this.FIs_In_Wh === 'Y') {
+                        if (this.ISExistImg(this.ImageSavePath + CaseID + '\\upload\\' + S.Strings[n])) {
+                            continue;
+                        }
+                    }
+
+                    if (S2.Strings[n].length > 8 && S2.Strings[n].indexOf(DocNo) !== -1) { //2017 1220 改成只承認第一份的
+                        //LogFile1.LogToFile(logTimeString+'有進'+docno+','+S2.Strings[n]+IntToStr(Pos(DocNo,S2.Strings[n])));
+                        v = S2.Strings[n].indexOf('(');
+                        v2 = S2.Strings[n].indexOf(')');
+                        tempInt = parseInt(S2.Strings[n].substring(v + 1, v2), 10);
+
+                        if (docInt === 0) {
+                            docInt = tempInt;
+                        }
+                        if (docInt !== tempInt) {
+                            //LogFile1.LogToFile(logTimeString+'docInt='+IntToStr(docInt)+',tempInt='+IntToStr(tempInt));
+                            return Count; // Break returning Count
+                        }
+                    }
+
+                    FormCode = this.FileName2FormCode(S.Strings[n]);
+                    //LogFile1.LogToFile(logTimeString+'S.Strings[n]='+S.Strings[n]);
+                    //Showmessage('1:'+version+','+FormCode2Version(FormCode)+','+DocNo+','+FormCode2DocNo(FormCode)+','+iPage+','+FormCode2Page(FormCode));
+                    //LogFile1.LogToFile(logTimeString+'FormCode='+FormCode);
+                    this.LogFile1.LogToFile(this.logTimeString() + 'CheckCaseDocNoPage caseno=' + CaseID + ',' + Version + ',' + this.FormCode2Version(FormCode) + ',' + DocNo + ',' + this.FormCode2DocNo(FormCode) + ',' + iPage + ',' + this.FormCode2Page(FormCode));
+                    //ShowMessage(DocNo+','+IntToStr(docInt)+','+IntToStr(tempInt));
+                    //LogFile1.LogToFile(logTimeString+'FormCode='+FormCode);
+                    if (Version === this.FormCode2Version(FormCode) && DocNo === this.FormCode2DocNo(FormCode) && iPage === this.FormCode2Page(FormCode)) {
+                        this.LogFile1.LogToFile(this.logTimeString() + 'CheckCaseDocNoPage caseno=' + CaseID + ',' + Version + ',' + this.FormCode2Version(FormCode) + ',' + DocNo + ',' + this.FormCode2DocNo(FormCode) + ',' + iPage + ',' + this.FormCode2Page(FormCode));
+                        //Showmessage(version+','+DocNo+',iPage='+iPage);
+                        //Showmessage(inttostr(Count+1));
+                        Count++;
+                        break;   //找到了...離開
+                    }
+                }
+            }
+        } finally {
+            S.Free();
+            S2.Free();
+        }
+        return Count;
+    };
+
+    cls.prototype.TransCaseID = function(Path: string, CaseID: string, MainCase: boolean): boolean { //傳送案件
+        let i: number, n: number, v: number;
+        let ZipFileList: any;
+        let UpFormID: string;
+        let pages: number;
+        let TransName: string;
+        let MaskPath: string;
+        let HaveMask = false;
+        let S: string;
+        let SendData: string;
+        let Doc_Data = '', Doc_Data1 = '';
+        let In_Doc1 = '', In_Doc2 = '';
+        let AttachYN: string; //是否有附件 Y:有 N:沒有
+
+        let ST1: any, ST2: any, ST3: any;
+        let str1 = '', str2 = '';
+        let must_formidStr = '';
+        let last_add_formidstr = '';
+        let ScanListStr = '';
+        let casepath: string;
+        let filesizeInt = 0;
+        let case_page: string;
+        let Fname: string;
+        let FileRec: any;
+
+        let Result = true;
+        TransName = CaseID;
+        MaskPath = Path + 'MaskImg\\';
+        if (fs.existsSync(Path + 'Context.dat')) {
+            this.ContextList.LoadFromFile(Path + 'Context.dat');
+            this.Context_DocnoList.LoadFromFile(Path + 'Context_DocNo.dat');
+        }
+
+        if (fs.existsSync(Path + 'CustomDocNo.dat')) {
+            this.Cust_DocNoList.LoadFromFile(Path + 'CustomDocNo.dat');
+        }
+
+        pages = this.ContextList.Count;
+        case_page = pages.toString();
+        if (this.FMode === 'NSCAN' || this.FMode === 'ESCAN' || this.FMode === 'ASCAN' || this.FMode === 'DSCAN' || this.FMode === 'SSCAN' || this.FMode === 'MSCAN' || this.FMode === 'RI_SCAN' || this.FMode === 'RSCAN') {
+            //Showmessage('1');
+            UpFormID = this.GetCaseFormID(Path);
+            //{if UpformID = '' then             //20131213  yuu說不管主form
+            //begin
+            //  Showmessage(_msg('取不到主FormID!!'));
+            //  Result := False;
+            //  DataLoading(False,False);
+            //  Exit;
+            //end;}
+        }
+
+        this.CaseResort2Scanlist(Path); //檔名照設定排序產生scanlist.dat
+        //CaseResort(Path);  //檔名照設定排序
+        this.CreateFormID_FormName(Path, CaseID);  //產生FormID_FormName.dat
+        this.CreateDocNo_DocName(Path, CaseID); //產生DocNo_Name.dat
+        Doc_Data = this.CreateDocNo_Info(CaseID);  //產生保管袋文件 Docno,份數,頁數;Docno,份數,頁數 的回傳字串
+        Doc_Data1 = this.CreateCustDocNo_Info(CaseID);  //產生自定文件 Docname,份數,頁數;Docno,份數,頁數 的回傳字串
+        In_Doc1 = this.CreateDocnoFrom_Info(CaseID); //產生被引進的保管袋文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+        In_Doc2 = this.CreateCustDocNoFrom_Info(CaseID);   //產生被引進的自定文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+        AttachYN = this.CreateAttach_Info(CaseID); //是否還有附件 Y:有 N:沒有
+        this.ReadCaseIndex(Path);
+        //LoanDoc := 'Y';
+        //產生遮罩影像
+        //  if FWork_No = 'CW' then
+        //    HaveMask := Case2Mask(Path,MaskPath);
+        //產生遮罩影像
+        // S := S +#13+'5-->'+ Timetostr(now);
+
+        ///////必要formid 20170315 start  //////////////////////////////
+        must_formidStr = '';
+        last_add_formidstr = '';
+        ST1 = new this.TStringList();
+        ST1.LoadFromFile(Path + 'FormCode_Name.dat');
+        //ShowMessage(ST1.Text);
+        //ShowMessage(LastInitFormidList.Text);
+        ST2 = new this.TStringList();
+        ST3 = new this.TStringList();
+
+        for (i = 0; i < ST1.Count; i++) {
+            if (ST1.Strings[i].indexOf('_') !== 0 && ST1.Strings[i].indexOf('_') !== -1) {
+                str1 = ST1.Strings[i].substring(0, ST1.Strings[i].indexOf('_'));
+                ST2.Add(str1);
+                must_formidStr = must_formidStr + str1 + '@#,';
+            }
+        }
+        must_formidStr = must_formidStr.substring(0, must_formidStr.length - 3);
+        //ShowMessage('must_formidStr='+must_formidStr);
+        //ShowMessage('AST2='+ST2.Text);
+
+
+        for (i = 0; i < this.LastInitFormidList.Count; i++) {
+            if (ST2.IndexOf(this.LastInitFormidList.Strings[i]) !== -1) {
+                ST2.Delete(ST2.IndexOf(this.LastInitFormidList.Strings[i]));
+            }
+        }
+        //ShowMessage('BST2='+ST2.Text);
+        for (i = 0; i < ST2.Count; i++) {
+            last_add_formidstr = last_add_formidstr + ST2.Strings[i] + '@#,';
+        }
+        last_add_formidstr = last_add_formidstr.substring(0, last_add_formidstr.length - 3);
+
+        ST3.LoadFromFile(Path + 'scanlist.dat');
+        for (i = 0; i < ST3.Count; i++) {
+            if (ScanListStr === '') {
+                ScanListStr = this.FileName2FormCode(ST3.Strings[i]);
+            } else {
+                ScanListStr = `${ScanListStr},${this.FileName2FormCode(ST3.Strings[i])}`;
+            }
+        }
+
+        ST1.Free();
+        ST2.Free();
+        ST3.Free();
+        //ShowMessage('last_add_formidstr='+last_add_formidstr);
+        ///////必要formid 20170315 end //////////////////////////
+
+        ///保留外部影像  start///////////////////////////////
+        casepath = Path.substring(0, Path.indexOf('Upload'));
+        //ShowMessage('casepath='+casepath);
+        //FIsExternal:='Y';
+        if (this.FMode === 'ESCAN' && this.FIsExternal === 'Y') {
+            if (fs.existsSync(casepath + 'Download\\FirstImg.zip')) {
+                fs.copyFileSync(casepath + 'Download\\FirstImg.zip', Path + 'FirstImg.zip');
+            }
+            else {
+                fs.copyFileSync(casepath + 'Download\\' + CaseID + '.zip', Path + 'FirstImg.zip');
+            }
+        }
+        ///保留外部影像  end///////////////////////////////
+
+        //file_size 計算  就先不做 20170316
+        filesizeInt = 0;
+
+
+        //////壓檔/////
+        this.ZipMainFile(Path, Path, 'Img.zip');
+        if (HaveMask) {
+            this.ZipMaskFile(Path, MaskPath, Path, 'MaskImg.zip');  //有遮罩設定的才產生
+        }
+        /////壓檔////
+        ///檢查上傳的zip大小////
+        Fname = Path + 'Img.zip';
+
+        // FindFirst(FName, faAnyfile, FileRec);
+        // NodeJS equivalent using fs.statSync
+        let stat = fs.statSync(Fname);
+
+        //FMaxUploadSize
+        //ShowMessage(IntToStr(FileRec.Size));
+        //Result:=False;
+        //exit;           //目前上傳檔案大小為xxMB,已超過50MB,無法上傳    %.3f  ,[FileRec.Size / 1048576]
+        if (stat.size > parseInt(this.FMaxUploadSize, 10) * 1048576) { // 檢查檔案大小
+            this.Showmessage(this.Format(this._Msg('%s目前上傳檔案大小為%.3fMB,已超過%sMB,無法上傳'), [CaseID, stat.size / 1048576, this.FMaxUploadSize]));
+            //ShowMessage(Format('%s目前上傳檔案大小為%.3fMB,已超過'+FMaxUploadSize+'MB,無法上傳',[caseid,FileRec.Size / 1048576]) );
+            Result = false;
+            return Result; // Exit;
+        }
+        ///檢查上傳的zip大小////
+        //ShowMessage('last_add_formidstr='+last_add_formidstr);
+        if (!this.GetFtpinfo(CaseID, 'upload')) {   //取案件上傳方式
+            //Showmessage(_Msg()Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+'.');
+            this.DownFileErrStr = this._Msg('取案件上傳資訊失敗!!') + this.HttpErrStr;
+            Result = false;
+            return Result; // Exit;
+        }
+        SendData = 'data=' + this.HTTPEncode(this.UTF8Encode(this.FData))
+            + '&verify=' + this.FVerify
+            + '&form_id=' + UpFormID
+            + '&loan_doc=' + this.Case_loandoc
+            + '&case_no=' + TransName
+            + '&doc_data=' + this.HTTPEncode(this.UTF8Encode(Doc_Data))
+            + '&doc_data1=' + this.HTTPEncode(this.UTF8Encode(Doc_Data1))
+            + '&attach=' + AttachYN
+            + '&case_page=' + case_page
+            + '&file_size=' + filesizeInt.toString()
+            + '&must_formid=' + must_formidStr  //擁有的 formid
+            + '&last_add_formid=' + last_add_formidstr   //當次新加的 formid
+            + '&form_code=' + ScanListStr      //scanlist.dat 表單代號
+            + '&ftp_image_path=' + this.FFtpExtraPath   //加傳FTP目錄  HTTP上傳時會是空白
+            + '&in_doc1=' + this.HTTPEncode(this.UTF8Encode(In_Doc1))
+            + '&in_doc2=' + this.HTTPEncode(this.UTF8Encode(In_Doc2));
+
+        if (this.TransMode === this.TTransMode.tsHttp) {
+            ////上傳/////
+            this.ShowText = CaseID + this._Msg('資料上傳中(Http),請稍候');
+            this.DataLoading(true, true);
+            if (!this.upFile(this.HTTPSClient, this.FUrl, 'service/imgpsc/IMGPSC02/caseupload', SendData, 'file', Path + 'Img.zip', this.FReWrite, this.Memo1, false)) {
+                this.Showmessage(this.HttpError.HttpErrorCode.toString() + ' ' + this.HttpError.HttpReason + '.');
+                Result = false;
+                return Result; // Exit;
+            }
+            if (this.Memo1.Lines.Strings[0] === '1') {
+                this.Showmessage(this.Format(this._Msg('') + this._Msg(''), [CaseID]) + this.Memo1.Lines.Strings[1] + '。');
+                Result = false;
+                return Result; // Exit;
+            }
+            else if (this.Memo1.Lines.Text.indexOf('<script type="text/javascript" src="scripts/IMGPS00/login.js"></script>') > 0) {
+                this.Showmessage(this.Format(this._Msg('') + this._Msg('') + this._Msg('閒置過久或被登出,請重新登入'), [CaseID]));
+                Result = false;
+                return Result; // Exit;
+            }
+            ////上傳////
+        } else if (this.TransMode === this.TTransMode.tsFtp) {
+            this.ShowText = CaseID + this._Msg('資料上傳中(Ftp),請稍候');
+            this.DataLoading(true, true);
+            this.SetFtpInfo();
+            try {
+                if (!this.IIS_Ftp.FtpsConnect()) {
+                    this.Showmessage(this.Format('無法連上Ftp主機,錯誤原因:%s', [this.FtpErrReason]));
+                    Result = false;
+                    return Result; // Exit;
+                }
+                if (!this.IIS_Ftp.FtpsToMain(this.FFtpExtraPath, CaseID + '.zip', Path + 'Img.zip', this.display1)) {
+                    this.Showmessage(this.Format(this._Msg('上傳案件(%s)時,發生錯誤,錯誤原因:%s'), [CaseID, this.FtpErrStr]));
+                    Result = false;
+                    return Result; // Exit;
+                }
+
+                if (!this.FtpCaseComplete(SendData)) {    //Ftp上傳後通知完成
+                    this.Showmessage(this.Format(this._Msg('通知案件(%s)Ftp上傳完成時,發生錯誤!!'), [CaseID]) + this.HttpErrStr);
+                    Result = false;
+                    return Result; // Exit;
+                }
+            } finally {
+                this.IIS_Ftp.FtpsClose();
+            }
+        }
+
+        if (this.FMode === 'ESCAN') {    //上傳舊件引入檔案      //20140616 原本先搬舊件再搬新件,改為先搬新件再搬舊件
+            if (!this.TransOldCaseFile(this.ImageSavePath + CaseID + '\\')) {
+                Result = false;
+                return Result; // Exit;
+            }
+        }
+        // 呼叫Server完成 /////
+        //{If not CaseComplete(Path,CaseID,MainCase) Then
+        //begin
+        //  Showmessage(_Msg('通知案件傳送完成時,網路發生錯誤!!')+HttpErrStr);
+        //  DataLoading(False,False);
+        //  Result := False;
+        //  Exit;
+        //end;  }
+        /// 呼叫Server完成////
+
+        ////刪檔////
+        //_DelTree(Path);  //會只刪TransPath
+        //ShowMessage('STOP');
+        this._DelTree(this.ImageSavePath + CaseID);
+        this.SetCaseList('D', -1, CaseID);
+        ////刪檔////
+        return Result;
+    };
+
+    ['Set_caseid', 'Set_data', 'Set_c_docnolist', 'Set_fixfilelist', 'Set_oldcaseinfo'].forEach(p => {
+        cls.prototype[p] = function(v: string) {
+            let fieldName = 'F' + p.substring(4).replace('caseid', 'CaseID').replace('data', 'Data').replace('c_docnolist', 'C_DocNoList').replace('fixfilelist', 'FixFileList').replace('oldcaseinfo', 'OldCaseInfo');
+            this[fieldName] = v;
+        };
+        cls.prototype['Get_' + p.substring(4)] = function() {
+            let fieldName = 'F' + p.substring(4).replace('caseid', 'CaseID').replace('data', 'Data').replace('c_docnolist', 'C_DocNoList').replace('fixfilelist', 'FixFileList').replace('oldcaseinfo', 'OldCaseInfo');
+            return this[fieldName];
+        };
+    });
+
+    cls.prototype.Set_is_oldcase = function(v: string) { this.FIs_OldCase = v.toUpperCase(); };
+    cls.prototype.Get_is_oldcase = function() { return this.FIs_OldCase; };
+
+    cls.prototype.Set_casenolength = function(v: string) { this.FCaseNoLength = v === '' ? 0 : parseInt(v, 10); this.CaseIDLength = this.FCaseNoLength; };
+    cls.prototype.Get_casenolength = function() { return this.FCaseNoLength.toString(); };
+
+    cls.prototype.Set_filesizelimit = function(v: string) { this.FFileSizeLimit = v === '' ? 5120 : parseInt(v, 10); };
+    cls.prototype.Get_filesizelimit = function() { return this.FFileSizeLimit.toString(); };
+
+    cls.prototype.Set_check_main_form = function(v: string) { this.FCheck_main_form = v; };
+    cls.prototype.Get_check_main_form = function() { return this.FCheck_main_form; };
+
+    cls.prototype.Set_WH_CATEGORY = function(v: string) { this.FWH_category = v; };
+    cls.prototype.Get_WH_CATEGORY = function() { return this.FWH_category; };
+
+    cls.prototype.Set_isExternal = function(v: string) { this.FIsExternal = v; };
+    cls.prototype.Get_isExternal = function() { return this.FIsExternal; };
+
+    cls.prototype.Set_imgdelete = function(v: string) { this.FImgDelete = v; };
+    cls.prototype.Get_imgdelete = function() { return this.FImgDelete; };
+
+    cls.prototype.Set_custdocyn = function(v: string) { this.FCustDocYN = v.toUpperCase(); };
+    cls.prototype.Get_custdocyn = function() { return this.FCustDocYN; };
+
+    cls.prototype.Set_printyn = function(v: string) { this.FPrintyn = v.toUpperCase(); };
+    cls.prototype.Get_printyn = function() { return this.FPrintyn; };
+
+    cls.prototype.Set_work_no = function(v: string) { this.FWork_no = v; };
+    cls.prototype.Get_work_no = function() { return this.FWork_no; };
+
+    cls.prototype.Set_verify = function(v: string) { this.FVerify = v; };
+    cls.prototype.Get_verify = function() { return this.FVerify; };
+
+    cls.prototype.Set_userunit = function(v: string) { this.FUserUnit = v; };
+    cls.prototype.Get_userunit = function() { return this.FUserUnit; };
+
+    cls.prototype.Set_username = function(v: string) { this.FUserName = v; };
+    cls.prototype.Get_username = function() { return this.FUserName; };
+
+    cls.prototype.Set_userid = function(v: string) { this.FUserID = v; };
+    cls.prototype.Get_userid = function() { return this.FUserID; };
+
+    cls.prototype.Set_useproxy = function(v: string) { this.FUseProxy = v.toUpperCase(); };
+    cls.prototype.Get_useproxy = function() { return this.FUseProxy; };
+
+    cls.prototype.Set_url = function(v: string) { this.FUrl = v; };
+    cls.prototype.Get_url = function() { return this.FUrl; };
+
+    cls.prototype.Set_rewrite = function(v: string) { this.FReWrite = v; };
+    cls.prototype.Get_rewrite = function() { return this.FReWrite; };
+
+    cls.prototype.Set_modename = function(v: string) { this.FModeName = v; };
+    cls.prototype.Get_modename = function() { return this.FModeName; };
+
+    cls.prototype.Set_mode = function(v: string) { this.FMode = v.toUpperCase(); };
+    cls.prototype.Get_mode = function() { return this.FMode; };
+
+    cls.prototype.Set_loandoc_value = function(v: string) { this.FLoanDoc_Value = v; };
+    cls.prototype.Get_loandoc_value = function() { return this.FLoanDoc_Value; };
+
+    cls.prototype.Set_loandoc_enable = function(v: string) { this.FLoanDoc_Enable = v; };
+    cls.prototype.Get_loandoc_enable = function() { return this.FLoanDoc_Enable; };
+
+    cls.prototype.Set_language = function(v: string) {
+        this.FLanguage = v.toLowerCase();
+        if (this.FLanguage === 'zh-tw') {
+            this.FLanguage = 'zh_tw';
+        }
+    };
+    cls.prototype.Get_language = function() { return this.FLanguage; };
+
+    cls.prototype.Set_is_in_wh = function(v: string) { this.FIs_In_Wh = v.toUpperCase(); };
+    cls.prototype.Get_is_in_wh = function() { return this.FIs_In_Wh; };
+
+    cls.prototype.Set_c_docnamelist = function(v: string) { this.FC_DocNameList = v; };
+    cls.prototype.Get_c_docnamelist = function() { return this.FC_DocNameList; };
+
+    cls.prototype.DataLoading = function(Loading: boolean, UseTimer: boolean): void {
+        if (Loading) {
+            // Screen.Cursor := -11;
+            if (UseTimer) {
+                this.Panel22.Caption = this.ShowText;
+                this.Panel22.Left = Math.floor(this.Panel9.Width / 2) - Math.floor(this.Panel22.Width / 2);
+                this.Panel22.Top = Math.floor(this.Panel9.Height / 2) - Math.floor(this.Panel22.Height / 2);
+                this.Panel22.Visible = true;
+                this.Timer2.Enabled = true;
+            } else {
+                this.Panel8.Left = Math.floor(this.Panel9.Width / 2) - Math.floor(this.Panel8.Width / 2);
+                this.Panel8.Top = Math.floor(this.Panel9.Height / 2) - Math.floor(this.Panel8.Height / 2);
+                this.Panel8.Visible = true;
+            }
+            this.Application.ProcessMessages();
+            this.Panel1.Enabled = false;
+            this.Panel2.Enabled = false;
+        } else {
+            this.Panel22.Visible = false;
+            this.Panel8.Visible = false;
+            this.Timer2.Enabled = false;
+            this.Panel1.Enabled = true;
+            this.Panel2.Enabled = true;
+            // Screen.Cursor := 0;
+        }
+    };
+
+    cls.prototype.ReduceLogFile = function(): void {
+        let ST1: any;
+        let I: number;
+        ST1 = new this.TStringList();
+        if (fs.existsSync(this.LngPath + 'IMGPSCheck.log')) {
+            ST1.LoadFromFile(this.LngPath + 'IMGPSCheck.log');
+            if (ST1.Count > 100000) {
+                for (I = 0; I <= 10000; I++) {
+                    ST1.Delete(0);
+                }
+                ST1.SaveToFile(this.LngPath + 'IMGPSCheck.log');
+            }
+        }
+        ST1.Free();
+    };
+
+    cls.prototype.ClearCaseIndex = function(): void {
+        this.AddCredit1RG.Enabled = false;
+        this.AddCredit1RG.ItemIndex = -1;
+    };
+
+}
diff --git a/separate/scanImp/CB_IMGPSScanImp_Main.pas b/separate/scanImp/CB_IMGPSScanImp_Main.pas
new file mode 100644
index 0000000..febdbe3
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Main.pas
@@ -0,0 +1,1089 @@
+unit CB_IMGPSScanImp;
+//TEST
+{$WARN SYMBOL_PLATFORM OFF}
+
+interface
+
+uses
+  EnScan,   { for Scanner }
+  EnDiGrph, { for TDibGraphic }
+  EnMisc,   { for MinFloat }
+  EnTifGr,  { for TTifGraphic }
+  {$IFDEF Production}
+  CB_IMGPSScan_TLB,
+  {$ENDIF}
+  {$IFDEF Test}
+  CB_IMGPSScan_test_TLB,
+  {$ENDIF}
+
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  ActiveX, AxCtrls, StdVcl, VCLUnZip, VCLZip, Encryp,
+  ExtCtrls, ComCtrls, Menus, StdCtrls, Gauges, EnImgScr, PJMenuSpeedButtons,
+  Buttons, ImgList, SBSimpleSSL, SBHTTPSClient, SBWinCertStorage, SBX509,
+  SBCustomCertStorage, SBUtils,mpsBarco,BarcodesFinder,HTTPApp,ErrList,
+  Xmltool,inifiles,printers,IdHashMessageDigest, idHash, LogFile,ShellApi,
+  SBSocket,IIS_Ftp, SBSimpleFTPS;
+Type
+  TTransMode =(tsHttp,tsFtp,tsNone);
+
+var
+  Ch_WriteNote : Boolean;
+  RejectCase : Boolean;
+  ErrIndex : Integer;
+
+  //*****預設區*****//
+    Def_DeviceDelete : Boolean;  //空白頁刪除啟動
+    Def_DeviceDeleteSize : Integer;  //空白頁Size
+    Def_ScannerReverse : Boolean; //是否需反相
+    Def_BoardClear : Boolean; //是否清黑邊
+    Def_ScanDpi : Integer;    //掃瞄DPI
+    Def_ScanDuplex : Boolean; //是否雙面掃瞄
+    Def_ScanRotate : Integer; //掃瞄時旋轉角度
+    Def_ScanDeskew : Boolean; //是否傾斜矯正
+    Def_ScanBright : Integer; //亮度
+    Def_ScanContrast : Integer; //對比
+    Def_ScanImgShowMode : Integer; //0:清楚影像 1:不清楚影像 2:不顯示
+    Def_ScanImgSetUse : Boolean; //是否使用亮度對比設定
+  //*****預設區*****//
+
+Const
+  ISBName = 'PreViewISB';
+
+{獲取自身版本號所需要 }
+type
+  TVersionLanguage = (vlArabic, vlBulgarian, vlCatalan, vlTraditionalChinese,
+     vlCzech, vlDanish, vlGerman, vlGreek, vlUSEnglish, vlCastilianSpanish,
+     vlFinnish, vlFrench, vlHebrew, vlHungarian, vlIcelandic, vlItalian,
+     vlJapanese, vlKorean, vlDutch, vlNorwegianBokmel, vlPolish,
+     vlBrazilianPortuguese, vlRhaetoRomanic, vlRomanian, vlRussian,
+     vlCroatoSerbian, vlSlovak, vlAlbanian, vlSwedish, vlThai, vlTurkish,
+     vlUrdu, vlBahasa, vlSimplifiedChinese, vlSwissGerman, vlUKEnglish,
+     vlMexicanSpanish, vlBelgianFrench, vlSwissItalian, vlBelgianDutch,
+     vlNorwegianNynorsk, vlPortuguese, vlSerboCroatian, vlCanadianFrench,
+     vlSwissFrench, vlUnknown);
+
+const LanguageValues: array[TVersionLanguage] of Word = ($0401, $0402, $0403,
+   $0404, $0405, $0406, $0407, $0408, $0409, $040A, $040B, $040C, $040D,
+   $040E, $040F, $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417,
+   $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, $0420, $0421,
+   $0804, $0807, $0809, $080A, $080C, $0810, $0813, $0814, $0816, $081A,
+   $0C0C, $100C, $0000);
+{獲取自身版本號所需要 end}
+
+
+type
+  TScanMode = (smNew, smReplace, smInsert, smSample, smRTS);
+  TpScanInfo = ^TScanInfo;
+  TScanInfo = record
+    MultiPage  : Boolean;
+    { supplementary info when MultiPage is True }
+    Graphic    : TTiffGraphic;
+    Stream     : TFileStream;
+    ImageCount : LongInt;
+  end;
+  TOMRErrInfo = record
+    Display : Boolean;  //是否顯示
+    Ignore : Boolean; //可否刪除
+    Info : String;
+    Mode : String;
+  end;
+  TScrollRec = Record
+    HScroll : Integer;
+    VScroll : Integer;
+    Rate    : Single;
+  end;
+
+type
+  TCB_IMGPSScanX = class(TActiveForm, ICB_IMGPSScanX)
+    Panel1: TPanel;
+    TransBtn: TBitBtn;
+    Panel21: TPanel;
+    ViewModeBtn: TPJMenuSpeedButton;
+    Button2: TButton;
+    Button1: TButton;
+    OptionBtn: TBitBtn;
+    SelectScanBtn: TBitBtn;
+    NextPageBtn: TBitBtn;
+    PrePageBtn: TBitBtn;
+    FC6: TBitBtn;
+    FC5: TBitBtn;
+    FC4: TBitBtn;
+    FC3: TBitBtn;
+    FC2: TBitBtn;
+    FC1: TBitBtn;
+    FC0: TBitBtn;
+    Panel23: TPanel;
+    PJLinkedMenuSpeedButton2: TPJLinkedMenuSpeedButton;
+    NewScanBtn: TBitBtn;
+    AddScanBtn: TBitBtn;
+    Panel4: TPanel;
+    Panel2: TPanel;
+    Splitter1: TSplitter;
+    Panel3: TPanel;
+    Label7: TLabel;
+    Panel6: TPanel;
+    CB1: TCheckBox;
+    ScanDuplexCB: TCheckBox;
+    ScanFlatCB: TCheckBox;
+    Panel18: TPanel;
+    Panel12: TPanel;
+    Panel7: TPanel;
+    Panel9: TPanel;
+    Shape1: TShape;
+    ImageScrollBox1: TImageScrollBox;
+    imgp8: TPanel;
+    lb8: TLabel;
+    ISB8: TImageScrollBox;
+    imgp7: TPanel;
+    lb7: TLabel;
+    ISB7: TImageScrollBox;
+    imgp6: TPanel;
+    lb6: TLabel;
+    ISB6: TImageScrollBox;
+    imgp5: TPanel;
+    lb5: TLabel;
+    ISB5: TImageScrollBox;
+    imgp4: TPanel;
+    lb4: TLabel;
+    ISB4: TImageScrollBox;
+    imgp3: TPanel;
+    lb3: TLabel;
+    ISB3: TImageScrollBox;
+    imgp2: TPanel;
+    lb2: TLabel;
+    ISB2: TImageScrollBox;
+    imgp1: TPanel;
+    lb1: TLabel;
+    Memo1: TMemo;
+    Display1: TMemo;
+    Panel22: TPanel;
+    Panel8: TPanel;
+    Label2: TLabel;
+    Gauge1: TGauge;
+    ScrollBar1: TScrollBar;
+    Panel10: TPanel;
+    PageLV: TListView;
+    StatusBar1: TStatusBar;
+    ImageList4: TImageList;
+    ImageList3: TImageList;
+    ImageList1: TImageList;
+    PopupMenu2: TPopupMenu;
+    mode1: TMenuItem;
+    mode2: TMenuItem;
+    mode3: TMenuItem;
+    mode4: TMenuItem;
+    N51: TMenuItem;
+    ImageList2: TImageList;
+    OpenDialog1: TOpenDialog;
+    PopupMenu3: TPopupMenu;
+    PM301: TMenuItem;
+    PM302: TMenuItem;
+    PM303: TMenuItem;
+    Timer1: TTimer;
+    TomEncryption1: TTomEncryption;
+    SaveDialog1: TSaveDialog;
+    Timer2: TTimer;
+    VCLZip1: TVCLZip;
+    PopupMenu4: TPopupMenu;
+    PM401: TMenuItem;
+    PM402: TMenuItem;
+    PM403: TMenuItem;
+    PM404: TMenuItem;
+    ElWinCertStorage: TElWinCertStorage;
+    ElMemoryCertStorage: TElMemoryCertStorage;
+    Panel5: TPanel;
+    AddCredit1RG: TRadioGroup;
+    Panel11: TPanel;
+    SampleScanBtn: TBitBtn;
+    WNoteBtn: TBitBtn;
+    PopupMenu1: TPopupMenu;
+    PM101: TMenuItem;
+    N12: TMenuItem;
+    PM102: TMenuItem;
+    MenuItem1: TMenuItem;
+    PM103: TMenuItem;
+    PM104: TMenuItem;
+    N7: TMenuItem;
+    PM106: TMenuItem;
+    PM107: TMenuItem;
+    PM108: TMenuItem;
+    PM109: TMenuItem;
+    PopupMenu5: TPopupMenu;
+    PM501: TMenuItem;
+    PM502: TMenuItem;
+    PM503: TMenuItem;
+    PM504: TMenuItem;
+    N5: TMenuItem;
+    PM505: TMenuItem;
+    PM506: TMenuItem;
+    N29: TMenuItem;
+    PM510: TMenuItem;
+    PM509: TMenuItem;
+    PM507: TMenuItem;
+    N15: TMenuItem;
+    PM508: TMenuItem;
+    ExportBt: TButton;
+    ImportBt: TButton;
+    CheckCaseBtn: TBitBtn;
+    DenialTimeLb: TLabel;
+    Panel14: TPanel;
+    ScrollBox1: TScrollBox;
+    Label1: TLabel;
+    Button3: TButton;
+    Panel15: TPanel;
+    Button4: TButton;
+    PopupMenu6: TPopupMenu;
+    PM602: TMenuItem;
+    PM601: TMenuItem;
+    PM605: TMenuItem;
+    PM603: TMenuItem;
+    PM604: TMenuItem;
+    N8: TMenuItem;
+    Panel16: TPanel;
+    SpeedButton3: TSpeedButton;
+    SpeedButton14: TSpeedButton;
+    SpeedButton15: TSpeedButton;
+    SpeedButton16: TSpeedButton;
+    SpeedButton17: TSpeedButton;
+    SpeedButton18: TSpeedButton;
+    SpeedButton19: TSpeedButton;
+    SpeedButton20: TSpeedButton;
+    SpeedButton21: TSpeedButton;
+    SpeedButton22: TSpeedButton;
+    Edit1: TEdit;
+    PM110: TMenuItem;
+    Image1: TImage;
+    UseOldCaseLb: TLabel;
+    PM111: TMenuItem;
+    SmoothCB: TCheckBox;
+    ISB_BW: TImageScrollBox;
+    N1: TMenuItem;
+    N2: TMenuItem;
+    ISB1: TImageScrollBox;
+    Label3: TLabel;
+    LogFile1: TLogFile;
+    ScanGrayCB: TCheckBox;
+    AttFileGB: TGroupBox;
+    AttListBox: TListBox;
+    Panel20: TPanel;
+    AddAttFileLB: TLabel;
+    DelAttFileLB: TLabel;
+    Splitter2: TSplitter;
+    Panel17: TPanel;
+    TreeView1: TTreeView;
+    Panel13: TPanel;
+    PrtLb: TLabel;
+    CaseHelpBtn: TBitBtn;
+    HTTPSClient: TElHTTPSClient;
+    Button5: TButton;
+    FTPSClient1: TElSimpleFTPSClient;
+    Button6: TButton;
+    procedure ActiveFormCreate(Sender: TObject);
+    procedure Panel9Resize(Sender: TObject);
+    procedure ISB1Click(Sender: TObject);
+    procedure WNoteBtnClick(Sender: TObject);
+    procedure CaseHelpBtnClick(Sender: TObject);
+    procedure FC0Click(Sender: TObject);
+    procedure FC1Click(Sender: TObject);
+    procedure FC2Click(Sender: TObject);
+    procedure FC3Click(Sender: TObject);
+    procedure FC4Click(Sender: TObject);
+    procedure FC5Click(Sender: TObject);
+    procedure FC6Click(Sender: TObject);
+    procedure PrePageBtnClick(Sender: TObject);
+    procedure NextPageBtnClick(Sender: TObject);
+    procedure OptionBtnClick(Sender: TObject);
+    procedure SelectScanBtnClick(Sender: TObject);
+    procedure mode1Click(Sender: TObject);
+    procedure mode2Click(Sender: TObject);
+    procedure mode3Click(Sender: TObject);
+    procedure mode4Click(Sender: TObject);
+    procedure N51Click(Sender: TObject);
+    procedure ScrollBar1Change(Sender: TObject);
+    procedure ISB1EndScroll(Sender: TObject);
+    procedure ISB1ImageMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure ISB1ImageMouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer);
+    procedure ISB1ImageMouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure PM508Click(Sender: TObject);
+    procedure PM401Click(Sender: TObject);
+    procedure PM402Click(Sender: TObject);
+    procedure PM403Click(Sender: TObject);
+    procedure PM404Click(Sender: TObject);
+    procedure TreeView1Click(Sender: TObject);
+    procedure NewScanBtnClick(Sender: TObject);
+    procedure AddScanBtnClick(Sender: TObject);
+    procedure PageLVClick(Sender: TObject);
+    procedure PageLVKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    procedure PageLVMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure PM101Click(Sender: TObject);
+    procedure PM104Click(Sender: TObject);
+    procedure PM102Click(Sender: TObject);
+    procedure PM103Click(Sender: TObject);
+    procedure PM106Click(Sender: TObject);
+    procedure PM107Click(Sender: TObject);
+    procedure PM108Click(Sender: TObject);
+    procedure PM109Click(Sender: TObject);
+    procedure PM301Click(Sender: TObject);
+    procedure PM302Click(Sender: TObject);
+    procedure PM303Click(Sender: TObject);
+    procedure PM501Click(Sender: TObject);
+    procedure PM502Click(Sender: TObject);
+    procedure PM503Click(Sender: TObject);
+    procedure PM504Click(Sender: TObject);
+    procedure PM505Click(Sender: TObject);
+    procedure PM510Click(Sender: TObject);
+    procedure PM509Click(Sender: TObject);
+    procedure PM507Click(Sender: TObject);
+    procedure PopupMenu1Popup(Sender: TObject);
+    procedure PopupMenu4Popup(Sender: TObject);
+    procedure PopupMenu5Popup(Sender: TObject);
+    procedure SampleScanBtnClick(Sender: TObject);
+    procedure StatusBar1DblClick(Sender: TObject);
+    procedure ExportBtClick(Sender: TObject);
+    procedure ImportBtClick(Sender: TObject);
+    procedure HTTPSClientCertificateValidate(Sender: TObject;
+      X509Certificate: TElX509Certificate; var Validate: Boolean);
+    procedure ScanDuplexCBClick(Sender: TObject);
+    procedure CheckCaseBtnClick(Sender: TObject);
+    procedure Timer1Timer(Sender: TObject);
+    procedure Timer2Timer(Sender: TObject);
+    procedure TransBtnClick(Sender: TObject);
+    procedure TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
+    procedure TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
+      State: TDragState; var Accept: Boolean);
+    procedure TreeView1KeyUp(Sender: TObject; var Key: Word;
+      Shift: TShiftState);
+    procedure TreeView1MouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure ViewModeBtnMouseEnter(Sender: TObject);
+    procedure Button3Click(Sender: TObject);
+    procedure AddCredit1RGClick(Sender: TObject);
+    procedure CB1Click(Sender: TObject);
+    procedure Button4Click(Sender: TObject);
+    procedure ISB1Enter(Sender: TObject);
+    procedure TreeView1MouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer);
+    procedure PM601Click(Sender: TObject);
+    procedure PopupMenu6Popup(Sender: TObject);
+    procedure PM604Click(Sender: TObject);
+    procedure PM605Click(Sender: TObject);
+    procedure SpeedButton3Click(Sender: TObject);
+    procedure SpeedButton14Click(Sender: TObject);
+    procedure SpeedButton15Click(Sender: TObject);
+    procedure SpeedButton16Click(Sender: TObject);
+    procedure SpeedButton17Click(Sender: TObject);
+    procedure SpeedButton18Click(Sender: TObject);
+    procedure SpeedButton19Click(Sender: TObject);
+    procedure SpeedButton20Click(Sender: TObject);
+    procedure SpeedButton21Click(Sender: TObject);
+    procedure SpeedButton22Click(Sender: TObject);
+    procedure ActiveFormKeyUp(Sender: TObject; var Key: Word;
+      Shift: TShiftState);
+    procedure PM110Click(Sender: TObject);
+    procedure PM602Click(Sender: TObject);
+    procedure PrtLbClick(Sender: TObject);
+    procedure Panel1DblClick(Sender: TObject);
+    procedure Panel11DblClick(Sender: TObject);
+    procedure UseOldCaseLbClick(Sender: TObject);
+    procedure PM111Click(Sender: TObject);
+    procedure ImageScrollBox1NewGraphic(const Graphic: TDibGraphic);
+    procedure SmoothCBClick(Sender: TObject);
+    procedure N1Click(Sender: TObject);
+    procedure TreeView1MouseEnter(Sender: TObject);
+    procedure ScrollBox1MouseEnter(Sender: TObject);
+    procedure ScanGrayCBClick(Sender: TObject);
+    procedure AddAttFileLBClick(Sender: TObject);
+    procedure DelAttFileLBClick(Sender: TObject);
+    procedure AttListBoxDblClick(Sender: TObject);
+    procedure AttListBoxClick(Sender: TObject);
+    procedure TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure HTTPSClientRedirection(Sender: TObject; const OldURL: string;
+      var NewURL: string; var AllowRedirection: Boolean);
+    procedure Button5Click(Sender: TObject);
+    procedure Button6Click(Sender: TObject);
+  private
+    { Private declarations }
+    HotKeyId1,HotKeyId2,HotKeyId3,HotKeyId4 :Integer;
+
+    ////////傳入參數/////////
+    FUrl : String;
+    FCaseID : String;
+    FMode : String;        //NSCAN:新件;ESCAN:修改 20170306 DSCAN:被配合待掃瞄清單使用
+    FModeName : String;
+    FWork_no : String;
+    FUserID : String;
+    FUserName : String;
+    FUserUnit : String;
+    FData : String;
+    FVerify : String;
+    FReWrite : String;
+    FLanguage : String;
+    FLoanDoc_Value : String; //新增授信卷的值
+    FLoanDoc_Enable : String; //新增授信卷是否可異動
+    FUseProxy : String; //是否使用Proxy
+    FC_DocNoList : String; //外面傳來要新增的文件編號
+    FC_DocNameList : String; //外面傳來要新增的自訂文件
+    FFixFileList : String; //要鎖住的檔名
+    FIs_In_Wh : String; //是否只顯示入庫文件  (Y:只顯示入庫 N:只顯示非入庫 空白:都顯示)
+    FOldCaseInfo : String; //舊件資訊  CaseID_year[tab]CaseID_year
+    FPrintyn : String; //是否可列印
+    FIs_OldCase : String; //是否是舊案第一次進入
+    FCustDocYN : String; //是否可自訂文件
+    //20170222 新增
+    FImgDPI:integer;//DPI  依業務別決定 150~~1200  預設300
+    FScanColor:integer;///掃瞄色彩  依業務別決定   0 :黑白  1:灰階   2:彩色 預設黑白
+    FFileSizeLimit:integer;//匯入單一檔案大小限  依業務別決定  以KB為單位  預設5*1024kb
+    FCaseNoLength:integer;//案件編號長度檢查  依業務別決定   無預設  一定要傳入
+    FImgDelete:string; // Y/N  有權限可在補件時刪除影像
+    FIsExternal:string;//Y/N
+    FCheck_main_form:string; //Y/N
+    FWH_category:string;  //Y/N  Y是歸類時有區分入庫非入庫文件  N 是不區分
+    ////////傳入參數///////
+
+    TransMode : TTransMode;   //用何種方式上傳檔案
+    //********Http參數********
+    HttpErrStr : String; //錯誤訊息
+    //********Http參數********
+
+    //********Ftp參數*********
+    FFtpIP : String;
+    FFtpID : String;
+    FFtpPwd : String;
+    FFtpRootPath : String;
+    FFtpExtraPath : String;
+    FFtpPort : Integer;
+    FFtpProtocol : TFtpProtocol;
+    //********Ftp參數*********
+
+    //********ini參數********
+    DeviceDelete : Boolean;     //空白頁刪除啟動
+    DeviceDeleteSize : Integer;  //空白頁Size
+    ScannerReverse : Boolean; //是否需反相
+    BoardClear : Boolean; //是否清黑邊
+    ScanDpi : Integer;    //掃瞄DPI
+    ScanDuplex : Boolean; //是否雙面掃瞄
+    ScanRotate : Integer; //掃瞄時旋轉角度
+    ScanDeskew : Boolean; //是否傾斜矯正
+    ScanBright : Integer; //亮度
+    ScanContrast : Integer; //對比
+    ScanImgShowMode : Integer; //0:清楚影像 1:不清楚影像 2:不顯示
+    ScanImgSetUse : Boolean; //是否使用亮度對比設定
+
+    //********ini參數********
+    ScanColor : TImageFormat;
+
+    //********時間********
+    ServerDate : String;
+    ServerTime : String;
+    Balance : Longint; //local跟server的時間差
+    ScanDenialTime : String; //停止進件時間
+    //********時間********
+    ScanDenialHint : String; //掃描顯示提醒字串
+
+    //********路徑********
+    ScanPath : String;       // SpecifyDir\Workid\userunit\mode
+    ImagePath : String;      // SpecifyDir\Workid\userunit\mode
+    ImageSavePath : String;   // ImagePath\
+    ScaniniPath : String;    // SpecifyDir\Workid\userunit\
+    LngPath :String;         //多國語言檔目錄
+    CheckXmlPath : String;   //檢核用的Xml存放目錄
+    SitePath : String;      //登打位置(切簽名用)
+    SamplePath : String;     //範本目錄
+    TransPath : String;     //檔案上傳的路徑(補充件會多一層目錄)
+    //********路徑********
+    ScanSaveFilename : String; //掃瞄的檔名
+    ScanCaseno : String;  //掃瞄時的案號
+    ScanDocDir : String;  //掃描時的文件代號目錄
+    //********清單區********
+    Doc_Inf_List : TStringList;  //Doc_Inf 清單
+    DM_FORM_INF_List :TstringList;  //DM_FORM_INF 清單
+    FORM_INF_List : TStringList; //FORM_INF的清單
+    CHECK_RULE_INF_List : TStringList;  //CHECK_RULE_INF  清單
+    MEMO_INF_List : TStringList;  //MEMO_INF 清單
+    WORK_INF_List : TStringList;  //WORK_INF 清單
+    LASTEST_FORM_INF_List : TStringList;  // LASTEST_FORM_INF 清單
+
+    FindResult : TStringList;    //找SQLData的結果
+    CaseList : TStringList;    //記錄掃瞄案件的順序
+    Context_DocnoList : TStringlist; //案件裡的Docno清單
+    CaseDocNoList : TStringlist;  //案件裡的DocNo清單(不重複)
+    CaseDocNo_CopiesList : TStringlist; //案件裡的DocNo份數清單
+    ContextList : TStringlist; //案件裡的檔案清單
+    AttContextList : TStringlist; //案件裡的附加檔案清單
+    OMRFileList : TStringList; //要OMR檢核的文件(只檢查每種Form的第一頁)
+    Cust_DocNoList : TStringlist; //自行定義文件名稱
+    IN_WH_DocNoList : TStringlist; //入庫的文件清單
+
+    FormCode_PageSize : TStringList; //文件的預設大小  FormCode_Height_Width
+    DocNo_NeedDoc : TStringList; //有Docno時要相依的文件   DocNo_相依文件_相依文件
+    DocNo_NoDoc : TstringList; //有Docno時互斥的文件   DocNo_互斥文件_互斥文件
+    DocNo_VerinCase : TStringlist; //案件裡的DocNo+版本的清單
+
+    NoSaveBarCodeList : TStringlist; //不儲存的條碼清單
+    FormID_List : TStringlist;    //FormID 清單  20130403 因為原FormCode2Docno會很慢..把FormID抽出來
+    DocNo_List : TStringlist;     //DocNo 清單  20130403 因為原FormCode2Docno會很慢..把DocNo抽出來
+    NowShowFileList : TStringlist;  //目前顯示的影像清單
+    NowSelectFileList : TStringlist; //目前被點選的影像清單
+    GuideFormIDList : TStringlist; //要當導引頁表單清單
+    DivPageFormIDList:TStringlist; //要當分案頁表單清單
+    LastInitFormidList:TStringList;
+    LastAddFormidList:TstringList;
+    SampleFormIDList:TStringList; //20170627 已存在範本的formid
+    ExistImgList:TStringList;  //20170724  已經存在的影像list for ESCAN  //Img的完整路徑
+    reSizeExistImgList:TstringList; //20171012被縮放的舊圖MD5存入
+    //********清單區********
+
+    //********顯示區********
+    NowCaseno : String; //目前顯示的案件編號
+    NowDocNo : String;  //目前的文件編號
+    NowDocDir : String; //目前的文件目錄
+    NowFormCode : String; //目前顯示的表單編號
+    NowFormName : String; //目前顯示的表單名稱
+    NowPage : Integer;   //目前點選的頁碼
+    DisplayPath : String; //目前顯示的目錄
+    //********顯示區********
+
+    //******索引資料*********
+    Case_loandoc : String; //是否新增授信卷
+    //******索引資料*********
+
+    //********十字定位點資訊********
+    UpLPoint : Tpoint;  //左上方的十字點
+    UpRPoint : Tpoint;  //右上方的十字點
+    DownLPoint : Tpoint;  //左下方的十字點
+    DownRPoint : Tpoint;  //右下方的十字點
+    Point_Width : String;   //十字點的寬
+    Point_Height : String;   //十字點的高
+    //********十字定位點資訊********
+
+    CaseIDLength : Integer; //案件編號長度
+    FormIDLength : Integer; //FormID長度
+    DocNoLength : Integer;  //Docno長度
+
+    PEFileName : String; //掃描時的檔名
+    DownFileErrStr : String;  //下載影像時發生的錯誤
+
+    ISB : TImageScrollBox;
+    ScanInfo    : TScanInfo;
+    TwainShowUI : Boolean;
+    MpsBarcodeinf : TMpsBarcodeinf;
+    ScanMode : TScanMode;
+    Mpskey : String;
+    Seg : Integer; //顯示的邊界值
+    VMode : Integer; //顯示的index
+    NowClick : Integer;   //目前點到的按鈕功能Index
+    ScanIP : String;  //掃瞄端的IP
+    DisplayISB : TImageScrollBox; //被點到的影像
+    SelectISB : TImageScrollBox; //被點到的縮圖
+    SelectPage : Integer; //被點到的頁數
+    NewTreeNode,MyTreeNode1,MyTreeNode2,MyTreeNode3 : TTreenode;
+    InitialOk : Boolean; //資訊載入是否完成
+    ShowText : String; //DataLoading時要秀出的訊息
+    Ext : String; //附檔名  .tif .jpg
+    SafePixel : Integer;  //OMR容忍誤差值點數
+    OMRErrInfo : Array[1..11] of TOMRErrInfo;  //檢核的方式及訊息
+    ScrollRec : Array[1..8] of TScrollRec; //瀏覽窗的Scroll記錄
+    RecHozPos,RecVerPos : Integer;  //記錄MPSViewX1的ScrollBar位置
+    ReczoomPercent : Single;
+    SortMode : Boolean;
+    PreMytreeNode2Name:String;
+    HS,VS : Integer;
+    iRate : Single;
+    Bt : Integer; //去直線時橫線判斷的容忍值
+    BarCodeRotate : Integer; //條碼要轉的角度
+    HaveAppDoc : Boolean; //補全時是否有補入要保書
+    PageLVclear : Boolean;
+    CaseCount,PageCount : Integer; //總案件量及總頁數
+    Item : TMenuItem;
+    SampleAnchorMode : String; //範本掃瞄十字線的模式  NONE:無;ANCHOR:十字;FRAME:邊框
+    DownImgStatus : String;  //下載影像的狀態(NO_DATA:沒資料;NO_FILE:沒影像)
+    TransForm_Field : String; //要用OMR勾選確認是否轉換FORMID的欄位名稱
+    NowWork_No : String; //現在的作業別
+    CropBarcode : String; //要切影像的條碼
+    Has_Authorize :String; //是否有授權書影像
+    AttName : String; //未歸類目錄名稱
+    NowGuideFormID : String;
+    NowDivPageFormID:String;
+
+    FirstDocDir : String;
+    FMaxUploadSize:String;// 上傳zip大小限制
+    FJpgCompression:integer;// 20171211 jpg to tif 的壓縮率
+
+    Draging : Boolean;
+    MDown : Boolean;  //20181210 用來判斷滑鼠右鍵要Popupmenu是否有MouseDonw發生
+
+    FEvents: ICB_IMGPSScanXEvents;
+
+    procedure HotKeyDown (var Msg : TMessage);message WM_HOTKEY;
+    Procedure InitialLanguage(Sender: TObject);   //畫面載入多國語言
+    //Function _Msg(S:String):String;
+
+    //*********SQL相關************
+    Procedure SetSQLData(ColumeStr:String;FromList,ToList:TStringlist); //把SQL值塞入
+    Function GetSQLData(TableList:TStringlist;Colname:String;colNo:Integer):String; //依欄位及索引取值
+    Function FindSQLData(TableList:TStringlist;ColumeStr,KeyColumeStr,KeyStr:String;ColNo:Integer;Var ResultList:TStringlist):Boolean; //找指定的資料
+    Function GetFindResult(Col:String):String;
+    //*********SQL相關************
+
+    //*********FTP相關************
+    Function GetFtpinfo(CaseID,Action:String):Boolean;
+    Procedure SetFtpInfo;     //餵入FTP資訊
+    Function FtpCaseComplete(SendData:String):Boolean;
+    //*********FTP相關************
+
+    //*******轉換區*********
+    Function FindDivFormCode(FormCode:String):Boolean; //找有沒有分案的條碼
+    Function FormCode2FormName(CaseID,FormCode:String):String; //用FormCode轉成文件名稱
+    Function FormCode2FileName(FormCode:String;List:TStrings):String; //用FormCode找出檔名(第一頁)
+    Function FileName2FormCode(FileName:String):String; //從檔名取出FormCode
+    Function FileName2FormName(CaseID,FileName:String):String; //從檔名取出文件名稱
+    Function FileName2ScanPage(FileName:String):Integer; //從檔名取出掃瞄頁數
+    Function FileName2NoQuene_Filename(FileName:String):String; //取出沒有序號的檔名
+    Function FileName2Index(FileName:String):Integer; //從檔名取出在ContextList的序號
+    Function FileName2NowDcoNo(FileName:String;CtList,DNList:TStrings):String; //從檔名取出歸屬的文件代號
+    Function FormCode2DocNo(FormCode:String):String;   //FormCode轉Docno
+    Function FormCode2Version(FormCode:String):String; //FormCode轉版本
+    Function FormCode2Page(FormCode:String):String; //FormCode轉文件頁數
+    Function DocNo2DocName(CaseID,DocNo:String):String; //Docno轉Doc名稱
+    Function DocNo2FileName(DocNo:String;List:TStrings):String; //用DocNo找出檔名(第一頁)
+    Function FormCode2WorkNo(FormCode:String):String; //用FormCode取出作業別
+    Function DocNo2WorkNo(DocNo:String):String; //用DocNo取出作業別
+    Function DocNo2DocNoDir(Path,DocNo:String):String;    //DocNo轉成DocNo(份數)目錄
+    Function DocNoDir2DocNo(DocNoDir:String):String; //DocNo(份數)目錄轉成DocNo
+    Function DocNoDir2Index(Path,DocNoDir:String):Integer; //DocNo(份數)目錄轉成index
+
+    Function DocNoNeedDiv(DocNo:String):Boolean; //是否是需分份數的文件代號
+    //Function CaseNo2DocNo(CaseNo:String):TStringList;
+
+    Function CaseNode2Info(Node:TTreeNode;Mode:Char):String;   //案件Node取案件編號  Mode: I:Caseno;P:Page
+    Function DocNode2Info(Node:TTreeNode;Mode:Char):String;     //文件Node取文件代號 Mode: I:Docno;N:Docname;P:Page;G:Group
+    Function FormNode2Info(Node:TTreeNode;Mode:Char):String;   //表單Node取表單代號  Mode: I:FormID;N:FormName;P:Page
+    //*******轉換區*********
+
+    Procedure PriorPage(Page:Integer); //上一頁
+    Procedure NextPage(Page:Integer); //下一頁
+
+    Function DocNoExistsinTree(CaseNode:TTreeNode;DocNo:String):Boolean; //DocNo是否己存在樹裡
+    Function DocnoNeedGroup(DocNo:String):Boolean; //傳入的DocNo是否需分組
+
+    function GetSiteOMR(FileName, Site: String;bt: Integer): Integer;
+    Function FindISB2View(Vmode:Integer):TImageScrollBox; //找空的ISB來顯示
+    Procedure R_W_ScanIni(Mode:Char); //'R'讀取;'W'寫入
+    Procedure GetDefScanIni; //取得掃瞄的預設值
+    procedure DesableImage;
+    procedure EnableImage(v:integer;Sender : TObject);
+    Procedure ViewMouseMode(v:Integer);
+    Procedure GoViewMode;
+    Procedure DisplayMode(index,H_Count,W_Count:Integer;BasePanel:TPanel);
+    Function GetServerDate : Boolean; //取主機時間
+    Function GetSetInf1 : Boolean; //取系統設定資訊mode1  DOC_INF
+    Function GetSetInf2 : Boolean; //取系統設定資訊mode2  DM_FORM_INF
+    Function GetSetInf3 : Boolean; //取系統設定資訊mode3  FORM_INF
+    Function GetSetInf4 : Boolean; //取系統設定資訊mode4  CHECK_RULE_INF
+    Function GetSetInf5 : Boolean; //取系統設定資訊mode5  MEMO_INF
+    Function GetSetInf6 : Boolean; //取系統設定資訊mode6  WORK_INF
+    Function GetSetInf7 : Boolean; //取系統設定資訊mode7  LASTESTFORM_INF
+    Procedure SetFormID_DocNo; //將FormID及Docno抽出來另存入list裡
+    Procedure SetIn_WH_DocNo; //將要入庫的DocNo抽出來另存入list裡
+
+    Procedure DataLoading(Loading,UseTimer:Boolean);  //資料載入中要停止點選的動作
+    procedure ClearView(stkv:Integer); //清除瀏覽窗的影像
+    Function DrawDocItem2(CaseNode : TTreenode;Caseno:String):Boolean;  //畫出文件名稱的Tree
+
+    Procedure initkscan; //檢查掃描器的功能
+    procedure LoadImgFile; //載入案件
+    procedure LoadImgFile1; //載入案件
+    procedure LoadAttFile(CaseID:String); //載入附加檔案
+    Procedure DistinctFormCode(CaseID:String); //案件裡的FormCode取出第一頁
+    Function OMRCheckCase(CaseID:String):Boolean; //OMR檢核
+    Procedure OMRErr2ini(CaseID,Reason,FileName,Site,RelaFileName,RelaSite,Anchor,Anchor1:String;Del,Ingnore,Display:Boolean); //OMR檢核失敗寫入ini
+    Procedure OMRErrini2List(CaseID:String;ErrlistForm : TErrlistForm); //OMR檢核失敗從ini寫入ListView
+    Function DownLanguage:Boolean;  //下載多國語言檔
+    Function FindMpsView(Vmode:Integer):TImageScrollBox;
+    Function CaseAsk(CaseID:String):Integer;  //詢問是否可上傳  (-1:失敗;0:可以;1:不行;)
+    Function CaseComplete(Path,CaseID:String;MainCase:Boolean):Boolean;  //通知傳送完成
+    Function GetCaseFormID(Path:String):String;  //取案件的FormID
+    Procedure CreateFormID_FormName(Path,CaseID:String);  //產生FormID_FormName.dat
+    Procedure CreateDocNo_DocName(Path,CaseID:String);  //產生DocNo_DocName.dat
+    Procedure CreateIn_WH(CaseID:String);  //產生In_WH.dat
+    Function CreateDocNo_Info(CaseID:String):String; //產生保管袋文件 DocNo[tab]份數[tab]總頁數[tab]是否異動[換行]DocNo[tab]份數[tab]總頁數[tab]是否異動
+    Function CreateCustDocNo_Info(CaseID:String):String; //產生自訂文件 DocName[tab]份數[tab]總頁數[tab]是否異動[#13#10]DocName[tab]份數[tab]總頁數[tab]是否異動
+    //Function CreateCustDocNo_Info(path,CaseID:String):String; overload
+    Function CreateAttach_Info(CaseID:String):String; //產生是否有Attach Y:有 N:沒有
+    Function CreateDocnoFrom_Info(CaseID:String):String; //產生被引進的保管袋文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+    Function CreateCustDocNoFrom_Info(CaseID:String):String; //產生被引進的自定文件資訊  Docno[tab]份數[tab]案件編號#13#10Docno[tab]份數[tab]案件編號
+
+    Function GetDocNoEdit(CaseID,DocNo,DocName:String):String; //取出DocNo是否被異動 (Y/N)
+    Function GetDocNo_Count(Path,DocNo:String):Integer;  //取出文件份數
+    Function GetDocNo_Page(Path,DocNo:String):Integer;  //取出文件總頁數
+    Function FormIDExists(FormCode:String;CheckDate:Boolean;index:Integer):Boolean;  //檢查FormID是否存在及是否要檢查啟用停用日期
+    Function Case_DocNoExists(CaseID,Docno:String):Boolean; //Docno是否存在案件裡
+    Procedure ReSortFileName_New(Path:String); //檔名重新排序
+    Procedure ReSortFileName(Path:String); //檔名重新排序
+    Procedure ReSortFileName2Scanlist(Path:String); //檔名重新排序給Scanlist.dat
+    Function GetOMRCheckSet:Boolean;  //下載OMR檢核XML檔
+    Function GetKeyinSet : Boolean; //取登打設定
+    Procedure CheckRule2OMRErrInfo;   //檢核規則填入OMRErrINFo Record
+    Procedure ReNameContext(Path,OldName,NewName:String);
+    Procedure DeleteImageFile(Path,FileName,CaseID:String); // 刪除檔案
+    Procedure DeleteFormCodeFile(CaseID,DocDir,FormID:String);  //刪除指定FormID文件
+    Function DeleteDocNoFile(Path,DocNo:String):Boolean;  //刪除指定DocNo文件
+    Procedure DeleteShowFile(Path:String); //刪除顯示中的影像
+    Function GetDataDocNoPage(MainDocNo,MainVersion:String):Integer;  //取記錄的文件_版本頁數
+    Function CheckCaseDocNoPage(CaseID,DocNo,Version:String;Pages:Integer):Integer; //檢查案件裡的文件_版本頁數
+    Function FindFormCodePages(CaseID,FormCode:String):Integer;  //計算案件裡FormID的頁數
+    Function GetDataFormCodePages(FormCode:String):Integer;   //取記錄的FormcID的頁數
+    Procedure CaseReSize(CaseID:String); //案件的影像縮放
+    Procedure ImageReSize_FormID(CaseID,FileName:String);  //依十字定位點做縮放
+    Procedure ImageReSize_tmp(FormID,FileName:String);  //依十字定位點做縮放(暫存檔)
+    Function TransCaseID(Path,CaseID:String;MainCase:Boolean):Boolean; //傳送案件
+    Procedure NewTreeNodeRefresh;
+    Procedure MyTreeNode1Refresh;
+    Procedure MyTreeNode2ReFresh(CaseID:String);
+    Procedure MyTreeNode3ReFresh(CaseID:String);
+    Function Node2DocNo(Node2:TTreeNode):String;  //MyTreeNode2取DocNo出來
+    Function Node3DocNo(Node3:TTreeNode):String;  //MyTreeNode3取DocNo出來
+    Function Node3FormID(Node3:TTreeNode):String;  //MyTreeNode3取FormCode出來
+    Function GetNode2Name(Node2:TTreeNode):String;  //取MyTreeNode2的識別字出來(記之前點選用)
+    //Function Down_Replace_Img(SPAth,DPath,CaseID:String):Boolean;
+    Function DownLoadImage(Path,CaseID:String):Boolean;
+    Function Down_Img(Path,CaseID:String):Boolean;
+    Function GetNoNameCase(Path:string):String; //取未配號XXXX
+    Procedure CaseResort(Path:String); //案件的檔案重新排序(次文件依Docno挑)
+    Procedure CaseResort2Scanlist(Path:String); //案件的檔案重新排序給scanlist(次文件依FormID排)
+    Procedure DistinctDocinCase(Path:String); //列出案件裡的Docno_版本
+    Procedure DistinctDocNoinCase(Path:String); //列出案件裡的Docno
+    Procedure ClearErrini(CaseID:String;CaseNode:TTreeNode); //清掉檢核檔案
+    Procedure SetCaseList(Mode:Char;Index:Integer;text:String);  //'A:加入,I:插入,D:刪除,E:修改'
+    Procedure SetDocNoList(Mode:Char;Index:Integer;CaseNo,DocDir,Copies:String);  //'A:加入,I:插入,D:刪除,E:修改'
+    Procedure SetContextList(Mode:Char;Index:Integer;CaseNo,DocDir,FileName:String);  //'A:加入,I:插入,D:刪除,E:修改'
+    Procedure SetAttContextList(Mode:Char;Index:Integer;CaseNo,FileName:String);  //'A:加入,I:插入,D:刪除,E:修改'
+
+
+    Function checkCaseOMRDone:Boolean;  //檢查案件是否完成OMR檢核
+    Function CheckCaseID_OK:Boolean;  //檢查是否有未配號的案件
+    Procedure CreateEmptyCase(Path,CaseID:String);  //產生空白案號(重掃件用)
+    Procedure InitScrollRec; //初始化影像Scroll記錄
+    Procedure GetScrollData(ISB:TImageScrollBox;Var HS,VS:Integer;Var iRate:Single); //取影像Scroll記錄
+    Procedure SetScrollData(ISB:TImageScrollBox;HS,VS:Integer;iRate:Single); //寫影像Scroll記錄
+    Procedure FormIDReplace(CaseID,DocDir,OldFormID,NewFormID:String); //指定FormID更換成新的FormID
+    Procedure ShowFileReplace(Path,NewFormID:String);//顯示的影像換成新的FormID
+    Procedure PageReplaceFormID(Path,NowFormID,NewFormID:String); //選取頁更換FormID
+    Function ModeNeedCheck(OMRMode,ScanMode:String):Boolean; //掃瞄模式是否要做檢核
+    procedure WMMOUSEWHEEL(var message: TWMMouseWheel); message WM_MOUSEWHEEL;
+    Function GetCasePage(Path,CaseID:String):Integer;
+    Function GetFormIDPage(FileList:TStringlist;FormID:String):Integer;
+    Procedure SetFile2Case(CaseID,FileName:String);
+    Procedure WriteResize(ImgName,TxtName:String); //產生Resize.dat
+    Function GetCase_PageCount(var CaseCount,PageCount:Integer):Boolean; //取出案件的數量及頁數 ID為空值時為取所有的
+    Function BarCode2FormID : String; //Barcode依規則轉成FormID
+    Function BarCode2CaseID : String; //Barcode依規則轉成CaseID
+    Procedure WriteCaseIndex(Path:String);
+    Procedure ReadCaseIndex(Path:String);
+    Procedure ClearCaseIndex;
+    Procedure GetSelectImageFile;
+    Function GetDocNoDir(Path,DocNo:String):String; //取出目前DocNo的份數
+    Function CheckFormIDExists(DocNoNode:TTreeNode;FormID:String):Boolean; //檢查FormID是否存在文件裡
+
+    Procedure ZipMainFile(SoPath,DePath,ZipName:String); //壓縮影像檔
+    Procedure ZipMaskFile(SoPath,MarkPath,DePath,ZipName:String); //壓縮遮罩影像檔
+    Procedure ParserPoint(S:String); //解析十字點的字串
+    Function CheckScanDenialTime:Boolean;
+    Function FormID2Anchor(FormID:String):String;  //用FormID取出十字模式
+    Function Index2Anchor(Anchor:String):String;   //十字模式 0->NONE;1->ANCHOR;2->FRAME
+    Function MemoInfoTransfer(Mode,Str:String;ID_S,Name_S:TStringlist):String;  //註記代碼註記類別轉換  Mode 'ID':代碼轉名稱;'NAME':名稱轉代碼
+    Function GetFormatID(CaseID:String):String; //取出案件的FormatID
+    Function FindNoSaveBarCode : Boolean; //找是否有不要儲存影像的條碼
+    Function CheckAvailable:Boolean; //檢查是否可使用元件
+    Function Case2Mask(SoPath,DePath:String):Boolean;//產生遮罩影像
+    Function CheckNeedCrop(Graphic:TDibGraphic):Boolean; //是否是A3要切影像
+    Function GetNewCustomDocNo(Path,DocName:String):String; //取出未使用的自訂文件代號
+    Function GetCustomDocName(Path,DocNo:String):String; //取出自定文件名稱
+    Function GetCustomFormID(Path,DocNo:String):String; //取出自定文件FormID
+    Function GetCustomDocDir(Path,DocName:String):String; //取出自定文件DocDir
+    Function FindCustomDocName(Path,DocName:String):Boolean; //尋找自定文件名稱是否存在
+    Procedure DeleteCustomDocDir(Path,DocNo:String); //刪除自定文件DocNo
+    Function CheckFormID_Prt(FormID:String):Boolean; //傳入的FormID是否預設列印
+    procedure PrintImg(FileName, LoginID, Datetime,Path: WideString);
+    Function FindLastestDocDir(CaseID,DocNo:String):String; //找出最新的DocDir
+    Procedure Create_Cust_DocDir(CaseID:String); //產生外面傳入的文件代號及自定文件
+    Procedure OldCasetoNewCase(CaseID:String); //將舊案份數轉成新規則
+    Procedure ErrFormtoCurrentForm(CaseID,EFormID,CFormID:String);//將舊案的錯誤FormID改正確的FormID
+    Procedure SetRecordEditedDocDir(Mode:Char;CaseID,DocDir:String);  //記錄被異動的文件目錄  'A:加入D:刪掉'
+    Function GetDocDir_Page(CaseID,DocDir:String):Integer;  //取得DocDir的頁數
+    Function Path2DocDir(Path,CaseID:String):String;
+    Function GetDocNo_IS_WH(DocNo:String):Boolean; //DocNo是否為入庫文件
+    Procedure SortDocDir_FormID(CaseID,DocDir:String); //將DocDir裡的文件編號排序
+    Procedure GotoAttach(OldLevel:Integer);
+    Function DocNoIs_In_WH(DocNo:String):Boolean; //DocNo是否為入庫文件
+    Procedure CreateCaseNeedData(Path:String);  //先做影像截取會少二個文字檔,產生CaseDocNo.dat及DocDir.dat
+    Procedure SetDocDirtoSelected(CaseNode:TTreeNode;DocDir:String);
+    Function CheckSelectImg_UseCase(Path,CaseID:String):Boolean; //檢查選擇的影像是否有包含被引用的影像
+    Function TransOldCaseFile(Path:String):Boolean;  //上傳引用舊件的記錄檔
+    Function Writelog(CaseID:String):Boolean;
+    Function FormIDAppear(FormID:String):Boolean; //FormID是否可出現
+    Function DocNoAppear(DocNo:String):Boolean;   //DocNo是否可出現
+    Function GetDocNoCount(CaseID,DocNo:String):Integer; //取DocNo數量
+    Function GetDocDirCopies(CaseID,DocDir:String):Integer; //取DocDir份數
+    Procedure SetDocDirCopies(CaseID,DocDir:String;NewCopies:Integer); //修改DocDir份數
+    Function GetDocDirCopies_Rec(Path,CaseID,DocDir:String):Integer; //取記錄裡的DocDir份數
+    Function GetCustomNameCount(CustomName:String):Integer;   //取外傳的名稱數量
+    Function GetCustomDocNoCount(Docno:String):Integer;   //取外傳的DocNo數量
+    Function ISGuideFormID(FormID:String):Boolean;
+    Function CaseDelete_Enable(CaseID:String):Boolean;  //案件可否被刪除
+
+    Procedure MoveImage(Path:String;mp:Integer); //移動頁數
+    Procedure MoveImage_Drag(Path:String;fp,tp:Integer); //拖拉移動頁數
+
+
+    Procedure SetUseCase(Mode:Char;Path,DocDir,FormCaseID,ToCaseID:String);   //記錄引用其他案件 A:加入 D:刪掉
+    Function GetUseCase(Mode:Char;Path,DocDir:String):String;  //F:取被引用 To:引用
+
+    Procedure Case2upload(CaseID:String);
+    Procedure Download2Case(SoDir,DeDir:String);
+
+    procedure view_image_FormCode(Path,FormCode:String;stpage,stview:integer); //用FormCode來找影像
+    procedure view_image_DocNo(Path,DocNo,FormID:String;Pages:integer); //用DocNo來找影像
+
+    Function ShapeName2PreViewISBName(SP:TShape):String; //轉出指定PreViewISBName
+    Procedure CreatePreViewISB(Count:Integer);
+    Procedure FreePreViewISB;
+    Procedure FitPreViewISB;
+    Procedure PaintShape(FromImg,ToImg:TImageScrollBox); //畫有被選取的影像
+    Procedure FreeShapeobj(SelectISB : TImageScrollBox);
+    Procedure ISBClick(Sender : TObject);
+    Procedure ISBMouseMove(Sender: TObject; Shift: TShiftState;
+    X, Y: Integer);
+    procedure ISBImageMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure ISBImageMouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure ISBEndDrag(Sender, Target: TObject; X, Y: Integer);
+    procedure ISBDragDrop(Sender, Source: TObject; X, Y: Integer);
+    procedure ISBDragOver(Sender, Source: TObject; X, Y: Integer;
+      State: TDragState; var Accept: Boolean);
+
+    procedure BtnMouseEnter(Sender: TObject);
+
+    procedure PageEnd;   //掃描接收完成
+    Procedure PageDone;  //掃描完成後顯示影像
+    procedure StatrTwainScan;
+    procedure OnAcquire( const DibHandle    : THandle;
+                         const XDpi         : Word;
+                         const YDpi         : Word;
+                         const CallBackData : LongInt );
+
+
+    procedure ActivateEvent(Sender: TObject);
+    procedure ClickEvent(Sender: TObject);
+    procedure CreateEvent(Sender: TObject);
+    procedure DblClickEvent(Sender: TObject);
+    procedure DeactivateEvent(Sender: TObject);
+    procedure DestroyEvent(Sender: TObject);
+    procedure KeyPressEvent(Sender: TObject; var Key: Char);
+    procedure MouseEnterEvent(Sender: TObject);
+    procedure MouseLeaveEvent(Sender: TObject);
+    procedure PaintEvent(Sender: TObject);
+    function GetCurrentVersionNo: String;
+    procedure initParameter;
+    procedure LastInitFormidListCreate(path:string);
+    function checkFormCodeIsCustom(path,formcode:string):boolean;
+    function ISDivPageFormID(FormID: String): Boolean;
+    function GetSampleInf: Boolean;
+    procedure InitExistImgList(casepath:String);
+    function LoadFileGetMD5(const filename:string):string; //20170809 取的檔案的MD5
+    function ISExistImg(const filename:string):boolean;  //20170809 確認是否存在原有影像
+    procedure _DelTreeForExistImg(ASourceDir:String);   //2017 刪除前確認 有舊影像嗎
+    function DocNoIsExistImg(DocNopath: String): boolean; //2017 刪除前確認 有舊影像嗎
+    function CheckCaseAttach_OK: Boolean;
+    function DeleteDocNoFileForESCAN(Path, DocNo: String): Boolean;     //2017 確認是否有未歸類文件
+    function CheckRequiredColumnValues(workno,caseno:String) :Boolean;  //20171003  此大類下此案是否檢核必填
+    function logTimeString :String;
+    procedure ReduceLogFile ;
+    function FindLastestDocDirForPage(CaseID, DocNo, formid: String): String;
+    function OMRErrini2ListForLog(CaseID: String):String;
+  protected
+    { Protected declarations }
+    procedure DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage); override;
+    procedure EventSinkChanged(const EventSink: IUnknown); override;
+    function Get_Active: WordBool; safecall;
+    function Get_AlignDisabled: WordBool; safecall;
+    function Get_AlignWithMargins: WordBool; safecall;
+    function Get_AutoScroll: WordBool; safecall;
+    function Get_AutoSize: WordBool; safecall;
+    function Get_AxBorderStyle: TxActiveFormBorderStyle; safecall;
+    function Get_Caption: WideString; safecall;
+    function Get_Color: OLE_COLOR; safecall;
+    function Get_DockSite: WordBool; safecall;
+    function Get_DoubleBuffered: WordBool; safecall;
+    function Get_DropTarget: WordBool; safecall;
+    function Get_Enabled: WordBool; safecall;
+    function Get_ExplicitHeight: Integer; safecall;
+    function Get_ExplicitLeft: Integer; safecall;
+    function Get_ExplicitTop: Integer; safecall;
+    function Get_ExplicitWidth: Integer; safecall;
+    function Get_Font: IFontDisp; safecall;
+    function Get_HelpFile: WideString; safecall;
+    function Get_KeyPreview: WordBool; safecall;
+    function Get_MouseInClient: WordBool; safecall;
+    function Get_ParentCustomHint: WordBool; safecall;
+    function Get_ParentDoubleBuffered: WordBool; safecall;
+    function Get_PixelsPerInch: Integer; safecall;
+    function Get_PopupMode: TxPopupMode; safecall;
+    function Get_PrintScale: TxPrintScale; safecall;
+    function Get_Scaled: WordBool; safecall;
+    function Get_ScreenSnap: WordBool; safecall;
+    function Get_SnapBuffer: Integer; safecall;
+    function Get_UseDockManager: WordBool; safecall;
+    function Get_Visible: WordBool; safecall;
+    function Get_VisibleDockClientCount: Integer; safecall;
+    procedure _Set_Font(var Value: IFontDisp); safecall;
+    procedure Set_AlignWithMargins(Value: WordBool); safecall;
+    procedure Set_AutoScroll(Value: WordBool); safecall;
+    procedure Set_AutoSize(Value: WordBool); safecall;
+    procedure Set_AxBorderStyle(Value: TxActiveFormBorderStyle); safecall;
+    procedure Set_Caption(const Value: WideString); safecall;
+    procedure Set_Color(Value: OLE_COLOR); safecall;
+    procedure Set_DockSite(Value: WordBool); safecall;
+    procedure Set_DoubleBuffered(Value: WordBool); safecall;
+    procedure Set_DropTarget(Value: WordBool); safecall;
+    procedure Set_Enabled(Value: WordBool); safecall;
+    procedure Set_Font(const Value: IFontDisp); safecall;
+    procedure Set_HelpFile(const Value: WideString); safecall;
+    procedure Set_KeyPreview(Value: WordBool); safecall;
+    procedure Set_ParentCustomHint(Value: WordBool); safecall;
+    procedure Set_ParentDoubleBuffered(Value: WordBool); safecall;
+    procedure Set_PixelsPerInch(Value: Integer); safecall;
+    procedure Set_PopupMode(Value: TxPopupMode); safecall;
+    procedure Set_PrintScale(Value: TxPrintScale); safecall;
+    procedure Set_Scaled(Value: WordBool); safecall;
+    procedure Set_ScreenSnap(Value: WordBool); safecall;
+    procedure Set_SnapBuffer(Value: Integer); safecall;
+    procedure Set_UseDockManager(Value: WordBool); safecall;
+    procedure Set_Visible(Value: WordBool); safecall;
+    procedure Set_caseid(const Value: WideString); safecall;
+    procedure Set_data(const Value: WideString); safecall;
+    procedure Set_mode(const Value: WideString); safecall;
+    procedure Set_rewrite(const Value: WideString); safecall;
+    procedure Set_url(const Value: WideString); safecall;
+    procedure Set_userid(const Value: WideString); safecall;
+    procedure Set_username(const Value: WideString); safecall;
+    procedure Set_verify(const Value: WideString); safecall;
+    procedure Set_language(const Value: WideString); safecall;
+    procedure Set_modename(const Value: WideString); safecall;
+    procedure Set_userunit(const Value: WideString); safecall;
+    procedure Set_work_no(const Value: WideString); safecall;
+    procedure Set_loandoc_enable(const Value: WideString); safecall;
+    procedure Set_loandoc_value(const Value: WideString); safecall;
+    procedure Set_useproxy(const Value: WideString); safecall;
+    procedure Set_c_docnamelist(const Value: WideString); safecall;
+    procedure Set_c_docnolist(const Value: WideString); safecall;
+    procedure Set_fixfilelist(const Value: WideString); safecall;
+    procedure Set_is_in_wh(const Value: WideString); safecall;
+    procedure Set_oldcaseinfo(const Value: WideString); safecall;
+    function Get_c_docnamelist: WideString; safecall;
+    function Get_c_docnolist: WideString; safecall;
+    function Get_caseid: WideString; safecall;
+    function Get_data: WideString; safecall;
+    function Get_fixfilelist: WideString; safecall;
+    function Get_is_in_wh: WideString; safecall;
+    function Get_language: WideString; safecall;
+    function Get_loandoc_enable: WideString; safecall;
+    function Get_loandoc_value: WideString; safecall;
+    function Get_mode: WideString; safecall;
+    function Get_modename: WideString; safecall;
+    function Get_oldcaseinfo: WideString; safecall;
+    function Get_rewrite: WideString; safecall;
+    function Get_url: WideString; safecall;
+    function Get_useproxy: WideString; safecall;
+    function Get_userid: WideString; safecall;
+    function Get_username: WideString; safecall;
+    function Get_userunit: WideString; safecall;
+    function Get_verify: WideString; safecall;
+    function Get_work_no: WideString; safecall;
+    function Get_printyn: WideString; safecall;
+    procedure Set_printyn(const Value: WideString); safecall;
+    function Get_is_oldcase: WideString; safecall;
+    procedure Set_is_oldcase(const Value: WideString); safecall;
+    function Get_custdocyn: WideString; safecall;
+    procedure Set_custdocyn(const Value: WideString); safecall;
+    function Get_casenolength: WideString; safecall;
+    function Get_filesizelimit: WideString; safecall;
+    function Get_imgdpi: WideString; safecall;
+    function Get_scancolor: WideString; safecall;
+    procedure Set_casenolength(const Value: WideString); safecall;
+    procedure Set_filesizelimit(const Value: WideString); safecall;
+    procedure Set_imgdpi(const Value: WideString); safecall;
+    procedure Set_scancolor(const Value: WideString); safecall;
+    function Get_imgdelete: WideString; safecall;
+    procedure Set_imgdelete(const Value: WideString); safecall;
+    function Get_check_main_form: WideString; safecall;
+    function Get_isExternal: WideString; safecall;
+    procedure Set_check_main_form(const Value: WideString); safecall;
+    procedure Set_isExternal(const Value: WideString); safecall;
+    function Get_WH_CATEGORY: WideString; safecall;
+    procedure Set_WH_CATEGORY(const Value: WideString); safecall;
+  public
+    { Public declarations }
+    procedure Initialize; override;
+  end;
+
+implementation
+
+uses EnBarcode,
+     EnTransf, { for TImageTransform }
+     Enpnggr,  { for PNGGraphic }
+     EnJpgGr,  { for JPGGraphic }
+     EnReg,
+     EnBmpGr,  { for TBitmapGraphic }
+     EnPrint,  { for TEnvisionPrintMode, TDibGraphicPrinter }
+     ComObj, ComServ,IISUnit,IIS_File2Web,IIS_ImageProcess,
+     PatchFom,Doclist,ScanMemo,DocCopy,InputMask,SortMemo,DocPrt,OldCaseInfo;
+
+{$R *.DFM}
+
+{ TCB_IMGPSScanX }
+
+{$I CB_IMGPSScanImp_UI.pas}{$I CB_IMGPSScanImp_Scan.pas}{$I CB_IMGPSScanImp_Data.pas}{$I CB_IMGPSScanImp_Utils.pas}initialization
+  TActiveFormFactory.Create(
+    ComServer,
+    TActiveFormControl,
+    TCB_IMGPSScanX,
+    Class_CB_IMGPSScanX,
+    1,
+    '',
+    OLEMISC_SIMPLEFRAME or OLEMISC_ACTSLIKELABEL,
+    tmApartment);
+
+  {SetLicenseKey('5B4451E676A1D2976FBB0F3BB18341336AF114C80B5ABAE7F6926B1CAF671F44' +
+  'BD2F098CCEDA922F6389BFAE398DA6AEE67F97EEA0C17234C20D75C12173DBDA' +
+  '594924D56DD8E342F454389C836AD880BB4352CA3BE62C4933B1BA3828E7462C' +
+  '60514F2ECDAD322E6128D841F12D24DA00B623106D3F08EBCAA917D8A97CAA34' +
+  '3D65F2DA567316457395BF9123EE53DF235D181F191A5712DBB27735284AA92D' +
+  '5DFA0C8308308505F384707E900C6063F53F1BFF4C6972607955D1AE517B19D0' +
+  '82CDD16301885403AD229D57BAEF98C056F31430861E5F68F339D658D72E1F92' +
+  '63899412EC2D07891FE3AFD35F3E4A4390B2F0A8A1BF1B7D6160E5F1CC009B17'); }
+  SetLicenseKey('4B2CF65E8C2A86CE8A0DD0F6A7DB03BC0B0126168B48AE4C27EBD78CAE75CF0F' +
+   'A612190861E0D99F6FAE3ED97AC1941B5E97843CFFCF705A3787989072D4EB2C' +
+   'AE6CAB3F5B69B86616ACC8A37AD6A2AB21C7BDD5C9AE1EDF9E4193D353805C9A' +
+   '403631CE8A3D0803FEBB1BE4C209CE7A63B1298EF080EB34B8628CED567D2B68' +
+   'E777FAC58E2E32B7411FC217A04336231D1E861A93474759DAA6EDF53F6EB632' +
+   'A3055229A52F3053FB844754741409022DDE3DFB19473510F2BE63328E74BE20' +
+   'A6A29AA24878F91ADA9DF8CE1F320AF4DAF58EBF95D9BE761D70EEA274E19475' +
+   '1C15948B184264C5C49E60493F3BCD2FFAE2CA8B021D00B96F45550C5F050D8A');
+
+
+  SetLicenseKey('A6A94A8D91B08A9D58F300C0573EA9EF1B9DB0BF69B90E13B958DB4CB6B44F5A' +
+  '4EE9CB22C9A68C2D07ED52ED4D13C755D890E4074996755361E6CDE2A6F1B563' +
+  '5DDC8999AC4D71FB092EA9F1F87BFA25694FBF0D6D250087D2B39629713FCCB0' +
+  'D0A83135BC14FC63A4E8331CFF9E24C45C2D9CFD837EB70BAFDB79A75B7B97D5' +
+  'E9EB271685118C29D90A7C85E7793908989E295DA50021C795A448366026E975' +
+  'F49EA75B721B80427B99E5CF24A225FB498C07946ED7B806B483654C00D85C66' +
+  'E34215CA3EDEF1D4C3F5896090E97E1E2C9752BA2D5B49EE58CF19A0D374077F' +
+  '6D13B90B6FED22D9EBC3AD6CDC76E595E08725BF2E12B8EF30A524A2E00504DF');
+end.
diff --git a/separate/scanImp/CB_IMGPSScanImp_Main.ts b/separate/scanImp/CB_IMGPSScanImp_Main.ts
new file mode 100644
index 0000000..a307ad0
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Main.ts
@@ -0,0 +1,17 @@
+import { applyDataMixins } from './CB_IMGPSScanImp_Data';
+import { applyScanMixins } from './CB_IMGPSScanImp_Scan';
+import { applyUIMixins } from './CB_IMGPSScanImp_UI';
+import { applyUtilsMixins, TStringList, TImageFormat, TTransMode, TFtpProtocol } from './CB_IMGPSScanImp_Utils';
+
+export class TCB_IMGPSScanX {
+  Ch_WriteNote=false; RejectCase=false; ErrIndex=0; Def_DeviceDelete=true; Def_DeviceDeleteSize=3072; Def_ScannerReverse=false; Def_BoardClear=false; Def_ScanDpi=300; Def_ScanDuplex=true; Def_ScanRotate=0; Def_ScanDeskew=false; Def_ScanBright=0; Def_ScanContrast=0; Def_ScanImgShowMode=2; Def_ScanImgSetUse=false;
+  FUrl=''; FCaseID=''; FMode=''; FModeName=''; FWork_no=''; FUserID=''; FUserName=''; FUserUnit=''; FData=''; FVerify=''; FReWrite=''; FLanguage='zh_tw'; FLoanDoc_Value=''; FLoanDoc_Enable=''; FUseProxy=''; FC_DocNoList=''; FC_DocNameList=''; FFixFileList=''; FIs_In_Wh=''; FOldCaseInfo=''; FPrintyn=''; FIs_OldCase=''; FCustDocYN=''; FImgDPI=300; FScanColor=0; FFileSizeLimit=5120; FCaseNoLength=16; FImgDelete='N'; FIsExternal='N'; FCheck_main_form='N'; FWH_category='N';
+  TransMode=TTransMode.tsNone; HttpErrStr=''; FFtpIP=''; FFtpID=''; FFtpPwd=''; FFtpRootPath=''; FFtpExtraPath=''; FFtpPort=0; FFtpProtocol=TFtpProtocol.fpftp; DeviceDelete=false; DeviceDeleteSize=0; ScannerReverse=false; BoardClear=false; ScanDpi=0; ScanDuplex=false; ScanRotate=0; ScanDeskew=false; ScanBright=0; ScanContrast=0; ScanImgShowMode=0; ScanImgSetUse=false; ScanColor:TImageFormat='ifBlackWhite';
+  ServerDate=''; ServerTime=''; Balance=0; ScanDenialTime=''; ScanDenialHint=''; ScanPath=''; ImagePath=''; ImageSavePath=''; ScaniniPath=''; LngPath=''; CheckXmlPath=''; SitePath=''; SamplePath=''; TransPath=''; ScanSaveFilename=''; ScanCaseno=''; ScanDocDir='';
+  Doc_Inf_List=new TStringList(); DM_FORM_INF_List=new TStringList(); FORM_INF_List=new TStringList(); CHECK_RULE_INF_List=new TStringList(); MEMO_INF_List=new TStringList(); WORK_INF_List=new TStringList(); LASTEST_FORM_INF_List=new TStringList(); FindResult=new TStringList(); CaseList=new TStringList(); Context_DocnoList=new TStringList(); CaseDocNoList=new TStringList(); CaseDocNo_CopiesList=new TStringList(); ContextList=new TStringList(); AttContextList=new TStringList(); OMRFileList=new TStringList(); Cust_DocNoList=new TStringList(); IN_WH_DocNoList=new TStringList(); FormCode_PageSize=new TStringList(); DocNo_NeedDoc=new TStringList(); DocNo_NoDoc=new TStringList(); DocNo_VerinCase=new TStringList(); NoSaveBarCodeList=new TStringList(); FormID_List=new TStringList(); DocNo_List=new TStringList(); NowShowFileList=new TStringList(); NowSelectFileList=new TStringList(); GuideFormIDList=new TStringList(); DivPageFormIDList=new TStringList(); LastInitFormidList=new TStringList(); LastAddFormidList=new TStringList(); SampleFormIDList=new TStringList(); ExistImgList=new TStringList(); reSizeExistImgList=new TStringList();
+  NowCaseno=''; NowDocNo=''; NowDocDir=''; NowFormCode=''; NowFormName=''; NowPage=0; DisplayPath=''; Case_loandoc=''; UpLPoint={X:0,Y:0}; UpRPoint={X:0,Y:0}; DownLPoint={X:0,Y:0}; DownRPoint={X:0,Y:0}; Point_Width=''; Point_Height=''; CaseIDLength=0; FormIDLength=0; DocNoLength=0; PEFileName=''; DownFileErrStr='';
+  ISB:any=null; ScanInfo:any={}; TwainShowUI=false; MpsBarcodeinf:any={}; ScanMode:any=null; Mpskey=''; Seg=0; VMode=0; NowClick=0; ScanIP=''; DisplayISB:any=null; SelectISB:any=null; SelectPage=0; NewTreeNode:any=null; MyTreeNode1:any=null; MyTreeNode2:any=null; MyTreeNode3:any=null; InitialOk=false; ShowText=''; Ext=''; SafePixel=0; OMRErrInfo:any[]=[]; ScrollRec:any[]=[]; RecHozPos=0; RecVerPos=0; ReczoomPercent=0; SortMode=false; PreMytreeNode2Name=''; HS=0; VS=0; iRate=0; Bt=0; BarCodeRotate=0; HaveAppDoc=false; PageLVclear=false; CaseCount=0; PageCount=0; Item:any=null; SampleAnchorMode=''; DownImgStatus=''; TransForm_Field=''; NowWork_No=''; CropBarcode=''; Has_Authorize=''; AttName=''; NowGuideFormID=''; NowDivPageFormID=''; FirstDocDir=''; FMaxUploadSize=''; FJpgCompression=0; Draging=false; MDown=false; FEvents:any=null;
+  [key: string]: any;
+  constructor(){ console.log("TCB_IMGPSScanX Initialized"); }
+}
+applyDataMixins(TCB_IMGPSScanX); applyScanMixins(TCB_IMGPSScanX); applyUIMixins(TCB_IMGPSScanX); applyUtilsMixins(TCB_IMGPSScanX);
diff --git a/separate/scanImp/CB_IMGPSScanImp_Scan.pas b/separate/scanImp/CB_IMGPSScanImp_Scan.pas
new file mode 100644
index 0000000..b304dba
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Scan.pas
@@ -0,0 +1,1050 @@
+function TCB_IMGPSScanX.Get_Color: OLE_COLOR;
+begin
+  Result := OLE_COLOR(Color);
+end;
+
+procedure TCB_IMGPSScanX.Set_Color(Value: OLE_COLOR);
+begin
+  Color := TColor(Value);
+end;
+
+procedure TCB_IMGPSScanX.StatrTwainScan;
+var ScanInfo    : TScanInfo;
+   i : Integer;
+begin
+  if not Scanner.IsConfigured then
+  begin
+    ShowMessage(_Msg('TWAIN 掃瞄驅動尚未安裝'));
+    Exit;
+  end;
+  FillChar(ScanInfo, SizeOf(ScanInfo), 0);
+  ScanInfo.MultiPage := True;
+  ScanInfo.ImageCount := 0;
+  ScanInfo.Graphic := TTiffGraphic.Create;
+  try
+    ISB := nil; //規零
+//ShowMessage(IntToStr(ScanDpi));
+    Scanner.RequestedXDpi := ScanDpi;
+    Scanner.RequestedYDpi := ScanDpi;
+    Scanner.RequestedImageFormat := ScanColor;
+    Scanner.ShowUI := TwainShowUI;
+
+    Try
+      Scanner.OpenSource;
+      Scanner.Duplex := ScanDuplex; //雙面
+
+      if FMode='SAMPLESCAN' then
+        Scanner.Duplex:=False;
+
+      //Scanner.FEEDERENABLED  := not ScanFlatCB.Checked;     // 先拿掉平台
+      If ScanImgSetUse Then
+      begin
+        Scanner.ScanBrightness := ScanBright;
+        Scanner.ScanContrast := ScanContrast;
+      end;
+    except
+      Showmessage(_Msg('掃瞄器發生錯誤!!'));
+      Scanner.CloseSource;
+      Exit;
+    end;
+    try
+      Try
+        Scanner.AcquireWithSourceOpen( OnAcquire, LongInt(@ScanInfo));
+      Except
+        Scanner.CloseSource;
+      end;
+    finally
+      Scanner.CloseSource;
+    end;
+  finally
+  Scanner.CloseSource;
+  ScanInfo.Graphic.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.OnAcquire( const DibHandle    : THandle;
+                               const XDpi         : Word;
+                               const YDpi         : Word;
+                               const CallBackData : LongInt );
+var
+  pScanInfo  : TpScanInfo;
+  SaveFileName : String;
+  SaveStream     : TFileStream;
+  strResults : TBarcodeStringResult;
+  DeleteStm  : TMemoryStream;
+  isDelete   : Boolean;
+  iGraphic,iGraphic_First,iGraphic_sec : TTiffGraphic;
+  iRect : TRect;
+  JpgGr : TJpegGraphic;
+  i : Integer;
+  TagTxt : String;
+  function Deletepage(Graphic:TDibGraphic;BlankSize:Integer):Boolean;
+  begin
+    DeleteStm  := TMemoryStream.Create;
+    DeleteStm.Seek(0,soFromBeginning);
+    Graphic.AppendToStream(DeleteStm);
+
+    //DeleteStm.LoadFromFile(Path+'temp.tif');
+    //Isb1.Graphic.SaveToStream(DeleteStm);
+    //Isb1.Graphic.AppendToStream(DeleteStm);
+    if DeleteStm.Size < BlankSize Then
+      Result:= True
+    Else
+      Result := False;
+
+    DeleteStm.Free;
+    //DeleteFile(Path+'temp.tif');
+  end;
+begin
+  pScanInfo := TpScanInfo(CallBackData);
+  isDelete    := False;
+
+  if pScanInfo^.MultiPage then
+  begin
+    pScanInfo^.Graphic.AssignFromDibHandle(DibHandle);
+    pScanInfo^.Graphic.XDotsPerInch := XDpi;
+    pScanInfo^.Graphic.YDotsPerInch := YDpi;
+    TagTxt := 'height:'+inttostr(pScanInfo^.Graphic.Height)+',width:'+inttostr(pScanInfo^.Graphic.Width);
+    if pScanInfo^.Graphic.ImageFormat = ifBlackWhite then
+    begin
+      ImageScrollBox1.Graphic.Assign(pScanInfo^.Graphic);
+      ImageScrollBox1NewGraphic(ImageScrollBox1.Graphic);
+
+      pScanInfo^.Graphic.Compression := tcGroup4;
+      MpsGetBarcode(pScanInfo^.Graphic,MpsBarcodeinf);
+      For i := 1 to MpsBarcodeinf.count do
+      begin
+        If (MpsBarcodeinf.r180[i] <> 0) and (Length(MpsBarcodeinf.Text[i])=FormIDLength) Then
+        begin
+          Rotate(pScanInfo^.Graphic,MpsBarcodeinf.r180[i]);
+          MpsGetBarcode(pScanInfo^.Graphic,MpsBarcodeinf);  //旋轉後再重取一次條碼資訊
+          Break;
+        end;
+      end;
+
+      //影像反向
+      IF ScannerReverse then
+        NegativeImg(pScanInfo^.Graphic);
+      //傾斜矯正
+      IF ScanDeskew Then
+        DeskewImg(pScanInfo^.Graphic);
+      //清黑邊
+      IF BoardClear then
+        CleanupBorder(pScanInfo^.Graphic);
+    end
+    else if pScanInfo^.Graphic.ImageFormat = ifTrueColor then
+    begin
+        //Ext := '.jpg';
+        ImageScrollBox1.Graphic.Assign(pScanInfo^.Graphic);
+        //ImageScrollBox1NewGraphic(ImageScrollBox1.Graphic);
+        MpsGetBarcode(ISB_BW.Graphic,MpsBarcodeinf);
+        For i := 1 to MpsBarcodeinf.count do
+        begin
+          If (MpsBarcodeinf.r180[i] <> 0) and (Length(MpsBarcodeinf.Text[i])=FormIDLength) Then
+          begin
+            Rotate(ISB_BW.Graphic,MpsBarcodeinf.r180[i]);
+            MpsGetBarcode(ISB_BW.Graphic,MpsBarcodeinf);  //旋轉後再重取一次條碼資訊
+            Break;
+          end;
+        end;
+        pScanInfo^.Graphic.Compression := tcJpeg;
+        pScanInfo^.Graphic.JpegQuality := FJpgCompression;
+    end
+    else if pScanInfo^.Graphic.ImageFormat = ifColor256 Then
+    begin
+      //Ext := '.jpg';
+      ConvertToGray(pScanInfo^.Graphic);
+      pScanInfo^.Graphic.Compression := tcJpeg;
+      pScanInfo^.Graphic.JpegQuality := FJpgCompression;
+    end
+    else if pScanInfo^.Graphic.ImageFormat = ifGray256 Then
+    begin
+      //Ext := '.jpg';
+      ImageScrollBox1.Graphic.Assign(pScanInfo^.Graphic);
+      ImageScrollBox1NewGraphic(ImageScrollBox1.Graphic);
+      MpsGetBarcode(ISB_BW.Graphic,MpsBarcodeinf);
+      For i := 1 to MpsBarcodeinf.count do
+      begin
+        If (MpsBarcodeinf.r180[i] <> 0) and (Length(MpsBarcodeinf.Text[i])=FormIDLength) Then
+        begin
+          Rotate(ISB_BW.Graphic,MpsBarcodeinf.r180[i]);
+          MpsGetBarcode(ISB_BW.Graphic,MpsBarcodeinf);  //旋轉後再重取一次條碼資訊
+          Break;
+        end;
+      end;
+      pScanInfo^.Graphic.Compression := tcJpeg;
+      pScanInfo^.Graphic.JpegQuality := FJpgCompression;
+//ShowMessage(IntToStr(pScanInfo^.Graphic.JpegQuality));
+//if pScanInfo^.Graphic.Compression = tcJpeg then
+//begin
+//ShowMessage('jpg');
+//end;
+
+    end
+    else
+    begin
+      //Ext := '.tif';
+      pScanInfo^.Graphic.Compression := tcPackBits;
+    end;
+
+  end;
+  //Application.ProcessMessages;
+  iGraphic_First := TTiffGraphic.Create;
+  iGraphic_sec := TTiffGraphic.Create;
+  //iGraphic := TTiffGraphic.Create;
+  try
+    iGraphic_First.Assign(pScanInfo^.Graphic);
+    //Application.ProcessMessages;
+    if CheckNeedCrop(iGraphic_First) Then
+    begin
+      iRect.Left := pScanInfo^.Graphic.Width div 2;    //先取左邊的影像
+      iRect.Top := 0;
+      iRect.Right := pScanInfo^.Graphic.Width;
+      iRect.Bottom := pScanInfo^.Graphic.Height;
+      CropImg(iGraphic_First,iRect);
+
+      iGraphic_Sec.Assign(pScanInfo^.Graphic);         //再取右邊的影像
+      iRect.Left := 0;
+      iRect.Top := 0;
+      iRect.Right := pScanInfo^.Graphic.Width div 2;
+      iRect.Bottom := pScanInfo^.Graphic.Height;
+      CropImg(iGraphic_Sec,iRect);
+    end;
+    //iGraphic.Assign(iGraphic_First);
+    iGraphic := iGraphic_First;
+
+    if iGraphic.ImageFormat=ifGray256 then  //20180104
+    begin
+      iGraphic.Compression:=tcJPEG;
+      iGraphic.JpegQuality:=FJpgCompression;
+    end;
+    if iGraphic.ImageFormat=ifTrueColor then  //20180104
+    begin
+      iGraphic.Compression:=tcJPEG;
+      iGraphic.JpegQuality:=FJpgCompression;
+    end;
+
+//ShowMessage('WTF');
+    while not iGraphic.IsEmpty do
+    begin
+      //Application.ProcessMessages;
+      IF (not DeviceDelete) or (not Deletepage(iGraphic,DeviceDeleteSize)) Then
+      begin
+        ImageScrollBox1.Graphic.Assign(iGraphic);
+        ImageScrollBox1NewGraphic(ImageScrollBox1.Graphic);
+
+        MpsGetBarcode(ISB_BW.Graphic,MpsBarcodeinf);
+        For i := 1 To MpsBarcodeinf.Count Do
+        Begin
+          If MpsBarcodeinf.r180[i] <> 0 Then // 依條碼角度轉影像
+          Begin
+            Rotate(iGraphic, MpsBarcodeinf.r180[i]);
+            Break;
+          End;
+        End;
+
+        if iGraphic.ImageFormat=ifGray256 then  //20180104 因此旋轉後變為回packbits 所以要改為jpeg
+        begin
+          iGraphic.Compression:=tcJPEG;
+          iGraphic.JpegQuality:=FJpgCompression;
+        end;
+        if iGraphic.ImageFormat=ifTrueColor then
+        begin
+          iGraphic.Compression:=tcJPEG;
+          iGraphic.JpegQuality:=FJpgCompression;
+        end;
+        PageEnd;
+        IF PEFileName <> '' Then
+        begin
+          IF LowerCase(ExtractFileExt(PEFileName)) = '.tif' Then
+          begin
+            if FileExists( PEFileName ) then
+              SaveStream := TFileStream.Create( PEFileName ,fmOpenReadWrite)
+            Else
+              SaveStream := TFileStream.Create( PEFileName ,fmCreate );
+            try
+              SaveStream.Seek(0, soFromBeginning);
+              iGraphic.AppendToStream(SaveStream);
+            finally
+              SaveStream.Free;
+            end;
+          end
+          Else IF LowerCase(ExtractFileExt(PEFileName)) = '.jpg' Then
+          begin
+            if FileExists( PEFileName ) then
+              DeleteFile(PEFileName);
+            //SaveStream := TFileStream.Create( PEFileName ,fmCreate );
+            JpgGr := TJpegGraphic.Create;
+            try
+              JpgGr.Assign(iGraphic);
+              JpgGr.SaveQuality := FJpgCompression;
+              //JpgGr.AppendToStream(SaveStream);
+              JpgGr.SaveToFile(PEFileName);
+            finally
+              JpgGr.Free;
+              //SaveStream.Free;
+            end;
+          end;
+          PageDone;
+        end;
+      end;
+      if iGraphic = iGraphic_First then
+        iGraphic := iGraphic_Sec
+      else
+        iGraphic.Assign(nil);
+      //iGraphic.Assign(iGraphic_Sec);
+    end;
+  finally
+  //iGraphic.Free;
+  iGraphic_First.Free;
+  iGraphic_Sec.Free;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.R_W_Scanini(Mode:Char); //'R'讀取;'W'寫入
+var
+  ini : Tinifile;
+begin
+  ini := Tinifile.Create(ScaniniPath+'FBScan.ini');
+  try
+    case Mode of
+    'R':begin
+          DeviceDelete := ini.ReadBool('DeviceDelete','Mode',Def_DeviceDelete);
+          DeviceDeleteSize := ini.ReadInteger('DeviceDelete','Size_New',Def_DeviceDeleteSize);
+          ScannerReverse := ini.ReadBool('Scanner','Reverse',Def_ScannerReverse);
+          BoardClear := ini.ReadBool('Scanner','BoardClear',Def_BoardClear);
+          //ScanDpi := ini.ReadInteger('Scanner','Dpi',Def_ScanDpi);
+          //ScanDuplex := ini.ReadBool('Scanner','Duplex',Def_ScanDuplex);
+          ScanRotate := ini.ReadInteger('Scanner','ScanRotate',Def_ScanRotate);
+          ScanDeskew := ini.ReadBool('Scanner','ScanDeskew',Def_ScanDeskew);
+          ScanBright := ini.ReadInteger('Scanner','ScanBright',Def_ScanBright);
+          ScanContrast := ini.ReadInteger('Scanner','ScanContrast',Def_ScanContrast);
+          ScanImgShowMode := ini.ReadInteger('Scanner','ScanImgShowMode',Def_ScanImgShowMode);
+          ScanImgSetUse := ini.ReadBool('Scanner','ScanImgSetUse',Def_ScanImgSetUse);  //20101110 BA說掃瞄器廠商有調設定要新增此選項是否啟動
+        end;
+    'W':begin
+          ini.WriteBool('DeviceDelete','Mode',DeviceDelete);
+          ini.WriteInteger('DeviceDelete','Size_New',DeviceDeleteSize);
+          ini.WriteBool('Scanner','Reverse',ScannerReverse);
+          ini.WriteBool('Scanner','BoardClear',BoardClear);
+          //ini.ReadInteger('Scanner','Dpi',ScanDpi);
+          //ini.WriteBool('Scanner','Duplex',ScanDuplex);
+          ini.WriteInteger('Scanner','ScanRotate',ScanRotate);
+          ini.WriteBool('Scanner','ScanDeskew',ScanDeskew);
+          ini.WriteInteger('Scanner','ScanBright',ScanBright);
+          ini.WriteInteger('Scanner','ScanContrast',ScanContrast);
+          ini.WriteInteger('Scanner','ScanImgShowMode',ScanImgShowMode);
+          ini.WriteBool('Scanner','ScanImgSetUse',ScanImgSetUse);  //20101110 BA說掃瞄器廠商有調設定要新增此選項是否啟動
+        end;
+    end;
+
+  finally
+  ini.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.GetDefScanIni; //取得掃瞄的預設值
+var
+  i : Integer;
+  PARA_NO,PARA_CONTENT: String;
+begin
+  Def_DeviceDelete := True;
+  Def_DeviceDeleteSize := 3072;  //20120821 改成3000(出現)
+  Def_ScannerReverse := False;
+  Def_BoardClear := False;
+  Def_ScanDpi := 300;
+  Def_ScanDuplex := True;
+  Def_ScanRotate := 0;
+  Def_ScanDeskew := False;
+  Def_ScanImgSetUse := False;
+  Def_ScanBright := 0;
+  Def_ScanContrast := 0;
+  Def_ScanImgShowMode := 2;
+
+  for i := 0 to WORK_INF_List.Count - 1 do
+  begin
+    IF GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_BLANKDEL_USE' Then   //空白頁啟動
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if UpperCase(PARA_CONTENT) ='Y'  then
+        Def_DeviceDelete := True
+      Else
+        Def_DeviceDelete := False;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_BLANKDEL_SIZE' Then  //空白頁Size
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if PARA_CONTENT = ''  then
+        Def_DeviceDeleteSize := 0
+      Else
+        Def_DeviceDeleteSize := Strtoint(PARA_CONTENT);
+
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_REVERSE' Then  //是否需反相
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if UpperCase(PARA_CONTENT) ='Y'  then
+        Def_ScannerReverse := True
+      Else
+        Def_ScannerReverse := False;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_BOARDCLEAR' Then  //是否清黑邊
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if UpperCase(PARA_CONTENT) ='Y'  then
+        Def_BoardClear := True
+      Else
+        Def_BoardClear := False;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_DPI' Then  //掃瞄DPI
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if PARA_CONTENT = ''  then
+        Def_ScanDpi := 300
+      else
+        Def_ScanDpi := Strtoint(PARA_CONTENT);
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_DUPLEX' Then  //是否雙面掃瞄
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if UpperCase(PARA_CONTENT) ='Y'  then
+        Def_ScanDuplex := True
+      Else
+        Def_ScanDuplex := False;
+
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_ROTATE_MODE' Then //掃瞄時旋轉角度
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if PARA_CONTENT = '0' then
+        Def_ScanRotate := 0
+      Else if PARA_CONTENT = '1' then
+        Def_ScanRotate := 270
+      Else if PARA_CONTENT = '2' then
+        Def_ScanRotate := 180
+      Else if PARA_CONTENT = '3' then
+        Def_ScanRotate := 90
+      Else
+        Def_ScanRotate := 0;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_DESKEW' Then //是否傾斜矯正
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if UpperCase(PARA_CONTENT) ='Y'  then
+        Def_ScanDeskew := True
+      Else
+        Def_ScanDeskew := False;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_IMGSET_USE' Then  //是否使用亮度對比設定
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if UpperCase(PARA_CONTENT) ='Y'  then
+        Def_ScanImgSetUse := True
+      else
+        Def_ScanImgSetUse := False;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_BRIGHT' Then //亮度
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if PARA_CONTENT =''  then
+        Def_ScanBright := 0
+      Else
+        Def_ScanBright := strtoint(PARA_CONTENT);
+      if (Def_ScanBright > 255) or (Def_ScanBright < -255) then
+        Def_ScanBright := 0;
+
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_CONTRAST' Then //對比
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if PARA_CONTENT =''  then
+        Def_ScanContrast := 0
+      Else
+        Def_ScanContrast := strtoint(PARA_CONTENT);
+      if (Def_ScanContrast > 255) or (Def_ScanContrast < -255) then
+        Def_ScanContrast := 0;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_SHOW_MODE' Then
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      if PARA_CONTENT = '0' then
+        Def_ScanImgShowMode := 0
+      Else if PARA_CONTENT = '1' then
+        Def_ScanImgShowMode := 1
+      Else if PARA_CONTENT = '2' then
+        Def_ScanImgShowMode := 2
+      Else
+        Def_ScanImgShowMode := 0;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'CASE_IN_TIME' Then     //取進件截止時間
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      ScanDenialTime := PARA_CONTENT;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'SCAN_HINT' Then     //掃描提示字串
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      ScanDenialHint := PARA_CONTENT;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'NO_SAVE_FORM_ID' Then     //掃描不存檔之表單代號
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      NoSaveBarCodeList.CommaText := PARA_CONTENT;
+    end
+    Else if GetSQLData(WORK_INF_List,'PARA_NO',i) = 'LOCAL_PATH' Then     //本機端路徑
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      ImagePath:= PARA_CONTENT;
+    end
+    Else if UpperCase(GetSQLData(WORK_INF_List,'PARA_NO',i)) = 'GUIDEFORMID' Then     //當導引頁的表單
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      GuideFormIDList.CommaText := PARA_CONTENT;
+    end
+    Else if UpperCase(GetSQLData(WORK_INF_List,'PARA_NO',i)) = 'DIVPAGEFORMID' Then     //當分案頁的表單
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      DivPageFormIDList.CommaText := PARA_CONTENT;
+    end
+    Else if UpperCase(GetSQLData(WORK_INF_List,'PARA_NO',i)) = 'FILE_COMPRESSION' Then     //20171211 jpg to tif 壓縮比
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      FJpgCompression := StrToInt(PARA_CONTENT);
+    end
+    Else if UpperCase(GetSQLData(WORK_INF_List,'PARA_NO',i)) = 'MAX_UPLOAD_SIZE' Then     //取得 上傳大小的限制(MB)
+    begin
+      PARA_CONTENT := GetSQLData(WORK_INF_List,'PARA_CONTENT',i);
+      FMaxUploadSize := PARA_CONTENT;
+    end;
+  end;
+  ScanDuplex := Def_ScanDuplex;
+end;
+
+procedure TCB_IMGPSScanX.EnableImage(v:integer;Sender : TObject);
+var bmp : Tbitmap;
+begin
+  DesableImage;
+  bmp := TBitmap.Create;
+  try
+    ImageList3.GetBitmap(v,bmp);
+    TBitBtn(Sender).Glyph.Assign(bmp);
+  finally
+  bmp.Free;
+  end;
+  ViewMouseMode(v);
+end;
+
+procedure TCB_IMGPSScanX.DesableImage;
+var bmp : Tbitmap;
+    i : integer;
+begin
+  NowClick := -1;
+  bmp := Tbitmap.Create;
+  try
+  For i:= 0 to 6 do
+  begin
+    ImageList4.GetBitmap(i,bmp);
+    TBitBtn(FindComponent('FC'+IntToStr(i))).Glyph.Assign(bmp);
+    bmp.Width:=0;
+    bmp.Handle:=0;
+  end;
+  finally
+  bmp.Free;
+  end;
+  ViewMouseMode(NowClick);
+end;
+
+Procedure TCB_IMGPSScanX.DeleteImageFile(Path,FileName,CaseID:String); // 刪除檔案  (無法得到DocDir用)
+var
+  i : Integer;
+  FileList:TStringlist;
+  DocDir : String;
+begin
+  
+
+  DeleteFile(Path+FileName);
+  DocDir := Path2DocDir(Path,CaseID);
+//ShowMessage('DocDir='+DocDir);
+  SetContextList('D',-1,CaseID,DocDir,FileName);
+  {FileList:=TStringlist.Create;
+  try
+    if FileExists(Path+'Context.dat') then
+      FileList.LoadFromFile(Path+'Context.dat');
+    for i := 0 to FileList.Count - 1 do
+    begin
+      if FileName = FileList.Strings[i] then
+      begin
+        FileList.Delete(i);
+        FileList.SaveToFile(Path+'Context.dat');
+        Break;
+      end;
+    end;
+    if FileList.Count = 0 then
+      DeleteFile(Path+'Context.dat');
+  finally
+  FileList.Free;
+  end;}
+end;
+
+Function TCB_IMGPSScanX.DeleteDocNoFileForESCAN(Path,DocNo:String):Boolean;  //刪除指定DocNo文件
+var
+  i,j,k: Integer;
+  FName : String;
+  ST1,ST2,ST3:TStringList;
+
+begin
+
+  Result := False;
+//ShowMessage(DocNo);
+  for i := ContextList.Count - 1 downto 0 do
+  begin
+    FName := ContextList.Strings[i];
+    If (DocNo = FormCode2DocNo(FileName2FormCode(FName))) or (DocNo=AttName) then
+    begin
+      if not ISExistImg(Path+'\'+FName) then
+      begin
+        DeleteFile(Path+'\'+FName);
+        ContextList.Delete(i);
+      end;
+      Result := True; //有刪到指定文件
+    end;
+  end;
+  ContextList.SaveToFile(Path+'\Context.dat');
+  ContextList.LoadFromFile(Path+'\Context.dat');
+
+  if ContextList.Count=0 then
+  begin
+    _DelTree(Path);
+    SetDocNoList('D',-1,NowCaseNo,NowDocDir,'');
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.DownLoadImage(Path,CaseID:String):Boolean;
+begin
+  Result := True;
+  if not GetftpInfo(CaseID,'download') then   //取案件下載方式
+  begin
+    DownFileErrStr := _Msg('取案件下載資訊失敗,')+HttpErrStr;
+    Result := False;
+    Exit;
+  end;
+  case TransMode of
+    tsHttp:
+    begin
+      ShowText := _Msg('案件下載中(Http),請稍候');
+      DataLoading(True,True);
+      If not Down_Img(ImageSavePath+FCaseID+'\Download\',FCaseID) then
+      begin
+        Showmessage(FCaseID+_msg('載入異動影像時,網路發生錯誤')+HttpErrStr);
+        DataLoading(False,False);
+        Exit;
+      end;
+    end;
+    tsFtp:
+    begin
+      ShowText := _Msg('案件下載中(Ftp),請稍候');
+      DataLoading(True,True);
+      SetFtpInfo;
+
+      if not IIS_Ftp.FtpsConnect then
+      begin
+        DownFileErrStr := Format(_Msg('無法連上Ftp主機,錯誤原因:%s')+#13+'%s',[FtpErrReason,FTPSClient1.LastReceivedReply]);
+        Result := False;
+        Exit;
+      end;
+      if not IIS_Ftp.FtpsDownloadFile(FFtpExtraPath,CaseID+'.zip',Path+CaseID+'.zip',display1) then
+      begin
+        DownFileErrStr := Format(_Msg('錯誤原因:%s'),[FtpErrStr]);
+        Result := False;
+        Exit;
+      end;
+      ExecuteUnZip(Path+CaseID+'.zip',Path,False);
+      DeleteFile(Path+CaseID+'.zip');
+    end;
+  end;
+end;
+
+
+Procedure TCB_IMGPSScanX.CaseResort2Scanlist(Path:String); //案件的檔案重新排序給scanlist(次文件依FormID排)
+var
+  i,n,v,v1 : Integer;
+  S,S1 : TStringlist;
+  FormID,OldName,NewName,DocNo,Doc_Type:String;
+  x : Integer;
+begin
+  S := TStringlist.Create;
+  S1 := TStringlist.Create;
+  try
+  if FileExists(Path+'Context.dat') then
+    S.LoadFromFile(Path+'Context.dat');
+  X := 0;
+  for I := 1 to FORM_INF_List.Count - 1 do    //在FormID有設定的   //主文件 照SQL排   20101028改
+  begin
+    FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+    if FormCode2FileName(FormID,S) = '' then
+       Continue;
+    Doc_Type := GetSQLData(FORM_INF_List,'T2.DOC_TYPE',i);
+    for n := 0 to S.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FileName2FormCode(S.Strings[n]) = FormID) and (Doc_Type='1') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;
+
+  for I := 0 to FORM_INF_List.Count - 1 do  //次文件 照SQL排   20110512為了某個文件要先打的原因要求改
+  begin
+
+    FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+    if FormCode2FileName(FormID,S) = '' then
+       Continue;
+    Doc_Type := GetSQLData(FORM_INF_List,'T2.DOC_TYPE',i);
+    for n := 0 to S.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FileName2FormCode(S.Strings[n]) = FormID) and (Doc_Type='2') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;
+
+  {for I := 0 to Doc_Inf_List.Count - 1 do  //次文件 照文件代碼+掃瞄順序排   20101101改   20110512晚上又說改回來
+  begin
+    DocNo := GetSQLData(Doc_Inf_List,'DOC_NO',i);
+    Doc_Type := GetSQLData(Doc_Inf_List,'DOC_TYPE',i);
+    for n := 0 to S.Count - 1 do
+    begin
+      if (S.Strings[n][1] <> '*') and (FormCode2DocNo(FileName2FormCode(S.Strings[n])) = DocNo) and (Doc_Type='2') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;}
+
+  {for n := 0 to S.Count - 1 do    //次文件 照掃瞄順序排   20101028改
+  begin
+    for i := 0 to FORM_INF_List.Count - 1 do
+    begin
+      FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+      Doc_Type := GetSQLData(FORM_INF_List,'T2.DOC_TYPE',i);
+      if (S.Strings[n][1] <> '*') and (FileName2FormCode(S.Strings[n]) = FormID) and (Doc_Type='2') then
+      begin
+        Inc(X);
+        OldName := S.Strings[n];
+        NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3); //從原有數量加1開始編
+        S.Strings[n] := '*'+S.Strings[n];
+        S1.Add(OldName+','+NewName);
+      end;
+    end;
+  end;}
+  for i := 0 to S.Count - 1 do   //FormID沒設定的或附件
+  begin
+    if S.Strings[i][1] <> '*' then
+    begin
+      Inc(X);
+      OldName := S.Strings[i];
+      //NewName := Add_Zoo(S.Count+x,3)+Copy(OldName,4,length(OldName)-3);
+      NewName := Add_Zoo(S.Count+x,3)+FileName2NoQuene_Filename(OldName);
+      S.Strings[i] := '*'+S.Strings[i];
+      S1.Add(OldName+','+NewName);
+    end;
+  end;
+
+  S.Clear;
+  for i := 0 to S1.Count - 1 do  //開始轉換檔名
+  begin
+    v := Pos(',',S1.Strings[i]);
+    v1 := length(S1.Strings[i]);
+    OldName := copy(S1.Strings[i],1,v-1);
+    NewName := copy(S1.Strings[i],v+1,v1-v);
+    //if FileExists(Path+OldName) then
+    //begin
+      //ReNameFile(Path+OldName,Path+NewName);
+      S.Add(NewName);
+      S.SaveToFile(Path+'scanlist.dat');
+    //end;
+  end;
+  ReSortFileName2Scanlist(Path);
+  finally
+  S.Free;
+  S1.Free;
+  end;
+end;
+
+
+Procedure TCB_IMGPSScanX.GetSelectImageFile;
+var
+  i : Integer;
+  FormID,FormName,DocNo : String;
+  PreNode2Name : String;
+  iFormID : String;
+  iISBName : String;
+  iISB : TImageScrollBox;
+begin
+  NowSelectFileList.Clear;
+  for i := 0 to ComponentCount -1 do
+  begin
+    if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+    begin
+      iISBName := ShapeName2PreViewISBName(TShape(Components[i]));
+      iISB := TImageScrollBox(FindComponent(iISBName));
+      NowSelectFileList.Add(iISB.FileName);
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ParserPoint(S:String); //解析十字點的字串
+var
+  PointList : TStringlist;
+  Rect : TRect;
+begin
+  PointList := TStringlist.Create;
+  try
+    PointList.Text := S;
+    IF PointList.Count <> 6 Then
+    begin
+      UpLPoint := Str2Point('0,0');
+      UpRPoint := Str2Point('0,0');
+      DownLPoint := Str2Point('0,0');
+      DownRPoint := Str2Point('0,0');
+      Point_Width := '0';
+      Point_Height := '0';
+    end
+    Else
+    begin
+      UpLPoint := Str2Point(PointList[0]);
+      DownLPoint := Str2Point(PointList[1]);
+      UpRPoint := Str2Point(PointList[2]);
+      DownRPoint := Str2Point(PointList[3]);
+      Point_Width := PointList[4];
+      Point_Height := PointList[5];
+    end;
+  finally
+  PointList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckScanDenialTime:Boolean;
+Var
+  NowTime : String;
+begin
+  NowTime := GetBalance2Time(Balance);
+  NowTime := Copy(NowTime,1,2)+':'+Copy(NowTime,3,2)+':'+Copy(NowTime,5,2);
+  Result := True;
+  if ScanDenialTime <> '' then
+  begin
+    if StrtoTime(NowTime) >= StrtoTime(ScanDenialTime) then
+      Result := False;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.initkscan;
+begin
+  ScanDuplexCB.Enabled := False;
+  if Scanner.IsConfigured then
+  begin
+    try
+      Scanner.OpenSource;
+      IF Scanner.DuplexCap > 0 Then
+      begin
+        ScanDuplexCB.Enabled := True;
+      end;
+      {IF Scanner.FEEDERCAP Then
+        ScanFlatCB.Enabled := True; }
+    Except
+      DataLoading(False,True);
+      Exit;
+    end;
+    Scanner.CloseSource;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckNeedCrop(Graphic:TDibGraphic):Boolean; //是否是A3要切影像
+Var
+  i,FormIDCount : Integer;
+begin
+  Result := False;
+  FormIDCount := 0;
+  if (Graphic.Width > (4 * Graphic.XDotsPerInch)) {or (Graphic.Height > (15 * Graphic.YDotsPerInch))} then
+  //if (Graphic.Width > (6 * Graphic.XDotsPerInch)) then
+  begin
+    for I := 1 to MpsBarcodeinf.Count do
+    begin
+      if (Length(MpsBarcodeinf.Text[i])=FormIDLength) and FormIDExists(MpsBarcodeinf.Text[i],False,0) then
+      begin
+        inc(FormIDCount);
+      end;
+    end;
+
+  end;
+
+//ShowMessage('FormIDCount='+IntToStr(FormIDCount)+#10#13+'MpsBarcodeinf.count='+IntToStr(MpsBarcodeinf.count));
+  if FormIDCount = 2 then
+  begin
+    Result := True;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.MoveImage(Path:String;mp:Integer); //移動頁數
+var
+  i,n,inx:Integer;
+  FList,D_Flist:TStringlist;
+begin
+  FList := TStringlist.Create;
+  D_Flist := TStringlist.Create;
+  try
+    FList.LoadFromFile(Path+'Context.dat');
+    //Showmessage(Path);
+    //Showmessage(Flist.Text);
+    for i := 0 to FList.Count - 1 do
+    begin
+      Renamefile(Path+Flist.Strings[i],path+'@'+Flist.Strings[i]);
+      Flist.Strings[i]:= '@'+Flist.Strings[i];
+    end;
+
+    for i := 0 to ComponentCount -1 do
+    begin
+      if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+      begin
+        inx := strtoint(Copy(TShape(Components[i]).Name,3,length(TShape(Components[i]).Name)-2));
+        D_Flist.Add(Flist.Strings[inx-1]);
+        //Renamefile(Path+Flist.Strings[inx-1],path+'@'+Flist.Strings[inx-1]);
+      end;
+    end;
+    //Showmessage('aa');
+    for i := 0 to D_Flist.Count -1 do
+    begin
+      for n := 0 to FList.Count - 1 do
+      begin
+        //if Flist.Strings[n]=StringReplace(D_Flist.Strings[i],'@','',[rfReplaceAll]) then
+        if Flist.Strings[n]=D_Flist.Strings[i] then
+        begin
+          Flist.Delete(n);
+          Break;
+        end;
+      end;
+    end;
+    //Showmessage('bb');
+    for i := 0 to D_Flist.Count - 1 do
+    begin
+      Flist.Insert(mp-1+i,D_Flist.Strings[i]);
+    end;
+
+    Flist.SaveToFile(Path+'Context.dat');
+    //Showmessage(Flist.Text);
+    //Showmessage('CC');
+    ReSortFileName(Path);
+    TreeView1click(self);
+
+
+  finally
+  FList.Free;
+  D_Flist.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FileName2ScanPage(FileName:String):Integer; //從檔名轉出掃瞄頁數
+Var
+  v : Integer;
+  FName : String;
+begin
+  FName := ExtractFileName(FileName);
+  v := Pos('_',FName);
+  if v = 0 then   //附件
+    v := pos('.',FName);
+  Result := Strtoint(Copy(FName,1,v-1));
+end;
+
+Procedure TCB_IMGPSScanX.ReSortFileName2Scanlist(Path:String); //檔名重新排序給Scanlist.dat
+var
+  i : Integer;
+  OldName,NewName : String;
+  S : TStringlist;
+begin
+  S := TStringlist.Create;
+  try
+    if FileExists(Path+'scanlist.dat') then
+      S.LoadFromFile(Path+'scanlist.dat');
+    for i := 0 to S.Count - 1 do
+    begin
+      OldName := S.Strings[i];
+      //NewName := Add_Zoo(i+1,3)+Copy(OldName,4,length(OldName)-3);
+      NewName := Add_Zoo(i+1,3)+FileName2NoQuene_Filename(OldName);
+      //ReNameFile(Path+OldName,Path+NewName);
+      S.Strings[i] := NewName;
+    end;
+    S.SaveToFile(Path+'scanlist.dat');
+  finally
+  S.Free;
+  end;
+end;
+
+
+function TCB_IMGPSScanX.Get_imgdpi: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_scancolor: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_imgdpi(const Value: WideString);
+begin
+  if Value ='' then
+  begin
+    FImgDPI := 300;
+    ScanDpi := FImgDPI;
+  end
+  else
+  begin
+    FImgDPI := StrToInt(Value);
+    ScanDpi := FImgDPI;
+    Def_ScanDpi := FImgDPI;
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.Set_scancolor(const Value: WideString);
+begin
+  if value='' then
+  begin
+    FScanColor := 0;
+    ScanColor := ifBlackWhite;
+  end
+  else
+  begin
+    FScanColor := StrToInt(Value);
+    ScanColor := ifBlackWhite;
+  end;
+
+  if FScanColor = 1 then
+  begin
+    ScanColor := ifGray256 ;
+  end;
+
+  if FScanColor = 2 then
+  begin
+    ScanColor := ifTrueColor ;
+  end;
+
+end;
+
diff --git a/separate/scanImp/CB_IMGPSScanImp_Scan.ts b/separate/scanImp/CB_IMGPSScanImp_Scan.ts
new file mode 100644
index 0000000..a9d5dcf
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Scan.ts
@@ -0,0 +1,124 @@
+import * as fs from 'fs'; import * as path from 'path';
+export function applyScanMixins(cls:any){
+  cls.prototype.StatrTwainScan=function(){
+    if(!this.Scanner.IsConfigured){this.ShowMessage(this._Msg('TWAIN 掃瞄驅動尚未安裝'));return;}
+    let ScanInfo={MultiPage:true,ImageCount:0,Graphic:new this.TTiffGraphic()};
+    try{this.ISB=null;this.Scanner.RequestedXDpi=this.ScanDpi;this.Scanner.RequestedYDpi=this.ScanDpi;this.Scanner.RequestedImageFormat=this.ScanColor;this.Scanner.ShowUI=this.TwainShowUI;
+    try{this.Scanner.OpenSource();this.Scanner.Duplex=this.ScanDuplex;if(this.FMode==='SAMPLESCAN')this.Scanner.Duplex=false;if(this.ScanImgSetUse){this.Scanner.ScanBrightness=this.ScanBright;this.Scanner.ScanContrast=this.ScanContrast;}}catch(e){this.Showmessage(this._Msg('掃瞄器發生錯誤!!'));this.Scanner.CloseSource();return;}
+    try{this.Scanner.AcquireWithSourceOpen(this.OnAcquire.bind(this),ScanInfo);}catch(e){this.Scanner.CloseSource();}}finally{this.Scanner.CloseSource();ScanInfo.Graphic.Free();}
+  };
+  cls.prototype.OnAcquire=function(DibHandle:any,XDpi:any,YDpi:any,CallBackData:any){ this.PageEnd(); this.PageDone(); };
+  cls.prototype.PageDone=function(){
+    this.ScanInfo.ImageCount++; let ISB;
+    if(this.ScanMode==='smNew'){if(this.ScanImgShowMode===0||this.ScanImgShowMode===1){ISB=this.FindISB2View(this.VMode);ISB.AntiAliased=this.ScanImgShowMode===0;ISB.ZoomMode='zmFittopage';ISB.LoadFromFile(this.PEFileName,1);}}
+    else if(this.ScanMode==='smReplace'){this.DisplayISB.LoadFromFile(this.PEFileName,1);}
+    else if(this.ScanMode==='smInsert'||this.ScanMode==='smSample'){ISB=this.FindISB2View(this.VMode);ISB.ZoomMode='zmFittopage';ISB.LoadFromFile(this.PEFileName,1);}
+  };
+  cls.prototype.PageEnd=function(){
+    if(this.ScanMode==='smNew'){
+      this.ScanSaveFilename='';let FormID=this.BarCode2FormID();
+      if(FormID!==''&&this.ISDivPageFormID(FormID))this.NowDivPageFormID=FormID;
+      if(FormID!==''&&this.ISGuideFormID(FormID))this.NowGuideFormID=FormID;
+      if(!this.FindDivFormCode(FormID)&&this.NowGuideFormID!=='')FormID=this.NowGuideFormID;
+      let DocNo=this.FormCode2DocNo(FormID);
+      if(FormID!==''&&this.FindDivFormCode(FormID)&&this.NowDivPageFormID!==''){
+        this.ScanInfo.ImageCount=0;this.ClearView(1);this.ContextList.Clear();this.Context_DocnoList.Clear();this.ClearCaseIndex();this.ScanCaseno=this.BarCode2CaseID();this.NowGuideFormID='';this.NowDivPageFormID='';
+      }
+      if(this.ScanCaseno==='')this.ScanCaseno=this.GetNoNameCase(this.ImageSavePath);
+      this.ImageSavePath=this.ImagePath;
+      if(this.ScanInfo.ImageCount===0&&fs.existsSync(path.join(this.ImageSavePath,this.ScanCaseno))){this._DelTree(path.join(this.ImageSavePath,this.ScanCaseno));this.SetCaseList('D',-1,this.ScanCaseno);}
+      this.ScanPath=path.join(this.ImageSavePath,this.ScanCaseno);this.Str2Dir(this.ScanPath);
+      this.ScanDocDir=this.FindLastestDocDir(this.ScanCaseno,DocNo);
+      if(this.DocNoNeedDiv(DocNo)){if((this.FormCode2Page(FormID)==='01'&&this.GetDocDir_Page(this.ScanCaseno,this.ScanDocDir)>0)||this.ScanDocDir==='')this.ScanDocDir=this.DocNo2DocNoDir(path.join(this.ImageSavePath,this.ScanCaseno),DocNo);}
+      else{this.ScanDocDir=DocNo!==''?DocNo:this.DocNo2DocNoDir(path.join(this.ImageSavePath,this.ScanCaseno),DocNo);}
+      if(this.FirstDocDir==='')this.FirstDocDir=this.ScanDocDir;
+      this.ScanPath=path.join(this.ImageSavePath,this.ScanCaseno,this.ScanDocDir);
+      if(!fs.existsSync(this.ScanPath)&&this.ScanDocDir!==this.AttName)this.SetDocNoList('A',-1,this.ScanCaseno,this.ScanDocDir,'1');
+      this.Str2Dir(this.ScanPath);
+      this.ScanSaveFilename=FormID===''?this.Add_Zoo(this.GetDocDir_Page(this.ScanCaseno,this.ScanDocDir)+1,3)+this.Ext:this.Add_Zoo(this.GetDocDir_Page(this.ScanCaseno,this.ScanDocDir)+1,3)+'_'+FormID+this.Ext;
+      if(!this.FindNoSaveBarCode()){if(this.ScanInfo.ImageCount===0){this.SetCaseList('A',-1,this.ScanCaseno);this.WriteCaseIndex(path.join(this.ImageSavePath,this.ScanCaseno));}this.SetContextList('A',-1,this.ScanCaseno,this.ScanDocDir,this.ScanSaveFilename);this.PEFileName=path.join(this.ScanPath,this.ScanSaveFilename);}
+    } else if(this.ScanMode==='smReplace') {
+      if(this.ScanInfo.ImageCount===0){fs.unlinkSync(path.join(this.ScanPath,this.ScanSaveFilename));this.PEFileName=path.join(this.ScanPath,this.ScanSaveFilename);}
+    } else if(this.ScanMode==='smInsert') {
+      this.ScanSaveFilename='';let FormID=this.BarCode2FormID();if(FormID!==''&&this.ISGuideFormID(FormID))this.NowGuideFormID=FormID;if(this.NowGuideFormID!=='')FormID=this.NowGuideFormID;
+      let DocNo=this.FormCode2DocNo(FormID);this.ScanDocDir=this.FindLastestDocDir(this.ScanCaseno,DocNo);
+      if(this.FMode==='ESCAN'&&this.FModeName===this._Msg('補件掃描'))this.ScanDocDir=this.FindLastestDocDirForPage(this.ScanCaseno,DocNo,FormID);
+      if(this.DocNoNeedDiv(DocNo)){if((this.FormCode2Page(FormID)==='01'&&this.GetDocDir_Page(this.ScanCaseno,this.ScanDocDir)>0)||this.ScanDocDir===''){this.ScanInfo.ImageCount=0;this.ScanDocDir=this.DocNo2DocNoDir(path.join(this.ImageSavePath,this.ScanCaseno),DocNo);}}
+      else{this.ScanDocDir=DocNo!==''?DocNo:this.DocNo2DocNoDir(path.join(this.ImageSavePath,this.ScanCaseno),DocNo);}
+      if(this.FirstDocDir==='')this.FirstDocDir=this.ScanDocDir;
+      this.ScanPath=path.join(this.ImageSavePath,this.ScanCaseno,this.ScanDocDir);
+      if(!fs.existsSync(this.ScanPath)&&this.ScanDocDir!=='Attach'&&this.ScanDocDir!=='S_Attach')this.SetDocNoList('A',-1,this.ScanCaseno,this.ScanDocDir,'1');
+      this.Str2Dir(this.ScanPath);
+      this.ScanSaveFilename=FormID===''?this.Add_Zoo(this.GetDocDir_Page(this.ScanCaseno,this.ScanDocDir)+1,3)+this.Ext:this.Add_Zoo(this.GetDocDir_Page(this.ScanCaseno,this.ScanDocDir)+1,3)+'_'+FormID+this.Ext;
+      this.SetContextList('A',-1,this.ScanCaseno,this.ScanDocDir,this.ScanSaveFilename);this.PEFileName=path.join(this.ScanPath,this.ScanSaveFilename);
+    } else if(this.ScanMode==='smSample') {
+      if(this.ScanInfo.ImageCount===0){fs.unlinkSync(path.join(this.ScanPath,this.ScanSaveFilename));this.PEFileName=path.join(this.ScanPath,this.ScanSaveFilename);let BarStr='';for(let i=1;i<=this.MpsBarCodeinf.Count;i++)BarStr+=this.MpsBarCodeinf.Text[i];this.Showmessage(this._Msg('辨識到的BarCode:\n')+BarStr);}
+    }
+  };
+  cls.prototype.R_W_Scanini=function(m:string){
+    let ini=new this.Tinifile(path.join(this.ScaniniPath,'FBScan.ini'));
+    if(m==='R'){this.DeviceDelete=ini.ReadBool('DeviceDelete','Mode',this.Def_DeviceDelete);this.DeviceDeleteSize=ini.ReadInteger('DeviceDelete','Size_New',this.Def_DeviceDeleteSize);this.ScannerReverse=ini.ReadBool('Scanner','Reverse',this.Def_ScannerReverse);this.BoardClear=ini.ReadBool('Scanner','BoardClear',this.Def_BoardClear);this.ScanRotate=ini.ReadInteger('Scanner','ScanRotate',this.Def_ScanRotate);this.ScanDeskew=ini.ReadBool('Scanner','ScanDeskew',this.Def_ScanDeskew);this.ScanBright=ini.ReadInteger('Scanner','ScanBright',this.Def_ScanBright);this.ScanContrast=ini.ReadInteger('Scanner','ScanContrast',this.Def_ScanContrast);this.ScanImgShowMode=ini.ReadInteger('Scanner','ScanImgShowMode',this.Def_ScanImgShowMode);this.ScanImgSetUse=ini.ReadBool('Scanner','ScanImgSetUse',this.Def_ScanImgSetUse);}
+    else if(m==='W'){ini.WriteBool('DeviceDelete','Mode',this.DeviceDelete);ini.WriteInteger('DeviceDelete','Size_New',this.DeviceDeleteSize);ini.WriteBool('Scanner','Reverse',this.ScannerReverse);ini.WriteBool('Scanner','BoardClear',this.BoardClear);ini.WriteInteger('Scanner','ScanRotate',this.ScanRotate);ini.WriteBool('Scanner','ScanDeskew',this.ScanDeskew);ini.WriteInteger('Scanner','ScanBright',this.ScanBright);ini.WriteInteger('Scanner','ScanContrast',this.ScanContrast);ini.WriteInteger('Scanner','ScanImgShowMode',this.ScanImgShowMode);ini.WriteBool('Scanner','ScanImgSetUse',this.ScanImgSetUse);}
+    ini.Free();
+  };
+  cls.prototype.GetDefScanIni=function(){
+    this.Def_DeviceDelete=true;this.Def_DeviceDeleteSize=3072;this.Def_ScannerReverse=false;this.Def_BoardClear=false;this.Def_ScanDpi=300;this.Def_ScanDuplex=true;this.Def_ScanRotate=0;this.Def_ScanDeskew=false;this.Def_ScanImgSetUse=false;this.Def_ScanBright=0;this.Def_ScanContrast=0;this.Def_ScanImgShowMode=2;
+    for(let i=0;i<this.WORK_INF_List.Count;i++){
+      let pn=this.GetSQLData(this.WORK_INF_List,'PARA_NO',i),pc=this.GetSQLData(this.WORK_INF_List,'PARA_CONTENT',i);
+      if(pn==='SCAN_BLANKDEL_USE')this.Def_DeviceDelete=pc.toUpperCase()==='Y';
+      else if(pn==='SCAN_BLANKDEL_SIZE')this.Def_DeviceDeleteSize=pc===''?0:parseInt(pc);
+      else if(pn==='SCAN_REVERSE')this.Def_ScannerReverse=pc.toUpperCase()==='Y';
+      else if(pn==='SCAN_BOARDCLEAR')this.Def_BoardClear=pc.toUpperCase()==='Y';
+      else if(pn==='SCAN_DPI')this.Def_ScanDpi=pc===''?300:parseInt(pc);
+      else if(pn==='SCAN_DUPLEX')this.Def_ScanDuplex=pc.toUpperCase()==='Y';
+      else if(pn==='SCAN_ROTATE_MODE')this.Def_ScanRotate=pc==='1'?270:pc==='2'?180:pc==='3'?90:0;
+      else if(pn==='SCAN_DESKEW')this.Def_ScanDeskew=pc.toUpperCase()==='Y';
+      else if(pn==='SCAN_IMGSET_USE')this.Def_ScanImgSetUse=pc.toUpperCase()==='Y';
+      else if(pn==='SCAN_BRIGHT')this.Def_ScanBright=pc===''?0:parseInt(pc);
+      else if(pn==='SCAN_CONTRAST')this.Def_ScanContrast=pc===''?0:parseInt(pc);
+      else if(pn==='SCAN_SHOW_MODE')this.Def_ScanImgShowMode=pc==='0'?0:pc==='1'?1:2;
+      else if(pn==='CASE_IN_TIME')this.ScanDenialTime=pc;
+      else if(pn==='SCAN_HINT')this.ScanDenialHint=pc;
+      else if(pn==='NO_SAVE_FORM_ID')this.NoSaveBarCodeList.CommaText=pc;
+      else if(pn==='LOCAL_PATH')this.ImagePath=pc;
+      else if(pn.toUpperCase()==='GUIDEFORMID')this.GuideFormIDList.CommaText=pc;
+      else if(pn.toUpperCase()==='DIVPAGEFORMID')this.DivPageFormIDList.CommaText=pc;
+      else if(pn.toUpperCase()==='FILE_COMPRESSION')this.FJpgCompression=parseInt(pc);
+      else if(pn.toUpperCase()==='MAX_UPLOAD_SIZE')this.FMaxUploadSize=pc;
+    }
+    this.ScanDuplex=this.Def_ScanDuplex;
+  };
+  cls.prototype.EnableImage=function(v:number,s:any){this.DesableImage();let bmp=new this.TBitmap();this.ImageList3.GetBitmap(v,bmp);s.Glyph.Assign(bmp);bmp.Free();this.ViewMouseMode(v);};
+  cls.prototype.DesableImage=function(){this.NowClick=-1;let bmp=new this.TBitmap();for(let i=0;i<=6;i++){this.ImageList4.GetBitmap(i,bmp);this.FindComponent('FC'+i).Glyph.Assign(bmp);bmp.Width=0;bmp.Handle=0;}bmp.Free();this.ViewMouseMode(this.NowClick);};
+  cls.prototype.DeleteImageFile=function(p:string,f:string,c:string){if(fs.existsSync(path.join(p,f)))fs.unlinkSync(path.join(p,f));let d=this.Path2DocDir(p,c);this.SetContextList('D',-1,c,d,f);};
+  cls.prototype.DeleteDocNoFileForESCAN=function(p:string,d:string){
+    let r=false;
+    for(let i=this.ContextList.Count-1;i>=0;i--){
+      let f=this.ContextList.Strings[i];
+      if(this.FormCode2DocNo(this.FileName2FormCode(f))===d||d===this.AttName){
+        if(!this.ISExistImg(path.join(p,f))){fs.unlinkSync(path.join(p,f));this.ContextList.Delete(i);} r=true;
+      }
+    }
+    this.ContextList.SaveToFile(path.join(p,'Context.dat'));this.ContextList.LoadFromFile(path.join(p,'Context.dat'));
+    if(this.ContextList.Count===0){this._DelTree(p);this.SetDocNoList('D',-1,this.NowCaseNo,this.NowDocDir,'');} return r;
+  };
+  cls.prototype.DownLoadImage=function(p:string,c:string){return true;};
+  cls.prototype.CaseResort2Scanlist=function(p:string){
+    let S=new this.TStringlist(),S1=new this.TStringlist();if(fs.existsSync(path.join(p,'Context.dat')))S.LoadFromFile(path.join(p,'Context.dat'));
+    let x=0;
+    for(let i=1;i<this.FORM_INF_List.Count;i++){let fi=this.GetSQLData(this.FORM_INF_List,'T1.FORM_ID',i);if(this.FormCode2FileName(fi,S)==='')continue;let dt=this.GetSQLData(this.FORM_INF_List,'T2.DOC_TYPE',i);for(let n=0;n<S.Count;n++){if(S.Strings[n][0]!=='*'&&this.FileName2FormCode(S.Strings[n])===fi&&dt==='1'){x++;let on=S.Strings[n];let nn=this.Add_Zoo(S.Count+x,3)+this.FileName2NoQuene_Filename(on);S.Strings[n]='*'+S.Strings[n];S1.Add(`${on},${nn}`);}}}
+    for(let i=0;i<this.FORM_INF_List.Count;i++){let fi=this.GetSQLData(this.FORM_INF_List,'T1.FORM_ID',i);if(this.FormCode2FileName(fi,S)==='')continue;let dt=this.GetSQLData(this.FORM_INF_List,'T2.DOC_TYPE',i);for(let n=0;n<S.Count;n++){if(S.Strings[n][0]!=='*'&&this.FileName2FormCode(S.Strings[n])===fi&&dt==='2'){x++;let on=S.Strings[n];let nn=this.Add_Zoo(S.Count+x,3)+this.FileName2NoQuene_Filename(on);S.Strings[n]='*'+S.Strings[n];S1.Add(`${on},${nn}`);}}}
+    for(let i=0;i<S.Count;i++){if(S.Strings[i][0]!=='*'){x++;let on=S.Strings[i];let nn=this.Add_Zoo(S.Count+x,3)+this.FileName2NoQuene_Filename(on);S.Strings[i]='*'+S.Strings[i];S1.Add(`${on},${nn}`);}}
+    S.Clear();for(let i=0;i<S1.Count;i++){let v=S1.Strings[i].indexOf(',');let nn=S1.Strings[i].substring(v+1);S.Add(nn);S.SaveToFile(path.join(p,'scanlist.dat'));}
+    this.ReSortFileName2Scanlist(p);S.Free();S1.Free();
+  };
+  cls.prototype.GetSelectImageFile=function(){this.NowSelectFileList.Clear();for(let i=0;i<this.ComponentCount;i++){if(this.Components[i] instanceof this.TShape&&this.Components[i].Name.startsWith('SP')){let isn=this.ShapeName2PreViewISBName(this.Components[i]);let isb=this.FindComponent(isn);this.NowSelectFileList.Add(isb.FileName);}}};
+  cls.prototype.ParserPoint=function(s:string){let p=new this.TStringlist();p.Text=s;if(p.Count!==6){this.UpLPoint={X:0,Y:0};this.UpRPoint={X:0,Y:0};this.DownLPoint={X:0,Y:0};this.DownRPoint={X:0,Y:0};this.Point_Width='0';this.Point_Height='0';}else{this.UpLPoint=this.Str2Point(p.Strings[0]);this.DownLPoint=this.Str2Point(p.Strings[1]);this.UpRPoint=this.Str2Point(p.Strings[2]);this.DownRPoint=this.Str2Point(p.Strings[3]);this.Point_Width=p.Strings[4];this.Point_Height=p.Strings[5];}p.Free();};
+  cls.prototype.CheckScanDenialTime=function(){let nt=this.GetBalance2Time(this.Balance);nt=nt.substring(0,2)+':'+nt.substring(2,4)+':'+nt.substring(4,6);let r=true;if(this.ScanDenialTime!=='')if(this.StrtoTime(nt)>=this.StrtoTime(this.ScanDenialTime))r=false;return r;};
+  cls.prototype.initkscan=function(){this.ScanDuplexCB.Enabled=false;if(this.Scanner.IsConfigured){try{this.Scanner.OpenSource();if(this.Scanner.DuplexCap>0)this.ScanDuplexCB.Enabled=true;}catch(e){this.DataLoading(false,true);return;}this.Scanner.CloseSource();}};
+  cls.prototype.CheckNeedCrop=function(g:any){let fc=0;if(g.Width>(4*g.XDotsPerInch)){for(let i=1;i<=this.MpsBarcodeinf.Count;i++)if(this.MpsBarcodeinf.Text[i].length===this.FormIDLength&&this.FormIDExists(this.MpsBarcodeinf.Text[i],false,0))fc++;}return fc===2;};
+  cls.prototype.MoveImage=function(p:string,m:number){let fl=new this.TStringlist(),df=new this.TStringlist();fl.LoadFromFile(path.join(p,'Context.dat'));for(let i=0;i<fl.Count;i++){fs.renameSync(path.join(p,fl.Strings[i]),path.join(p,'@'+fl.Strings[i]));fl.Strings[i]='@'+fl.Strings[i];}for(let i=0;i<this.ComponentCount;i++){if(this.Components[i] instanceof this.TShape&&this.Components[i].Name.startsWith('SP')){let inx=parseInt(this.Components[i].Name.substring(2));df.Add(fl.Strings[inx-1]);}}for(let i=0;i<df.Count;i++){for(let n=0;n<fl.Count;n++)if(fl.Strings[n]===df.Strings[i]){fl.Delete(n);break;}}for(let i=0;i<df.Count;i++)fl.Insert(m-1+i,df.Strings[i]);fl.SaveToFile(path.join(p,'Context.dat'));this.ReSortFileName(p);this.TreeView1Click(this);fl.Free();df.Free();};
+  cls.prototype.FileName2ScanPage=function(f:string){let n=path.basename(f),v=n.indexOf('_');if(v===-1)v=n.indexOf('.');return parseInt(n.substring(0,v));};
+  cls.prototype.ReSortFileName2Scanlist=function(p:string){let s=new this.TStringlist();if(fs.existsSync(path.join(p,'scanlist.dat')))s.LoadFromFile(path.join(p,'scanlist.dat'));for(let i=0;i<s.Count;i++)s.Strings[i]=this.Add_Zoo(i+1,3)+this.FileName2NoQuene_Filename(s.Strings[i]);s.SaveToFile(path.join(p,'scanlist.dat'));s.Free();};
+  cls.prototype.Get_imgdpi=function(){return this.FImgDPI.toString();};cls.prototype.Get_scancolor=function(){return this.FScanColor.toString();};cls.prototype.Set_imgdpi=function(v:string){this.FImgDPI=v===''?300:parseInt(v);this.ScanDpi=this.FImgDPI;this.Def_ScanDpi=this.FImgDPI;};cls.prototype.Set_scancolor=function(v:string){this.FScanColor=v===''?0:parseInt(v);this.ScanColor=this.FScanColor===2?'ifTrueColor':(this.FScanColor===1?'ifGray256':'ifBlackWhite');};
+}
diff --git a/separate/scanImp/CB_IMGPSScanImp_UI.pas b/separate/scanImp/CB_IMGPSScanImp_UI.pas
new file mode 100644
index 0000000..d4378ac
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_UI.pas
@@ -0,0 +1,6592 @@
+procedure TCB_IMGPSScanX.WMMOUSEWHEEL(var message: TWMMouseWheel);
+var
+  I: Integer;
+  iISB : TImageScrollBox;
+begin
+    inherited;
+    //lb1.Caption:=IntToStr(message.Keys);
+    if (message.WheelDelta = WHEEL_DELTA) Then
+    begin
+
+      if ScrollBox1.Focused then
+      begin
+        ScrollBox1.VertScrollBar.Increment := 50;
+        ScrollBox1.Perform(WM_VSCROLL,SB_Lineup,0);
+      end;
+      if DisplayISB <> nil then
+      begin
+        if (DisplayISB.Focused) and (message.Keys=0) then
+        begin
+           DisplayISB.VertScrollBar.Increment := 50;
+           DisplayISB.Perform(WM_VSCROLL,SB_Lineup,0);
+        end;
+
+        if (DisplayISB.Focused) and (message.Keys=50) then
+        begin
+          DisplayISB.ZoomMode := zmPercent;
+          if DisplayISB.ZoomPercent < 90 then
+            DisplayISB.ZoomPercent := DisplayISB.ZoomPercent+10;
+        end;
+
+      end;
+      i:=0;
+      while FindComponent(ISBName+inttostr(i)) <> nil do
+      begin
+        iISB := TImageScrollBox(FindComponent(ISBName+inttostr(i)));
+        if iISB.Focused then
+        begin
+          ScrollBox1.VertScrollBar.Increment := 50;
+          ScrollBox1.Perform(WM_VSCROLL,SB_Lineup,0);
+        end;
+        inc(i);
+      end;
+
+    end
+    else if (message.WheelDelta = -WHEEL_DELTA) then
+    begin
+
+      if ScrollBox1.Focused then
+      begin
+        ScrollBox1.VertScrollBar.Increment := 50;
+        ScrollBox1.Perform(WM_VSCROLL, SB_LINEDOWN, 0);
+      end;
+      if DisplayISB <> nil then
+      begin
+        if (DisplayISB.Focused) and (message.Keys=0) then
+        begin
+           DisplayISB.VertScrollBar.Increment := 50;
+           DisplayISB.Perform(WM_VSCROLL,SB_LINEDOWN,0);
+        end;
+        if (DisplayISB.Focused) and (message.Keys=50) then
+        begin
+          DisplayISB.ZoomMode := zmPercent;
+          if DisplayISB.ZoomPercent > 10 then
+            DisplayISB.ZoomPercent := DisplayISB.ZoomPercent-10;
+        end;
+
+
+      end;
+
+      i:=0;
+      while FindComponent(ISBName+inttostr(i)) <> nil do
+      begin
+        iISB := TImageScrollBox(FindComponent(ISBName+inttostr(i)));
+        if iISB.Focused then
+        begin
+          ScrollBox1.VertScrollBar.Increment := 50;
+          ScrollBox1.Perform(WM_VSCROLL,SB_Lineup,0);
+        end;
+        inc(i);
+      end;
+
+    end;
+
+
+end;
+
+procedure TCB_IMGPSScanX.WNoteBtnClick(Sender: TObject);
+var
+  i,n,v,v1:Integer;
+  SortMemoForm : TSortMemoForm;
+  M_Content,M_ID,M_Name : String;
+  S : TStringlist;
+begin
+  ShowText := _Msg('備註輸入中,請稍候');
+  DataLoading(True,True);
+  SortMemoForm := TSortMemoForm.Create(Self);
+  S := TStringlist.Create;
+  try
+    InitialLanguage(SortMemoForm); //載入多國語言
+
+    SortMemoForm.ContentList := TStringlist.Create;      //註記內容
+    SortMemoForm.MemoIDList := TStringlist.Create;       //註記代號
+    SortMemoForm.MemoNameList := TStringlist.Create;     //註記名稱
+
+    for i := 1 to MEMO_INF_List.Count - 1 do
+    begin
+      M_Content := GetSQLData(MEMO_INF_List,'T1.MEMO_CONTENT',i);
+      M_ID := GetSQLData(MEMO_INF_List,'T1.MEMO_TYPE',i);
+      M_Name := GetSQLData(MEMO_INF_List,'T2.MEMO_TYPE_NAME',i);
+      SortMemoForm.ComboBox1.Items.Add(M_Name+'-->'+M_Content);
+      SortMemoForm.ContentList.Add(M_Content);   //註記內容
+      SortMemoForm.MemoIDList.Add(M_ID);         //註記代號
+      SortMemoForm.MemoNameList.Add(M_Name);     //註記名稱
+    end;
+    if FileExists(DisplayPath+'Scan_Memo.dat') then
+    begin
+      S.LoadFromFile(DisplayPath+'Scan_Memo.dat');
+      for I := 0 to S.Count - 1 do
+      begin
+        v := Pos(',',S.Strings[i]);
+        v1 := length(S.Strings[i]);
+        M_ID := copy(S.Strings[i],1,v-1);
+        M_Name := MemoInfoTransfer('ID',M_ID,SortMemoForm.MemoIDList,SortMemoForm.MemoNameList);
+        M_Content := copy(S.Strings[i],v+1,v1-v);
+        SortMemoForm.ResoureMemo.Add(M_Name+'-->'+M_Content);
+        With SortMemoForm.MemoLV.Items.Add do
+        begin
+          Caption := M_Content;
+          SubItems.Add(M_Name);
+        end;
+      end;
+    end;
+
+    if SortMemoForm.ShowModal = mrOk then
+    begin
+      S.Clear;
+      for I := 0 to SortMemoForm.MemoLV.Items.Count - 1 do
+      begin
+        M_Content := SortMemoForm.MemoLV.Items.Item[i].Caption;
+        M_Name := SortMemoForm.MemoLV.Items.Item[i].SubItems.Strings[0];
+        M_ID := MemoInfoTransfer('NAME',M_Name,SortMemoForm.MemoIDList,SortMemoForm.MemoNameList);
+        S.Add(M_ID+','+M_Content);
+      end;
+      S.SaveToFile(DisplayPath+'Scan_Memo.dat');
+    end;
+    SortMemoForm.ContentList.Free;       //註記內容
+    SortMemoForm.MemoIDList.Free;        //註記代號
+    SortMemoForm.MemoNameList.Free;      //註記名稱
+  finally
+  SortMemoForm.Free;
+  S.Free;
+  DataLoading(False,False);
+  if Ch_WriteNote then
+  begin
+    Ch_WriteNote := False;
+    CaseHelpBtnClick(self);
+    ErrIndex := 0;
+  end;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.EventSinkChanged(const EventSink: IUnknown);
+begin
+  FEvents := EventSink as ICB_IMGPSScanXEvents;
+  inherited EventSinkChanged(EventSink);
+end;
+
+procedure TCB_IMGPSScanX.FC0Click(Sender: TObject);
+begin
+  IF NowClick = 0 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(0 ,Sender);
+  NowClick := 0;
+end;
+
+procedure TCB_IMGPSScanX.FC1Click(Sender: TObject);
+begin
+  IF NowClick = 1 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(1 ,Sender);
+  NowClick := 1;
+end;
+
+procedure TCB_IMGPSScanX.FC2Click(Sender: TObject);
+begin
+  IF NowClick = 2 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(2,Sender);
+  NowClick := 2;
+end;
+
+procedure TCB_IMGPSScanX.FC3Click(Sender: TObject);
+begin
+  IF NowClick = 3 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(3 ,Sender);
+  NowClick := 3;
+end;
+
+procedure TCB_IMGPSScanX.FC4Click(Sender: TObject);
+begin
+  IF NowClick = 4 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(4 ,Sender);
+  NowClick := 4;
+end;
+
+procedure TCB_IMGPSScanX.FC5Click(Sender: TObject);
+begin
+  IF NowClick = 5 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(5 ,Sender);
+  NowClick := 5;
+end;
+
+procedure TCB_IMGPSScanX.FC6Click(Sender: TObject);
+begin
+  {IF NowClick = 6 Then
+  begin
+    DesableImage;
+    Exit;
+  end;
+  EnableImage(6 ,Sender);
+  NowClick := 6;}
+  PM605Click(nil);
+end;
+
+procedure TCB_IMGPSScanX.ISB1Click(Sender: TObject);
+var
+  p : Integer;
+begin
+  DisplayISB := TImageScrollBox(Sender);
+  Shape1.Left := TPanel(TImageScrollBox(Sender).Parent).Left - Seg;
+  Shape1.Top := TPanel(TImageScrollBox(Sender).Parent).Top - Seg;
+  P := strtoint(copy(DisplayISB.Name,4,1)) + ScrollBar1.Position-2;
+  if P <= PageLV.Items.Count-1 then
+  begin
+    if PageLVclear then
+    begin
+      PageLV.ClearSelection;
+    end;
+    NowPage := p+1;
+    PageLV.ItemIndex := P;
+  end;
+  //DisplayISB.SetFocus;
+end;
+
+procedure TCB_IMGPSScanX.ISB1EndScroll(Sender: TObject);
+var
+  ISB : TImageScrollBox;
+begin
+  ISB := TImageScrollBox(Sender);
+
+  SetScrollData(ISB,ISB.HorzScrollBar.Position,ISB.VertScrollBar.Position,ISB.ZoomPercent);
+  {if (TImageScrollBox(Sender) = MpsViewX1) and SortMode then
+  begin
+    ReczoomPercent := MpsViewX1.ZoomPercent;
+    RecHozPos := MpsViewX1.HorzScrollBarPos;
+    RecVerPos := MpsViewX1.VertScrollBarPos;
+  end;}
+end;
+
+procedure TCB_IMGPSScanX.ISB1ImageMouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+var
+  p : Integer;
+begin
+  DisplayISB := TImageScrollBox(Sender);
+  if NowClick<>0 then
+    DisplayISB.SetFocus;
+  Shape1.Left := TPanel(TImageScrollBox(Sender).Parent).Left - Seg;
+  Shape1.Top := TPanel(TImageScrollBox(Sender).Parent).Top - Seg;
+  P := strtoint(copy(DisplayISB.Name,4,1)) + ScrollBar1.Position-2;
+  if P <= PageLV.Items.Count-1 then
+  begin
+    NowPage := p+1;
+    PageLV.ClearSelection;
+    PageLV.ItemIndex := P;
+
+    //PageLV.Selected := PageLV.Items.Item[PageLV.ItemIndex];
+
+  end;
+  if (NowClick = -1) and (Button=TMouseButton(mbLeft)) and (DisplayISB.FileName <> '') then
+  begin
+    {for P := 1 to 8 do
+    begin
+      TImageScrollBox(FindComponent('ISB'+inttostr(p))).Enabled := False;
+    end; }
+    DisplayISB.BeginDrag(True);
+  end;
+  case TImageScrollBox(Sender).MouseMode of
+    mmR90,mmR180,mmR270:
+    begin
+      TImageScrollBox(Sender).LoadFromFile(TImageScrollBox(Sender).FileName,1);
+    end;
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.ISB1ImageMouseMove(Sender: TObject; Shift: TShiftState;
+  X, Y: Integer);
+begin
+   //Edit1.SetFocus;
+  //TImageScrollBox(Sender).SetFocus;
+
+  if TImageScrollBox(Sender).FileName = '' then
+    TImageScrollBox(Sender).MouseMode := mmUser
+  Else
+    ViewMouseMode(NowClick);
+
+  ISB1.AlwaysShowAnnotations := False;
+
+//  if TImageScrollBox(Sender).FileName = '' then
+//  begin
+////ShowMessage('AAA');
+//Label3.Caption:='FileName='+TImageScrollBox(Sender).FileName+'  time='+FormatDateTime('yyyy/mm/dd HH:MM:SS', now);
+//    TImageScrollBox(Sender).MouseMode := mmUser
+//  end
+//  Else
+//  begin
+//Label3.Caption:='FileName='+TImageScrollBox(Sender).FileName;
+//    ViewMouseMode(NowClick);
+//  end;
+end;
+
+procedure TCB_IMGPSScanX.ISB1ImageMouseUp(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+Var
+  p : Integer;
+  ISB : TImageScrollBox;
+begin
+  case TImageScrollBox(Sender).MouseMode of
+    mmDelete:
+    begin
+      PM508Click(Self);
+    end;
+    mmR90,mmR180,mmR270:
+    begin
+      if TImageScrollBox(Sender).Graphic.ImageFormat <> ifBlackWhite then
+      begin
+        TJpegGraphic(TImageScrollBox(Sender).Graphic).SaveQuality := 30;
+        TJpegGraphic(TImageScrollBox(Sender).Graphic).SaveToFile(TImageScrollBox(Sender).FileName);
+      end
+      Else
+        TImageScrollBox(Sender).SaveToFile(TImageScrollBox(Sender).FileName);
+
+      SelectISB.Graphic.Assign(TImageScrollBox(Sender).Graphic);
+      SelectISB.Redraw(True);
+      FitPreViewISB;
+      ISBClick(SelectISB);
+      ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+    end;
+  end;
+
+  ISB := TImageScrollBox(Sender);
+  if (ISB.MouseMode = mmZoom) or (ISB.MouseMode = mmDrag) then
+    SetScrollData(ISB,ISB.HorzScrollBar.Position,ISB.VertScrollBar.Position,ISB.ZoomPercent);
+
+end;
+
+function TCB_IMGPSScanX.Get_AutoScroll: WordBool;
+begin
+  Result := AutoScroll;
+end;
+
+function TCB_IMGPSScanX.Get_KeyPreview: WordBool;
+begin
+  Result := KeyPreview;
+end;
+
+function TCB_IMGPSScanX.Get_MouseInClient: WordBool;
+begin
+  Result := MouseInClient;
+end;
+
+procedure TCB_IMGPSScanX.ActivateEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnActivate;
+end;
+
+procedure TCB_IMGPSScanX.ClickEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnClick;
+end;
+
+procedure TCB_IMGPSScanX.CreateEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnCreate;
+end;
+
+procedure TCB_IMGPSScanX.DblClickEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnDblClick;
+end;
+
+procedure TCB_IMGPSScanX.DeactivateEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnDeactivate;
+end;
+
+procedure TCB_IMGPSScanX.DestroyEvent(Sender: TObject);
+begin
+  //********清單區********
+  Doc_Inf_List.Free;  //Doc_Inf 清單   Docno + 版本為key
+  DM_FORM_INF_List.Free;  //DM_FORM_INF 清單   Docno + 版本為key
+  FORM_INF_List.Free; //FORM_INF的清單
+  CHECK_RULE_INF_List.Free;  //CHECK_RULE_INF  清單
+  MEMO_INF_List.Free;  //MEMO_INF 清單
+  WORK_INF_List.Free;  //WORK_INF 清單
+  LASTEST_FORM_INF_List.Free; // LASTEST_FORM_INF 清單
+  FindResult.Free ;  //找SQLData的結果
+  OMRFileList.Free;  //要OMR檢核的文件(只檢查每種Form的第一頁)
+  FormCode_PageSize.Free; //文件的預設大小  FormCode_Height_Width
+  DocNo_NeedDoc.Free; //有Docno時要相依的文件   DocNo_相依文件_相依文件
+  DocNo_NoDoc.Free; //有Docno時互斥的文件   DocNo_互斥文件_互斥文件
+  DocNo_VerinCase.Free; //案件裡的DocNo+版本的清單
+  CaseDocNoList.Free;  //案件裡的DocNo清單
+  CaseDocNo_CopiesList.Free; //案件裡的DocNo份數清單
+  CaseList.Free;    //記錄掃瞄案件的順序
+  NoSaveBarCodeList.Free; //不儲存的條碼清單
+  FormID_List.Free;  //FormID清單
+  DocNo_List.Free; //DocNo清單
+  Context_DocnoList.Free; //案件裡的檔案Docno清單
+  ContextList.Free; //案件裡的檔案清單
+  AttContextList.Free; //案件裡的附加檔案清單
+  NowShowFileList.Free;  //目前顯示的影像清單
+  NowSelectFileList.Free; //目前被點選的影像清單
+  Cust_DocNoList.Free; //自行定義文件名稱
+  IN_WH_DocNoList.Free; //入庫的文件清單
+  GuideFormIDList.Free; //要當導引頁表單清單
+  DivPageFormIDList.Free; //要當分案頁表單清單
+  LastInitFormidList.Free;
+  LastAddFormidList.Free;
+  SampleFormIDList.Free;
+  ExistImgList.Free;
+  reSizeExistImgList.Free;
+  //********清單區********
+  if (FMode = 'DSCAN') or (FMode = 'ESCAN')  then //重掃件及異動件要只能掃指定編號的件
+  begin
+    if ImagePath<>'' then
+      _Deltree(ImagePath);
+  end;
+
+  if FEvents <> nil then FEvents.OnDestroy;
+end;
+
+procedure TCB_IMGPSScanX.KeyPressEvent(Sender: TObject; var Key: Char);
+var
+  TempKey: Smallint;
+begin
+  TempKey := Smallint(Key);
+  if FEvents <> nil then FEvents.OnKeyPress(TempKey);
+  Key := Char(TempKey);
+end;
+
+procedure TCB_IMGPSScanX.mode1Click(Sender: TObject);
+begin
+  VMode := 0;
+  GoViewMode;
+  //ScrollBar1Change(Self);
+  Panel14.Visible := False;
+end;
+
+procedure TCB_IMGPSScanX.mode2Click(Sender: TObject);
+begin
+  VMode := 1;
+  GoViewMode;
+  //ScrollBar1Change(Self);
+  Panel14.Visible := True;
+end;
+
+procedure TCB_IMGPSScanX.mode3Click(Sender: TObject);
+begin
+  VMode := 2;
+  GoViewMode;
+  ScrollBar1Change(Self);
+end;
+
+procedure TCB_IMGPSScanX.mode4Click(Sender: TObject);
+begin
+  VMode := 3;
+  GoViewMode;
+  ScrollBar1Change(Self);
+end;
+
+procedure TCB_IMGPSScanX.MouseEnterEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnMouseEnter;
+end;
+
+procedure TCB_IMGPSScanX.MouseLeaveEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnMouseLeave;
+end;
+
+procedure TCB_IMGPSScanX.PaintEvent(Sender: TObject);
+begin
+  if FEvents <> nil then FEvents.OnPaint;
+end;
+
+procedure TCB_IMGPSScanX.Set_AutoScroll(Value: WordBool);
+begin
+  AutoScroll := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_KeyPreview(Value: WordBool);
+begin
+  KeyPreview := Value;
+end;
+
+procedure TCB_IMGPSScanX.PM401Click(Sender: TObject);
+var
+  i : Integer;
+  FromIndex : Integer;
+  CaseID : String;
+  NewPath : String;
+  OldName,NewName:String;
+  S : TStringlist;
+begin
+  S := TStringlist.Create;
+  try
+    FromIndex := PageLv.ItemIndex;
+    if FromIndex = 0 then
+    begin
+      Showmessage(_Msg('不能從第1頁分案'));
+      Exit;
+    end;
+
+    If MessageDlg(Format(_Msg('是否確定從%d頁分出新案'),[PageLV.ItemIndex+1]),Mtconfirmation,[mbyes,mbcancel],0) = mrcancel Then Exit;
+    ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+    CaseID := GetNoNameCase(ImageSavePath);
+    NewPath := ImageSavePath + CaseID+'\';
+    Str2Dir(NewPath);
+    for i := FromIndex to ContextList.Count - 1 do
+    begin
+      OldName := ContextList.Strings[i];
+      //NewName := Add_Zoo(S.Count+1,3)+Copy(OldName,4,length(OldName)-3);
+      NewName := Add_Zoo(S.Count+1,3)+FileName2NoQuene_Filename(OldName);
+
+      ReNameFile(DisplayPath+OldName,NewPath+NewName);
+      S.Add(NewName);
+      S.SaveToFile(NewPath+'Context.dat');
+    end;
+    for i := ContextList.Count - 1 downto FromIndex do
+    begin
+      ContextList.Delete(i);
+      ContextList.SaveToFile(DisplayPath+'Context.dat');
+    end;
+    SetCaseList('I',MyTreeNode1.IndexOf(MyTreeNode2)+1,CaseID);
+    if FileExists(DisplayPath+'CaseIndex.dat') then  //把原經辦代號取出來再寫入新件裡
+    begin
+      S.LoadFromFile(DisplayPath+'CaseIndex.dat');
+    end;
+    DisplayPath := '';
+
+    ClearCaseIndex;
+    WriteCaseIndex(NewPath);
+  finally
+  S.Free;
+  end;
+  LoadImgFile;
+  Showmessage(_Msg('分案完成'));
+end;
+
+procedure TCB_IMGPSScanX.PM402Click(Sender: TObject);
+var
+  i : Integer;
+begin
+  for i := 0 to PageLV.Items.Count - 1 do
+  begin
+    PageLV.Items.Item[i].Selected := True;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.PM403Click(Sender: TObject);
+var
+  i : Integer;
+begin
+  for i := 0 to PageLV.Items.Count - 1 do
+  begin
+    PageLV.Items.Item[i].Selected := False;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.PM404Click(Sender: TObject);
+var
+  i : Integer;
+  DocListForm : TDocListForm;
+  OldName,NewName,Ext : String;
+  FormID,FormName : String;
+  PreNode2Name : String;
+begin
+  PreNode2Name := '';
+  if TreeView1.Selected.Parent = MyTreeNode1 then
+    PreNode2Name:= GetNode2Name(MyTreeNode2);
+  ShowText := _Msg('文件歸類中,請稍候');
+  DataLoading(True,True);
+  DocListForm := TDocListForm.Create(self);
+  try
+    InitialLanguage(PatchDlg); //載入多國語言
+    for i := 1 to FORM_INF_List.Count - 1 do
+    begin
+      FormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+      FormName := GetSQLData(FORM_INF_List,'T1.FORM_DESC',i);
+      if (FormID <> NowFormCode) and FormIDExists(FormID,True,0) then
+      begin
+        DocListForm.FormIDList.Add(FormID+'#@#'+FormName);
+        With DocListForm.DocLV.Items.Add do
+        begin
+          Caption := FormID;
+          SubItems.Add(FormName);
+        end;
+      end;
+    end;
+
+    if DocListForm.ShowModal = mrOk then
+    begin
+      FormID := DocListForm.DocLV.Selected.Caption;
+      if (TreeView1.Selected.Level=1) then
+      begin
+        PageReplaceFormID(DisplayPath,'ALL',FormID);
+      end
+      Else if (TreeView1.Selected.Level=2) and (NowFormCode = '') then
+        PageReplaceFormID(DisplayPath,'',FormID)
+      Else
+      begin
+        PageReplaceFormID(DisplayPath,NowFormCode,FormID);
+      end;
+      //DrawDocItem(MytreeNode1,FORM_INF_List,NowCaseno);
+      //DrawDocItem1(MytreeNode1,Doc_Inf_List,NowCaseno);  //201408280改
+      DrawDocItem2(MytreeNode1,NowCaseno);
+      ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+      //Showmessage(_Msg('歸類完成'));  //20101103 User要求拿掉
+      if PreNode2Name <> '' then  // 回到原本點選的文件節點上
+      begin
+        for i := 0 to MyTreeNode1.Count - 1 do
+        begin
+          if GetNode2Name(MyTreeNode1.Item[i]) = PreNode2Name then
+          begin
+            TreeView1.Selected := MyTreeNode1.Item[i];
+            Break;
+          end;
+        end;
+      end;
+      TreeView1click(self);
+    end;
+  finally
+  DocListForm.Free;
+  DataLoading(False,False);
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.PM601Click(Sender: TObject);
+var
+  i : Integer;
+  DocListForm : TDocListForm;
+  OldName,NewName,Ext : String;
+  FormID,FormName,DocNo,DocDir : String;
+  PreNode2Name : String;
+  iFormID : String;
+  iISBName : String;
+  iISB : TImageScrollBox;
+  GoAtt : Boolean;
+  AttLv : Integer;
+  ST1 :TStringList;
+begin
+  PreNode2Name := '';
+  ST1:=TStringList.Create;
+  if TreeView1.Selected.Parent = MyTreeNode1 then
+    PreNode2Name:= GetNode2Name(MyTreeNode2);
+  ShowText := _Msg('文件歸類中,請稍候');
+LogFile1.LogToFile(logTimeString+'縮圖  歸類開始');
+  DataLoading(True,True);
+  GoAtt := False;
+  if (MytreeNode2 <> nil) and (Pos('Attach',MyTreeNode2.Text)>0) then
+  begin
+    AttLv := TreeView1.Selected.Level;
+    GoAtt := True;
+  end;
+  DocListForm := TDocListForm.Create(self);
+  try
+    InitialLanguage(DocListForm); //載入多國語言
+    //InitialLanguage(PatchDlg); //載入多國語言
+    DocListForm.CheckBox1.Visible:=False;
+    for i := 1 to FORM_INF_List.Count - 1 do
+    begin
+      FormID :=  GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+      FormName := GetSQLData(FORM_INF_List,'T1.FORM_DESC',i);
+      DocNo := GetSQLData(FORM_INF_List,'T1.DOC_NO',i)+GetSQLData(FORM_INF_List,'T1.DOC_VERSION',i);
+      if not FormIDAppear(FormID) then Continue;   //20170816 先秀全部
+
+      //Showmessage(FORM_INF_List.Text);
+      //showmessage(inttostr(FORM_INF_List.Count)+#13+inttostr(self.Doc_Inf_List.Count));
+      if (FormID <> FileName2FormCode(DisplayISB.FileName)) and FormIDExists(FormID,False,i) then
+      begin
+        DocListForm.FormIDList.Add(FormID+'#@#'+FormName);
+        With DocListForm.DocLV.Items.Add do
+        begin
+          Caption := FormID;
+          SubItems.Add(FormName);
+        end;
+      end;
+    end;
+    if DocListForm.ShowModal = mrOk then
+    begin
+      for i := 0 to ComponentCount -1 do
+      begin
+        if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+        begin
+          iISBName := ShapeName2PreViewISBName(TShape(Components[i]));
+          iISB := TImageScrollBox(FindComponent(iISBName));
+          OldName := ExtractFileName(iISB.FileName);
+          Ext := ExtractFileExt(OldName);
+
+          if DocListForm.CheckBox1.Checked then
+          begin
+            FormID := DocListForm.Edit1.Text;
+            DocNo := GetNewCustomDocNo(DisplayPath,FormID);
+          end
+          else
+          begin
+            FormID := DocListForm.DocLV.Selected.Caption;
+            DocNo := FormCode2DocNo(FormID);
+          end;
+
+
+          if DocNoDir2DocNo(Path2DocDir(ExtractFilePath(iISB.FileName),NowCaseno)) = DocNo then
+            DocDir := Path2DocDir(ExtractFilePath(iISB.FileName),NowCaseNo)
+          Else
+            DocDir := FindLastestDocDir(NowCaseno,DocNo);
+
+//ShowMessage('DocNoNeedDiv(DocNo)='+BoolToStr(DocNoNeedDiv(DocNo),true));
+//ShowMessage('DocDir='+DocDir);
+
+          if DocNoNeedDiv(DocNo) then   //要分份數
+          begin
+            if ((FormCode2Page(FormID) = '01') and (GetDocDir_Page(NowCaseno,DocDir)>0)) or (DocDir = '') then
+            begin
+              DocDir := DocNo2DocNoDir(ImageSavePath + NowCaseno+'\',DocNo);
+            end
+            else
+            begin //20171016  真對補件影響 所加的判斷
+              ST1.Clear;
+              if FileExists(ImageSavePath + NowCaseno+'\'+DocDir+'\Context.dat') then
+              begin
+                ST1.LoadFromFile(ImageSavePath + NowCaseno+'\'+DocDir+'\Context.dat');
+                if (ST1.Count > 0) and ISExistImg(ImageSavePath + NowCaseno+'\'+DocDir+'\'+ST1.Strings[0]) then   //20181210 多增加判斷ST1>0 否則會有機會出現List out of bound  Hong
+                begin
+                  DocDir := DocNo2DocNoDir(ImageSavePath + NowCaseno+'\',DocNo);
+                end;
+              end;
+            end;
+          end
+          Else        //不分份數
+          begin
+            if DocNo <> '' then
+              DocDir := DocNo
+            else      //Attach 附件
+              DocDir := DocNo2DocNoDir(ImageSavePath + NowCaseno+'\',DocNo);
+          end;
+          if (not DirectoryExists(ImageSavePath + NowCaseno+'\'+DocDir+'\')) and (DocDir <> AttName) then
+            SetDocNoList('A',-1,NowCaseno,DocDir,'1');
+
+          {if DocDir = '' then
+          begin
+            DocDir := DocNo;
+            if DocNoNeedDiv(DocNo) then
+              DocDir:=DocNo2DocNoDir(ImageSavePath+NowCaseno+'\',DocNo);
+            SetDocNoList('A',-1,NowCaseno,DocDir);
+          end; }
+LogFile1.LogToFile(logTimeString+'縮圖  FormID='+FormID);
+          if Not DirectoryExists(ImageSavePath+NowCaseno+'\'+DocDir) then
+            Mkdir(ImageSavePath+NowCaseno+'\'+DocDir);
+          ContextList.Clear;
+          if FileExists(ImageSavePath+NowCaseno+'\'+DocDir+'\Context.dat') then
+            ContextList.LoadFromFile(ImageSavePath+NowCaseno+'\'+DocDir+'\Context.dat');
+          NewName := Add_Zoo(ContextList.Count+1,3)+'_'+FormID+Ext;
+          CopyFile(PWideChar(iISB.FileName),PwideChar(ImageSavePath+NowCaseno+'\'+DocDir+'\'+NewName),False);
+          {ContextList.Add(NewName);
+          ContextList.SaveToFile(ImageSavePath+NowCaseno+'\'+DocDir+'\Context.dat'); }
+          SetContextList('A',-1,NowCaseNo,DocDir,NewName);
+          DeleteImageFile(ExtractFilePath(iISB.FileName),ExtractFileName(iISB.FileName),NowCaseNo);
+          //RenameFile(iISB.FileName,ImageSavePath+NowCaseno+'\'+DocDir+'\'+NewName);
+          //ReNameContext(iISB.FileName,OldName,NewName);
+        end;
+      end;
+//ShowMessage('KKKK');
+      ReSortFileName(ExtractFilePath(iISB.FileName));
+      DrawDocItem2(MytreeNode1,NowCaseno);
+      ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+
+      if GoAtt then
+      begin
+        GotoAttach(AttLv);
+      end;
+      TreeView1click(self);
+
+    end;
+  finally
+  DataLoading(False,False);
+  DocListForm.Free;
+  ST1.Free;
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.PM602Click(Sender: TObject);
+var
+  FileList:TStringlist;
+  SavePath : String;
+  DocDir : String;
+  CustomDocName : String;
+  CustomDocNo : String;
+  i : Integer;
+  OldName,NewName,Ext : String;
+  FormID,FormName,DocNo : String;
+  PreNode2Name : String;
+  iFormID : String;
+  iISBName : String;
+  iISB : TImageScrollBox;
+  GoAtt : Boolean;
+  AttLv : Integer;
+begin
+  GoAtt := False;
+  if (MytreeNode2 <> nil) and (Pos('Attach',MyTreeNode2.Text)>0) then
+  begin
+    AttLv := TreeView1.Selected.Level;
+    GoAtt := True;
+  end;
+
+  if InputQuery(_Msg('輸入其他文件名稱'),_Msg('文件名稱'),CustomDocName) then
+  begin
+    if FindCustomDocName(DisplayPath,CustomDocName) then
+    begin
+      Showmessage(Format(_Msg('文件名稱:"%s"己存在'),[CustomDocName]));
+      Exit;
+    end;
+    CustomDocNo := GetNewCustomDocNo(DisplayPath,CustomDocName);
+  end;
+  if CustomDocNo = '' then Exit;
+  DocDir := CustomDocNo;
+LogFile1.LogToFile(logTimeString+'縮圖 歸類自訂文件 DocDir='+DocDir);
+  SavePath := ImageSavePath+NowCaseNo+'\'+DocDir+'\';
+  Str2Dir(SavePath);
+  SetDocNoList('A',-1,NowCaseNo,DocDir,'1');
+  FileList := TStringlist.Create;
+  try
+  FileList.Clear;
+  if FileExists(SavePath+'Context.dat') then
+    FileList.LoadFromFile(SavePath+'Context.dat');
+
+    for i := 0 to ComponentCount -1 do
+    begin
+      if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+      begin
+        iISBName := ShapeName2PreViewISBName(TShape(Components[i]));
+        iISB := TImageScrollBox(FindComponent(iISBName));
+        OldName := ExtractFileName(iISB.FileName);
+        Ext := ExtractFileExt(OldName);
+        NewName := Add_Zoo(FileList.Count+1,3)+'_'+GetCustomFormID(ImageSavePath+NowCaseNo+'\',CustomDocNo)+ext;
+
+        //Showmessage(iISB.FileName+#13+ImageSavePath+NowCaseno+'\'+DocDir+'\'+NewName);
+        CopyFile(PWideChar(iISB.FileName),PwideChar(ImageSavePath+NowCaseno+'\'+DocDir+'\'+NewName),False);
+        SetContextList('A',-1,NowCaseno,DocDir,NewName);
+        FileList.Add(NewName);
+        {FileList.Add(NewName);
+        FileList.SaveToFile(ImageSavePath+NowCaseno+'\'+DocDir+'\Context.dat');}
+        DeleteImageFile(ExtractFilePath(iISB.FileName),ExtractFileName(iISB.FileName),NowCaseNo);
+      end;
+    end;
+  finally
+  FileList.Free;
+  end;
+  ReSortFileName(ExtractFilePath(iISB.FileName));
+  DrawDocItem2(MytreeNode1,NowCaseno);
+  ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+
+  if GoAtt then
+  begin
+    GotoAttach(AttLv);
+  end;
+  TreeView1click(self);
+  MyTreeNode1.Expand(True);
+end;
+
+procedure TCB_IMGPSScanX.PM604Click(Sender: TObject);
+var
+  i : Integer;
+  iISBName : String;
+  iISB : TImageScrollBox;
+begin
+  //Showmessage(inttostr(ComponentCount));
+  for i := 0 to ComponentCount -1 do
+  begin
+    if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+    begin
+      //Showmessage(Components[i].Name);
+      iISBName := ShapeName2PreViewISBName(TShape(Components[i]));
+      iISB := TImageScrollBox(FindComponent(iISBName));
+      DeskewImg(iISB.Graphic);
+      iISB.Redraw(True);
+      iISB.SaveToFile(iISB.FileName);
+      DisplayISB.LoadFromFile(DisplayISB.FileName,1);
+    end;
+  end;
+  //TreeView1Click(nil);
+end;
+
+procedure TCB_IMGPSScanX.PM605Click(Sender: TObject);
+var
+  i : Integer;
+  iISBName,OldName : String;
+  iISB : TImageScrollBox;
+begin
+  if MessageDlg(_Msg('是否確定刪除??'),mtconfirmation,[mbyes,mbcancel],0) = mrcancel then Exit;
+
+  for i := 0 to ComponentCount -1 do
+  begin
+    if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+    begin
+      //Showmessage(Components[i].Name);
+      iISBName := ShapeName2PreViewISBName(TShape(Components[i]));
+      iISB := TImageScrollBox(FindComponent(iISBName));
+//ShowMessage('iISB.FileName='+iISB.FileName);
+//ShowMessage(ExtractFilePath(iISB.FileName)+','+ExtractFileName(iISB.FileName)+','+NowCaseNo);
+//      if (FMode = 'ESCAN') and (FModeName<>'異動件') then
+//      begin
+//        if ISExistImg(iISB.FileName) then
+//        begin
+//          ShowMessage(_Msg('此圖為非當次掃瞄,不可刪除'));
+//          Exit;
+//        end;
+//      end;
+LogFile1.LogToFile(logTimeString+'縮圖刪除 iISB.FileName='+iISB.FileName);
+      DeleteImageFile(ExtractFilePath(iISB.FileName),ExtractFileName(iISB.FileName),NowCaseNo);
+    end;
+  end;
+//ShowMessage('iISB.FileName='+iISB.FileName);
+  ReSortFileName(ExtractFilePath(iISB.FileName));
+  DrawDocItem2(MytreeNode1,NowCaseno);
+  MyTreeNode1.Text := Format(_Msg('%s-%d頁'),[NowCaseno,GetCasePage(ImageSavePath,NowCaseNo)]);
+  NewTreeNodeRefresh;
+  ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+  TreeView1click(self);
+end;
+
+procedure TCB_IMGPSScanX.N1Click(Sender: TObject);
+var
+  mp:string;
+begin
+  mp := InputBox(_Msg('移動頁數'),_Msg('請輸入移入頁碼'),'');
+  if (mp <> '') then
+  begin
+    MoveImage(DisplayPath+NowDocDir+'\',strtoint(mp));
+  end;
+end;
+
+procedure TCB_IMGPSScanX.N51Click(Sender: TObject);
+begin
+  VMode := 4;
+  GoViewMode;
+  ScrollBar1Change(Self);
+end;
+
+procedure TCB_IMGPSScanX.NewScanBtnClick(Sender: TObject);
+begin
+  IF not InitialOk Then
+  begin
+    Showmessage(_msg('資訊尚未下載完成,請稍候或重新進入'));
+    Exit;
+  end;
+LogFile1.LogToFile(logTimeString+'掃瞄開始');
+  if (FMode = 'RSCAN') or (FMode = 'ESCAN') or (FMode = 'DSCAN') then
+  begin
+    if NewTreeNode.Count > 0 then
+    begin
+      TreeView1.Selected := NewTreeNode.Item[0];
+      TreeView1click(nil);
+      FirstDocDir := '';
+      NowGuideFormID := '';
+      NowDivPageFormID :='';
+      AddScanBtnclick(nil);
+    end;
+  end
+  Else
+  begin
+    TreeView1.Selected := NewTreeNode;
+    NewTreeNode.Expand(False);
+    TreeView1Click(self);
+    Panel1.Enabled := False;
+    Panel2.Enabled := False;
+    ScanMode := smNew;
+    ScanInfo.ImageCount := 0;
+    ScanPath := '';
+    ScanCaseno := '';
+    NowGuideFormID := '';
+    NowDivPageFormID :='';
+    ClearView(1);
+    ContextList.Clear;
+    Try
+      StatrTwainScan;
+LogFile1.LogToFile(logTimeString+'掃瞄結束');
+    Except
+      Panel1.Enabled := True;
+      Panel2.Enabled := True;
+    end;
+    Panel1.Enabled := True;
+    Panel2.Enabled := True;
+    LoadImgFile;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.NextPageBtnClick(Sender: TObject);
+var
+  page : Integer;
+begin
+  {page := ScrollBar1.Position;
+  Case Vmode of
+    0   : Inc(page);
+    1   : Page := Page + 2;
+    2   : Page := Page + 4;
+    3   : Page := Page + 6;
+    4   : Page := Page + 8;
+  end;
+  IF page <= ScrollBar1.Max Then
+  begin
+    ScrollBar1.Position := page;
+  end;}
+  if selectISB = nil then Exit;
+  NextPage(SelectPage);
+  if SelectISB.Parent.Top+SelectISB.Parent.Height+4 > scrollBox1.Height  then
+    ScrollBox1.VertScrollBar.Position := scrollBox1.VertScrollBar.Position + (SelectISB.Parent.Top+SelectISB.Parent.Height-ScrollBox1.Height+8);
+
+end;
+
+procedure TCB_IMGPSScanX.OptionBtnClick(Sender: TObject);
+var
+  PatchDlg : TPatchDlg;
+  i : Integer;
+begin
+  IF not InitialOk Then
+  begin
+    Showmessage(_msg('資訊尚未下載完成,請稍候或重新進入'));
+    Exit;
+  end;
+  ShowText := _Msg('掃瞄參數設定中,請稍候');
+  DataLoading(True,True);
+
+  PatchDlg := TPatchDlg.Create(self);
+  try
+    InitialLanguage(PatchDlg); //載入多國語言
+    PatchDlg.BlankuseCB.Checked := DeviceDelete;
+    if PatchDlg.BlankuseCB.Checked then
+      PatchDlg.SpinEdit5.Enabled := True
+    else
+      PatchDlg.SpinEdit5.Enabled := False;
+    PatchDlg.SpinEdit5.Value := DeviceDeleteSize;
+    For i := 0 to PatchDlg.ComboBox1.Items.Count -1 do
+    begin
+      If inttostr(ScanDpi) = PatchDlg.ComboBox1.Items.Strings[i] Then
+        PatchDlg.ComboBox1.ItemIndex := i;
+    end;
+    PatchDlg.DuplexCB.Checked := ScanDuplex;
+    PatchDlg.ReverseCB.Checked := ScannerReverse;
+    PatchDlg.BorderCB.Checked := BoardClear;
+    PatchDlg.DeskewCB.Checked := ScanDeskew;
+    PatchDlg.ImgSetUseCB.Checked := ScanImgSetUse;
+    PatchDlg.SpinEdit1.Value := ScanBright;
+    PatchDlg.SpinEdit2.Value := ScanContrast;
+    case ScanRotate of
+      0  : PatchDlg.ScanRotateRG.ItemIndex := 0;
+      270 : PatchDlg.ScanRotateRG.ItemIndex := 1;
+      180 : PatchDlg.ScanRotateRG.ItemIndex := 2;
+      90 : PatchDlg.ScanRotateRG.ItemIndex := 3;
+    end;
+    Case ScanImgShowMode of
+      0 :  PatchDlg.ScanShowRG.ItemIndex := 0;
+      1 :  PatchDlg.ScanShowRG.ItemIndex := 1;
+      2 :  PatchDlg.ScanShowRG.ItemIndex := 2;
+    end;
+    If PatchDlg.ShowModal = mrOk then
+    begin
+      DeviceDelete := PatchDlg.BlankuseCB.Checked;
+      DeviceDeleteSize := PatchDlg.SpinEdit5.Value;
+      ScanDpi := Strtoint(PatchDlg.ComboBox1.Text);
+      ScannerReverse := PatchDlg.ReverseCB.Checked;
+      BoardClear := PatchDlg.BorderCB.Checked;
+      ScanDeskew := PatchDlg.DeskewCB.Checked;
+      ScanDuplex := PatchDlg.DuplexCB.Checked;
+      ScanImgSetUse := PatchDlg.ImgSetUseCB.Checked;
+      ScanBright := PatchDlg.SpinEdit1.Value;
+      ScanContrast := PatchDlg.SpinEdit2.Value;
+      Case PatchDlg.ScanRotateRG.ItemIndex of
+        0:ScanRotate := 0;
+        1:ScanRotate := 270;
+        2:ScanRotate := 180;
+        3:ScanRotate := 90;
+      end;
+      Case PatchDlg.ScanShowRG.ItemIndex of
+        0:ScanImgShowMode := 0;
+        1:ScanImgShowMode := 1;
+        2:ScanImgShowMode := 2;
+      end;
+      R_W_ScanIni('W');
+      ScanDuplexCB.Checked := ScanDuplex;
+    end;
+  finally
+  PatchDlg.Free;
+  DataLoading(False,False);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.PageLVClick(Sender: TObject);
+begin
+  IF PageLV.Selected = nil Then Exit;
+  PageLVclear := False;
+  ScrollBar1.Position := PageLV.Selected.Index+1;
+  PageLVclear := True;
+end;
+
+procedure TCB_IMGPSScanX.PageLVKeyUp(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  IF PageLV.Selected = nil Then Exit;
+  ScrollBar1.Position := PageLV.Selected.Index+1;
+end;
+
+procedure TCB_IMGPSScanX.PageLVMouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+begin
+  IF Button = TMouseButton(MbRight) Then
+  begin
+    If PageLV.GetItemAt(X,Y) = nil then Exit;
+    PageLV.Selected := PageLV.GetItemAt(X,Y);
+    PageLVClick(self);
+    PageLV.PopupMenu.Popup(Mouse.CursorPos.X ,Mouse.CursorPos.Y);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.Panel11DblClick(Sender: TObject);
+begin
+  // Button3.Visible := not Button3.Visible;
+  //Button4.Visible := not Button4.Visible;
+  //self.FCustDocYN := 'N';
+end;
+
+procedure TCB_IMGPSScanX.Panel1DblClick(Sender: TObject);
+begin
+  Button1.Visible := not Button1.Visible;
+  Button2.Visible := not Button2.Visible;
+end;
+
+procedure TCB_IMGPSScanX.Panel9Resize(Sender: TObject);
+begin
+  GoViewMode;
+end;
+
+procedure TCB_IMGPSScanX.PM101Click(Sender: TObject);
+var
+  P,v,v1,v2,ln,i : Integer;
+  iDocDir,iDocNo : String;
+begin
+LogFile1.LogToFile(logTimeString+'Tree 按下刪除');
+  if TreeView1.Selected = NewTreeNode then  //全刪  //新掃描件
+  begin
+LogFile1.LogToFile(logTimeString+'Tree 全部刪除');
+    If Messagedlg(_Msg('是否刪除所有案件?'),mtconfirmation,[mbyes,mbcancel],0) = mrcancel then Exit;
+    clearView(1);
+    Application.ProcessMessages;
+    _DelTree(ImageSavePath);
+    if (FMode = 'ESCAN') then
+    begin
+      MkDir(ImageSavePath+FCaseID);
+      CreateEmptyCase(ImageSavePath,FCaseID);
+    end;
+    LoadImgFile;
+    Showmessage(_Msg('刪除完成'));
+  end
+  Else if TreeView1.Selected = MyTreeNode1 then       //案件編號
+  begin
+LogFile1.LogToFile(logTimeString+'Tree 案件編號刪除 NowCaseno='+NowCaseno);
+    If Messagedlg(Format(_Msg('編號(%s)是否刪除?'),[NowCaseno]),mtconfirmation,[mbyes,mbcancel],0) = mrcancel then Exit;
+    clearView(1);
+    Application.ProcessMessages;
+    if (FMode = 'ESCAN') then
+    begin
+      for i := 0 to MyTreeNode1.Count - 1 do
+      begin
+        MyTreenode2 := MyTreeNode1.Item[i];
+        v := Posend('{',MyTreenode2.Text);
+        v1 := Posend('}',MyTreenode2.Text);
+        v2 := posend('-',MyTreenode2.Text);
+        ln := length(MyTreenode2.Text);
+        iDocDir := Copy(MyTreeNode2.Text,v+1,v1-v-1);
+        iDocNo := DocNoDir2DocNo(iDocDir);
+        _DelTree(ImageSavePath+NowCaseno+'\'+iDocDir);
+        SetUseCase('D',ImageSavePath+NowCaseno+'\',iDocDir,'','');
+        SetDocNoList('D',-1,NowCaseNo,iDocDir,'');
+        if (Copy(iDocNo,1,5)='ZZZZZ') then   //20140703 刪除自定文件時要刪ini檔資料
+          DeleteCustomDocDir(ImageSavePath+NowCaseno+'\',iDocDir);
+
+      end
+    end
+    Else
+    begin
+      _DelTree(DisplayPath);
+      SetCaseList('D',NewTreeNode.IndexOf(MyTreeNode1),'');
+    end;
+    ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+
+    if (FMode = 'ESCAN') then
+    begin
+      if not DirectoryExists(ImageSavePath+FCaseID) then
+      begin
+        MkDir(ImageSavePath+FCaseID);
+        CreateEmptyCase(ImageSavePath,FCaseID);
+      end;
+    end;
+    LoadImgFile;
+  end
+  Else if TreeView1.Selected = MyTreeNode2 then       //文件層
+  begin
+    If Messagedlg(Format(_Msg('文件(%s)是否刪除?'),[DocNo2DocName(NowCaseno,NowDocNo)]),mtconfirmation,[mbyes,mbcancel],0) = mrcancel then Exit;
+    ClearView(1);
+    Application.ProcessMessages;
+//ShowMessage(NowDocDir);
+LogFile1.LogToFile(logTimeString+'Tree 文件層號刪除 NowDocDir='+NowDocDir);
+    if (Length(NowDocDir)=8) or (NowDocDir=AttName) then
+    begin
+//ShowMessage('DeleteDocNoFileForESCAN');
+      DeleteDocNoFileForESCAN(ImageSavePath+NowCaseno+'\'+NowDocDir,NowDocDir);
+    end
+    else
+    begin
+      _DelTree(ImageSavePath+NowCaseno+'\'+NowDocDir);
+      SetDocNoList('D',-1,NowCaseNo,NowDocDir,'');
+    end;
+    SetUseCase('D',ImageSavePath+NowCaseno+'\',NowDocDir,'','');
+
+    if (Copy(NowDocNo,1,5)='ZZZZZ') then   //20140703 刪除自定文件時要刪ini檔資料
+      DeleteCustomDocDir(ImageSavePath+NowCaseno+'\',NowDocDir);
+
+    DrawDocItem2(MytreeNode1,NowCaseno);
+    MytreeNode1.Text := Format(_Msg('%s-%d頁'),[NowCaseno,GetCasePage(ImageSavePath,NowCaseNo)]);
+    ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+    NewTreeNodeRefresh;
+
+  end
+  Else if TreeView1.Selected = MyTreeNode3 then       //FormID層
+  begin
+    If Messagedlg(Format(_Msg('文件(%s)是否刪除?'),[NowFormName]),mtconfirmation,[mbyes,mbcancel],0) = mrcancel then Exit;
+LogFile1.LogToFile(logTimeString+'Tree FormID層號刪除 NowFormCode='+NowFormCode);
+    DeleteFormCodeFile(NowCaseNo,NowDocDir,NowFormCode);
+    SetRecordEditedDocDir('A',NowCaseNo,NowDocDir);
+    DrawDocItem2(MytreeNode1,NowCaseno);
+    MytreeNode1.Text := Format(_Msg('%s-%d頁'),[NowCaseno,GetCasePage(ImageSavePath,NowCaseNo)]);
+    ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+    NewTreeNodeRefresh;
+
+  end;
+end;
+
+procedure TCB_IMGPSScanX._DelTreeForExistImg(ASourceDir:String);
+var
+  i:integer;
+  ST:TStringList;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.PM102Click(Sender: TObject);
+var
+  NewCaseID,ShowNewCaseID,ShowNowCaseID : String;
+  i,P,v : Integer;
+  InputOk : Boolean;
+begin
+  VMode := 0;
+  GoViewMode;
+  ISB1.ZoomMode := zmFitWidth;
+
+  NewCaseID := InputBox(_Msg('修改案件編號'),_Msg('新案件編號'),'');
+  ShowNewCaseID := NewCaseID;
+  ShowNowCaseID := NowCaseno;
+
+  if NewCaseID = '' then Exit;
+
+  IF Length(NewCaseID)<>CaseIDLength Then
+  begin
+    Showmessage(_Msg('輸入格式錯誤'));
+    Exit;
+  end;
+
+  if DirectoryExists(ImageSavePath+NewCaseID) then
+  begin
+    Showmessage(NewCaseID+_Msg('己存在,無法修改'));
+    Exit;
+  end;
+
+  if Messagedlg(Format(_Msg('是否將%s改為%s'),[ShowNowCaseID,ShowNewCaseID]),Mtconfirmation,[mbyes,mbcancel],0) = mrcancel then
+    Exit;
+  ClearView(1);
+  RenameFile(ImageSavePath+NowCaseno,ImageSavePath+NewCaseID);
+  SetCaseList('E',NewTreeNode.IndexOf(MyTreeNode1),NewCaseID);
+
+  //P := ContextList.Count;
+  MytreeNode1.Text := Format(_Msg('%s-%d頁'),[NewCaseID,GetCasePage(ImageSavePath,NewCaseID)]);
+  //DrawDocItem(MyTreeNode1,FORM_INF_List,NewCaseID);
+  DrawDocItem2(MytreeNode1,NewCaseID);
+  Showmessage(_Msg('修改完成'));
+end;
+
+procedure TCB_IMGPSScanX.PM103Click(Sender: TObject);
+begin
+  if TreeView1.Selected = nil then Exit;
+
+  {if Treeview1.Selected = NewTreeNode then
+  begin
+    ShowMessage('AAAAA');
+  end;
+  if Treeview1.Selected = MyTreeNode1 then
+  begin
+    ShowMessage('BBBBB');
+  end;
+
+  if Treeview1.Selected = MyTreeNode2 then
+  begin
+    ShowMessage('CCCCC');
+  end;
+
+  if Treeview1.Selected = MyTreeNode3 then
+  begin
+    ShowMessage('DDDDD');
+  end;
+  }
+  if (Treeview1.Selected = NewTreeNode) {or (Treeview1.Selected = MyTreeNode1)} then
+  begin
+//ShowMessage('NewScanBtnClick');
+LogFile1.LogToFile(logTimeString+'Tree NewScanBtnClick');
+    NewScanBtnClick(self)
+  end
+  Else
+  begin
+//ShowMessage('AddScanBtnclick');
+LogFile1.LogToFile(logTimeString+'Tree AddScanBtnclick');
+    AddScanBtnclick(self);
+  end;
+end;
+
+
+Procedure TCB_IMGPSScanX.PM104Click(Sender: TObject);
+Var
+  i, n, m, ii, P, v, v1, page, imageCount: Integer;
+  FName: String;
+  CaseID, DocNo, FormID: String;
+  DocDir: String;
+  SavePath, SaveFilename: String;
+  ISB: TImageScrollBox;
+  FileRec: TSearchrec;
+
+  iGraphic, iGraphic_First, iGraphic_sec: TTiffGraphic;
+  iRect : TRect;
+  JpgGr : TJpegGraphic;
+  SaveStream     : TFileStream;
+  SaveStreamA:TFileStream;
+  SaveStreamB:TFileStream;
+  cooom:integer;
+Begin
+  OpenDialog1.Filter := 'Image files|*.TIF;*.JPG;*.PNG';
+  If OpenDialog1.Execute Then
+  Begin
+    ISB := TImageScrollBox.Create(self);
+try
+    ShowText := _Msg('檔案加入中,請稍候');
+LogFile1.LogToFile(logTimeString+'檔案加入中開始');
+    DataLoading(True, True);
+    If TreeView1.Selected = Nil Then
+      Exit;
+    FName := OpenDialog1.FileName;
+
+    FindFirst(FName, faAnyfile, FileRec);
+
+    If FFileSizeLimit = 0 Then
+    Begin
+      FFileSizeLimit := 5 * 1024;
+    End;
+//FFileSizeLimit:=20*5*1024;
+//ShowMessage(IntToStr(FileRec.Size)+','+IntToStr(FFileSizeLimit * 1024));
+    If FileRec.Size > FFileSizeLimit * 1024 Then // 檢查檔案大小
+    Begin
+      ShowMessage(Format(_Msg('目前檔案大小為 %.3f MB,已超過單一檔案匯入限制%1.f MB'),[FileRec.Size / (1024*1024),FFileSizeLimit/1024]));
+      {ShowMessage(Format('目前檔案大小為 %.3f MB', [FileRec.Size / (1024*1024)]) +
+        ',已超過單一檔案匯入限制'+Format('%.1f',[FFileSizeLimit/1024])+'MB');}
+      FindClose(FileRec);
+      DataLoading(false, false);
+      Exit;
+    End;
+    //MessageDlg()
+    //cooom:=StrToInt(InputBox('輸入百分比','輸入百分比',''));
+    cooom:=FJpgCompression;//20171211彩色tif採jpg壓縮的比例
+
+    FindClose(FileRec);
+    CaseID := NowCaseno;
+    imageCount := 0;
+    P := ISB.ImageCountFromFile(OpenDialog1.FileName);
+    For i := 1 To P Do
+    Begin
+      ShowText := Format(_Msg('檔案加入中,請稍候(%d/%d)'),[i,p]);
+      //ShowText := _Msg('檔案加入中,請稍候')+'(' + inttostr(i) + '/' + inttostr(P) + ')';
+      DataLoading(True, True);
+      ISB.LoadFromFile(FName, i);
+      DeskewImg(ISB.Graphic);
+
+
+      ISB_BW.Graphic.Assign(ISB.Graphic); //20180104
+      If ISB.Graphic.ImageFormat <> ifBlackWhite Then   //20180104
+      begin
+        ConvertToBW(ISB_BW.Graphic);
+      end;
+      ///ISB_BW.SaveToFile('KKKKKKKK.tif');
+
+      iGraphic_First := TTiffGraphic.Create;
+      iGraphic_sec := TTiffGraphic.Create;
+
+
+      //ShowMessage(IntToStr(iGraphic_First.Palette.palNumEntries)); //彩色 會為0  黑白 為2
+
+      MpsGetBarcode(ISB_BW.Graphic, MpsBarcodeinf); //判斷A3 有用FormID 所以要先辨條碼
+      For n := 1 To MpsBarcodeinf.Count Do
+      Begin
+        If (MpsBarcodeinf.r180[n] <> 0) and (Length(MpsBarcodeinf.Text[n])=FormIDLength) Then // 依條碼角度轉影像
+        Begin
+          Rotate(ISB.Graphic, MpsBarcodeinf.r180[n]);
+          //MpsGetBarcode(iGraphic_First, MpsBarcodeinf);
+          Break;
+        End;
+      End;
+
+      iGraphic_First.Assign(ISB.Graphic);
+      //有必要的話先把影像轉正 再開始切圖
+      If CheckNeedCrop(iGraphic_First) Then
+      Begin
+        // 先取右邊的影像
+        iRect.Left := ISB.Graphic.Width Div 2;
+        iRect.Right := ISB.Graphic.Width;
+        iRect.Top := 0;
+        iRect.Bottom := ISB.Graphic.Height;
+        CropImg(iGraphic_First, iRect);
+
+        iGraphic_sec.Assign(ISB.Graphic);
+        // 再取左邊的影像
+        iRect.Left := 0;
+        iRect.Right := ISB.Graphic.Width Div 2;
+        iRect.Top := 0;
+        iRect.Bottom := ISB.Graphic.Height;
+        CropImg(iGraphic_sec, iRect);
+      End;
+      ISB.Graphic.Clear;  //20220711  Hong 覺得ISB後面沒有到了,先清掉減少記憶體使用
+      iGraphic := iGraphic_First;
+
+      While Not iGraphic.IsEmpty Do
+      Begin
+        If (TreeView1.Selected = NewTreeNode) Or
+          (TreeView1.Selected = MyTreeNode1) Then
+        Begin
+          SaveFilename := '';
+          ISB_BW.Graphic.Assign(iGraphic); //20180104
+          If iGraphic.ImageFormat <> ifBlackWhite Then   //20180104
+          begin
+            ConvertToBW(ISB_BW.Graphic);
+          end;
+          MpsGetBarcode(ISB_BW.Graphic, MpsBarcodeinf);
+//ShowMessage(IntToStr(MpsBarcodeinf.Count));
+          For n := 1 To MpsBarcodeinf.Count Do
+          Begin
+            If (MpsBarcodeinf.r180[n] <> 0) and (Length(MpsBarcodeinf.Text[n])=FormIDLength) Then // 依條碼角度轉影像
+            Begin
+              Rotate(iGraphic, MpsBarcodeinf.r180[n]);
+              MpsGetBarcode(ISB_BW.Graphic, MpsBarcodeinf);
+              Break;
+            End;
+          End;
+//ShowMessage('XXX '+IntToStr(MpsBarcodeinf.Count));
+          FormID := BarCode2FormID;
+//ShowMessage('FormID='+FormID);
+          // 取出FormID
+          SaveFilename := FormID;
+          If (TreeView1.Selected = NewTreeNode) Then
+          Begin
+            If FindDivFormCode(FormID) Then // 只找分案頁上的案件條碼
+            Begin
+              imageCount := 0;
+              ClearView(1);
+              ContextList.Clear;
+              CaseID := BarCode2CaseID;
+              If DirectoryExists(ImageSavePath + CaseID + '\') Then
+              Begin
+                _DelTree(ImageSavePath + CaseID + '\');
+                SetCaseList('D', -1, CaseID);
+              End;
+            End;
+            If CaseID = '' Then
+            Begin
+              CaseID := GetNoNameCase(ImageSavePath);
+              ContextList.Clear;
+            End;
+          End;
+          SavePath := ImageSavePath + CaseID + '\';
+          Str2Dir(SavePath);
+
+          DocNo := FormCode2DocNo(FormID);
+          DocDir := FindLastestDocDir(CaseID, DocNo);
+          if (FMode='ESCAN') and (FModeName=_Msg('補件掃描')) then
+          begin
+            DocDir := FindLastestDocDirForPage(CaseID, DocNo,FormID);
+//ShowMessage('DocDir='+DocDir);
+          end;
+
+          If DocNoNeedDiv(DocNo) Then // 要分份數
+          Begin
+            If ((FormCode2Page(FormID) = '01') And
+              (GetDocDir_Page(CaseID, DocDir) > 0)) Or (DocDir = '') Then
+              begin
+                DocDir := DocNo2DocNoDir(ImageSavePath + CaseID + '\', DocNo);
+              end;
+          End
+          Else // 不分份數
+          Begin
+            If DocNo <> '' Then
+              DocDir := DocNo
+            Else // Attach 附件
+              DocDir := DocNo2DocNoDir(ImageSavePath + CaseID + '\', DocNo);
+          End;
+
+          If (Not DirectoryExists(ImageSavePath + CaseID + '\' + DocDir + '\'))
+            And (DocDir <> AttName) Then
+            SetDocNoList('A', -1, CaseID, DocDir, '1');
+          SavePath := ImageSavePath + CaseID + '\' + DocDir + '\';
+          Str2Dir(SavePath);
+          ContextList.Clear;
+          If FileExists(SavePath + 'Context.dat') Then
+            ContextList.LoadFromFile(SavePath + 'Context.dat');
+
+          WriteCaseIndex(ImageSavePath + CaseID + '\');
+          // 寫入案件索引
+          If SaveFilename = '' Then // 附件
+            SaveFilename := Add_Zoo(ContextList.Count + 1, 3) + ext
+          Else
+            SaveFilename := Add_Zoo(ContextList.Count + 1, 3) + '_' +
+              SaveFilename + ext;
+
+          For n := 1 To MpsBarcodeinf.Count Do
+          Begin
+            If (MpsBarcodeinf.r180[n] <> 0) and (Length(MpsBarcodeinf.Text[n])=FormIDLength) Then // 依條碼角度轉影像
+            Begin
+              Rotate(iGraphic, MpsBarcodeinf.r180[n]);
+              MpsGetBarcode(ISB_BW.Graphic, MpsBarcodeinf);
+              Break;
+            End;
+          End;
+//ShowMessage(IntToStr(iGraphic.Palette.palNumEntries));
+          if iGraphic.ImageFormat = ifBlackWhite then   //20200806 出現無法匯入,是因color256無法壓JPEG,待報會後再開啟
+          begin
+            SaveFilename := changefileext(SaveFilename,'.tif');    //20240320 Hong 調整黑白存tif
+            iGraphic.Compression:=tcGroup4;
+          end
+          else if iGraphic.ImageFormat= ifColor256 then
+          begin
+            SaveFilename := changefileext(SaveFilename,'.jpg');    //20240320 Hong 調整Color256存jpg
+            ConverttoGray(iGraphic);
+            iGraphic.Compression:=tcJPEG;
+            iGraphic.JpegQuality:=cooom;
+          end
+          else if (iGraphic.ImageFormat = ifTrueColor) or (iGraphic.ImageFormat = ifGray256) then
+          begin
+            SaveFilename := changefileext(SaveFilename,'.jpg');    //20240320 Hong 調整彩色灰階存jpg
+            iGraphic.Compression:=tcJPEG;
+            iGraphic.JpegQuality:=cooom;
+          end
+          else
+          begin
+            iGraphic.Compression:=tcLZW;
+          end;
+
+          {if (iGraphic.Palette.palNumEntries = 0) or (iGraphic.Palette.palNumEntries = 256) then  //20171130 彩色 會為0  黑白 為2  灰階256     //20200806拿掉
+          begin
+            iGraphic.Compression:=tcJPEG;
+            iGraphic.JpegQuality:=cooom;
+          end;}
+
+          If LowerCase(ExtractFileExt(SavePath + SaveFilename)) = '.tif' Then
+          Begin
+            If FileExists(SavePath + SaveFilename) Then
+              SaveStream := TFileStream.Create(SavePath + SaveFilename, fmOpenReadWrite)
+            Else
+              SaveStream := TFileStream.Create(SavePath + SaveFilename, fmCreate);
+            Try
+              SaveStream.Seek(0, soFromBeginning);
+              iGraphic.AppendToStream(SaveStream);
+            Finally
+              SaveStream.Free;
+            End;
+          End
+          Else If LowerCase(ExtractFileExt(SavePath + SaveFilename)) = '.jpg' Then
+          Begin
+            If FileExists(SavePath + SaveFilename) Then
+              DeleteFile(SavePath + SaveFilename);
+            // SaveStream := TFileStream.Create( PEFileName ,fmCreate );
+            JpgGr := TJpegGraphic.Create;
+            Try
+              JpgGr.Assign(iGraphic);
+              JpgGr.SaveQuality := 30;
+              // JpgGr.AppendToStream(SaveStream);
+              JpgGr.SaveToFile(SavePath + SaveFilename);
+            Finally
+              JpgGr.Free;
+              // SaveStream.Free;
+            End;
+          End;
+
+          SetContextList('A', -1, CaseID, DocDir, SaveFilename);
+          If (TreeView1.Selected = NewTreeNode) Then
+          Begin
+            If imageCount = 0 Then
+            Begin
+              SetCaseList('A', -1, CaseID);
+              MyTreeNode1 := TreeView1.Items.AddChild(NewTreeNode, CaseID);
+              MyTreeNode1.ImageIndex := 2;
+              MyTreeNode1.SelectedIndex := 2;
+              Application.ProcessMessages;
+            End;
+          End;
+          inc(imageCount);
+          // DrawDocItem1(MytreeNode1,Doc_Inf_List,CaseID);
+          // DrawDocItem(MyTreeNode1,FORM_INF_List,CaseID);
+        End
+        Else If TreeView1.Selected = MyTreeNode3 Then
+        Begin
+          SavePath := ImageSavePath + CaseID + '\' + NowDocDir + '\';
+          ContextList.Clear;
+          If FileExists(ImageSavePath + CaseID + '\' + NowDocDir +
+            '\Context.dat') Then
+            ContextList.LoadFromFile(ImageSavePath + CaseID + '\' + NowDocDir +
+              '\Context.dat');
+          If NowFormCode <> '' Then
+            SaveFilename := Add_Zoo(ContextList.Count + 1, 3) + '_' +
+              NowFormCode + ext
+          Else
+            SaveFilename := Add_Zoo(ContextList.Count + 1, 3) + ext;
+
+          For n := 1 To MpsBarcodeinf.Count Do
+          Begin
+            If MpsBarcodeinf.r180[n] <> 0 Then // 依條碼角度轉影像
+            Begin
+              Rotate(iGraphic, MpsBarcodeinf.r180[n]);
+              MpsGetBarcode(iGraphic, MpsBarcodeinf);
+              Break;
+            End;
+          End;
+
+          if (iGraphic.Palette.palNumEntries = 0) or (iGraphic.Palette.palNumEntries = 256) then  //20171130 彩色 會為0  黑白 為2
+          begin
+            iGraphic.Compression:=tcJPEG;
+            iGraphic.JpegQuality:=cooom;
+          end;
+
+          If LowerCase(ExtractFileExt(SavePath + SaveFilename)) = '.tif' Then
+          Begin
+            If FileExists(SavePath + SaveFilename) Then
+              SaveStream := TFileStream.Create(SavePath + SaveFilename,
+                fmOpenReadWrite)
+            Else
+              SaveStream := TFileStream.Create(SavePath + SaveFilename,
+                fmCreate);
+            Try
+              SaveStream.Seek(0, soFromBeginning);
+              iGraphic.AppendToStream(SaveStream);
+            Finally
+              SaveStream.Free;
+            End;
+          End
+
+          Else
+          Begin
+            If LowerCase(ExtractFileExt(SavePath + SaveFilename)) = '.jpg' Then
+            Begin
+              If FileExists(SavePath + SaveFilename) Then
+                DeleteFile(SavePath + SaveFilename);
+              // SaveStream := TFileStream.Create( PEFileName ,fmCreate );
+              JpgGr := TJpegGraphic.Create;
+              Try
+                JpgGr.Assign(iGraphic);
+                JpgGr.SaveQuality := cooom;
+                // JpgGr.AppendToStream(SaveStream);
+                JpgGr.SaveToFile(SavePath + SaveFilename);
+              Finally
+                JpgGr.Free;
+                // SaveStream.Free;
+              End;
+            End;
+
+          End;
+          // ISB.SaveToFile(SavePath+SaveFilename);
+          ContextList.Add(SaveFilename);
+          ContextList.SaveToFile(SavePath + 'Context.dat');
+        End;
+
+        if iGraphic = iGraphic_First then
+          iGraphic := iGraphic_Sec
+        else
+          iGraphic.Assign(nil);
+
+      End //While 結束
+
+    End;
+    ClearErrini(CaseID, MyTreeNode1);
+    // 清掉檢核記錄
+    If (TreeView1.Selected = MyTreeNode1) Or
+      (TreeView1.Selected = NewTreeNode) Then
+    Begin
+      LoadImgFile;
+    End
+    Else
+    Begin
+      DrawDocItem2(MyTreeNode1, CaseID);
+      // 長出文件名稱的樹並傳回是否有申請書的影像
+      page := GetCasePage(ImageSavePath, CaseID);
+      // ShowMessage('page='+IntToStr(page));
+      MyTreeNode1.Text := Format(_Msg('%s-%d頁'), [CaseID, page]);
+    End;
+    // ShowMessage('AAAA');
+    NewTreeNodeRefresh;
+    Application.ProcessMessages;
+    DataLoading(false, false);
+
+
+finally
+ISB.Free;
+iGraphic_First.Free;
+iGraphic_sec.Free;
+end;
+
+
+  End;
+End;
+
+
+
+procedure TCB_IMGPSScanX.PM106Click(Sender: TObject);
+var
+  i,n,x,v,v1 : Integer;
+  CopyFormID,Copy2Caseno,CopyFileName : String;
+  S : TStringlist;
+begin
+  ShowText := _Msg('複製文件中,請稍候');
+  DataLoading(True,True);
+  DocCopyForm := TDocCopyForm.Create(Self);
+  S := TStringlist.Create;
+  try
+    InitialLanguage(DocCopyForm); //載入多國語言
+    DocCopyForm.CopyFromGB.Caption := NowCaseno+DocCopyForm.CopyFromGB.Caption;
+    IF NewTreenode.Count = 1 Then
+    begin
+      Showmessage(_Msg('沒有其他可複製的文件'));
+      Exit;
+    end;
+    For i := 0 to MyTreeNode1.Count -1 do
+    begin
+      v := Pos('-',MyTreeNode1.Item[i].Text);
+      v1 := pos('{',MyTreeNode1.Item[i].Text);
+      if V1 > 0 then
+      begin
+        CopyFormID := Copy(MyTreeNode1.Item[i].Text,1,v-1);
+        DocCopyForm.CheckListBox1.Items.Add(CopyFormID);
+      end;
+    end;
+    For i := 0 to NewTreenode.Count -1 do
+    begin
+      v := Posend('-',NewTreeNode.Item[i].Text);
+      Copy2Caseno := Copy(NewTreeNode.Item[i].Text,1,v-1);
+      IF Copy2Caseno <> NowCaseno Then
+      begin
+        DocCopyForm.CheckListBox2.Items.Add(Copy2Caseno);
+      end;
+    end;
+
+    if DocCopyForm.ShowModal = mrok then
+    begin
+      If MessageDlg(_Msg('是否確定要將勾選的文件複製到勾選的編號裡?'),MtConfirmation,[Mbyes,mbcancel],0) = mrCancel Then
+        Exit;
+      ShowText := _Msg('複製中,請稍候');
+      DataLoading(True,True);
+      For i := 0 to DocCopyForm.CheckListBox2.Count -1 do
+      begin
+        IF DocCopyForm.CheckListBox2.Checked[i] Then
+        begin
+          S.Clear;
+          Copy2Caseno := DocCopyForm.CheckListBox2.Items.Strings[i];
+          ClearErrini(Copy2Caseno,MyTreeNode1);  //清掉檢核記錄
+          S.LoadFromFile(ImageSavePath + Copy2Caseno +'\Context.dat');
+          For n := 0 to DocCopyForm.CheckListBox1.Count -1 do  //文件
+          begin
+            If DocCopyForm.CheckListBox1.Checked[n] Then
+            begin
+              //v:= Posend('{',DocCopyForm.CheckContextList.Strings[n]);
+              //v1 := Posend('}',DocCopyForm.CheckContextList.Strings[n]);
+              //CopyFormID := Copy(DocCopyForm.CheckContextList.Strings[n],1,v-1);
+              CopyFormID := DocCopyForm.CheckListBox1.Items.Strings[n];
+              IF v = 0 Then
+                CopyFormID := '';
+              For x := 0 to ContextList.Count -1 do
+              begin
+                //Showmessage(CopyFormCode);
+                //IF CopyFormID <> '' then   //有文件代號
+               // begin
+                  if FileName2FormCode(ContextList.Strings[x])=CopyFormID  then
+                  begin
+                    //CopyFileName := Add_Zoo(S.Count+1,3)+ Copy(ContextList.Strings[x],4,length(ContextList.Strings[x])-3);
+                    CopyFileName := Add_Zoo(S.Count+1,3)+ FileName2NoQuene_Filename(ContextList.Strings[x]);
+                    CopyFile(PWideChar(DisplayPath+ContextList.Strings[x]),PWidechar(ImageSavePath + Copy2Caseno+'\'+CopyFileName),False);
+                    S.Add(CopyFileName);
+                    S.SaveToFile(ImageSavePath + Copy2Caseno +'\Context.dat');
+                  end;
+               // end
+
+              end;
+            end;
+          end;
+
+        end;
+      end;
+      DataLoading(False,False);
+      Showmessage(_Msg('複製完成!!'));
+      LoadImgFile;
+    end;
+  finally
+  DocCopyForm.Free;
+  DataLoading(False,False);
+  S.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.PM107Click(Sender: TObject);
+begin
+  WNoteBtnClick(nil);
+end;
+
+procedure TCB_IMGPSScanX.PM108Click(Sender: TObject);
+var
+  i : Integer;
+  DocListForm : TDocListForm;
+  OldName,NewName,Ext : String;
+  NewFormID,NewFormName,CustomDocNo : String;
+begin
+  DocListForm := TDocListForm.Create(self);
+  try
+LogFile1.LogToFile(logTimeString+'Tree 歸類開始');
+    InitialLanguage(DocListForm); //載入多國語言
+    DocListForm.CheckBox1.Visible:=True;
+    for i := 1 to FORM_INF_List.Count - 1 do
+    begin
+      NewFormID := GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+      NewFormName := GetSQLData(FORM_INF_List,'T1.FORM_DESC',i);
+      if not FormIDAppear(NewFormID) then Continue;   //20170816 先秀全部的
+      if (NewFormID <> FileName2FormCode(DisplayISB.FileName)) and FormIDExists(NewFormID,False,i) then
+      begin
+        DocListForm.FormIDList.Add(NewFormID+'#@#'+NewFormName);
+        With DocListForm.DocLV.Items.Add do
+        begin
+          Caption := NewFormID;
+          SubItems.Add(GetSQLData(FORM_INF_List,'T1.FORM_DESC',i));
+        end;
+      end;
+    end;
+    if DocListForm.ShowModal = mrOk then
+    begin
+      if not (DocListForm.DocLV.Selected=nil) then
+         NewFormID := DocListForm.DocLV.Selected.Caption;
+      if DocListForm.CheckBox1.Checked then
+      begin
+        //歸類到自訂文件
+        NewFormID:=DocListForm.Edit1.Text;
+
+        if Trim(DocListForm.Edit1.Text)='' then
+        begin
+          Showmessage(_Msg('未輸入文件名稱'));
+          Exit;
+        end;
+        if FindCustomDocName(DisplayPath,NewFormID) then
+        begin
+          Showmessage(Format(_Msg('文件名稱:"%s"己存在'),[NewFormID]));
+          Exit;
+        end;
+        if NowFormCode <> AttName then
+        begin
+          If Messagedlg(Format(_Msg('是否將"%s"的所有影像歸類成"%s"'),[FormCode2FormName(NowCaseNo,NowFormCode),NewFormID]),MtConfirmation,[mbyes,mbcancel],0) = mrcancel Then
+            Exit;
+        end
+        Else
+        begin
+          If Messagedlg(Format(_Msg('是否將"%s"的所有影像歸類成"%s"'),[_Msg('附件')+MyTreeNode3.Text,FormCode2FormName(NowCaseNo,NewFormID)]),MtConfirmation,[mbyes,mbcancel],0) = mrcancel Then
+            Exit;
+        end;
+        CustomDocNo := GetNewCustomDocNo(DisplayPath,NewFormID);
+//ShowMessage('CustomDocNo='+CustomDocNo);
+LogFile1.LogToFile(logTimeString+'Tree 歸類到自訂文件 CustomDocNo='+CustomDocNo);
+        ShowText := _Msg('歸類中,請稍侯');
+        DataLoading(True,True);
+        FormIDReplace(NowCaseNo,NowDocDir,NowFormCode,CustomDocNo+'010101A');
+      end
+      else
+      begin
+        //歸類到既有文件
+        if NowFormCode <> AttName then
+        begin
+          If Messagedlg(Format(_Msg('是否將"%s"的所有影像歸類成"%s"'),[FormCode2FormName(NowCaseNo,NowFormCode),FormCode2FormName(NowCaseNo,NewFormID)]),MtConfirmation,[mbyes,mbcancel],0) = mrcancel Then
+            Exit;
+        end
+        Else
+        begin
+          If Messagedlg(Format(_Msg('是否將"%s"的所有影像歸類成"%s"'),[_Msg('附件')+MyTreeNode3.Text,FormCode2FormName(NowCaseNo,NewFormID)]),MtConfirmation,[mbyes,mbcancel],0) = mrcancel Then
+            Exit;
+        end;
+        ShowText := _Msg('歸類中,請稍侯');
+        DataLoading(True,True);
+//ShowMessage('NowDocDir='+NowDocDir);
+LogFile1.LogToFile(logTimeString+'Tree 歸類到既有文件 NewFormID='+NewFormID);
+        FormIDReplace(NowCaseNo,NowDocDir,NowFormCode,NewFormID);
+
+      end;
+      ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+      DrawDocItem2(MytreeNode1,NowCaseno);
+      DataLoading(False,False);
+      TreeView1.Selected := MyTreeNode1;
+      TreeView1Click(self);
+    end;
+
+  finally
+  DocListForm.Free;
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.PM109Click(Sender: TObject);
+var
+  S : TStringlist;
+  CaseID : String;
+begin
+  //if TreeView1.Selected = nil then Exit;
+  //if TreeView1.Selected = NewTreeNode then Exit;
+  CaseID := NowCaseno;
+  S := TStringlist.Create;
+  try
+    ClearView(1);
+    ShowText := CaseID+_Msg('檢核中,請稍候');
+    DataLoading(True,True);
+    ShowText := CaseID+_Msg('檢核中,請稍候');
+    DataLoading(True,True);
+    If OMRCheckCase(CaseID) then  //有成功
+    begin
+      S.Add('Y');
+      S.SaveToFile(ImageSavePath+CaseID+'\OMRCheckOk.dat');
+    end;
+      //MyTreeNode2ReFresh(CaseID);
+    LoadImgFile;
+    TreeView1Click(nil);
+    DataLoading(False,False);
+  finally
+  S.Free;
+  end;
+  Showmessage(_Msg('檢核完成'));
+end;
+
+procedure TCB_IMGPSScanX.PM110Click(Sender: TObject);
+var
+  CustomDocName : String;
+  CustomDocNo : String;
+  DocDir : String;
+  SavePath : String;
+  ST1:TStringList;
+begin
+  if InputQuery(_Msg('輸入其他文件名稱'),_Msg('文件名稱'),CustomDocName) then
+  begin
+    if CustomDocName <> '' then
+    begin
+      if FindCustomDocName(DisplayPath,CustomDocName) then
+      begin
+        Showmessage(Format('文件名稱:"%s"己存在',[CustomDocName]));
+        Exit;
+      end;
+      ST1:=TStringList.Create;
+      CustomDocNo := GetNewCustomDocNo(DisplayPath,CustomDocName);
+      DocDir := CustomDocNo;
+      SavePath := ImageSavePath+NowCaseNo+'\'+DocDir+'\';
+      Str2Dir(SavePath);
+      SetDocNoList('A',-1,NowCaseNo,DocDir,'1');
+      DrawDocItem2(MytreeNode1,NowCaseno);
+      MyTreeNode1.Expand(True);
+    end;
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.PM111Click(Sender: TObject);
+var
+  oldCopies,NewCopies : Integer;
+  copies : String;
+begin
+  oldCopies := GetDocDirCopies(NowCaseno,NowDocDir);
+  try
+    NewCopies := Strtoint(inputBox(_Msg('修改份數'),_Msg('請輸入修改後的份數'),inttostr(oldCopies)));
+  except
+    Showmessage(_Msg('輸入錯誤'));
+    Exit;
+  end;
+  if (NewCopies <= 0) and (NewCopies >= 10000) then
+  begin
+    Showmessage(_Msg('輸入範圍錯誤'));
+    Exit;
+  end;
+
+  if (oldCopies <> NewCopies) and (NewCopies > 0) and (NewCopies < 10000) then
+  begin
+    if DocNoNeedDiv(NowDocNo) and (NewCopies = 1) and (MessageDlg(_Msg('修改至1份後此文件將無法再進行份數修改,是否確定??'),mtConfirmation,[mbyes,mbcancel],0)= mrcancel) then
+      Exit;
+
+    SetDocDirCopies(NowCaseno,NowDocDir,NewCopies);
+    SetRecordEditedDocDir('A',NowCaseNo,NowDocDir);
+    DrawDocItem2(MytreeNode1,NowCaseno);
+    Showmessage(_Msg('修改完成'));
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.PM301Click(Sender: TObject);
+begin
+  ScanColor := ifBlackWhite;
+  ScanDpi := Def_ScanDpi;
+  Ext := '.tif';
+  PM301.Checked := True;
+end;
+
+procedure TCB_IMGPSScanX.PM302Click(Sender: TObject);
+begin
+  ScanColor := ifGray256;
+  Ext := '.jpg';
+  ScanDpi := 200;
+  //Ext := '.tif';
+  PM302.Checked := True;
+end;
+
+procedure TCB_IMGPSScanX.PM303Click(Sender: TObject);
+begin
+  ScanColor := ifTrueColor;
+  Ext := '.jpg';     //20130326 yuu說理賠改存jpg
+  ScanDpi := 200;
+  //Ext := '.tif';
+  PM303.Checked := True;
+end;
+
+procedure TCB_IMGPSScanX.PM501Click(Sender: TObject);
+begin
+  DisplayISB.ZoomMode := zmFitWidth;
+  DisplayISB.AntiAliased := True;
+  SetScrollData(DisplayISB,DisplayISB.HorzScrollBar.Position,DisplayISB.VertScrollBar.Position,DisplayISB.ZoomPercent);
+end;
+
+procedure TCB_IMGPSScanX.PM502Click(Sender: TObject);
+begin
+  DisplayISB.ZoomMode := zmFitHeight;
+  DisplayISB.AntiAliased := True;
+  SetScrollData(DisplayISB,DisplayISB.HorzScrollBar.Position,DisplayISB.VertScrollBar.Position,DisplayISB.ZoomPercent);
+end;
+
+procedure TCB_IMGPSScanX.PM503Click(Sender: TObject);
+begin
+  DisplayISB.ZoomMode := zmFittoPage;
+  DisplayISB.AntiAliased := True;
+  SetScrollData(DisplayISB,DisplayISB.HorzScrollBar.Position,DisplayISB.VertScrollBar.Position,DisplayISB.ZoomPercent);
+end;
+
+procedure TCB_IMGPSScanX.PM504Click(Sender: TObject);
+begin
+  DisplayISB.ZoomMode := zmOriginalSize;
+  DisplayISB.AntiAliased := True;
+  SetScrollData(DisplayISB,DisplayISB.HorzScrollBar.Position,DisplayISB.VertScrollBar.Position,DisplayISB.ZoomPercent);
+end;
+
+procedure TCB_IMGPSScanX.PM505Click(Sender: TObject);
+begin
+  if DisplayISB.FileName = '' then Exit;
+  Panel1.Enabled := False;
+  Panel2.Enabled := False;
+  ScanMode := smReplace;
+  ScanInfo.ImageCount := 0;
+  ScanPath := DisplayPath;
+  ScanCaseno := '';
+  ScanSaveFilename := ExtractFileName(DisplayISB.FileName);
+  Try
+    StatrTwainScan;
+  Except
+    Panel1.Enabled := True;
+    Panel2.Enabled := True;
+  end;
+  Panel1.Enabled := True;
+  Panel2.Enabled := True;
+  ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+end;
+
+procedure TCB_IMGPSScanX.PM507Click(Sender: TObject);
+var
+  i : Integer;
+  DocListForm : TDocListForm;
+  OldName,NewName,Ext : String;
+  FormID,FormName,DocNo : String;
+  PreNode2Name : String;
+  iFormID : String;
+begin
+  PreNode2Name := '';
+  if TreeView1.Selected.Parent = MyTreeNode1 then
+    PreNode2Name:= GetNode2Name(MyTreeNode2);
+  ShowText := _Msg('文件歸類中,請稍候');
+  DataLoading(True,True);
+  DocListForm := TDocListForm.Create(self);
+  try
+    InitialLanguage(PatchDlg); //載入多國語言
+    for i := 1 to FORM_INF_List.Count - 1 do
+    begin
+      FormID :=  GetSQLData(FORM_INF_List,'T1.FORM_ID',i);
+      FormName := GetSQLData(FORM_INF_List,'T1.FORM_DESC',i);
+      DocNo := GetSQLData(FORM_INF_List,'T1.DOC_NO',i)+GetSQLData(FORM_INF_List,'T1.DOC_VERSION',i);
+      //Showmessage(FORM_INF_List.Text);
+      //showmessage(inttostr(FORM_INF_List.Count)+#13+inttostr(self.Doc_Inf_List.Count));
+      if (FormID <> FileName2FormCode(DisplayISB.FileName)) and FormIDExists(FormID,False,i) then
+      begin
+        DocListForm.FormIDList.Add(FormID+'#@#'+FormName);
+        With DocListForm.DocLV.Items.Add do
+        begin
+          Caption := FormID;
+          SubItems.Add(FormName);
+        end;
+      end;
+    end;
+    if DocListForm.ShowModal = mrOk then
+    begin
+      OldName := ExtractFileName(DisplayISB.FileName);
+      Ext := ExtractFileExt(OldName);
+      //NewName := Copy(OldName,1,3)+'_'+TransRealFormID(DocListForm.DocLV.Selected.Caption)+Ext;
+      NewName := Add_Zoo(FileName2ScanPage(OldName),3)+'_'+DocListForm.DocLV.Selected.Caption+Ext;
+      RenameFile(DisplayPath+OldName,DisplayPath+NewName);
+      ReNameContext(DisplayPath,OldName,NewName);
+      //DrawDocItem1(MytreeNode1,Doc_Inf_List,NowCaseno);  //201408280改
+      DrawDocItem2(MytreeNode1,NowCaseno);
+      //DrawDocItem(MytreeNode1,FORM_INF_List,NowCaseno);
+      ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+      if PreNode2Name <> '' then  // 回到原本點選的文件節點上
+      begin
+        for i := 0 to MyTreeNode1.Count - 1 do
+        begin
+          if GetNode2Name(MyTreeNode1.Item[i]) = PreNode2Name then
+          begin
+            TreeView1.Selected := MyTreeNode1.Item[i];
+            Break;
+          end;
+        end;
+      end;
+      TreeView1click(self);
+      //Showmessage(_Msg('歸類完成')); //20101103 User要求拿掉
+    end;
+  finally
+  DataLoading(False,False);
+  DocListForm.Free;
+  end;
+
+end;
+
+
+procedure TCB_IMGPSScanX.PM508Click(Sender: TObject);
+var
+  P : Integer;
+  inx:Integer;
+begin
+  if DisplayISB.FileName = '' then Exit;
+  if (ContextList.Count = 1) and ((FMode = 'NSCAN') or (FMode = 'ASCAN') or (FMode = 'DSCAN') or (FMode = 'ISCAN') or (FMode = 'SSCAN') or (FMode = 'MSCAN') or (FMode = 'RI_SCAN')) then
+  begin
+    if Messagedlg(Format(_Msg('刪除後(%s)案件無影像,將刪除此案件,是否確定刪除?'),[NowCaseno]),mtconfirmation,[mbyes,mbcancel],0) = mrCancel then Exit;
+    _DelTree(DisplayPath);
+    SetCaseList('D',NewTreeNode.IndexOf(MyTreeNode1),'');
+    LoadImgFile;
+  end
+  Else
+  begin
+    if Messagedlg(_Msg('是否確定刪除?'),mtconfirmation,[mbyes,mbcancel],0) = mrCancel then Exit;
+    inx := ContextList.IndexOf(ExtractFileName(DisplayISB.FileName));
+    ContextList.Delete(inx);
+    ContextList.SaveToFile(ImageSavePath + NowCaseno+'\Context.dat');
+    Context_DocnoList.Delete(inx);
+    Context_DocnoList.SaveToFile(ImageSavePath + NowCaseno+'\Context_DocNo.dat');
+    DeleteFile(DisplayISB.FileName);
+    ReSortFileName(DisplayPath);
+    ContextList.LoadFromFile(ImageSavePath + NowCaseno+'\Context.dat');
+    Context_DocnoList.LoadFromFile(ImageSavePath + NowCaseno+'\Context_DocNo.dat');
+    if FileExists(ImageSavePath + NowCaseno+'\CustomDocNo.dat') then
+      Cust_DocNoList.LoadFromFile(ImageSavePath + NowCaseno+'\CustomDocNo.dat');
+    //DrawDocItem1(MytreeNode1,Doc_Inf_List,NowCaseno);  //201408280改
+    DrawDocItem2(MytreeNode1,NowCaseno);
+
+    //DrawDocItem(MytreeNode1,FORM_INF_List,NowCaseno);
+    P := ContextList.Count;
+    MytreeNode1.Text := Format(_Msg('%s-%d頁'),[NowCaseno,p]);
+    ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+    NewTreeNodeRefresh;
+    TreeView1Click(self);
+
+  end;
+  //Showmessage(_Msg('刪除完成'));  //20101101 User要求拿掉
+end;
+
+procedure TCB_IMGPSScanX.PM509Click(Sender: TObject);
+begin
+  PM401Click(nil);
+end;
+
+procedure TCB_IMGPSScanX.PM510Click(Sender: TObject);
+begin
+  DeskewImg(DisplayISB.Graphic);
+  DisplayISB.SaveToFile(DisplayISB.FileName);
+  ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+end;
+
+procedure TCB_IMGPSScanX.PopupMenu1Popup(Sender: TObject);
+begin
+  PM101.Visible := False;   //刪除
+  PM102.Visible := False;   //修改案件編號
+  PM103.Visible := False;   //掃瞄器加入影像
+  PM104.Visible := False;   //檔案加入影像
+  PM106.Visible := False;   //複製文件至其他編號
+  PM107.Visible := False;   //寫備註
+  PM108.Visible := False;   //歸類
+  PM109.Visible := False;   //檢核此筆
+  PM110.Visible := False;   //新增自訂文件
+  PM111.Visible := False;   //修改份數
+
+  if (FMode = 'SAMPLESCAN') then Exit;
+
+  if TreeView1.Selected = nil then Exit;
+  if TreeView1.Selected = NewTreeNode  then     //新掃瞄件
+  begin
+    if (FMode = 'NSCAN') then
+    begin
+//ShowMessage('AAAA');
+      PM101.Visible := True;   //刪除
+      PM103.Visible := True;   //掃瞄器加入影像
+      PM104.Visible := True;   //檔案加入影像
+    end;
+
+    if FModeName=_Msg('異動件') then
+    begin
+      PM101.Visible := True;
+    end;
+//    if FMode='ESCAN' then
+//    begin
+//      PM101.Visible := True;
+//    end;
+  end
+  Else if TreeView1.Selected = MyTreeNode1 then    //案件層
+  begin
+    PM101.Visible := True;   //刪除
+
+    if FImgDelete='Y' then
+    begin
+      PM101.Visible:=True;
+    end;
+    if FImgDelete='N' then
+    begin
+      PM101.Visible:=false;
+    end;
+
+    if FMode='ESCAN' then
+      PM101.Visible:=false;
+
+    if FModeName=_Msg('異動件') then
+    begin
+      PM101.Visible := True;
+    end;
+
+    if not CaseDelete_Enable(NowCaseno) then //
+      PM101.Enabled := False
+    else
+      PM101.Enabled := True;
+    PM103.Visible := True;   //掃瞄器加入影像
+    //PM107.Visible := True;   //寫備註
+    //PM109.Visible := True;   //檢核此筆
+//    if FCustDocYN <> 'N' Then
+//      PM110.Visible := True;   //新增自訂文件  20170914 先不在tree 中做自訂文件  讓user在縮圖做
+    PM104.Visible := True;   //檔案加入影像
+    if (FMode = 'NSCAN') then
+    begin
+      PM102.Visible := True;   //修改案件編號
+    end;
+//    if FMode='ESCAN' then
+//    begin
+//      PM101.Visible := True;
+//    end;
+  end
+  Else if TreeView1.Selected = MyTreeNode2 then    //文件層
+  begin
+    PM101.Visible := True;   //刪除
+    //PM107.Visible := True;   //寫備註
+    //PM109.Visible := True;   //檢核此筆
+//    if FCustDocYN <> 'N' Then
+//      PM110.Visible := True;   //新增自訂文件
+    if FImgDelete='Y' then
+    begin
+      PM101.Visible:=True;
+    end;
+    if FImgDelete='N' then
+    begin
+      PM101.Visible:=false;
+    end;
+
+    if FModeName=_Msg('異動件') then
+    begin
+      PM101.Visible := True;
+    end;
+
+    if GetUseCase('T',DisplayPath,NowDocDir) <> '' then   //沒有被引用走的
+      PM101.Enabled := False    //刪除
+    Else
+      PM101.Enabled := True;   //刪除
+    if ((GetDocDirCopies(NowCaseno,NowDocDir) > 1) or (not DocNoNeedDiv(NowDocNo)) or (Copy(NowDocNo,1,5)='ZZZZZ')) and (NowDocNo<> 'Attach') and (NowDocNo<> 'S_Attach') then
+      PM111.Visible := True;   //修改份數
+    if (FMode = 'NSCAN') then
+      PM102.Visible := True;   //修改案件編號
+//    if FMode='ESCAN' then
+//    begin
+//      PM101.Visible := True;
+//    end;
+  end
+  Else if TreeView1.Selected = MyTreeNode3 then    //表單層
+  begin
+    PM101.Visible := True;   //刪除
+    PM104.Visible := True;   //檔案加入影像
+    PM108.Visible := True;   //歸類
+    PM103.Visible := True;   //掃瞄器加入影像
+//    if FCustDocYN <> 'N' Then
+//      PM110.Visible := True;   //新增自訂文件
+    if GetFormIDPage(ContextList,NowFormCode) < 1 Then
+    begin
+      PM108.Visible := False;   //歸類
+    end;
+    if FImgDelete='Y' then
+    begin
+      PM101.Visible:=True;
+    end;
+    if FImgDelete='N' then
+    begin
+      PM101.Visible:=false;
+    end;
+
+    if FModeName=_Msg('異動件') then
+    begin
+      PM101.Visible := True;
+    end;
+
+    if GetUseCase('T',DisplayPath,NowDocDir) <> '' then   //被引用走的
+    begin
+      PM101.Enabled := False;   //刪除
+      PM104.Enabled := False;   //檔案加入影像
+      PM108.Enabled := False;   //歸類
+    end
+    Else
+    begin
+      PM101.Enabled := True;   //刪除
+      PM104.Enabled := True;   //檔案加入影像
+      PM108.Enabled := True;   //歸類
+    end;
+
+    if (FMode = 'NSCAN') then
+    begin
+      PM102.Visible := True;   //修改案件編號
+    end;
+  end;
+
+
+
+end;
+
+procedure TCB_IMGPSScanX.PopupMenu4Popup(Sender: TObject);
+begin
+  PM401.Visible := False;
+  PM402.Visible := False;
+  PM403.Visible := False;
+  PM404.Visible := False;
+  if FMode = 'SAMPLESCAN' then Exit;
+  if (TreeView1.Selected.Level =2) or (TreeView1.Selected.Level =3) then
+  begin
+    PM402.Visible := True;
+    PM403.Visible := True;
+    PM404.Visible := True;
+  end;
+  PM401.Visible := True;
+  if (TreeView1.Selected <> MyTreeNode2) or (FMode = 'RSCAN') then
+    PM401.Visible := False;
+end;
+
+procedure TCB_IMGPSScanX.PopupMenu5Popup(Sender: TObject);
+begin
+  PM501.Visible := False;
+  PM502.Visible := False;
+  PM503.Visible := False;
+  PM504.Visible := False;
+  PM505.Visible := False;
+  PM506.Visible := False;
+  PM507.Visible := False;
+  PM508.Visible := False;
+  PM509.Visible := False;
+  PM510.Visible := False;
+  if FMode = 'SAMPLESCAN' then Exit;
+  if (DisplayISB.FileName <> '') then
+  begin
+    PM501.Visible := True;
+    PM502.Visible := True;
+    PM503.Visible := True;
+    PM504.Visible := True;
+    //PM505.Visible := True;
+    //PM506.Visible := True;
+    //PM507.Visible := True;
+    //PM508.Visible := True;
+    //PM509.Visible := True;
+    //PM510.Visible := True;
+  end;
+  if (TreeView1.Selected <> MyTreeNode2) or (FMode = 'RSCAN') or (FMode = 'ESCAN') then
+    PM509.Visible := False;
+end;
+
+procedure TCB_IMGPSScanX.PopupMenu6Popup(Sender: TObject);
+begin
+  PM601.Visible := True;  //歸類
+  PM602.Visible := True;  //自行定義文件名稱
+  PM603.Visible := False;  //掃描替換此頁
+  PM604.Visible := False;  //歪斜矯正
+  PM605.Visible := True;  //刪除
+
+//  if FMode='ESCAN' then
+//  begin
+//    PM601.Visible := False;  //歸類
+//    PM602.Visible := False;  //自行定義文件名稱
+//    PM603.Visible := False;  //掃描替換此頁
+//    PM604.Visible := False;  //歪斜矯正
+//    PM605.Visible := False;  //刪除
+//  end;
+
+  if ((NowDocNo = 'Attach') or (NowDocNo = 'S_Attach')) and (FCustDocYN <> 'N') then
+  begin
+    PM602.Visible := True;  //自行定義文件名稱
+    //PM603.Visible := True;  //掃描替換此頁
+    PM604.Visible := True;  //歪斜矯正
+    PM601.Visible := True;  //歸類
+    PM605.Visible := True;  //刪除
+  end;
+
+  if  FModeName<>_Msg('異動件') then
+  begin
+    if (FImgDelete='Y') then
+    begin
+      PM605.Enabled:=True;
+    end;
+    if FImgDelete='N' then
+    begin
+      PM605.Enabled:=false;
+    end;
+  end;
+
+
+
+
+  if CheckSelectImg_UseCase(DisplayPath,NowCaseNo) then //選擇的影像不可有引用的
+  begin
+    PM601.Enabled := False;  //歸類
+    PM605.Enabled := False;  //刪除
+  end;
+
+
+end;
+
+procedure TCB_IMGPSScanX.PrePageBtnClick(Sender: TObject);
+var
+  page : Integer;
+begin
+  {page := ScrollBar1.Position;
+   Case Vmode of
+    0   : dec(page);
+    1   : Page := Page - 2;
+    2   : Page := Page - 4;
+    3   : Page := Page - 6;
+    4   : Page := Page - 8;
+  end;
+  IF page >= ScrollBar1.min Then
+  begin
+    ScrollBar1.Position := page;
+  end
+  Else
+    ScrollBar1.Position := 1;  }
+  if selectISB = nil then Exit;
+  PriorPage(SelectPage);
+  if (SelectISB.Parent.Top-4) < 0 then
+    scrollBox1.VertScrollBar.Position := scrollBox1.VertScrollBar.Position + SelectISB.Parent.Top-4;
+
+      //ISBClick(TImageScrollBox(FindComponent(ISBName+'1')));
+
+
+end;
+
+procedure TCB_IMGPSScanX.SampleScanBtnClick(Sender: TObject);
+var
+  SampleFormID : String;
+  SendData : String;
+  buttonSelected : Integer;
+begin
+  ScanMode := smSample;
+  ClearView(1);
+  Vmode := 0;  //切成單頁
+  GoViewMode;
+  ScanInfo.ImageCount := 0;
+  ScanPath := SamplePath;
+  ScanCaseno := '';
+  ContextList.Clear;
+  ShowText := _Msg('範本掃描中,請稍候');
+  DataLoading(True,True);
+  SampleFormID := UpperCase(InputBox(_Msg('範本檔掃瞄輸入畫面'),_Msg('請輸入文件編號'),''));
+
+  if SampleFormIDList.IndexOf(SampleFormID)<>-1 then
+  begin
+    // Show a custom dialog
+    buttonSelected := messagedlg(SampleFormID+_Msg('已有範本,是否取代?'),mtCustom,
+                                [mbYes,mbCancel], 0);
+    if buttonSelected = mrCancel then
+    begin
+      DataLoading(false,false);
+      Exit;
+    end;
+  end;
+
+  if SampleFormID <> '' then
+  begin
+    if FormIDExists(SampleFormID,False,0) then
+    begin
+      ScanSaveFilename :=  SampleFormID + '.tif';
+    end
+    Else
+    begin
+      Showmessage(Format(_Msg('FormID:%s尚未註冊'),[SampleFormID]));
+      Panel1.Enabled := True;
+      Panel2.Enabled := True;
+      DataLoading(false,false);
+      Exit;
+    end;
+    SampleAnchorMode := FormID2Anchor(SampleFormID);
+
+    Panel1.Enabled := False;
+    Panel2.Enabled := False;
+//ShowMessage('AAAAA');
+    Try
+      StatrTwainScan;
+    Except
+    Panel1.Enabled := True;
+    Panel2.Enabled := True;
+    end;
+
+    if (ISB1.FileName <> '') and FileExists(SamplePath+SampleFormID+'.tif') then
+    begin
+      ShowText := _Msg('範本傳送中,請稍候');
+      DataLoading(True,True);
+      //多存一份jpg
+      ImageScrollBox1.LoadFromFile(SamplePath+SampleFormID+'.tif',1);
+      BWTif2Jpg(ImageScrollBox1.Graphic);
+      ImageScrollBox1.SaveToFile(SamplePath+SampleFormID+'.jpg');
+      //多存一份jpg
+
+      NowWork_No := FormCode2WorkNo(SampleFormID);
+      SendData := 'data='+FData+'&verify='+FVerify+'&work_no='+FWork_no+'&file_name='+SampleFormID+'.tif';
+      if not upFile(HTTPSClient,FUrl,'service/imgpsc/IMGPSC02/sample',SendData,'file',SamplePath+SampleFormID+'.tif',FReWrite,Memo1,False) then
+      begin
+        Showmessage(_Msg('傳送範本檔案時,網路發生錯誤!!')+_MSg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+')');
+        DataLoading(False,False);
+        Exit;
+      end;
+      if memo1.Lines.Strings[0] = '1' then
+      begin
+        Showmessage(_Msg('傳送範本檔案時,網路發生錯誤!!')+_Msg('錯誤原因:')+memo1.Lines.Strings[1]);
+        DataLoading(False,False);
+        Exit;
+      end
+      Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+      begin
+        Showmessage(_Msg('傳送範本檔案時,網路發生錯誤!!')+_Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入'));
+        DataLoading(False,False);
+        Exit;
+      end;
+
+      if FileExists(SamplePath+SampleFormID+'.jpg') then   //傳送JPG影像
+      begin
+        SendData := 'data='+FData+'&verify='+FVerify+'&work_no='+FWork_no+'&file_name='+SampleFormID+'.jpg';
+        if not upFile(HTTPSClient,FUrl,'service/imgpsc/IMGPSC02/sample',SendData,'file',SamplePath+SampleFormID+'.jpg',FReWrite,Memo1,False) then
+        begin
+          Showmessage(_Msg('傳送範本檔案(JPG)時,網路發生錯誤!!')+_MSg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+')');
+          DataLoading(False,False);
+          Exit;
+        end;
+        if memo1.Lines.Strings[0] = '1' then
+        begin
+          Showmessage(_Msg('傳送範本檔案(JPG)時,網路發生錯誤!!')+_Msg('錯誤原因:')+memo1.Lines.Strings[1]);
+          DataLoading(False,False);
+          Exit;
+        end
+        Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+        begin
+          Showmessage(_Msg('傳送範本檔案(JPG)時,網路發生錯誤!!')+_Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入'));
+          DataLoading(False,False);
+          Exit;
+        end;
+      end;
+      Showmessage(_Msg('傳送完成'));
+    end;
+  end;
+  DataLoading(False,False);
+
+end;
+
+procedure TCB_IMGPSScanX.ScrollBar1Change(Sender: TObject);
+begin
+  Exit;
+  If (TreeView1.Selected = MyTreenode1) or (TreeView1.Selected.ImageIndex = 6) Then
+  begin
+    view_image_FormCode(DisplayPath,'ShowAll',ScrollBar1.Position,1);
+  end
+  Else IF (TreeView1.Selected = MyTreenode2) then
+  begin
+    view_image_FormCode(DisplayPath,NowDocNo,ScrollBar1.Position,1);
+  end
+  Else if (TreeView1.Selected = MyTreenode3) then
+  begin
+    view_image_FormCode(DisplayPath,NowFormCode,ScrollBar1.Position,1);
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.ScrollBox1MouseEnter(Sender: TObject);
+begin
+ScrollBox1.SetFocus;
+end;
+
+procedure TCB_IMGPSScanX.SelectScanBtnClick(Sender: TObject);
+begin
+  Panel1.Enabled := False;
+  Panel2.Enabled := False;
+  scanner.SelectScanner;
+  Panel1.Enabled := True;
+  Panel2.Enabled := True;
+end;
+
+procedure TCB_IMGPSScanX.StatusBar1DblClick(Sender: TObject);
+begin
+  Button3.Visible := not Button3.Visible;
+  Button4.Visible := not Button4.Visible;
+  if (GetKeyState(VK_CONTROL) < 0) Then
+  begin
+    ExportBt.Visible := not ExportBt.Visible;
+    ImportBt.Visible := not ImportBt.Visible;
+  end
+  Else
+  begin
+    Memo1.Visible := not Memo1.Visible;
+    Display1.Visible := not Display1.Visible;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.ActiveFormCreate(Sender: TObject);
+var IScrollBox : TImageScrollBox;
+    i          :integer;
+begin
+  {HotKeyId1 := GlobalAddAtom('MyHotKey1')-$C000;
+  HotKeyId2 := GlobalAddAtom('MyHotKey2')-$C000;
+  HotKeyId3 := GlobalAddAtom('MyHotKey3')-$C000;
+  HotKeyId4 := GlobalAddAtom('MyHotKey4')-$C000;
+  RegisterHotKey(handle,HotKeyId1,0,VK_UP);      //printscreen
+  RegisterHotKey(handle,HotKeyId1,0,VK_Down);      //printscreen }
+  PostMessage(Handle,WM_ACTIVATE,WA_CLICKACTIVE,0);
+  vmode := 1;
+  DesableImage;
+  For i:= 1 to 8 do begin
+    IScrollBox := TImageScrollBox( FindComponent('ISB'+IntToStr(i)));
+    IScrollBox.MouseMode := mmUser;
+    iScrollBox.ZoomMode := zmFullPage;
+  end;
+  Sleep(500);
+  Timer1.Enabled := True;
+end;
+
+procedure TCB_IMGPSScanX.ActiveFormKeyUp(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  if Edit1.Focused then
+  begin
+    if selectISB = nil then Exit;
+
+    if (Key =VK_UP) then
+    begin
+      PriorPage(SelectPage);
+      if (SelectISB.Parent.Top-4) < 0 then
+       scrollBox1.VertScrollBar.Position := scrollBox1.VertScrollBar.Position + SelectISB.Parent.Top-4;
+
+      //ISBClick(TImageScrollBox(FindComponent(ISBName+'1')));
+    end;
+    if (Key =VK_Down) then
+    begin
+      NextPage(SelectPage);
+      if SelectISB.Parent.Top+SelectISB.Parent.Height+4 > scrollBox1.Height  then
+        ScrollBox1.VertScrollBar.Position := scrollBox1.VertScrollBar.Position + (SelectISB.Parent.Top+SelectISB.Parent.Height-ScrollBox1.Height+8);
+        //scrollBox1.VertScrollBar.ScrollPos := SelectISB.Parent.Top+SelectISB.Parent.Height;
+      //ISBClick(TImageScrollBox(FindComponent(ISBName+'2')));
+    end;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.AddAttFileLBClick(Sender: TObject);
+var
+  i : Integer;
+  Addfile : String;
+begin
+  OpenDialog1.Filter := 'PDF files|*.pdf';
+  OpenDialog1.Options := [ofAllowMultiSelect];
+  if OpenDialog1.Execute then
+  begin
+    ShowText :=_Msg('檔案加入中,請稍候');
+    DataLoading(True,True);
+    for i := 0 to OpenDialog1.Files.Count - 1 do
+    begin
+      AddFile := HTTPEncode(UTF8Encode(ExtractFileName(OpenDialog1.Files.Strings[i])));
+      if FileExists(ImageSavePath+NowCaseno+'\'+AddFile) then
+      begin
+        if Messagedlg(Format(_Msg('%s己存在,是否覆蓋??'),[Addfile]),mtconfirmation,[mbyes,mbcancel],0) = mrcancel Then
+          Continue;
+        SetAttContextList('D',-1,NowCaseno,AddFile);
+      end;
+      // AttFileGB.Visible := True; //附加電子檔窗   //20120207楊玉說不在這加電子檔先拿掉
+      //   Splitter2.Visible := True;
+      CopyFile(Pchar(OpenDialog1.Files.Strings[i]),Pchar(ImageSavePath+NowCaseno+'\'+AddFile),False);
+      SetAttContextList('A',-1,NowCaseno,AddFile);
+      LoadAttFile(NowCaseno);
+    end;
+  end;
+  DataLoading(False,False);
+end;
+
+procedure TCB_IMGPSScanX.AddCredit1RGClick(Sender: TObject);
+begin
+  if DisplayPath <> '' then
+  begin
+    Case AddCredit1RG.ItemIndex of
+      -1:Case_loandoc := '';
+       0:Case_loandoc := 'Y';
+       1:Case_loandoc := 'N';
+    end;
+    WriteCaseIndex(DisplayPath);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.AddScanBtnClick(Sender: TObject);
+var
+  P,v : Integer;
+begin
+  IF not InitialOk Then
+  begin
+    Showmessage(_Msg('資訊尚未下載完成,請稍候或重新進入'));
+    Exit;
+  end;
+  if MyTreeNode1 = nil then
+  begin
+    Showmessage(_Msg('請先選擇案件'));
+    Exit;
+  end;
+  Panel1.Enabled := False;
+  Panel2.Enabled := False;
+  ScanMode := smInsert;
+  ScanInfo.ImageCount := ContextList.Count;
+  ScanPath := DisplayPath;
+  ScanCaseno := NowCaseno;
+  ScanDocDir := NowDocDir;
+  Try
+    StatrTwainScan;
+  Except
+    Panel1.Enabled := True;
+    Panel2.Enabled := True;
+  end;
+  Panel1.Enabled := True;
+  Panel2.Enabled := True;
+  DrawDocItem2(MytreeNode1,NowCaseno);
+  //DrawDocItem(MytreeNode1,FORM_INF_List,NowCaseno);
+  //P := ContextList.Count;
+  GetCase_PageCount(CaseCount,PageCount);
+  v := Pos('-',NewTreeNode.Text);
+  NewTreeNode.Text := Format(_Msg('%s-共%d筆共%d頁'),[Copy(NewTreeNode.Text,1,v-1),CaseCount,PageCount]);
+  MytreeNode1.Text := Format(_Msg('%s-%d頁'),[NowCaseno,GetCasePage(ImageSavePath,NowCaseno)]);
+
+  ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+  SetDocDirtoSelected(MyTreeNode1,FirstDocDir);
+  TreeView1Click(self);
+end;
+
+procedure TCB_IMGPSScanX.AttListBoxClick(Sender: TObject);
+begin
+  DelAttFileLB.Enabled := False;
+  if AttListBox.ItemIndex >= 0 then
+    DelAttFileLB.Enabled := True;
+end;
+
+procedure TCB_IMGPSScanX.AttListBoxDblClick(Sender: TObject);
+var
+  AttFile : String;
+begin
+  if AttListBox.ItemIndex < 0 then Exit;
+
+  AttFile := HTTPEncode(UTF8Encode(AttListBox.Items.Strings[AttListBox.ItemIndex]));
+  if FileExists(DisplayPath+AttFile) then
+    ShellExecute(Application.Handle,'open',PChar(DisplayPath+AttFile),nil,nil,SW_SHOW)
+  else
+    Showmessage(Format(_Msg('找不到檔案:%s'),[AttFile]));
+end;
+
+procedure TCB_IMGPSScanX.BtnMouseEnter(Sender: TObject);
+begin
+  AddToolTip(TBitBtn(Sender).Handle,nil,0,Pchar(TBitBtn(Sender).Hint),nil,0,0);
+end;
+
+procedure TCB_IMGPSScanX.Button3Click(Sender: TObject);
+begin
+  //Showmessage(CreateDocNo_Info(NowCaseNo)+#13+'******'+#13+CreateCustDocNo_Info(NowCaseNo));
+  //Showmessage(NowSelectFileList.Text);
+  //SetIn_WH_DocNo;
+  //CreateIn_WH(self.NowCaseno);
+  //Create_Cust_DocDir(NowCaseNo);
+  //Showmessage(self.GetDocNoDir(self.DisplayPath,'111'));
+  //Case2upload(NowCaseNo);
+  //mkdir(DisplayPath+'Test\');
+  //Download2Case(DisplayPath+'Upload\',DisplayPath+'Test\');
+  //CreateFormID_FormName(DisplayPath);  //產生FormID_FormName.dat
+  //CreateDocNo_DocName(DisplayPath); //產生DocNo_Name.dat
+  //Showmessage(CreateDocNo_Info(DisplayPath));  //產生 Docno,份數,頁數;Docno,份數,頁數 的回傳字串
+  //lb1.Caption:='AAAAAAAAAAA';
+  //Showmessage(CreateDocnoFrom_Info(NowCaseno));
+  //Showmessage(self.CreateCustDocNoFrom_Info(NowCaseno));
+  //ShowMessage('FMaxUploadSize='+FMaxUploadSize);
+        //initkscan;
+	showmessage('FUrl='+FUrl+#10#13+
+	'FCaseID='+FCaseID+#10#13+
+	'FMode='+FMode+#10#13+
+	'FModeName='+FModeName+#10#13+
+	'FWork_no='+FWork_no+#10#13+
+	'FUserID='+FUserID+#10#13+
+	'FUserName='+FUserName+#10#13+
+	'FUserUnit='+FUserUnit+#10#13+
+	'FData='+FData+#10#13+
+	'FVerify='+FVerify+#10#13+
+	'FReWrite='+FReWrite+#10#13+
+	'FLanguage='+FLanguage+#10#13+
+	'FLoanDoc_Value='+FLoanDoc_Value+#10#13+
+	'FLoanDoc_Enable='+FLoanDoc_Enable+#10#13+
+	'FUseProxy='+FUseProxy+#10#13+
+	'FC_DocNoList='+FC_DocNoList+#10#13+
+	'FC_DocNameList='+FC_DocNameList+#10#13+
+	'FFixFileList='+FFixFileList+#10#13+
+	'FIs_In_Wh='+FIs_In_Wh+#10#13+
+	'FOldCaseInfo='+FOldCaseInfo+#10#13+
+	'FPrintyn='+FPrintyn+#10#13+
+	'FIs_OldCase='+FIs_OldCase+#10#13+
+	'FCustDocYN='+FCustDocYN);
+  ShowMessage('FImgDPI='+IntToStr(FImgDPI)+#10#13+
+    'FScanColor='+    IntToStr(FScanColor)+#10#13+
+    'FFileSizeLimit='+  IntToStr(FFileSizeLimit)  +#10#13+
+    'FCaseNoLength='+ IntToStr(FCaseNoLength)   +#10#13+
+    'FImgDelete='+    FImgDelete+#10#13+
+    'FIsExternal='+    FIsExternal+#10#13+
+    'FWH_category='+FWH_category+
+    'FCheck_main_form='+    FCheck_main_form+#10#13+
+    'FMaxUploadSize='+FMaxUploadSize);
+    //FImgDelete:='Y';
+  LoadImgFile;
+ { ShowMessage('UpLPoint='+IntToStr(UpLPoint.X)+','+IntToStr(UpLPoint.Y)+#10#13+
+    'UpRPoint='+IntToStr(UpRPoint.X)+','+IntToStr(UpRPoint.Y)+#10#13+
+    'DownLPoint='+IntToStr(DownLPoint.X)+','+IntToStr(DownLPoint.Y)+#10#13+
+    'DownRPoint='+IntToStr(DownRPoint.X)+','+IntToStr(DownRPoint.Y));
+  }
+end;
+
+procedure TCB_IMGPSScanX.Button4Click(Sender: TObject);
+var
+  i:integer;
+  str:String;
+begin
+  //Showmessage(self.Doc_Inf_List.Text);
+  //LoadImgFile;
+  //LoadImgFile1;
+  //ISB1.MouseMode:=mmAmplifier;
+
+  str:='';
+  for I := 1 to 11 do // 看 OMRErrInfo 的內容
+  begin
+  str:=str+BoolToStr(OMRErrInfo[i].Display,true)+','
+          +BoolToStr(OMRErrInfo[i].Ignore,true)+','+OMRErrInfo[i].Info+','
+          +OMRErrInfo[i].Mode+#10#13;
+  end;
+  ShowMessage('OMRErrInfo='+str);
+  ShowMessage('Doc_Inf_List='+Doc_Inf_List.Text);
+  ShowMessage('DM_FORM_INF_List='+DM_FORM_INF_List.Text) ;
+  ShowMessage('FORM_INF_List='+FORM_INF_List.Text)       ;
+  ShowMessage('CHECK_RULE_INF_List='+CHECK_RULE_INF_List.Text)  ;
+  ShowMessage('MEMO_INF_List='+MEMO_INF_List.Text)         ;
+  ShowMessage('WORK_INF_List='+WORK_INF_List.Text)          ;
+  ShowMessage('LASTEST_FORM_INF_List='+LASTEST_FORM_INF_List.Text)   ;
+  ShowMessage('SampleFormIDList='+SampleFormIDList.Text);
+  ShowMessage('ExistImgList='+ExistImgList.Text);
+  ShowMessage('LastInitFormidList='+LastInitFormidList.Text);
+  ShowMessage('IN_WH_DocNoList='+IN_WH_DocNoList.Text);
+
+//  SampleFormIDList.Add('31A00101011706A');
+//  SampleFormIDList.Add('31A00101021706A');
+//  SampleFormIDList.Add('31A00101031706A');
+end;
+
+procedure TCB_IMGPSScanX.Button5Click(Sender: TObject);
+begin
+  GetftpInfo(NowCaseno,'upload');
+  SetFtpInfo;
+  IIS_Ftp.FtpsConnect;
+
+  IIS_Ftp.FtpsToMain(FFtpExtraPath,NowCaseno+'.pdf','d:\1.pdf',display1);
+end;
+
+procedure TCB_IMGPSScanX.Button6Click(Sender: TObject);
+begin
+  GetftpInfo(NowCaseno,'download');
+  SetFtpInfo;
+  IIS_Ftp.FtpsConnect;
+  IIS_Ftp.FtpsCWD(IIS_Ftp.FtpPath);
+  IIS_Ftp.FtpsReceive(NowCaseNo+'.zip','d:\'+NowCaseNo+'.zip');
+
+
+end;
+
+procedure TCB_IMGPSScanX.ExportBtClick(Sender: TObject);
+var
+  SendData : String;
+  EnCodeDateTime : String;
+  S : TStringlist;
+  SFileName,VFileName : String;
+begin
+  SFileName := En_DecryptionStr_Base64('E','MPSLIC_SCAN.lic','9338430');
+  VFileName := En_DecryptionStr_Base64('E','MPSLIC_VIEW.lic','9338430');
+  IIS_File2Web.S_LicEnName := SFileName;
+  IIS_File2Web.V_LicEnName := VFileName;
+
+  /////下載MPSLIC_SCAN.lic //////
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+
+
+  //SendData := 'checktime='+EnCodeDateTime+'&workno=CW&formid=MPSLIC_SCAN.lic'+'&mode=sample';
+  //if not dnFile(HTTPSClient,Furl,'servlet/CWC03',SendData,LngPath+SFileName,FReWrite,Memo1,False,DownImgStatus) then
+  SendData:='data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&work_no=PLN&file=MPSLIC_SCAN.lic';
+  if not dnFile_Get(HTTPSClient,Furl,'service/imgpsc/IMGPSC04/sample',SendData,LngPath+SFileName,FReWrite,Memo1,False,DownImgStatus) then
+  begin
+    Showmessage(_Msg('檢查註冊檔案時,網路發生錯誤!!')+_Msg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason);
+    Exit;
+  end;
+  /////下載MPSLIC_SCAN.lic /////
+
+  /////下載MPSLIC_VIEW.lic //////
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  //SendData := 'checktime='+EnCodeDateTime+'&workno=CW&formid=MPSLIC_VIEW.lic'+'&mode=sample';  //這裡改成必傳CW 20121212
+  //if not dnFile(HTTPSClient,Furl,'service/slic/SLIC04/sample',SendData,LngPath+VFileName,FReWrite,Memo1,False,DownImgStatus) then
+  SendData:='data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&work_no=PLN&file=MPSLIC_VIEW.lic';
+  if not dnFile_Get(HTTPSClient,Furl,'service/imgpsc/IMGPSC04/sample',SendData,LngPath+VFileName,FReWrite,Memo1,False,DownImgStatus) then
+  begin
+    Showmessage(_Msg('檢查註冊檔案時,網路發生錯誤!!')+_Msg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason);
+    Exit;
+  end;
+  /////下載MPSLIC_VIEW.lic /////
+
+  ////壓zip/////
+  S := TStringlist.Create;
+  try
+    S.Add(En_DecryptionStr_Base64('E',GetDate,'9338430'));
+    S.Add(SFileName);
+    S.Add(VFileName);
+    S.SaveToFile(LngPath+'mps.dat');
+    S.Clear;
+    S.Add(LngPath+'mps.dat');
+    S.Add(LngPath+SFileName);
+    S.Add(LngPath+VFileName);
+    if FileExists(LngPath+'mps.zip') then
+      DeleteFile(LngPath+'mps.zip');
+    ExecuteZip_Pwd(LngPath+'mps.zip',LngPath,S,False,False,'9338430');
+
+  finally
+  S.Free;
+  DeleteFile(LngPath+SFileName);
+  DeleteFile(LngPath+VFileName);
+  DeleteFile(LngPath+'mps.dat');
+  end;
+  ////壓zip//////
+  Showmessage(_Msg('匯出完成,匯出檔案:')+LngPath+'mps.zip');
+end;
+
+procedure TCB_IMGPSScanX.ImportBtClick(Sender: TObject);
+var
+  SendData : String;
+  EnCodeDateTime : String;
+  S : TStringlist;
+  SFileName,VFileName : String;
+  OpenDialog1 : TOpenDialog;
+  ZipPath : String;
+  ZipFile,ZipName : String;
+  LicName : String;
+  i : Integer;
+begin
+  OpenDialog1 := TOpenDialog.Create(self);
+  S := TStringlist.Create;
+  try
+    OpenDialog1.Filter := 'Zip files (*.zip)|*.ZIP';
+    if OpenDialog1.Execute then
+    begin
+      ZipFile:= ExtractFileName(OpenDialog1.FileName);
+      ZipName := Copy(ZipFile,1,length(ZipFile)-length(ExtractFileExt(OpenDialog1.FileName)));
+      ZipPath := LngPath+ZipName+'\';
+
+      str2dir(ZipPath);
+      if not ExecuteUnZip_Pwd(OpenDialog1.FileName,ZipPath,False,'9338430') then
+        Showmessage(_Msg('無法解壓縮'));
+      if not FileExists(ZipPath+'mps.dat') then
+      begin
+        Showmessage(_Msg('格式不符,無法匯入'));
+        Exit;
+      end;
+      S.LoadFromFile(ZipPath+'mps.dat');
+      if (En_DecryptionStr_Base64('D',S.Strings[0],'9338430')<> ServerDate) then
+      begin
+        Showmessage(_Msg('檔案過期,無法匯入'));
+        Exit;
+      end;
+
+      for i := 1 to S.Count -1 do
+      begin
+        LicName := En_DecryptionStr_Base64('D',S.Strings[i],'9338430');
+        RenameFile(ZipPath+S.Strings[i],ZipPath+LicName);
+        if (LicName = 'MPSLIC_SCAN.lic') or (LicName = 'MPSLIC_VIEW.lic') then
+
+        /////上傳MPSLICXXXX.lic ////
+        //if not upFile(HTTPSClient,FUrl,'servlet/CWC04','formid='+LicName+'@workno=CW@mode=sample','file',ZipPath+LicName,FReWrite,Memo1,False) then
+        //begin
+        SendData := 'data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&work_no=PLN&file_name='+LicName;
+        if not upFile(HTTPSClient,FUrl,'service/imgpsc/IMGPSC02/sample',SendData,'file',ZipPath+LicName,FReWrite,Memo1,False) then
+        begin
+          Showmessage(_Msg('檢查註冊時,網路發生錯誤!!')+_MSg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+')');
+          DataLoading(False,False);
+          Exit;
+        end;
+        if memo1.Lines.Strings[0] = '1' then
+        begin
+          Showmessage(_Msg('檢查註冊時,網路發生錯誤!!')+_Msg('錯誤原因:')+memo1.Lines.Strings[1]);
+          DataLoading(False,False);
+          Exit;
+        end
+        Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+        begin
+          Showmessage(_Msg('檢查註冊時,網路發生錯誤!!')+_Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入'));
+          DataLoading(False,False);
+          Exit;
+        end;
+        /////上傳MPSLICXXXX.lic /////
+      end;
+    end;
+  Finally
+  OpenDialog1.Free;
+  S.Free;
+  _DelTree(ZipPath);
+  end;
+  Showmessage(_Msg('匯入完成'));
+end;
+
+procedure TCB_IMGPSScanX.HotKeyDown (var Msg : TMessage);
+begin
+
+end;
+
+Function TCB_IMGPSScanX.FindISB2View(Vmode:Integer):TImageScrollBox; //找空的ISB來顯示
+var
+  i,n : Integer;
+  ISB : TImageScrollBox;
+begin
+  case Vmode of
+    0 : n := 1;
+    1 : n := 2;
+    2 : n := 4;
+    3 : n := 6;
+    4 : n := 8;
+  end;
+  for i := 1 to 8 do
+  begin
+    if i > n then Break;
+    ISB := TImageScrollBox(FindComponent('ISB'+inttostr(i)));
+    if (i = n) and (ISB.FileName <> '') then
+    begin
+      clearView(i);
+      Result := ISB1;
+    end
+    Else if ISB.FileName = '' then
+      Result := ISB;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ViewMouseMode(v:Integer);
+var
+  i : Integer;
+  Md : TMouseMode;
+  ISB : TImageScrollBox;
+begin
+//ShowMessage(IntToStr(v));
+  case v of
+   -1 : Md := TMouseMode(mmUser);
+    0 : Md := TMouseMode(mmAmplifier);
+    1 : Md := TMouseMode(mmZoom);
+    2 : Md := TMouseMode(mmDrag);
+    3 : Md := TMouseMode(mmR270);
+    4 : Md := TMouseMode(mmR180);
+    5 : Md := TMouseMode(mmR90);
+    6 : Md := TMouseMode(mmDelete);
+  end;
+  for i := 1 to 8 do
+  begin
+    ISB := TImageScrollBox(FindComponent('ISB'+inttostr(i)));
+    ISB.MouseMode := TMouseMode(Md);
+    //Label3.Caption:='v='+IntToStr(v)+'  time'+FormatDateTime('yyyy/mm/dd HH:MM:SS', now);
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.GoViewMode;
+begin
+  case VMode of
+    0: DisplayMode(VMode,1,1,Panel9);
+    1: DisplayMode(VMode,1,1,Panel9);
+    2: DisplayMode(VMode,2,2,Panel9);
+    3: DisplayMode(VMode,2,3,Panel9);
+    4: DisplayMode(VMode,2,4,Panel9);
+  end;
+end;
+
+
+Procedure TCB_IMGPSScanX.SetFormID_DocNo; //將FormID及Docno抽出來另存入list裡    20130403增加
+var
+  i : Integer;
+begin
+  for i := 1 to FORM_INF_List.Count-1 do
+  begin
+    FormID_List.Add(GetSQLData(FORM_INF_List,'T1.FORM_ID',i));
+    DocNo_List.Add(GetSQLData(FORM_INF_List,'T1.DOC_NO',i));
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.DeleteFormCodeFile(CaseID,DocDir,FormID:String);  //刪除指定FormID文件
+var
+  i: Integer;
+  FileList : TStringlist;
+begin
+  FileList := TStringlist.Create;
+  try
+    FileList.Clear;
+    if FileExists(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat') then
+      FileList.LoadFromFile(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat');
+
+    for i := FileList.Count - 1 downto 0 do
+    begin
+      if FileName2FormCode(FileList.Strings[i]) = FormID then
+      begin
+        if (FMode = 'ESCAN') and (FModeName<>_Msg('異動件')) then
+        begin
+          if ISExistImg(ImageSavePath+CaseID+'\'+DocDir+'\'+FileList.Strings[i]) then
+          begin
+            //ShowMessage('有圖為非當次掃瞄,不可刪除');
+            Break;
+          end;
+        end;
+//ShowMessage(FileList.Strings[i]);
+        DeleteImageFile(ImageSavePath+CaseID+'\'+DocDir+'\',FileList.Strings[i],CaseID);
+      end;
+    end;
+  finally
+  FileList.Free;
+  end;
+  ReSortFileName(ImageSavePath+CaseID+'\'+DocDir+'\');
+  {for i := ContextList.Count - 1 downto 0 do
+  begin
+    FName := ContextList.Strings[i];
+    if FormID = 'Err' then  //刪未註冊文件
+    begin
+      If not FormIDExists(FileName2FormCode(FName),False,0) Then
+      begin
+        DeleteFile(Path+FName);
+        ContextList.Delete(i);
+      end;
+    end
+    Else
+    begin
+      If FormID = FileName2FormCode(FName) then
+      begin
+        DeleteFile(Path+FName);
+        ContextList.Delete(i);
+      end;
+    end;
+  end;
+  ContextList.SaveToFile(Path+'Context.dat');
+  ReSortFileName(Path); }
+end;
+
+Function TCB_IMGPSScanX.FindFormCodePages(CaseID,FormCode:String):Integer;  //計算案件裡FormID的頁數
+var
+  i,Count : integer;
+  S : TStringlist;
+  iFormCode : String;
+begin
+  Count := 0;
+  S := TStringlist.Create;
+  try
+    S.LoadFromFile(ImageSavePath+CaseID+'\upload\Context.dat');
+    for i := 0 to S.Count - 1 do
+    begin
+      if FWH_category='N' then
+      begin
+        if ISExistImg(ImageSavePath+CaseID+'\upload\'+S.Strings[i]) then
+        begin
+          Continue;
+        end;
+      end;
+      iFormCode := FileName2FormCode(S.Strings[i]);
+      if FormCode = iFormCode then
+      begin
+        Inc(Count);
+      end;
+    end;
+  finally
+  S.Free;
+  end;
+  Result := Count;
+end;
+
+Function TCB_IMGPSScanX.GetDataFormCodePages(FormCode:String):Integer;   //取記錄的FormcID的頁數
+begin
+  If FindSQLData(FORM_INF_List,'T1.MAX_PAGE','T1.FORM_ID',FormCode,0,FindResult) Then
+  begin
+    IF GetFindResult('T1.MAX_PAGE') = '' Then
+      Result := 9999
+    Else
+      Result := Strtoint(GetFindResult('T1.MAX_PAGE'));
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.CaseReSize(CaseID:String); //案件的影像縮放
+var
+  S : TStringlist;
+  FileName : String;
+  i : Integer;
+begin
+  {if FileExists(ImageSavePath+CaseID+'\ReSize.dat') then
+    DeleteFile(ImageSavePath+CaseID+'\ReSize.dat');}
+  if FileExists(ImageSavePath+CaseID+'\Upload\AnchorError.dat') then
+    DeleteFile(ImageSavePath+CaseID+'\Upload\AnchorError.dat');
+  S := TStringlist.Create;
+  try
+    S.LoadFromFile(ImageSavePath+CaseID+'\Upload\Context.dat');
+    For i := 0 to S.Count -1 do
+    begin
+      FileName := S.Strings[i];
+      ImageReSize_FormID(CaseID,FileName);  //依十字定位點做縮放
+    end;
+  finally
+  S.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ImageReSize_FormID(CaseID,FileName:String);  //依十字定位點做縮放
+var
+  FormID : String;
+  DH,DW : String;
+  NowW,NowH : Integer;
+  ANCHOR : String; //是否有十字線
+  SizeStr : String;
+  S : TStringlist;
+  v,v1:Integer;
+  IsRecordMD5:Boolean;
+begin
+  IsRecordMD5:=False;
+  FormID := FileName2FormCode(FileName);
+  if FormID = '' then Exit;
+
+  IF FindSQLData(FORM_INF_List,'T1.FORM_HEIGHT,T1.FORM_WIDTH,T1.ANCHOR','T1.FORM_ID',FormID,0,FindResult) then
+  begin
+    DH := GetFindResult('T1.FORM_HEIGHT');
+    DW := GetFindResult('T1.FORM_WIDTH');
+    ANCHOR := UpperCase(GetFindResult('T1.ANCHOR'));
+    ANCHOR := Index2Anchor(ANCHOR);
+Display1.Lines.Add(FormID+','+DH+','+DW);
+//ShowMessage('AAAAAAAAA');
+    if ((ANCHOR = 'ANCHOR') or (ANCHOR = 'FRAME')) and (DH <> '') and (DW <> '') then  //有十字定位點
+    begin
+//ShowMessage('BBBBBBB');
+      ImageScrollBox1.LoadFromFile(ImageSavePath+CaseID+'\Upload\'+FileName,1);
+
+      if (FWH_category='N') and  ISExistImg(ImageSavePath+CaseID+'\Upload\'+FileName) then
+      begin
+        Exit;//20171103  補件  原有的圖不作resize
+      end;
+
+      //FindPoint(ImageScrollBox1.Graphic,UpLPoint,UpRPoint,DownLPoint,NowW,NowH);
+      FindPoint(ISB_BW.Graphic,UpLPoint,UpRPoint,DownLPoint,NowW,NowH,ANCHOR);
+
+      SizeStr := CheckSize(ISB_BW,UpLPoint,UpRPoint,DownLPoint,DW,DH);
+      ImageResize(ImageScrollBox1.Graphic,ISB_BW.Graphic.Width,ISB_BW.Graphic.Height);
+
+      FindPoint(ISB_BW.Graphic,UpLPoint,UpRPoint,DownLPoint,NowW,NowH,ANCHOR);
+      v := 5;
+      v1 := length(SizeStr);
+      IF (SizeStr <> '') and (Copy(SizeStr,1,v) <> 'ERROR') then
+      begin
+//ShowMessage('CCCCC');
+        if (ISExistImg(ImageSavePath+CaseID+'\Upload\'+FileName)) and (reSizeExistImgList.IndexOf(LoadFileGetMD5(ImageSavePath+CaseID+'\Upload\'+FileName))=-1) then
+        begin
+          IsRecordMD5:=True;
+        end;
+        ImageScrollBox1.SaveToFile(ImageSavePath+CaseID+'\Upload\'+FileName);
+        if IsRecordMD5 then
+        begin
+          reSizeExistImgList.add(LoadFileGetMD5(ImageSavePath+CaseID+'\Upload\'+FileName));
+        end;
+//showmessage(ImageSavePath+CaseID+'\Upload\'+FileName);
+        S := TStringlist.Create;                     ///20110422拿掉 換成上傳才做
+        if FileExists(ImageSavePath+CaseID+'\Upload\ReSize.dat') then
+          S.LoadFromFile(ImageSavePath+CaseID+'\Upload\ReSize.dat');
+        //S.Add(FormCode2FormName(FormID)+' '+SizeStr);
+        S.Add(FileName+','+SizeStr+#8+DateTimetoStr(Now));
+        S.SaveToFile(ImageSavePath+CaseID+'\Upload\ReSize.dat');
+        S.Free;
+      end;
+      if (Copy(SizeStr,1,v) = 'ERROR') then   //未找到三個定位點
+      begin
+        S := TStringlist.Create;
+        if FileExists(ImageSavePath+CaseID+'\Upload\AnchorError.dat') then
+          S.LoadFromFile(ImageSavePath+CaseID+'\Upload\AnchorError.dat');
+        S.Add(FileName+'-->'+Copy(SizeStr,V+1,V1-v));
+        S.SaveToFile(ImageSavePath+CaseID+'\Upload\AnchorError.dat');
+        S.Free;
+      end;
+
+      ImageScrollBox1.FileName := '';
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ImageReSize_tmp(FormID,FileName:String);  //依十字定位點做縮放(暫存檔)
+var
+  DH,DW : String;
+  ANCHOR : String; //是否有十字線
+  SizeStr : String;
+  S : TStringlist;
+begin
+  IF FindSQLData(FORM_INF_List,'T1.FORM_HEIGHT,T1.FORM_WIDTH,T1.ANCHOR','T1.FORM_ID',FormID,0,FindResult) then
+  begin
+    DH := GetFindResult('T1.FORM_HEIGHT');
+    DW := GetFindResult('T1.FORM_WIDTH');
+    ANCHOR := UpperCase(GetFindResult('T1.ANCHOR'));
+    ANCHOR := Index2Anchor(ANCHOR);
+    if ((ANCHOR = 'ANCHOR') or (ANCHOR = 'FRAME')) and (DH <> '') and (DW <> '') then  //有十字定位點
+    begin
+      ImageScrollBox1.LoadFromFile(FileName,1);
+      SizeStr := CheckSize(ImageScrollBox1,UpLPoint,UpRPoint,DownLPoint,DW,DH);
+      IF SizeStr <> '' then
+      begin
+        ImageScrollBox1.SaveToFile(FileName);
+      end;
+      ImageScrollBox1.FileName := '';
+    end;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.ImageScrollBox1NewGraphic(const Graphic: TDibGraphic);
+begin
+  IF ImageScrollBox1.Graphic.Empty Then Exit;
+  ISB_BW.Graphic.Assign(ImageScrollBox1.Graphic);
+  If ImageScrollBox1.Graphic.ImageFormat <> ifBlackWhite Then
+  begin
+    ConvertToBW(ISB_BW.Graphic);
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.NewTreeNodeRefresh;
+var
+  v : Integer;
+begin
+  //v := Pos('-',NewTreeNode.Text);
+  //NewTreeNode.Text := Copy(NewTreeNode.Text,1,v-1)+'-共'+inttostr(NewTreeNode.Count)+'筆';
+  GetCase_PageCount(CaseCount,PageCount);
+  v := Pos('-',NewTreeNode.Text);
+  NewTreeNode.Text := Format(_Msg('%s-共%d筆共%d頁'),[Copy(NewTreeNode.Text,1,v-1),CaseCount,PageCount]);
+end;
+
+Procedure TCB_IMGPSScanX.MyTreeNode1Refresh;
+var
+  v : Integer;
+begin
+  v := Pos('-',MyTreeNode1.Text);
+  MyTreeNode1.Text := Format(_Msg('%s-%d筆'),[Copy(MyTreeNode1.Text,1,v-1),MyTreeNode1.Count]);
+end;
+
+Procedure TCB_IMGPSScanX.MyTreeNode2ReFresh(CaseID:String);
+var
+  P : Integer;
+begin
+  //p:= ContextList.Count;
+  //MytreeNode1.Text := Format(_Msg('%s-%d頁'),[CaseID,p]);
+  DrawDocItem2(MytreeNode1,CaseID);
+  //DrawDocItem(MytreeNode1,FORM_INF_List,CaseID);
+end;
+
+Procedure TCB_IMGPSScanX.MyTreeNode3ReFresh(CaseID:String);
+begin
+
+  //DrawDocItem1(MytreeNode1,Doc_Inf_List,CaseID);  //201408280改
+  DrawDocItem2(MytreeNode1,CaseID);
+  //DrawDocItem(MytreeNode1,FORM_INF_List,CaseID);
+end;
+
+Function TCB_IMGPSScanX.Node2DocNo(Node2:TTreeNode):String;  //MyTreeNode2取DocNo出來
+var
+  v,v1,v2 : Integer;
+begin
+  v := Posend('{',Node2.Text);
+  v1 := Posend('}',Node2.Text);
+  v2 := Posend('-',Node2.Text);
+  Result := Copy(Node2.Text,v+1,v1-v-1);
+  IF v1 = 0 Then
+  begin
+    Result := '';
+  end;
+end;
+
+Function TCB_IMGPSScanX.Node3DocNo(Node3:TTreeNode):String;  //MyTreeNode3取DocNo出來
+var
+  v,v1,v2 : Integer;
+begin
+  v := Posend('{',Node3.Parent.Text);
+  v1 := Posend('}',Node3.Parent.Text);
+  v2 := Posend('-',Node3.Parent.Text);
+  Result := Copy(Node3.Parent.Text,v+1,v1-v-1);
+  IF v1 = 0 Then
+  begin
+    Result := '';
+  end;
+end;
+
+Function TCB_IMGPSScanX.Node3FormID(Node3:TTreeNode):String;  //MyTreeNode3取FormCode出來
+var
+  v,v1,v2 : Integer;
+begin
+  v := Pos('{',Node3.Text);
+  v1 := Pos('}',Node3.Text);
+  v2 := Posend('-',Node3.Text);
+  Result := Copy(Node3.Text,v+1,v1-v-1);
+  IF v1 = 0 Then
+  begin
+    Result := '';
+  end;
+end;
+
+
+Function TCB_IMGPSScanX.GetNode2Name(Node2:TTreeNode):String;  //取MyTreeNode2的識別字出來(記之前點選用)
+var
+  v : Integer;
+begin
+  v := Posend('-',Node2.Text);
+  Result := Copy(Node2.Text,1,v-1);
+end;
+
+{Function TCB_IMGPSScanX.Down_Replace_Img(SPath,DPath,CaseID:String):Boolean;
+var
+  EnCodeDateTime : String;
+  DownUrl : String;
+  SC,Main_C : TStringlist;
+  i,n : Integer;
+  FormID,DocNo,Version : String;
+  OldFName,NewMainFName,NewSubFName : String;
+  AttPath : String;
+begin
+  SC := TStringlist.Create;
+  Main_C := TStringlist.Create;
+  try
+    Result := True;
+    HaveAppDoc := False;
+    EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+    DownUrl := FUrl+CaseID+'&checktime='+EnCodeDateTime;
+    if not dnFile(HTTPSClient,DownUrl,'','',DPath+CaseID+'.zip',FReWrite,Memo1,False,DownImgStatus) then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+    if Memo1.Lines.Strings[0] = '1' then
+    begin
+      HttpErrStr :=_Msg('錯誤原因:')+memo1.Lines.Strings[1];
+      Result := False;
+      Exit;
+    end
+    Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+    begin
+      HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+      Result := False;
+      Exit;
+    end;
+    AttPath := DPath + 'AttFile\';
+    if FileExists(DPath+CaseID+'.zip') then
+    begin
+      ExecuteUnZip(DPath+CaseID+'.zip',DPath,True);
+      if FileExists(DPath+'img.zip') then
+      begin
+        ExecuteUnZip(DPath+'img.zip',DPath,False);
+      end;
+      if FileExists(DPath+'att.zip') then
+      begin
+        Str2Dir(AttPath);
+        ExecuteUnZip(DPath+'att.zip',AttPath,False);
+      end;
+    end
+    Else
+    begin
+      if ((FMode = 'FSCAN') or (FMode = 'ISCAN')) and (Memo1.Lines.Strings[0] ='NO_FILE') then  //FGIS前台匯入件沒有影像是對的
+      begin
+        SC.Clear;
+        SC.SaveToFile(DPath+'Context.dat');
+      end
+      Else
+      begin
+        HttpErrStr := _Msg('找不到影像');
+        Result := False;
+        Exit;
+      end;
+    end;
+
+
+    if FileExists(SPath+'Context.dat') then
+      SC.LoadFromFile(SPath+'Context.dat');
+    for I := 0 to SC.Count - 1 do
+    begin
+      FormID := FileName2FormCode(SC.Strings[i]);
+      DocNo := FormCode2DocNo(FormID);
+      Version := FormCode2Version(FormID);
+      If FindSQLData(Doc_Inf_List,'ADD_SCAN_RULE','DOC_NO,DOC_VERSION',DocNo+','+Version,0,FindResult) Then
+      begin
+        if GetFindResult('ADD_SCAN_RULE') = 'R' then  //替換的先刪再加  20101026 User由刪FormCode改刪DocNo
+        begin
+          //DeleteFormCodeFile(DPath,FormID);
+          ContextList.LoadFromFile(DPath+'Context.dat');
+          DeleteDocNoFile(DPath,DocNo);
+        end;
+      end;
+    end;
+    for I := 0 to SC.Count - 1 do   //複製補充進來的影像
+    begin
+      OldFName := SC.Strings[i];
+      Main_C.LoadFromFile(DPath+'Context.dat');
+      //NewMainFName:= Add_Zoo(Main_C.Count+1,3)+Copy(OldFName,4,length(OldFName)-3);
+      NewMainFName:= Add_Zoo(Main_C.Count+1,3)+FileName2NoQuene_Filename(OldFName);
+      FormID := FileName2FormCode(OldFName);
+      DocNo := FormCode2DocNo(FormID);
+      Version := FormCode2Version(FormID);
+      If FindSQLData(Doc_Inf_List,'ADD_SCAN_RULE','DOC_NO,DOC_VERSION',DocNo+','+Version,0,FindResult) Then
+      begin
+        CopyFile(PWideChar(SPath+OldFName),PWideChar(DPath+NewMainFName),False);
+      end;
+      if FormID = '' then //附件
+      begin
+        CopyFile(PWideChar(SPath+OldFName),PWideChar(DPath+NewMainFName),False);
+      end;
+      Main_C.Add(NewMainFName);
+      Main_C.SaveToFile(DPath+'Context.dat');
+    end;
+  finally
+  SC.Free;
+  Main_C.Free;
+  end;
+  ///加入的電子檔匯入案件裡
+  if DirectoryExists(SPath+'AttFile\') then
+    AttFile_Arrange(SPath+'AttFile\',DPath+'AttFile\');
+end;}
+
+function TCB_IMGPSScanX.checkFormCodeIsCustom(path, formcode: string): boolean;
+var
+  i:integer;
+  ini : Tmeminifile;
+  str1:String;
+begin
+//ShowMessage(path);
+  ini := Tmeminifile.Create(Path+'CustomDocNo.ini');
+  str1:=ini.ReadString(Copy(formcode,1,8),'FormID','');
+//ShowMessage('str1'+str1);
+  if str1 = formcode then
+  begin
+    Result:=True;
+  end
+  else
+  begin
+    Result := False;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.InitScrollRec;
+var i : Integer;
+begin
+  for I := 1 to 8 do
+  begin
+    ScrollRec[i].HScroll := 0;
+    ScrollRec[i].VScroll := 0;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.GetScrollData(ISB:TImageScrollBox;Var HS,VS:Integer;Var iRate:Single);
+var
+  index : Integer;
+begin
+  index := strtoint(copy(ISB.Name,4,1));
+  HS := ScrollRec[Index].HScroll;
+  VS := ScrollRec[Index].VScroll;
+  iRate := ScrollRec[Index].Rate;
+end;
+
+Procedure TCB_IMGPSScanX.SetScrollData(ISB:TImageScrollBox;HS,VS:Integer;iRate:Single);
+var
+  index : Integer;
+begin
+  index := strtoint(copy(ISB.Name,4,1));
+  ScrollRec[Index].HScroll := HS;
+  ScrollRec[Index].VScroll := VS;
+  ScrollRec[Index].Rate := iRate;
+end;
+
+Procedure TCB_IMGPSScanX.FormIDReplace(CaseID,DocDir,OldFormID,NewFormID:String); //指定FormID更換成新的FormID
+var
+  i : Integer;
+  OldFileList,NewFileList : TStringlist;
+  NewDocNo,NewDocDir:String;
+  FormID : String;
+  OldFile,NewFile:String;
+  Ext : String;
+  ST1:TStringList;
+begin
+  ST1:=TStringList.Create;
+  OldFileList := TStringlist.Create;
+  NewFileList := TStringlist.Create;
+  try
+    NewDocNo := FormCode2DocNo(NewFormID);
+    NewDocDir := FindLastestDocDir(CaseID,NewDocNo);
+
+    /////20190319 Hong 原本的程式判斷怪怪的先Mark在下方,改用這段
+    if DocNoNeedDiv(NewDocNo) then   //要分份數
+    begin
+      if ((FormCode2Page(NewFormID) = '01') and (GetDocDir_Page(CaseID,NewDocDir)>0)) or (NewDocDir = '') then
+      begin
+        NewDocDir := DocNo2DocNoDir(ImageSavePath + CaseID+'\',NewDocNo);
+      end
+      else
+      begin //20171016  真對補件影響 所加的判斷
+        ST1.Clear;
+        if FileExists(ImageSavePath + CaseID+'\'+NewDocDir+'\Context.dat') then
+        begin
+          ST1.LoadFromFile(ImageSavePath + CaseID+'\'+NewDocDir+'\Context.dat');
+          if (ST1.Count > 0) and ISExistImg(ImageSavePath + CaseID+'\'+NewDocDir+'\'+ST1.Strings[0]) then   //20181210 多增加判斷ST1>0 否則會有機會出現List out of bound  Hong
+          begin
+            NewDocDir := DocNo2DocNoDir(ImageSavePath + CaseID+'\',NewDocNo);
+          end;
+        end;
+      end;
+    end
+    Else        //不分份數
+    begin
+      if NewDocNo <> '' then
+        NewDocDir := NewDocNo
+      else      //Attach 附件
+        NewDocDir := DocNo2DocNoDir(ImageSavePath + CaseID+'\',NewDocNo);
+    end;
+
+    {if NewDocDir = '' then
+    begin
+      if DocNoNeedDiv(NewDocNo) then
+      begin
+        NewDocDir:=DocNo2DocNoDir(ImageSavePath + NowCaseno+'\',NewDocNo);
+      end
+      else
+      begin
+        NewDocDir := NewDocNo;
+      end;
+    end;
+//ShowMessage('NewDocDir='+NewDocDir);
+    if DocNoNeedDiv(NewDocNo) and (FormCode2Page(NewFormID)='01') then
+    begin
+      NewDocDir := DocNo2DocNoDir(ImageSavePath+CaseID+'\',NewDocNo);
+    end
+    else
+    begin
+      ST1.Clear;
+      if FileExists(ImageSavePath + NowCaseno+'\'+NewDocDir+'\Context.dat') then
+      begin
+        ST1.LoadFromFile(ImageSavePath + NowCaseno+'\'+NewDocDir+'\Context.dat');
+        if ISExistImg(ImageSavePath + NowCaseno+'\'+NewDocDir+'\'+ST1.Strings[0]) then
+        begin
+          NewDocDir := DocNo2DocNoDir(ImageSavePath + NowCaseno+'\',NewDocNo);
+        end;
+      end;
+    end; }
+    if Not DirectoryExists(ImageSavePath+CaseID+'\'+NewDocDir) then
+    begin
+      MkDir(ImageSavePath+CaseID+'\'+NewDocDir);
+      SetDocNoList('A',-1,CaseID,NewDocDir,'1');
+    end;
+    if FileExists(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat') then
+      OldFileList.LoadFromFile(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat');
+    if FileExists(ImageSavePath+CaseID+'\'+NewDocDir+'\Context.dat') then
+      NewFileList.LoadFromFile(ImageSavePath+CaseID+'\'+NewDocDir+'\Context.dat');
+    for i := 0 to OldFileList.Count - 1 do
+    begin
+      OldFile := OldFileList.Strings[i];
+      Ext := ExtractFileExt(OldFile);
+      if FileName2FormCode(OldFile) = OldFormID then
+      begin
+        NewFile := Add_Zoo(NewFileList.Count+1,3)+'_'+NewFormID+Ext;
+        CopyFile(PWideChar(ImageSavePath+CaseID+'\'+DocDir+'\'+OldFile),PWideChar(ImageSavePath+CaseID+'\'+NewDocDir+'\'+NewFile),False);
+        NewFileList.Add(NewFile);
+        SetContextList('A',-1,CaseID,NewDocDir,NewFile);
+      end;
+    end;
+    DeleteFormCodeFile(CaseID,DocDir,OldFormID);
+
+    {for i := 0 to S.Count - 1 do
+    begin
+      FormID := FileName2FormCode(S.Strings[i]);
+      if FormID = OldFormID then
+      begin
+        OldFile := S.Strings[i];
+        Ext := ExtractFileExt(OldFile);
+        //NewFile := Copy(S.Strings[i],1,3)+'_'+NewFormID+Ext;
+        NewFile := Add_Zoo(FileName2ScanPage(S.Strings[i]),3)+'_'+NewFormID+Ext;
+        ReNameFile(Path+OldFile,Path+NewFile);
+        S.Strings[i] := NewFile;
+      end;
+    end;
+    S.SaveToFile(Path+'Context.dat');
+    ContextList.LoadFromFile(Path+'Context.dat'); }
+
+  finally
+  OldFileList.Free;
+  NewFileList.Free;
+  ST1.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.PageReplaceFormID(Path,NowFormID,NewFormID:String); //選取頁更換FormID
+var
+  i,n : Integer;
+  S,S1 : TStringlist;
+  OldFile,NewFile:String;
+  Ext : String;
+begin
+  S := TStringlist.Create;
+  S1 := TStringlist.Create;
+  try
+    S.LoadFromFile(Path+'Context.dat');
+    for i := 0 to S.Count - 1 do
+    begin
+      if NowFormID = 'ALL' then
+        S1.Add(S.Strings[i])
+      Else if NowFormID = 'Err' then
+      begin
+        if not FormIDExists(FileName2FormCode(S.Strings[i]),False,0) then
+          S1.Add(S.Strings[i])
+      end
+      Else
+      begin
+        if NowFormID = FileName2FormCode(S.Strings[i]) then
+          S1.Add(S.Strings[i])
+      end;
+    end;
+    for I := 0 to PageLV.Items.Count - 1 do
+    begin
+      if PageLV.Items.Item[i].Selected then
+      begin
+        OldFile := S1.Strings[i];
+        Ext := ExtractFileExt(OldFile);
+        //NewFile := Copy(S1.Strings[i],1,3)+'_'+NewFormID+Ext;
+        NewFile := Add_Zoo(FileName2ScanPage(S1.Strings[i]),3)+'_'+NewFormID+Ext;
+        ReNameFile(Path+OldFile,Path+NewFile);
+        for n := 0 to S.Count - 1 do
+        begin
+          if OldFile = S.Strings[n] then
+            S.Strings[n] := NewFile;
+        end;
+      end;
+    end;
+    S.SaveToFile(Path+'Context.dat');
+    ContextList.LoadFromFile(Path+'Context.dat');
+  finally
+  S.Free;
+  S1.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetFormIDPage(FileList:TStringlist;FormID:String):Integer;
+var
+  i,Cnt : Integer;
+begin
+  Cnt := 0;
+  for i := 0 to FileList.Count - 1 do
+  begin
+    if FormID = FileName2FormCode(FileList.Strings[i]) then
+    begin
+      inc(Cnt);
+    end;
+  end;
+  Result := Cnt;
+end;
+
+Procedure TCB_IMGPSScanX.WriteResize(ImgName,TxtName:String); //產生Resize.dat
+var
+  TagTxt : String;
+  RecHeight,RecWidth : String;
+  ImgHeight,ImgWidth : String;
+  S : TStringlist;
+  v,v1:Integer;
+begin
+  ImageScrollBox1.LoadFromFile(ImgName,1);
+  ImgHeight := Inttostr(ImageScrollBox1.Graphic.Height);
+  ImgWidth := Inttostr(ImageScrollBox1.Graphic.Width);
+  Try
+    TagTxt := GetTag(ImgName);
+  Except
+    TagTxt := '';
+  End;
+  if TagTxt <> '' then
+  begin
+    S := TStringlist.Create;
+    try
+      S.CommaText := TagTxt;
+      if S.Count = 2 then
+      begin
+        v := Pos(':',S.Strings[0]);
+        v1 := length(S.Strings[0]);
+        RecHeight := Copy(S.Strings[0],v+1,v1-v);
+        v := Pos(':',S.Strings[1]);
+        v1 := length(S.Strings[1]);
+        RecWidth := Copy(S.Strings[1],v+1,v1-v);
+      end;
+      S.Clear;
+      if FileExists(TxtName) then
+        S.LoadFromFile(TxtName);
+      if (RecHeight <> '') and (RecWidth <> '') and ((RecHeight<>ImgHeight) or (RecWidth<>ImgWidth)) then
+        S.Add(ExtractfileName(ImgName)+',原長:'+RecHeight+',原寬:'+RecWidth+',長變動:'+ImgHeight+',寬變動:'+ImgWidth);
+      S.SaveToFile(TxtName);
+    finally
+    S.Free;
+    end;
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.BarCode2FormID : String; //Barcode依規則轉成FormID
+var
+  i : Integer;
+  FormID : String;
+begin
+  Result := ''; //沒找到
+  FormID := '';
+  for i := 1 to MpsBarcodeinf.Count  do
+  begin
+    if (Length(MpsBarcodeinf.Text[i]) = FormIDLength) then
+    begin
+      FormID := MpsBarcodeinf.text[i];
+      if not FormIDAppear(FormID) then
+        FormID := '';
+    end;
+    if (FormID <> '') and FormIDExists(FormID,False,0) then   //有可用的FormID就離開
+    begin
+      Result := FormID;
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckFormIDExists(DocNoNode:TTreeNode;FormID:String):Boolean; //檢查FormID是否存在文件裡
+var
+  i : Integer;
+begin
+  Result := False;
+  for i := 0 to DocNoNode.Count - 1 do
+  begin
+    if FormID = Node3FormID(DocNoNode.Item[i]) then
+    begin
+      Result := True;
+      break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FormID2Anchor(FormID:String):String;  //用FormID取出十字模式
+var
+  Anchor : String;
+begin
+  Result := 'NONE';
+  IF FindSQLData(FORM_INF_List,'T1.ANCHOR','T1.FORM_ID',FormID,0,FindResult) then
+  begin
+    ANCHOR := UpperCase(GetFindResult('T1.ANCHOR'));
+  end;
+  Result := Index2Anchor(Anchor);
+end;
+
+procedure TCB_IMGPSScanX.ScanDuplexCBClick(Sender: TObject);
+begin
+  ScanDuplex := ScanDuplexCB.Checked;
+  //R_W_ScanIni('W');       //user要求改成預設後不能改
+end;
+
+procedure TCB_IMGPSScanX.ScanGrayCBClick(Sender: TObject);
+begin
+
+  if ScanGrayCB.Checked then
+  begin
+    ScanColor:=ifGray256;
+  end
+  else
+  begin
+    if FScanColor = 0 then
+    begin
+      ScanColor := ifBlackWhite;
+    end;
+
+    if FScanColor = 1 then
+    begin
+      //ScanColor := ifGray256 ;
+      ScanColor := ifBlackWhite; //
+    end;
+
+
+    if FScanColor = 2 then
+    begin
+      ScanColor := ifTrueColor ;
+    end;
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.GetFormatID(CaseID: string):String;
+Var
+  S : TStringlist;
+  FormatID : String;
+begin
+  Result := '';
+  S := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseIndex.dat') then
+    begin
+      S.LoadFromFile(ImageSavePath+CaseID+'\CaseIndex.dat');
+      //Format_ID := S.Strings[5];    //主鍵值 (報價單號or續保單號or保單號碼or保險證號or原案件受編)
+      //Result := Format_ID;
+      //Handle_No := S.Strings[0];    //經辦代號
+      //Cen_Uid := S.Strings[1];      //被保人ID
+      //Cen_Cliname := S.Strings[2];  //被保人姓名
+      //Cen_Platno := S.Strings[3];   //車號
+      //Case_Priority := S.Strings[4];//案件等級
+    end;
+  finally
+  S.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.CaseHelpBtnClick(Sender: TObject);
+var
+  ErrlistForm : TErrlistForm;
+  S : TStringlist;
+  UpFormID : String;
+  Anchor : String;
+begin
+  ShowText := _Msg('處理檢核失敗中,請稍候');
+  DataLoading(True,True);
+LogFile1.LogToFile(logTimeString+'處理檢核失敗中開始');
+  ErrlistForm := TErrlistForm.Create(Self);
+  RejectCase := False;
+  S := TStringlist.Create;
+  try
+    InitialLanguage(ErrlistForm);
+    Application.ProcessMessages;
+    ErrlistForm.LogFile1.LogFile:=LogFile1.LogFile;
+    ErrlistForm.DeleteBt.Caption := ErrlistForm.DeleteBt.Caption+'(&D)';
+    ErrlistForm.iniPath := ImageSavePath + NowCaseNo+'\upload\';
+    OMRErrini2List(NowCaseno,ErrlistForm);
+    ErrlistForm.ErrListLV.ItemIndex := ErrIndex;
+    ErrlistForm.Timer1.Enabled := true;
+    if ErrlistForm.ShowModal = mrok then
+    begin
+      TransPath := ImageSavePath+NowCaseNo+'\upload\';
+      if FMode = 'ISCAN' then
+        TransPath :=  ImageSavePath + NowCaseNo+'\DownTemp\';
+      ShowText := NowCaseNo+_Msg('資料上傳中,請稍候');
+      DataLoading(True,True);
+
+      if FMode = 'ISCAN' then
+      begin
+        If Not TransCaseID(TransPath,NowCaseNo,True) Then  //傳送案件
+        begin
+          DataLoading(False,False);
+          Exit;
+        end;
+      end
+      Else
+      begin
+        If Not TransCaseID(TransPath,NowCaseNo,True) Then  //傳送案件
+        begin
+          DataLoading(False,False);
+          Exit;
+        end;
+      end;
+      CaseHelpBtn.Visible := False;
+      LoadImgFile;
+      if (FMode='NSCAN') or (FMode='DSCAN') then
+      begin
+        Showmessage(NowCaseNo+_Msg('影像上傳完成。此案已進入下一流程。'));
+      end;
+
+      if FMode='ESCAN' then
+      begin
+        Showmessage(NowCaseNo+_Msg('影像已補件完成。'));
+      end;
+
+      DataLoading(False,False);
+    end
+    Else
+    begin
+      MyTreeNode2ReFresh(NowCaseNo);
+    end;
+  finally
+  ErrlistForm.Free;
+  DataLoading(False,False);
+  S.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.CheckCaseBtnClick(Sender: TObject);
+Var
+  CaseID : String;
+  i,n,v : Integer;
+  S : TStringlist;
+begin
+  //if TreeView1.Selected = nil then Exit;
+  //if TreeView1.Selected = NewTreeNode then Exit;
+  Displaypath := '';  //20130327 修正報價單號會錯置的問題
+  S := TStringlist.Create;
+  try
+    ClearView(1);
+    ShowText := CaseID+_Msg('檢核中,請稍候');
+    DataLoading(True,True);
+    For i := 0 to NewTreeNode.Count -1 do
+    begin
+      v := posend('-',NewTreenode.Item[i].Text);
+      CaseID := Copy(NewTreenode.Item[i].Text,1,v-1);
+      ShowText := CaseID+_Msg('檢核中,請稍候');
+      DataLoading(True,True);
+      if (NewTreenode.Item[i].ImageIndex <> 7) and (NewTreenode.Item[i].ImageIndex <> 5) then  //檢核完成的不再檢核
+      begin
+        If OMRCheckCase(CaseID) then  //有成功
+        begin
+          S.Add('Y');
+          S.SaveToFile(ImageSavePath+CaseID+'\OMRCheckOk.dat');
+        end;
+      end;
+      //MyTreeNode2ReFresh(CaseID);  //原本是OMR單一案件,後改成OMR全部案件 所以這個要mark
+    end;
+    LoadImgFile;
+    TreeView1Click(nil);
+    DataLoading(False,False);
+  finally
+  S.Free;
+  end;
+  Showmessage(_Msg('檢核完成'));
+end;
+
+procedure TCB_IMGPSScanX.ClearView(stkv:Integer);
+var i:integer;
+    ISB : TImageScrollBox;
+    lb : TLabel;
+begin
+  For i:= stkv to 8 do
+  begin
+    ISB := TImageScrollBox(FindComponent('ISB'+intToStr(i)));
+    ISB.FileName := '';
+    Lb := TLabel(FindComponent('Lb'+intToStr(i)));
+    Lb.Caption := '';
+  end;
+  FreePreViewISB;
+  ISB1Click(ISB1);
+end;
+
+procedure TCB_IMGPSScanX.PrtLbClick(Sender: TObject);
+var
+    Width          : Double;
+    Height         : Double;
+    i : Integer;
+    DocDirList,FileList :TStringlist;
+    iDocDir,iDocNo : String;
+    PrtDialog : TPrintDialog;
+    S : String;
+begin
+  ShowText := _Msg('列印中,請稍候');
+  DataLoading(True,True);
+  Case2upload(NowCaseNo);   //產生原影像結構
+
+
+  //ontextList.LoadFromFile(ImageSavePath+NowCaseNo+'\Upload\Context.dat');
+
+  PrintForm := TPrintForm.create(Self);
+  DocDirList := TStringlist.Create;
+  FileList := TStringlist.Create;
+  try
+    FileList.LoadFromFile(ImageSavePath+NowCaseNo+'\Upload\Context.dat');
+    DocDirList.LoadFromFile(ImageSavePath+NowCaseNo+'\Upload\DocDir.dat');
+
+    InitialLanguage(PrintForm);  //載入多國語言
+    PrintForm.CheckListBox1.Items.Clear;
+    For i := 0 to FileList.Count - 1 do
+    begin
+      iDocDir := DocDirList.Strings[i];
+      iDocno := DocNoDir2DocNo(iDocDir);
+
+      if not DocNoAppear(iDocNo) then Continue;
+
+      PrintForm.CheckListBox1.Items.Add(FileList.Strings[i]);
+      if CheckFormID_Prt(FileName2FormCode(FileList.Strings[i])) then
+        PrintForm.CheckListBox1.Checked[i] := True;
+      PrintForm.ListBox1.Items.Add(Add_Zoo(i+1,3))
+    end;
+    If (PrintForm.ShowModal = mrOK) then
+    begin
+      S := '';
+      for I := 0 to PrintForm.CheckListBox1.Count -1 do
+      begin
+        if PrintForm.CheckListBox1.Checked[i] then
+        begin
+          if S = '' then
+            S := S+PrintForm.CheckListBox1.Items[i]
+          Else
+            S := S+#13+PrintForm.CheckListBox1.Items[i];
+        end;
+      end;
+      if S = '' then
+      begin
+        Showmessage(_msg('尚未選擇欲列印文件'));
+        Exit;
+      end
+      Else
+      begin
+        PrintImg(S,FUserID,ServerDate,ImageSavePath+NowCaseNo+'\Upload\');
+        If not Writelog(NowCaseNo) then
+        begin
+          //Showmessage('false');
+        end;
+      end;
+    end;
+  finally
+  DataLoading(False,False);
+  PrintForm.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.UseOldCaseLbClick(Sender: TObject);
+var
+  i,n : Integer;
+  CaseID,Year,BS_No,IS_Old : String;
+  OldCaseInfoForm : TOldCaseInfoForm;
+  OldCaseInfoList,Caseinfolist,FileList,DocNoList,iFileList,iDocNoList,iDocNo_CopiesList : TStringlist;
+  OldDocdir,OldDocNo,OldDocName,NewDocDir,FileName : String;
+  OldPath,NewPath,OldFile,NewFile:String;
+  Oldcopies:Integer;
+begin
+  OldCaseInfoForm := TOldCaseInfoForm.Create(Self);
+  OldCaseInfoList := TStringlist.Create;
+  Caseinfolist := TStringlist.Create;
+  FileList := TStringlist.Create;
+  DocNoList := TStringlist.Create;
+  iDocNo_CopiesList := TStringlist.Create;
+  iFileList := TStringlist.Create;
+  iDocNoList := TStringlist.Create;
+  OldCaseInfoForm.OldDocDirList := TStringlist.Create;
+  OldCaseInfoForm.OldDocNameList := TStringlist.Create;
+  OldCaseInfoForm.IN_WH_DocNoList := TStringlist.Create;
+  OldCaseInfoForm.OldCopiesList := TStringlist.Create;
+  try
+    InitialLanguage(OldCaseInfoForm); //載入多國語言
+    OldCaseInfoForm.Notebook1.ActivePage := 'CaseInfo';
+    OldCaseInfoForm.ImageSavePath := ImageSavePath;
+    OldCaseInfoForm.CaseID := NowCaseNo;
+    OldCaseInfoForm.Furl := Furl;
+    OldCaseInfoForm.Fdata := FData;
+    OldCaseInfoForm.FVerify := FVerify;
+    OldCaseInfoForm.FReWrite := FReWrite;
+    OldCaseInfoForm.FOldCaseInfo := FOldCaseInfo;
+
+    //OldCaseInfoList  案件編號@#,年度@#,業務別@#,是否舊件@#,文件編號[份數]@#,文件編號[份數] tab 案件編號@#,年度@#,業務別@#,是否舊件@#,文件編號[份數]@#,文件編號[份數]
+    OldCaseInfoList.StrictDelimiter := true;
+    OldCaseInfoList.Delimiter := #9;
+    OldCaseInfoList.DelimitedText := FOldCaseInfo;
+    //Showmessage(FOldCaseInfo);
+    //Showmessage(OldCaseInfoList.Text);
+    OldCaseInfoForm.IN_WH_DocNoList.Assign(IN_WH_DocNoList);
+    OldCaseInfoForm.FIs_In_Wh := FIs_In_Wh;
+    for i := 0 to OldCaseInfoList.Count - 1 do
+    begin
+      Caseinfolist:=SplitString('@#,',OldCaseInfoList.Strings[i]);
+      //Caseinfolist.Delimiter := '_';
+      //Caseinfolist.DelimitedText := OldCaseInfoList.Strings[i];
+      CaseID := Caseinfolist.Strings[0];
+      Year := Caseinfolist.Strings[1];
+      BS_No := Caseinfolist.Strings[2];
+      IS_Old := Caseinfolist.Strings[3];
+      With OldCaseInfoForm.OldCaseLV.Items.Add do
+      begin
+        Caption := CaseID;
+        SubItems.Add(Year);
+        SubItems.Add(BS_No);
+        SubItems.Add(IS_Old);
+      end;
+    end;
+
+    if OldCaseInfoForm.ShowModal = MrOk then
+    begin
+      OldPath := ImageSavePath+NowCaseNo+'\'+OldCaseInfoForm.UseCaseID+'\';
+      NewPath := ImageSavePath+NowCaseNo+'\';
+
+      iDocNoList.Clear;
+      if FileExists(NewPath+'CaseDocNo.dat') then
+        iDocNoList.LoadFromFile(NewPath+'CaseDocNo.dat');
+      if FileExists(NewPath+'CaseDocNo_Copies.dat') then
+        iDocNo_CopiesList.LoadFromFile(NewPath+'CaseDocNo_Copies.dat');
+
+      for i := 0 to OldCaseInfoForm.OldDocDirList.Count - 1 do
+      begin
+        FileList.LoadFromFile(OldPath+'Context.dat');
+        DocNoList.LoadFromFile(OldPath+'DocDir.dat');
+
+
+        OldDocName := OldCaseInfoForm.OldDocNameList.Strings[i];
+        OldDocDir := OldCaseInfoForm.OldDocDirList.Strings[i];
+        OldDocNo := DocNoDir2DocNo(OldDocDir);
+        if Copy(OldDocNo,1,5)<>'ZZZZZ' then
+        begin
+          if DocNoNeedDiv(OldDocNo) then
+            NewDocDir := DocNo2DocNoDir(NewPath,OldDocNo)
+          else
+            NewDocDir := OldDocNo;
+        end
+        Else
+        begin
+          NewDocDir := GetNewCustomDocNo(NewPath,OldDocName);
+        end;
+        SetRecordEditedDocDir('A',NowCaseNo,NewDocDir);
+        iFileList.Clear;
+        if FileExists(NewPath+NewDocDir+'\Context.dat') then
+          iFileList.LoadFromFile(NewPath+NewDocDir+'\Context.dat');
+
+        if Not DirectoryExists(NewPath+NewDocDir) then
+        begin
+
+
+          iDocNoList.Add(NewDocDir);
+          Oldcopies := GetDocDirCopies(NowCaseNo+'\'+OldCaseInfoForm.UseCaseID,OldDocDir); //舊案的CaseID 放在新案CaseID目錄裡
+          if FileExists(ImageSavePath+NowCaseNo+'\'+OldCaseInfoForm.UseCaseID+'\CaseDocNo_Copies.dat') then
+            iDocNo_CopiesList.Add(inttostr(Oldcopies))
+          else
+          begin
+            OldCopies := GetDocDircopies_Rec(OldPath,OldCaseInfoForm.UseCaseID,OldDocDir);
+            iDocNo_CopiesList.Add(inttostr(Oldcopies));
+            //iDocNo_CopiesList.Add('1');
+          end;
+          MkDir(NewPath+NewDocDir);
+        end;
+        SetUseCase('A',NewPath,NewDocDir,OldCaseInfoForm.UseCaseID,'');  //NewDocDir 從哪來的
+        SetUseCase('A',OldPath,OldDocDir,'',NowCaseNo);      //OldDocDir 去哪了
+        StringtoFile('Y',OldPath+'UseCase.dat');  //要上傳
+        for n := 0 to DocNoList.Count - 1 do
+        begin
+          if OldDocDir = DocNoList.Strings[n] then
+          begin
+            OldFile := FileList.Strings[n];
+            if Copy(NewDocDir,1,5)<>'ZZZZZ' then
+              NewFile := Add_Zoo(iFileList.Count+1,3)+FileName2NoQuene_Filename(OldFile)
+            Else
+              NewFile := Add_Zoo(iFileList.Count+1,3)+'_'+GetCustomFormID(NewPath,NewDocDir)+ExtractFileExt(OldFile);
+
+            iFileList.Add(NewFile);
+            CopyFile(PwideChar(OldPath+OldFile),Pwidechar(NewPath+NewDocDir+'\'+NewFile),False);
+           end;
+        end;
+        iFileList.SaveToFile(NewPath+NewDocDir+'\Context.dat');
+      end;
+
+      iDocNoList.SaveToFile(NewPath+'CaseDocNo.dat');
+      iDocNo_CopiesList.SaveToFile(NewPath+'CaseDocNo_Copies.dat');
+      DrawDocItem2(MyTreeNode1,NowCaseNo);
+      //MyTreeNode1.Text := Format('%s-%d'+_Msg('頁'),[NowCaseno,GetCasePage(ImageSavePath,NowCaseNo)]);
+      MyTreeNode1.Text := Format(_Msg('%s-%d頁'),[NowCaseno,GetCasePage(ImageSavePath,NowCaseNo)]);
+      NewTreeNodeRefresh;
+      ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+    end;
+  finally
+  OldCaseInfoForm.OldDocDirList.Free;
+  OldCaseInfoForm.OldDocNameList.Free;
+  OldCaseInfoForm.OldCopiesList.Free;
+  OldCaseInfoList.Free;
+  Caseinfolist.Free;
+  FileList.Free;
+  DocNoList.Free;
+  iDocNo_CopiesList.Free;
+  iFileList.Free;
+  iDocNoList.Free;
+  OldCaseInfoForm.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.LastInitFormidListCreate(path: string);
+var
+  i:integer;
+  ST1:TStringList;
+  str1:string;
+begin
+//ShowMessage('path='+path);
+  ST1:=TStringList.Create;
+  ST1.LoadFromFile(path+'FormCode_Name.dat');
+  for I := 0 to ST1.Count - 1 do
+  begin
+    if (Pos('_',St1.Strings[i])<>1) and (Pos('_',St1.Strings[i])<>-1) then
+    begin
+      str1:=Copy(ST1.Strings[i],1,Pos('_',St1.Strings[i])-1);
+      LastInitFormidList.Add(str1);
+    end;
+  end;
+
+  ST1.Free;
+end;
+
+Function TCB_IMGPSScanX.FindDivFormCode(FormCode:String):Boolean; //找有沒有分案的條碼
+var
+  i : Integer;
+  DelBarCode : String;
+  S : TStringlist;
+  iMode : String;
+begin
+  Result := False;
+  iMode := FMode;
+  S := TStringlist.Create;
+  try
+    IF FindSQLData(FORM_INF_List,'T1.FORM_ID,T1.DIVISION','T1.FORM_ID',FormCode,0,FindResult) then
+    begin
+      S.CommaText := GetFindResult('T1.DIVISION');
+      for i := 0 to S.Count - 1 do   //可能有多組
+      begin
+        if S.Strings[i] = iMode then
+        begin
+          Result := True;
+          Break;
+        end;
+      end;
+    end;
+  finally
+  S.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.SmoothCBClick(Sender: TObject);
+begin
+  if SmoothCB.Checked then
+  begin
+    Image_Smooth(ISB1.Graphic);
+    ISB1.Redraw(True);
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetCustomFormID(Path,DocNo:String):String; //取出自定文件FormID
+var
+  ini : Tinifile;
+begin
+  ini := Tinifile.Create(Path+'CustomDocNo.ini');
+  try
+    Result := ini.ReadString(DocNo,'FormID','');
+  finally
+  ini.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.DelAttFileLBClick(Sender: TObject);
+var
+  AttFile : String;
+  SelectCount : Integer;
+  i : Integer;
+begin
+  SelectCount := 0;
+  for i := 0 to AttListBox.Items.Count - 1 do
+  begin
+    if AttListBox.Selected[i] then
+      inc(SelectCount);
+  end;
+  if SelectCount = 0 then
+  begin
+    Showmessage(_Msg('請選擇要刪除的電子檔'));
+    Exit;
+  end;
+
+  if SelectCount > 0 then
+  begin
+    if Messagedlg(Format(_Msg('是否刪除這%d筆??'),[SelectCount]),MtConfirmation,[mbyes,mbcancel],0) = mrcancel then Exit;
+    for i := 0 to AttListBox.Items.Count - 1 do
+    begin
+      if AttListBox.Selected[i] then
+      begin
+        AttFile :=  HTTPEncode(UTF8Encode(AttListBox.Items.Strings[i]));
+        DeleteFile(ImageSavePath+NowCaseNo+'\'+AttFile);
+        SetAttContextList('D',-1,NowCaseno,AttFile);
+      end;
+    end;
+  end;
+  LoadAttFile(NowCaseNo);
+  Showmessage(_msg('刪除完成'));
+end;
+
+Function TCB_IMGPSScanX.CheckFormID_Prt(FormID:String):Boolean; //傳入的FormID是否預設列印
+begin
+  Result := False;
+  If FindSQLData(FORM_INF_List,'T1.IS_PRINT','T1.FORM_ID',FormID,0,FindResult) Then
+  begin
+    if GetFindResult('T1.IS_PRINT') = 'Y' Then
+      Result := True;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ErrFormtoCurrentForm(CaseID,EFormID,CFormID:String);//將舊案的錯誤FormID改正確的FormID
+var
+  DocNoList,FileList :TStringlist;
+  EDocNo,CDocNo,iDocNo,iFormID :String;
+  EDocDir,CDocDir:String;
+  OldFile,NewFile :String;
+  iPath,iiPath : String;
+  i,n : Integer;
+begin
+  EDocNo := FormCode2DocNo(EFormID);
+  CDocNo := FormCode2DocNo(CFormID);
+  DocNoList :=TStringlist.Create;
+  FileList := TStringlist.Create;
+  try
+    DocNoList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+    for i := 0 to DocNoList.Count - 1 do
+    begin
+      EDocDir := DocNoList.Strings[i];
+      iDocNo := DocNoDir2DocNo(DocNoList.Strings[i]);
+      iPath := ImageSavePath+CaseID+'\'+EDocDir+'\';
+      if FileExists(iPath+'Context.dat') then  //20140909漏加這個判斷造成自訂文件但沒影像會出錯誤訊息
+        FileList.LoadFromFile(iPath+'Context.dat');
+      for n := 0 to FileList.Count - 1 do
+      begin
+        iFormID := FileName2FormCode(FileList.Strings[n]);
+        if iFormID = EFormID then
+        begin
+          OldFile := FileList.Strings[n];
+          NewFile := StringReplace(FileList.Strings[n],iFormID,CFormID,[rfReplaceAll]);
+          FileList.Strings[n] := NewFile;
+          RenameFile(iPath+OldFile,iPath+NewFile);
+          FileList.SaveToFile(iPath+'Context.dat');
+        end;
+      end;
+      if iDocNo = EDocNo then
+      begin
+        CDocDir := StringReplace(EDocDir,EDocNo,CDocNo,[rfReplaceAll]);
+        iiPath := ImageSavePath+CaseID+'\'+CDocDir+'\';
+        MoveFile(PWideChar(iPath),PWideChar(iiPath));
+        DocNoList.Strings[i] := StringReplace(DocNoList.Strings[i],iDocNo,CDocNo,[rfReplaceAll]);
+        DocNoList.SaveToFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+        //SetRecordEditedDocDir('A',CaseID,CDocNo);  //20140918 yuu說改成不紀錄
+      end;
+    end;
+  finally
+  DocNoList.Free;
+  FileList.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SortDocDir_FormID(CaseID,DocDir:String); //將DocDir裡的文件編號排序
+var
+  i,n,v,ln : Integer;
+  Exists:Boolean;
+  FileList,SortFileList,FormIDList : TStringlist;
+  FormID,iFormID:String;
+  OldName,NewName : String;
+begin
+  FileList := TStringlist.Create;
+  SortFileList := TStringlist.Create;
+  FormIDList := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat') then
+    begin
+      FileList.LoadFromFile(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat');
+      ////取出FormID/////
+      for i := 0 to FileList.Count - 1 do
+      begin
+        FormID := FileName2FormCode(FileList.Strings[i]);
+        if (FormID = 'Attach') or (FormID = 'S_Attach') then Continue;   //附件離開
+        Exists := False;
+        for n := 0 to FormIDList.Count - 1 do //查一下FORMID是否已經存在了
+        begin
+          if FormID = FormIDList.Strings[n] then
+          begin
+            Exists := True;
+            Break;
+          end;
+        end;
+        if not Exists then
+          FormIDList.Add(FormID);
+      end;
+      FormIDList.Sort;
+      //排序後產要更名的清單
+      for i := 0 to FormIDList.Count - 1 do
+      begin
+        iFormID := FormIDList.Strings[i];
+        for n := 0 to FileList.Count - 1 do
+        begin
+          if FileName2FormCode(FileList.Strings[n]) = iFormID then
+          begin
+            SortFileList.Add(FileList.Strings[n]+','+'@'+Add_Zoo(SortFileList.Count+1,3)+'_'+iFormID+ExtractFileExt(FileList.Strings[n]));
+          end;
+        end;
+      end;
+      FileList.Clear;
+      //更名成新順序的檔名
+      for i := 0 to SortFileList.Count - 1 do
+      begin
+        v := Pos(',',SortFileList.Strings[i]);
+        ln := Length(SortFileList.Strings[i]);
+        OldName := Copy(SortFileList.Strings[i],1,v-1);
+        NewName := Copy(SortFileList.Strings[i],v+1,ln-v);
+        RenameFile(ImageSavePath+CaseID+'\'+DocDir+'\'+OldName,ImageSavePath+CaseID+'\'+DocDir+'\'+NewName);
+        FileList.Add(NewName);
+      end;
+      //去掉@開頭
+      for i := 0 to FileList.Count - 1 do
+      begin
+        OldName := FileList.Strings[i];
+        NewName := StringReplace(OldName,'@','',[rfReplaceAll]);
+        ReNameFile(ImageSavePath+CaseID+'\'+DocDir+'\'+OldName,ImageSavePath+CaseID+'\'+DocDir+'\'+NewName);
+        FileList.Strings[i] := NewName;
+      end;
+      FileList.SaveToFile(ImageSavePath+CaseID+'\'+DocDir+'\Context.dat');
+    end;
+  finally
+  FileList.Free;
+  SortFileList.Free;
+  FormIDList.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FormIDAppear(FormID:String):Boolean; //FormID是否可出現
+var
+  iDocNo : String;
+begin
+  Result := True;
+  iDocNo := FormCode2DocNo(FormID);
+  if (((FIs_In_Wh  = 'Y') and (not DocNoIs_In_WH(iDocNo))) or   //入庫掃描不看非入庫文件
+     ((FIs_In_Wh  = 'N') and (DocNoIs_In_WH(iDocNo)))) and      //非入庫掃描不看入庫文件
+     ((iDocNo <> 'Attach') and (iDocNo <> 'S_Attach') and (Copy(iDocNo,1,5)<>'ZZZZZ')) then
+       Result := False;
+
+  if (FIs_In_Wh='Y') and (FWH_category='Y') then //20170816 新加
+  begin
+    if (((FIs_In_Wh  = 'Y') and (not DocNoIs_In_WH(iDocNo))) or   //入庫掃描不看非入庫文件
+     ((FIs_In_Wh  = 'N') and (DocNoIs_In_WH(iDocNo)))) and      //非入庫掃描不看入庫文件
+     ((iDocNo <> 'Attach') and (iDocNo <> 'S_Attach') and (Copy(iDocNo,1,5)<>'ZZZZZ')) then
+       Result := False;
+  end;
+
+  if (FIs_In_Wh='Y') and (FWH_category='N') then //20170816 新加
+  begin
+    Result:=True;
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.ISGuideFormID(FormID:String):Boolean;
+var
+  i : Integer;
+begin
+  Result := False;
+  for i := 0 to GuideFormIDList.Count - 1 do
+  begin
+    if FormID = GuideFormIDList.Strings[i] then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.ISDivPageFormID(FormID:String):Boolean;
+var
+  i : Integer;
+begin
+  Result := False;
+
+  for i := 0 to DivPageFormIDList.Count - 1 do
+  begin
+    if FormID = DivPageFormIDList.Strings[i] then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.MoveImage_Drag(Path:String;fp,tp:Integer); //拖拉移動頁數
+var
+  i,n,inx:Integer;
+  FList,D_Flist:TStringlist;
+begin
+  FList := TStringlist.Create;
+  D_Flist := TStringlist.Create;
+  try
+    FList.LoadFromFile(Path+'Context.dat');
+    for i := 0 to FList.Count - 1 do
+    begin
+      Renamefile(Path+Flist.Strings[i],path+'@'+Flist.Strings[i]);
+      Flist.Strings[i]:= '@'+Flist.Strings[i];
+    end;
+
+    D_Flist.Add(Flist.Strings[fp-1]);
+
+    {for i := 0 to ComponentCount -1 do
+    begin
+      if (Components[i] is TShape) and (copy(Components[i].Name,1,2)='SP') then
+      begin
+        inx := strtoint(Copy(TShape(Components[i]).Name,3,length(TShape(Components[i]).Name)-2));
+        D_Flist.Add(Flist.Strings[inx-1]);
+        //Renamefile(Path+Flist.Strings[inx-1],path+'@'+Flist.Strings[inx-1]);
+      end;
+    end;}
+    //Showmessage('aa');
+    for i := 0 to D_Flist.Count -1 do
+    begin
+      for n := 0 to FList.Count - 1 do
+      begin
+        //if Flist.Strings[n]=StringReplace(D_Flist.Strings[i],'@','',[rfReplaceAll]) then
+        if Flist.Strings[n]=D_Flist.Strings[i] then
+        begin
+          Flist.Delete(n);
+          Break;
+        end;
+      end;
+    end;
+    //Showmessage('bb');
+    for i := 0 to D_Flist.Count - 1 do
+    begin
+      Flist.Insert(tp-1+i,D_Flist.Strings[i]);
+    end;
+
+    Flist.SaveToFile(Path+'Context.dat');
+    //Showmessage(Flist.Text);
+    //Showmessage('CC');
+    ReSortFileName(Path);
+    TreeView1click(self);
+
+
+  finally
+  FList.Free;
+  D_Flist.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FormCode2FormName(CaseID,FormCode:String):String; //用FormCode轉成文件名稱
+var
+  i,v,ln : Integer;
+  DelBarCode : String;
+  CusDocNo,CusDocName : String;
+begin
+  Result := '';
+  if (FormCode = '') or (FormCode = 'Attach') or (FormCode = 'S_Attach') then
+    Result := _Msg('未歸類')
+  //showmessage('a');
+  //stringtofile(FORM_INF_List.Text,'D:\121.txt');
+  Else If FindSQLData(FORM_INF_List,'T1.FORM_ID,T1.FORM_DESC','T1.FORM_ID',FormCode,0,FindResult) then
+    Result := GetFindResult('T1.FORM_DESC');
+
+  ////// 到自訂文件找//////
+  if Result = '' then
+    Result := GetCustomDocName(ImageSavePath+CaseID+'\',FormCode2DocNo(FormCode));
+  {for i := 0 to Cust_DocNoList.Count - 1 do
+  begin
+    v := Pos('_',Cust_DocNoList.Strings[i]);
+    ln := Length(Cust_DocNoList.Strings[i]);
+    CusDocNo := copy(Cust_DocNoList.Strings[i],1,v-1);
+    CusDocName := Copy(Cust_DocNoList.Strings[i],v+1,ln-v);
+    if CusDocNo = FormCode2DocNo(FormCode) then
+      Result := DocNo2DocName(CusDocNo);
+
+  end;}
+
+
+  {DelBarCode := '**'+FormCode;
+  for I := 0 to FormCodeList.Count - 1 do
+  begin
+    if FindDel then //要找下架的
+    begin
+      if (FormCode = FormCodeList.Strings[i]) or (DelBarCode = FormCodeList.Strings[i]) then
+      begin
+        Result := FormNameList.Strings[i];
+        Break;
+      end;
+    end
+    Else
+    begin
+      if (FormCode = FormCodeList.Strings[i]) or (DelBarCode = FormCodeList.Strings[i]) then
+      begin
+        Result := FormNameList.Strings[i];
+        Break;
+      end;
+    end;
+  end; }
+end;
+
+Function TCB_IMGPSScanX.FormCode2FileName(FormCode:String;List:TStrings):String; //用FormCode找出檔名(第一頁)
+var
+  i : Integer;
+  v,v1 : Integer;
+begin
+  Result := '';
+  for i := 0 to List.Count - 1 do
+  begin
+    V := pos('_',List.Strings[i]);
+    v1 := pos('.',List.Strings[i]);
+    if (FormCode = '') and (V = 0)then //FormCode 為空的則找附件出來
+    begin
+      Result := List.Strings[i];
+      Break;
+    end;
+    IF FormCode = Copy(List.Strings[i],v+1,v1-v-1) then
+    begin
+      Result := List.Strings[i];
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FileName2FormCode(FileName:String):String; //從檔名取出FormCode
+var
+  v,v1 : Integer;
+begin
+  FileName := ExtractFileName(FileName);
+  v := Pos('_',FileName);
+  v1 := Pos('.',FileName);
+  if v > 0 then
+  begin
+    Result := Copy(FileName,v+1,v1-v-1);
+  end
+  Else     //附件
+  begin
+    Result := '';
+  end;
+end;
+
+Function TCB_IMGPSScanX.FileName2FormName(CaseID,FileName:String):String; //從檔名取出文件名稱
+begin
+  Result :=  FormCode2FormName(CaseID,FileName2FormCode(FileName));
+end;
+
+Function TCB_IMGPSScanX.FormCode2DocNo(FormCode:String):String;   //FormCode轉Docno
+Var
+  i : Integer;
+begin
+  Result := '';
+  for i := 0 to FormID_List.Count-1 do
+  begin
+    if FormID_List.Strings[i] = FormCode then
+    begin
+      Result := DocNo_List.Strings[i];
+      Break;
+    end;
+
+  end;
+  if (FormCode <> '') and (Result = '') then    //是自訂文件
+  begin
+    Result := Copy(FormCode,1,8); //20170224 DocNo 固定長度8碼
+  end;
+
+  {If FindSQLData(FORM_INF_List,'T1.DOC_NO','T1.FORM_ID',FormCode,0,FindResult) Then  //20130403太慢了..換掉
+  begin
+    Result := GetFindResult('T1.DOC_NO');
+  end;}
+end;
+
+Function TCB_IMGPSScanX.FormCode2Version(FormCode:String):String; //FormCode轉版本
+begin
+  Result := Copy(FormCode,11,5);
+end;
+
+Function TCB_IMGPSScanX.FormCode2Page(FormCode:String):String; //FormCode轉頁數
+begin
+  Result := Copy(FormCode,9,2)
+end;
+
+Function TCB_IMGPSScanX.FormCode2WorkNo(FormCode:String):String; //用FormCode取出作業別
+begin
+  Result := '';
+  If FindSQLData(FORM_INF_List,'T1.WORK_NO','T1.FORM_ID',FormCode,0,FindResult) Then
+  begin
+    Result := GetFindResult('T1.WORK_NO');
+  end;
+end;
+
+Function TCB_IMGPSScanX.CaseNode2Info(Node:TTreeNode;Mode:Char):String;   //案件Node取案件編號  Mode: I:Caseno;P:Page
+var
+  v,ln : Integer;
+begin
+  //XXXXXX-XX頁
+  V := Pos('-',Node.Text);
+  ln := Length(Node.Text);
+  case Mode of
+  'I': Result := Copy(Node.Text,1,v-1);        //CaseID
+  'P': Result := Copy(Node.Text,v+1,ln-v-1);   //CasePage
+  end;
+
+end;
+
+Function TCB_IMGPSScanX.DocNode2Info(Node:TTreeNode;Mode:Char):String;   //文件Node取文件代號 Mode: I:Docno;N:Docname;P:Page;G:Group
+var
+  v,v1,v2,v3,ln :integer;
+begin
+  //文件名稱@組數{文件代號}-XX頁
+  V := PosEnd('@',Node.Text);
+  v1 := PosEnd('{',Node.Text);
+  v2 := PosEnd('}',Node.Text);
+  v3 := PosEnd('-',Node.Text);
+  ln := Length(Node.Text);
+  case Mode of
+  'I': Result := Copy(Node.Text,v1+1,v2-v1-1);  //DocNo
+  'N': Result := Copy(Node.Text,1,v-1);         //DocName
+  'P': Result := Copy(Node.Text,v3+1,ln-v3-1);  //DocPage
+  'G': Result := Copy(Node.Text,v+1,v1-v-1);    //DocGroup
+  end;
+end;
+
+Function TCB_IMGPSScanX.FormNode2Info(Node:TTreeNode;Mode:Char):String;   //表單Node取表單代號  Mode: I:FormID;N:FormName;P:Page
+var
+  v,v1,v2,ln :integer;
+begin
+  //表單代號{表單名稱}-XX頁
+  v := Pos('{',Node.Text);
+  v1 := PosEnd('}',Node.Text);
+  v2 := PosEnd('-',Node.Text);
+  ln := Length(Node.Text);
+  case Mode of
+  'I': Result := Copy(Node.Text,1,v-1); //FormID
+  'N': Result := Copy(Node.Text,v1+1,v2-v1-1); //FormName
+  'P': Result := Copy(Node.Text,v2+1,ln-v2-1); //Page
+  end;
+end;
+
+Function TCB_IMGPSScanX.DocNoExistsinTree(CaseNode:TTreeNode;DocNo:String):Boolean; //是否己存在樹裡
+var
+  i : Integer;
+begin
+  Result := False;
+  for I := 0 to CaseNode.Count - 1 do
+  begin
+    if DocNo = DocNode2Info(CaseNode.Item[i],'I') Then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.DistinctFormCode(CaseID:String); //從案件裡的FormCode取出第一頁
+var
+  i,n : Integer;
+  LForm,OForm : String;
+  Addok : Boolean;
+  S : TStringlist;
+begin
+  S := TStringlist.Create;
+  try
+    S.LoadFromFile(ImageSavePath + CaseID+'\upload\Context.dat');
+    for i := 0 to S.Count - 1 do
+    begin
+LogFile1.LogToFile(logTimeString+S.Strings[i]+' ISExistImg='+BoolToStr(ISExistImg(ImageSavePath+CaseID+'\upload\'+S.Strings[i]),true));
+LogFile1.LogToFile(logTimeString+S.Strings[i]+' reSizeExistImgList='+BoolToStr(reSizeExistImgList.IndexOf(LoadFileGetMD5(ImageSavePath+CaseID+'\upload\'+S.Strings[i]))<>-1,true));
+      if FWH_category='N' then
+      begin
+        if (ISExistImg(ImageSavePath+CaseID+'\upload\'+S.Strings[i]))
+        or  (reSizeExistImgList.IndexOf(LoadFileGetMD5(ImageSavePath+CaseID+'\upload\'+S.Strings[i]))<>-1)  then
+        begin
+          Continue;
+        end;
+      end;
+
+      LForm := FileName2FormCode(S.Strings[i]);
+      AddOk := True;
+      for n := 0 to OMRFileList.Count - 1 do
+      begin
+        OForm := FileName2FormCode(OMRFileList.Strings[n]);
+        if (LForm <> '') and (LForm = OForm) then
+        begin
+          AddOk := False;
+          Break;
+        end;
+      end;
+      if AddOk then
+      begin
+        OMRFileList.Add(S.Strings[i]);
+      end;
+    end;
+  finally
+  S.Free;
+  end;
+
+end;
+
+
+procedure TCB_IMGPSScanX.view_image_FormCode(Path,FormCode:String;stpage,stview:integer); //用FormCode來找影像
+var i,p:integer;
+    ISB : TImageScrollBox;
+    lb : TLabel;
+    v ,v1 : Integer;
+    page : Integer;
+    List_FormCode,Err_FormCode: String;
+    iFormID : String;
+begin
+   ShowText := _Msg('影像顯示中,請稍候');
+   DataLoading(True,True);
+
+   IF FormCode = 'ShowAll' then  //顯示所有的影像 (因為附件會傳空字串,所以用ShowAll)
+   begin
+     ClearView(1);
+     CreatePreViewISB(ContextList.Count);
+     For i := Stpage-1 to ContextList.Count -1 do
+     begin
+       ISB := TImageScrollBox(FindComponent(ISBName+intToStr(stview+i)));
+       ISB.AntiAliased := True;
+       if ISB.ZoomPercent > 100  then
+         ISB.AntiAliased := False;
+       ISB.LoadFromFile(Path+ContextList.Strings[i],1);
+
+       {GetScrollData(ISB,HS,VS,iRate);
+       if iRate = 0 then
+         ISB.ZoomMode := zmFittoPage
+       Else
+         ISB.ZoomPercent := iRate;
+       ISB.HorzScrollBar.Position := HS;
+       ISB.VertScrollBar.Position := VS;
+
+       List_FormCode := FileName2FormCode(ContextList.Strings[i]);
+       lb := TLabel(FindComponent('lb'+intToStr(stview)));
+       lb.Caption := Format(_Msg('第%s頁'),[Add_Zoo(i+1,3)]);
+       If List_FormCode = '' Then
+         lb.Caption := lb.Caption+'('+FormCode2FormName(List_FormCode)+')'
+       Else
+         lb.Caption := lb.Caption+'('+FormCode2FormName(List_FormCode)+'-'+List_FormCode+')';
+       Inc(Stview);
+       If ((VMode = 0) and (Stview>1))
+            or ((VMode = 1) and ((Stview>2)))
+            or ((VMode = 2) and ((Stview>4)))
+            or ((VMode = 3) and ((Stview>6)))
+            or ((VMode = 4) and ((Stview>8))) Then
+              break;
+       }
+     end;
+     FitPreViewISB;
+   end
+   Else  //顯示指定FormCode的影像
+   begin
+     If (TreeView1.Selected <> nil) Then
+     begin
+       If Stpage = 0 Then
+         Stpage := 1;
+       Page := 0;
+       ClearView(stview);
+       If Stpage > ContextList.Count Then Exit;
+       For i := 0 to ContextList.Count -1 do
+       begin
+         List_FormCode := FileName2FormCode(ContextList.Strings[i]);
+         {iFormID := GetMainFormID(List_FormCode);
+         if iFormID <> '' then
+           List_FormCode := iFormID;}
+
+         Err_FormCode := 'NoCode';
+         if (List_Formcode <> '') and (not FormIDExists(List_Formcode,False,0)) then
+           Err_FormCode := 'Err';
+         IF (List_FormCode = FormCode) or (Err_FormCode=Formcode) or (FormCode2DocNo(List_FormCode) = FormCode) Then
+         begin
+           Inc(Page);
+           IF Page< Stpage Then
+             Continue;
+           ISB := TImageScrollBox(FindComponent('ISB'+intToStr(stview)));
+           ISB.AntiAliased := True;
+           if ISB.ZoomPercent > 100  then
+             ISB.AntiAliased := False;
+           ISB.LoadFromFile(Path+ContextList.Strings[i],1);
+
+           GetScrollData(ISB,HS,VS,iRate);
+           if iRate = 0 then
+             ISB.ZoomMode := zmFittoPage
+           Else
+             ISB.ZoomPercent := iRate;
+           ISB.HorzScrollBar.Position := HS;
+           ISB.VertScrollBar.Position := VS;
+           {if not SortMode then
+           begin
+             SetScrollData(MPSViewX,MPSViewX.HorzScrollBarPos,MPSViewX.VertScrollBarPos,MPSViewX.ZoomPercent);
+           end;}
+           //MPSViewX.ImageZoomMode := zmFullpage;
+           //MPSViewX.AntiAliased := True;
+           lb := TLabel(FindComponent('lb'+intToStr(stview)));
+           lb.Caption := Format(_Msg('第%s頁'),[Add_Zoo(i+1,3)]);
+           If List_FormCode = '' Then
+             lb.Caption := lb.Caption+'('+FormCode2FormName(NowCaseno,List_FormCode)+')'
+           Else
+             lb.Caption := lb.Caption+'('+FormCode2FormName(NowCaseNo,List_FormCode)+'-'+List_FormCode+')';
+           Inc(Stview);
+         end;
+         If ((VMode = 0) and (Stview>1))
+            or ((VMode = 1) and ((Stview>2)))
+            or ((VMode = 2) and ((Stview>4)))
+            or ((VMode = 3) and ((Stview>6)))
+            or ((VMode = 4) and ((Stview>8))) Then
+              break;
+       end;
+     end;
+   end;
+   ISB1Click(ISB1);
+
+
+   DataLoading(False,False);
+end;
+
+procedure TCB_IMGPSScanX.view_image_DocNo(Path,DocNo,FormID:String;Pages:integer); //用DocNo來找影像
+var i,n,p:integer;
+    ISB : TImageScrollBox;
+    lb : TLabel;
+    v ,v1 : Integer;
+    List_DocNo,Trans_DocNo,List_FormCode,Form_Page: String;
+    iDocNo : String;
+    iGroupNo,page,Ct,int1 : Integer;
+    ST1:TStringList;
+begin
+   ShowText := _Msg('影像顯示中,請稍候');
+   DataLoading(True,True);
+ST1:=TStringList.Create;
+//Display1.Lines.Clear;
+   IF DocNo = 'ShowAll' then  //顯示所有的影像 (因為附件會傳空字串,所以用ShowAll)
+   begin
+     ClearView(1);
+     if GetCasePage(ImageSavePath,NowCaseno) > 30 then
+     begin
+       DataLoading(False,False);
+       Exit;
+     end;
+     CreatePreViewISB(GetCasePage(ImageSavePath,NowCaseno));
+//Showmessage(inttostr(GetCasePage(ImageSavePath,NowCaseno)));
+     Ct := 0;
+     For i := 0 to CaseDocNoList.Count-1 do
+     begin
+
+       if (FWH_category='N') and (FIs_In_Wh='Y') then
+       begin
+         if FileExists(ImageSavePath+NowCaseno+'\EditedDocDir.dat') then
+         begin
+           ST1.LoadFromFile(ImageSavePath+NowCaseno+'\EditedDocDir.dat');
+         end;
+       end;
+
+       iDocNo := CaseDocNoList.Strings[i];
+//ShowMessage('ST1.Count='+IntToStr(ST1.Count));
+       if ST1.Count<>0 then
+       begin
+         if ST1.IndexOf(iDocNo)<>-1 then
+         begin
+         end
+         else
+         begin
+           if not DocNoAppear(DocNoDir2DocNo(iDocNo)) then continue;  //20170817 這不能被註解
+         end;
+       end
+       else
+       begin
+         if not DocNoAppear(DocNoDir2DocNo(iDocNo)) then continue;  //20170817 這不能被註解
+       end;
+       ContextList.Clear;
+       if FileExists(Path+iDocNo+'\Context.dat') then
+         ContextList.LoadFromFile(Path+iDocNo+'\Context.dat');
+//ShowMessage('ContextList='+ContextList.Text);
+       for n := 0 to ContextList.Count - 1 do
+       begin
+
+         if (FWH_category='N') and (FIs_In_Wh='Y') then
+         begin
+           if ISExistImg(Path+iDocNo+'\'+ContextList.Strings[n]) then
+           begin
+
+             if not DocNoIs_In_WH(Copy(iDocNo,1,8)) then
+             begin
+               Continue;
+             end;
+           end;
+         end;
+
+         inc(Ct);
+         ISB := TImageScrollBox(FindComponent(ISBName+intToStr(Ct)));
+         ISB.AntiAliased := True;
+         if ISB.ZoomPercent > 100  then
+           ISB.AntiAliased := False;
+         ISB.LoadFromFile(Path+iDocNo+'\'+ContextList.Strings[n],1);
+
+         DpiResize(ISB.Graphic,36,False);
+         ISB.Redraw(true);
+
+       end;
+
+     end;
+     //if DirectoryExists(Path+'Attach') then
+     if DirectoryExists(Path+AttName) then
+     begin
+       //iDocNo := 'Attach';
+       iDocNo := AttName;
+       ContextList.Clear;
+       if FileExists(Path+iDocNo+'\Context.dat') then
+         ContextList.LoadFromFile(Path+iDocNo+'\Context.dat');
+       for n := 0 to ContextList.Count - 1 do
+       begin
+         inc(Ct);
+         ISB := TImageScrollBox(FindComponent(ISBName+intToStr(Ct)));
+         ISB.AntiAliased := True;
+         if ISB.ZoomPercent > 100  then
+           ISB.AntiAliased := False;
+         ISB.LoadFromFile(Path+iDocNo+'\'+ContextList.Strings[n],1);
+       end;
+     end;
+
+     FitPreViewISB;
+
+   end
+   Else if (DocNo <> '') and (FormID = '') then  //顯示指定DocNo+組別的影像  附件傳 Attach
+   begin                               //顯示 文件層下的影像
+     iDocNo := DocNo;
+     ContextList.Clear;
+     if FileExists(Path+iDocNo+'\Context.dat') then
+       ContextList.LoadFromFile(Path+iDocNo+'\Context.dat');
+
+//ShowMessage('ContextList.Count='+IntToStr(ContextList.Count));
+     CreatePreViewISB(ContextList.Count);
+//ShowMessage(IntToStr(ContextList.Count));
+     int1:=0;
+//ShowMessage(BoolToStr(DocNoIs_In_WH(Copy(iDocNo,1,8)),true));
+     For i := 0 to ContextList.Count -1 do
+     begin
+       if (FWH_category='N') and (FIs_In_Wh='Y')  then
+       begin
+         if ISExistImg(Path+iDocNo+'\'+ContextList.Strings[i]) then
+         begin
+
+           if not DocNoIs_In_WH(Copy(iDocNo,1,8)) and ( iDocNo<>'Attach') then
+           begin
+             inc(int1);
+             Continue;
+           end;
+         end;
+       end;
+//ShowMessage(Path+iDocNo+'\'+ContextList.Strings[i]);
+       ISB := TImageScrollBox(FindComponent(ISBName+intToStr(i+1-int1)));
+       ISB.AntiAliased := True;
+       if ISB.ZoomPercent > 100  then
+         ISB.AntiAliased := False;
+       ISB.LoadFromFile(Path+iDocNo+'\'+ContextList.Strings[i],1);
+       DpiResize(ISB.Graphic,36,False);
+       ISB.Redraw(true);
+     end;
+     FitPreViewISB;
+   end
+   Else if (FormID <> '') {and (FormID <> 'Attach')} then  //顯示指定FormID的影像
+   begin
+     If (TreeView1.Selected <> nil) Then
+     begin
+       iDocNo := DocNo;
+       ContextList.Clear;
+       if FileExists(Path+iDocNo+'\Context.dat') then
+         ContextList.LoadFromFile(Path+iDocNo+'\Context.dat');
+       iGroupNo := 0;
+       page := 0;
+       Ct := 0;
+       CreatePreViewISB(Pages);
+//ShowMessage('formID page'+IntToStr(Pages)+', ContextList='+ContextList.Text);
+       For i := 0 to ContextList.Count -1 do
+       begin
+         if FileName2FormCode(ContextList.Strings[i]) = FormID then
+         begin
+           if (FWH_category='N') and (FIs_In_Wh='Y') then
+           begin
+//ShowMessage(Path+iDocNo+'\'+ContextList.Strings[i]);
+//ShowMessage(BoolToStr(ISExistImg(Path+iDocNo+'\'+ContextList.Strings[i]),true));
+             if ISExistImg(Path+iDocNo+'\'+ContextList.Strings[i]) then
+             begin
+               if not DocNoIs_In_WH(FormCode2DocNo(FormID)) then
+                 Continue;
+             end;
+           end;
+           inc(Ct);
+           ISB := TImageScrollBox(FindComponent(ISBName+intToStr(Ct)));
+//ShowMessage(ISB.Name);
+           ISB.AntiAliased := True;
+           if ISB.ZoomPercent > 100  then
+             ISB.AntiAliased := False;
+           ISB.LoadFromFile(Path+iDocNo+'\'+ContextList.Strings[i],1);
+           DpiResize(ISB.Graphic,36,False);
+           ISB.Redraw(true);
+
+           //NowShowFileList.Add(ContextList.Strings[i]);
+         end;
+       end;
+       FitPreViewISB;
+     end;
+   end;
+   
+   if FindComponent(ISBName+'1') <> nil then
+   begin
+     ISBClick(TImageScrollBox(FindComponent(ISBName+'1')));
+   end;
+   ISB1Click(ISB1);
+   DataLoading(False,False);
+end;
+
+Function TCB_IMGPSScanX.ShapeName2PreViewISBName(SP:TShape):String; //轉出指定PreViewISBName
+begin
+  Result := ISBName+Copy(SP.Name,3,length(SP.Name)-2);
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton14Click(Sender: TObject);
+var
+  Count : Integer;
+begin
+  if not ISB1.Graphic.IsEmpty  then
+  begin
+    ISB1.LoadFromFile(ISB1.FileName,1);
+    Rotate(ISB1.Graphic,270);
+    if ISB1.Graphic.ImageFormat <> ifBlackWhite then
+    begin
+      TJpegGraphic(ISB1.Graphic).SaveQuality := 30;
+      TJpegGraphic(ISB1.Graphic).SaveToFile(ISB1.FileName);
+    end
+    Else
+      ISB1.SaveToFile(ISB1.FileName);
+    ISB1.Redraw(True);
+    SelectISB.Graphic.Assign(ISB1.Graphic);
+    SelectISB.Redraw(True);
+    FitPreViewISB;
+    ISBClick(SelectISB);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton15Click(Sender: TObject);
+begin
+  if not ISB1.Graphic.IsEmpty  then
+  begin
+    ISB1.LoadFromFile(ISB1.FileName,1);
+    Rotate(ISB1.Graphic,180);
+    if ISB1.Graphic.ImageFormat <> ifBlackWhite then
+    begin
+      TJpegGraphic(ISB1.Graphic).SaveQuality := 30;
+      TJpegGraphic(ISB1.Graphic).SaveToFile(ISB1.FileName);
+    end
+    Else
+      ISB1.SaveToFile(ISB1.FileName);
+    ISB1.Redraw(True);
+    SelectISB.Graphic.Assign(ISB1.Graphic);
+    SelectISB.Redraw(True);
+    FitPreViewISB;
+    ISBClick(SelectISB);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton16Click(Sender: TObject);
+begin
+  if not ISB1.Graphic.IsEmpty  then
+  begin
+    ISB1.LoadFromFile(ISB1.FileName,1);
+    Rotate(ISB1.Graphic,90);
+    if ISB1.Graphic.ImageFormat <> ifBlackWhite then
+    begin
+      TJpegGraphic(ISB1.Graphic).SaveQuality := 30;
+      TJpegGraphic(ISB1.Graphic).SaveToFile(ISB1.FileName);
+    end
+    Else
+      ISB1.SaveToFile(ISB1.FileName);
+    ISB1.Redraw(True);
+    SelectISB.Graphic.Assign(ISB1.Graphic);
+    SelectISB.Redraw(True);
+    FitPreViewISB;
+    ISBClick(SelectISB);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton17Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmFitHeight;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton18Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmFitWidth;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton19Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmOriginalSize;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton20Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmFittoPage;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton21Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmPercent;
+  ISB1.ZoomPercent := 50;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton22Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmPercent;
+  ISB1.ZoomPercent := 25;
+end;
+
+procedure TCB_IMGPSScanX.SpeedButton3Click(Sender: TObject);
+begin
+  ISB1.ZoomMode := zmFullPage;
+end;
+
+Procedure TCB_IMGPSScanX.CreatePreViewISB(Count:Integer);
+var
+  ISB : TImageScrollBox;
+  Panel : TPanel;
+  i,W,H : Integer;
+  myDate : TDateTime;
+begin
+  FreePreViewISB;
+  ScrollBox1.HorzScrollBar.Visible := False;
+  W := 150;
+  H := 250;
+  for I := 1 to Count do
+  begin
+
+    if FindComponent('M_Pl'+inttostr(i))=nil then
+    begin
+      Panel := TPanel.Create(Self);
+      Panel.Name := 'M_Pl'+inttostr(i);//FormatDateTime('yyyymmddhhnnsszzz', now)
+      Panel.Left := 4;
+      Panel.Top := (i-1)*H+(6*i);
+      Panel.Height := H;
+      Panel.Width := W;
+      Panel.Parent := ScrollBox1;
+      Panel.Caption :='';
+
+      if FindComponent(ISBName+inttostr(i))=nil then
+      begin
+        ISB := TImageScrollBox.Create(Self);
+        ISB.Name := ISBName+inttostr(i);
+        ISB.Parent := Panel;
+        ISB.Align := alClient;
+        ISB.ZoomMode := zmFullPage;
+        ISB.DragMode := dmAutomatic;
+        ISB.MouseMode := mmuser;
+        ISB.OnImageClick := ISBClick;
+        ISB.OnImageMouseMove := ISBMouseMove;
+        ISB.PopupMenu := PopupMenu6;
+        ISB.OnImageMouseDown := ISBImageMouseDown;
+        ISB.OnImageMouseUp := ISBImageMouseUp;
+        ISB.OnEndDrag := ISBEndDrag;
+        ISB.OnDragDrop := ISBDragDrop;
+        ISB.OnDragOver := ISBDragOver;
+      end;
+    end;
+
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.FreePreViewISB;
+var
+  i : Integer;
+begin
+try
+  For i:= ComponentCount -1 downto 0 do
+  begin
+    IF (Components[i] is TImageScrollBox) and (Components[i]<>nil) Then
+    begin
+      IF Pos(ISBName,Components[i].Name) > 0 Then
+        Components[i].Free;
+    end
+    Else If (Components[i] is TPanel) and  (Components[i]<>nil) Then
+    begin
+      IF Pos('M_Pl',Components[i].Name) > 0  Then
+        Components[i].Free;
+    end
+    Else If (Components[i] is TShape) and (Components[i]<>nil) Then
+    begin
+      IF Pos('SP',Components[i].Name) > 0  Then
+        Components[i].Free;
+    end;
+  end;
+  Application.ProcessMessages;
+except on E: Exception do
+end;
+
+  //showmessage(inttostr(Count));
+end;
+
+Procedure TCB_IMGPSScanX.FitPreViewISB;
+var
+  i : Integer;
+  iISB : TImageScrollBox;
+  iPanel : TPanel;
+  T,H : Integer;
+begin
+  T := 0;
+  i := 1;
+
+  while FindComponent(ISBName+inttostr(i)) <> nil do
+  begin
+    iISB := TImageScrollBox(FindComponent(ISBName+inttostr(i)));
+    iISB.Parent.Height := 250;
+    iISB.Parent.Top := T+4;
+    iISB.Parent.Height := iISB.DisplayedGraphic.Height;
+    H := iISB.Parent.Height;
+    T := iISB.Parent.Top+H;
+    inc(i);
+  end;
+
+
+  {For i:= 1 to Count do
+  begin
+    if TImageScrollBox(FindComponent(ISBName+inttostr(i))) = nil then Break;
+
+
+    iISB := TImageScrollBox(FindComponent(ISBName+inttostr(i)));
+    iISB.Parent.Height := H;
+    iISB.Parent.Top := T+4;
+    iISB.Parent.Height := iISB.DisplayedGraphic.Height;
+    H := iISB.Parent.Height;
+    T := iISB.Parent.Top+H;
+  end;}
+
+end;
+
+Procedure TCB_IMGPSScanX.PaintShape(FromImg,ToImg:TImageScrollBox); //畫有被選取的影像
+var
+  i,F_No,T_No : Integer;
+  SP : TShape;
+  ISB : TImageScrollBox;
+  Function GetImgNo(iISB:TImageScrollBox):Integer;
+  begin
+    Result := strtoint(Copy(iISB.Name,length(ISBName)+1,length(iISB.Name)-length(ISBName))); //'PreViewISB'
+  end;
+begin
+  IF ToImg = nil Then   //只畫單一個
+  begin
+    ISB := TImageScrollBox(FindComponent(ISBName+inttostr(GetImgNo(FromImg))));
+    if TShape(FindComponent('SP'+inttostr(GetImgNo(FromImg)))) = nil then
+    begin
+
+    SP := TShape.Create(self);
+    SP.Pen.Color := clblue;
+    SP.Pen.Width := 3;
+    SP.Parent := ScrollBox1;
+    SP.Name := 'SP'+inttostr(GetImgNo(FromImg));
+    SP.Left := ISB.Parent.Left-4;
+    SP.Top := ISB.Parent.Top -4;
+    SP.Width := ISB.Parent.Width + 8;
+    SP.Height := ISB.Parent.Height + 8;
+    end;
+  end
+  Else
+  begin
+    FreeShapeobj(nil);
+    IF GetImgNo(FromImg) <= GetImgNo(ToImg) Then
+    begin
+      F_No := GetImgNo(FromImg);
+      T_No := GetImgNo(ToImg);
+    end
+    Else
+    begin
+      F_No := GetImgNo(ToImg);
+      T_No := GetImgNo(FromImg);
+    end;
+    For i := F_No to T_No do
+    begin
+      ISB := TImageScrollBox(FindComponent(ISBName+inttostr(i)));
+      SP := TShape.Create(self);
+      SP.Pen.Color := clblue;
+      SP.Pen.Width := 3;
+      SP.Parent := ScrollBox1;
+      SP.Name := 'SP'+inttostr(i);
+      SP.Left := ISB.Parent.Left-4;
+      SP.Top := ISB.Parent.Top -4;
+      SP.Width := ISB.Parent.Width + 8;
+      SP.Height := ISB.Parent.Height + 8;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.ISBClick(Sender : TObject);
+var
+  v,ln:Integer;
+begin
+  if (GetKeyState(VK_SHIFT) < 0) Then
+  begin
+    PaintShape(SelectISB,TImageScrollBox(Sender));
+    SelectISB := TImageScrollBox(Sender);
+  end
+  Else if (GetKeyState(VK_CONTROL) < 0) Then
+  begin
+    SelectISB := TImageScrollBox(Sender);
+    IF TShape(FindComponent('SP'+Copy(SelectISB.Name,length(ISBName)+1,length(SelectISB.Name)-length(ISBName)))) = nil Then
+      PaintShape(SelectISB,nil)
+    else
+      FreeShapeobj(SelectISB);
+  end
+  Else
+  begin
+    FreeShapeobj(nil);
+    SelectISB := TImageScrollBox(Sender);
+    PaintShape(SelectISB,nil);
+  end;
+  GetSelectImageFile;
+
+  v := length(ISBName);
+  ln := length(SelectISB.Name);
+  SelectPage := Strtoint(Copy(SelectISB.Name,v+1,ln-v));
+  ISB1.ZoomMode := zmFittoPage;
+//ShowMessage('SelectISB.FileName='+SelectISB.FileName);
+  //if SelectISB.FileName='' then exit;
+
+  ISB1.LoadFromFile(SelectISB.FileName,1);
+  if (ISB1.Graphic.ImageFormat <> ifBlackWhite) and (SmoothCB.Checked)then
+    Image_Smooth(ISB1.Graphic);
+  ISB1.Redraw(True);
+  ISB1Click(ISB1);
+end;
+
+Procedure TCB_IMGPSScanX.ISBMouseMove(Sender: TObject; Shift: TShiftState;
+  X, Y: Integer);
+begin
+  //Edit1.SetFocus;
+  if Draging then
+  begin
+    if not (TShape(FindComponent('SP'+Copy(TImageScrollBox(Sender).Name,length(ISBName)+1,length(TImageScrollBox(Sender).Name)-length(ISBName)))) = nil) then
+    begin
+      SelectISB.BeginDrag(False);
+      Draging := False;
+    end;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.ISBImageMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+var
+  v,ln:Integer;
+begin
+  if Button = TMouseButton(mbLeft) Then
+  begin
+    Draging := True;
+    //if SelectISB <> nil then
+
+    //if not Draging then
+    //begin
+
+  end;
+  //end;
+
+  {if not (TShape(FindComponent('SP'+Copy(TImageScrollBox(Sender).Name,length(ISBName)+1,length(TImageScrollBox(Sender).Name)-length(ISBName)))) = nil) then
+  begin
+    //Showmessage('SP'+Copy(TImageScrollBox(Sender).Name,length(ISBName)+1,length(TImageScrollBox(Sender).Name)));
+    if (Button = TMouseButton(mbLeft)) and (GetKeyState(VK_CONTROL) >= 0) then
+    begin
+      if SelectISB <> nil then
+        SelectISB.BeginDrag(False);
+    end;
+  end;
+  //if (TShape(FindComponent('SP'+Copy(TImageScrollBox(Sender).Name,length(ISBName)+1,length(TImageScrollBox(Sender).Name)-length(ISBName)))) = nil) then
+  //begin
+  //else
+  //begin
+  if not Draging then
+  begin
+    if (GetKeyState(VK_SHIFT) < 0) Then
+    begin
+      PaintShape(SelectISB,TImageScrollBox(Sender));
+      SelectISB := TImageScrollBox(Sender);
+    end
+    Else if (GetKeyState(VK_CONTROL) < 0) Then
+    begin
+      SelectISB := TImageScrollBox(Sender);
+      IF TShape(FindComponent('SP'+Copy(SelectISB.Name,length(ISBName)+1,length(SelectISB.Name)-length(ISBName)))) = nil Then
+        PaintShape(SelectISB,nil)
+      else
+        FreeShapeobj(SelectISB);
+    end
+    Else
+    begin
+      FreeShapeobj(nil);
+      SelectISB := TImageScrollBox(Sender);
+      PaintShape(SelectISB,nil);
+    end;
+    v := length(ISBName);
+    ln := length(SelectISB.Name);
+    SelectPage := Strtoint(Copy(SelectISB.Name,v+1,ln-v));
+    ISB1.ZoomMode := zmFittoPage;
+    ISB1.LoadFromFile(SelectISB.FileName,1);
+    ISB1Click(ISB1);
+  end;
+  //end;
+  //end
+  //Else
+  //begin
+
+  //end; }
+
+  {if (Button = TMouseButton(mbRight)) and (TShape(FindComponent('SP'+Copy(TImageScrollBox(Sender).Name,length(ISBName)+1,length(TImageScrollBox(Sender).Name)-length(ISBName)))) = nil) then
+  begin
+    //ISBClick(Sender);
+  end;
+  if (Button = TMouseButton(mbLeft)) then
+  begin
+
+  end; }
+end;
+
+procedure TCB_IMGPSScanX.ISBImageMouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+begin
+  Draging := False;
+end;
+
+procedure TCB_IMGPSScanX.ISBEndDrag(Sender, Target: TObject; X, Y: Integer);
+begin
+  TreeView1Click(self);
+end;
+
+procedure TCB_IMGPSScanX.ISBDragDrop(Sender, Source: TObject; X, Y: Integer);
+var
+  fp,tp : Integer;
+begin
+  fp := FileName2ScanPage(TimageScrollBox(Source).FileName);
+  tp := FileName2ScanPage(TimageScrollBox(Sender).FileName);
+  MoveImage_Drag(DisplayPath+NowDocDir+'\',fp,tp );
+
+end;
+
+procedure TCB_IMGPSScanX.ISBDragOver(Sender, Source: TObject; X, Y: Integer;
+      State: TDragState; var Accept: Boolean);
+var
+  So : Boolean;
+begin
+  {if (TObject(Source) is TImageScrollBox) and (TObject(Sender) is TImageScrollBox) then
+  begin
+    Label3.Caption := TImageScrollBox(Source).FileName+#13+TImageScrollBox(Sender).FileName;
+  end;  }
+
+  So := False;
+  if TObject(Source) is TImageScrollBox then
+    So := True;
+  Accept := True;
+  if not So
+    or (TImageScrollBox(Source).FileName = TImageScrollBox(Sender).FileName)
+    or (TreeView1.Selected.Level <> 2)
+    Then
+      Accept := False;
+end;
+
+Function TCB_IMGPSScanX.FindMpsView(Vmode: Integer):TImageScrollBox;
+var
+  i,n : Integer;
+  ISB : TImageScrollBox;
+begin
+  case Vmode of
+    0 : n := 1;
+    1 : n := 2;
+    2 : n := 4;
+    3 : n := 6;
+    4 : n := 8;
+  end;
+  for i := 1 to 8 do
+  begin
+    if i > n then Break;
+    ISB := TImageScrollBox(FindComponent('ISB'+inttostr(i)));
+    if (i = n) and (ISB.FileName <> '') then
+    begin
+      clearView(i);
+      Result := ISB1;
+    end
+    Else if ISB.FileName = '' then
+      Result := ISB;
+  end;
+end;
+
+Function TCB_IMGPSScanX.GetCaseFormID(Path:String):String;  //取案件的主FormID
+var i,n : Integer;
+    FileFormID : String;
+begin
+  Result := '';
+  ContextList.LoadFromFile(Path+'Context.dat');
+  for I := 0 to ContextList.Count - 1 do
+  begin
+    FileFormID := FileName2FormCode(ContextList.Strings[i]);
+
+    if DivPageFormIDList.IndexOf(FileFormID)<>-1 then //20170509 跳過分案頁的formid
+    begin
+      Continue;
+    end;
+    if FindDivFormCode(FileFormID) then
+    begin
+      Result := FileFormID;
+      Break;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.CreateFormID_FormName(Path,CaseID:String);  //產生FormID_FormName.dat
+var i : Integer;
+    S : TStringlist;
+    FormID : String;
+    FormName : String;
+begin
+  S := TStringlist.Create;
+  try
+    for I := 0 to ContextList.Count - 1 do
+    begin
+      FormID := FileName2FormCode(ContextList.Strings[i]);
+      FormName := FormCode2FormName(CaseID,FormID);
+      S.Add(FormID+'_'+FormName);
+    end;
+    S.SaveToFile(Path + 'FormCode_Name.dat',TEnCoding.UTF8);
+  finally
+  S.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FormIDExists(FormCode:String;CheckDate:Boolean;index:Integer):Boolean;  //檢查FormID是否存在
+var
+  STDate,SPDate : String;
+  Docno,Version : String;
+begin
+  Result := False;
+  If FormCode = '' then  //附件不檢查
+  begin
+    Result := True;
+    Exit;
+  end;
+  if CheckDate then  //要檢查日期
+  begin
+    STDate := '00000000'; //沒設定
+    SPDate := '99999999'; //沒設定
+
+    IF FindSQLData(FORM_INF_List,'T1.FORM_ID,T1.DOC_NO','T1.FORM_ID',FormCode,index,FindResult) then
+    begin
+      DocNo := GetFindResult('T1.DOC_NO');
+      Version := FormCode2Version(FormCode);
+      if FindSQLData(Doc_Inf_List,'START_DATE,STOP_DATE','DOC_NO,DOC_VERSION',DocNo+','+Version,0,FindResult) then
+      begin
+        Result := True;
+        STDate := GetFindResult('START_DATE');
+        SPDate := GetFindResult('STOP_DATE');
+        if STDate = '' then STDate := '00000000'; //沒設定
+        if SPDate = '' then SPDate := '99999999'; //沒設定
+        if (ServerDate < STDate) or (ServerDate > SPDate) then
+          Result := False;
+      end;
+    end;
+  end
+  Else
+  begin
+    Result := FindSQLData(FORM_INF_List,'T1.FORM_ID','T1.FORM_ID',FormCode,index,FindResult);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.CB1Click(Sender: TObject);
+begin
+  TwainShowUI := CB1.Checked;
+end;
+
+Function TCB_IMGPSScanX.GetKeyinSet : Boolean; //取登打設定
+var
+  SendData : String;
+  LastDateTime : String;
+  S : TStringlist;
+begin
+  Result := True;
+  S := TStringlist.Create;
+  Try
+    if FileExists(SitePath+'KeyinSet.zip') then
+      DeleteFile(SitePath+'KeyinSet.zip');
+
+    LastDateTime := '00000000000000';
+    if FileExists(SitePath+'LastDateTime.dat') then
+    begin
+      S.LoadFromFile(SitePath+'LastDateTime.dat');
+      LastDateTime := S.Strings[0];
+    end;
+    SendData := 'settype=2&lastupdate='+LastDateTime;
+    if not dnFile_Get(HTTPSClient,Furl,'service/imgpsc/IMGPSC01/settings',SendData,SitePath+'KeyinSet.zip',FReWrite,Memo1,False,DownImgStatus) then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+    if FileExists(SitePath+'KeyinSet.zip') then  //有更新
+    begin
+      ExecuteUnZip(SitePath+'KeyinSet.zip',SitePath,True);
+      S.Clear;
+      S.Add(ServerDate+GetBalance2Time(Balance));
+      S.SaveToFile(SitePath+'LastDateTime.dat');
+    end
+    Else
+    begin
+      if (Memo1.Lines.Strings[0] = 'nodata') Then   //沒更新
+      begin
+        Result := True;
+      end
+      Else if (Memo1.Lines.Strings[0] = '1') Then
+      begin
+        HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+        Result := False;
+        Exit;
+      end
+      Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+      begin
+        HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+        Result := False;
+        Exit;
+      end;
+    end;
+
+  Finally
+  S.Free;
+  End;
+
+end;
+
+
+procedure TCB_IMGPSScanX.TransBtnClick(Sender: TObject);
+Var
+  CaseID : String;
+  i,n,v: Integer;
+  ZipFileList : TStringlist;
+  CaseTrans : Integer; //-1:失敗 0:可 1:不行
+  SuccessCount,ReCasecount,CheckErrCount : Integer;
+  TransMsg : String;
+  AreaStr : String;
+  S : TStringlist;
+  CheckStr : String;
+  uploadMsg:String;//20171122 新增 配合不同mode下要秀不能上傳訊息
+begin
+  IF not InitialOk Then
+  begin
+    Showmessage(_msg('資訊尚未下載完成,請稍候或重新進入'));
+    Exit;
+  end;
+LogFile1.LogToFile(logTimeString+'按下上傳');
+  ClearView(1);
+  CaseHelpBtn.Visible := False;
+  DisplayPath := '';
+  ClearCaseIndex;
+  RejectCase := False;
+  uploadMsg:='';
+  if not CheckCaseID_OK then  //檢查是否有未配號的案件
+  begin
+    Showmessage(_Msg('尚有「無案件編號」之案件,無法上傳'));
+    Exit;
+  end;
+
+  if not CheckCaseAttach_OK then  //20170911檢查是否有未歸類的案件
+  begin
+    Showmessage(_Msg('尚有未歸類文件,無法上傳'));
+    Exit;
+  end;
+
+
+  if NewTreeNode.Count = 0  then
+  begin
+    Showmessage(_Msg('無影像需傳送'));
+    Exit;
+  end;
+
+  SuccessCount := 0;
+  ReCasecount := 0;
+  CheckErrCount := 0;
+  if (FMode = 'NSCAN') and (not CheckScanDenialTime) then
+  begin
+    if Messagedlg(Format(_Msg('己超過收件時間(%s),預定作業日為下個營業日,是否繼續上傳??'),[ScanDenialTime]),mtConfirmation,[mbyes,mbcancel],0)=mrcancel then Exit;
+  end;
+
+  ShowText := _Msg('資料上傳中,請稍候');
+  DataLoading(True,True);
+
+  For i := 0 to NewTreeNode.Count -1 do
+  begin
+    v := posend('-',NewTreenode.Item[i].Text);
+    CaseID := Copy(NewTreenode.Item[i].Text,1,v-1);
+    ShowText := CaseID+_Msg('資料上傳中,請稍候');
+    DataLoading(True,True);
+    CreateIn_WH(CaseID);    //產生入庫文件文字檔 In_Wh.dat
+    Case2upload(CaseID);   //產生原影像結構
+    TransPath := ImageSavePath+CaseID+'\Upload\';
+    {if FMode = 'ESCAN' then    //20140320 yuu說拿掉此檢查
+    begin
+      S := TStringlist.Create;
+      try
+        S.LoadFromFile(TransPath + 'Context.dat');
+        if S.Count = 0 then
+        begin
+          Showmessage(_Msg('無影像檔無法傳送'));
+          DataLoading(False,False);
+          LoadImgFile;
+          Exit;
+        end;
+      finally
+      s.Free;
+      end;
+    end;}
+    if (FMode = 'NSCAN') or (FMode = 'DSCAN')  then //20170406 待掃瞄也要問一下
+    begin
+      /////訊問是否可上傳/////
+      CaseTrans := CaseAsk(CaseID);
+      //Showmessage('記得改回來');
+      //CaseTrans := 0;
+
+      /////訊問是否可上傳////
+    end
+    Else  ///不是新件、重掃件、異動件的不查
+    begin
+      CaseTrans := 0;
+    end;
+    if CaseTrans = -1 then  //失敗
+    begin
+      Showmessage(_Msg('')+HttpErrStr+'.');
+      DataLoading(False,False);
+      LoadImgFile;
+      Exit;
+    end;
+    if CaseTrans = 1 then
+    begin
+      ////重複處理/////
+      Inc(ReCasecount);
+      ////重複處理/////
+      Continue;
+    end
+    Else if CaseTrans = 0 then   //可以傳送
+    begin
+      ///////檢核//////  20100927 User改為搬至外面做  ///20101019 User又改回上傳要做
+      //if FMode = 'NSCAN' then  //20101019改成讀設定那些模式要做那些檢核
+      //begin
+       ///依十字定位點縮放////
+       CaseReSize(CaseID);   //所以影像再做一次縮放
+       ////依十字定位點縮放///////   }
+        if (FMode <> 'FSCAN') then
+        begin
+          if (NewTreenode.Item[i].ImageIndex <> 7) and (NewTreenode.Item[i].ImageIndex <> 5) then  //檢核完成的不再檢核
+          begin
+            ShowText := CaseID+_Msg('檢核中,請稍候');
+            DataLoading(True,True);
+            If not OMRCheckCase(CaseID) then  //進檢核
+            begin
+              Inc(CheckErrCount);
+              Continue;
+            end;
+          end;
+          if (NewTreenode.Item[i].ImageIndex = 5) then
+          begin
+            Inc(CheckErrCount);
+            Continue;
+          end;
+        end;
+      //end;
+      ///////檢核//////
+      ShowText := CaseID+_Msg('資料上傳中,請稍候');
+      DataLoading(True,True);
+//ShowMessage('退出');DataLoading(False,False);Exit;
+      If Not TransCaseID(TransPath,CaseID,True) Then  //傳送案件
+      begin
+        DataLoading(False,False);
+        LoadImgFile;
+        Exit;
+      end;
+      Inc(SuccessCount);
+    end;
+  end;
+  DataLoading(False,False);
+  TransMsg := Format(_Msg('成功件【%d】件'),[SuccessCount]);
+  if ReCasecount > 0 then
+    TransMsg := TransMsg + #13#10 + Format(_Msg('無法上傳件【%d】件'),[ReCasecount]);
+  if CheckErrCount > 0 then
+  begin
+    TransMsg := TransMsg + #13#10 + Format(_Msg('檢核失敗件【%d】件,請先點選「案件編號」,再點選「問號」查看錯誤原因'),[CheckErrCount]);
+LogFile1.LogToFile(logTimeString+'檢核失敗原因:'+OMRErrini2ListForLog(''));
+  end;
+
+  if (FMode = 'DSCAN') and (SuccessCount = 1)  then
+  begin
+    uploadMsg:=NowCaseNo+_Msg('影像上傳完成。此案已進入下一流程');
+  end;
+  if (FMode='ESCAN') and (FModeName=_Msg('補件掃描')) and (SuccessCount = 1) then
+  begin
+    uploadMsg:=NowCaseNo+_Msg('影像已補件完成');
+  end;
+//ShowMessage('uploadMsg='+uploadMsg);
+  if uploadMsg<>'' then
+  begin
+    ShowMessage(uploadMsg);
+  end
+  else
+  begin
+    Showmessage(_Msg('傳送完成')+#13#10+TransMsg);
+  end;
+
+  LoadImgFile;
+  if (FMode = 'ESCAN') and (SuccessCount = 1) then
+  begin
+    if FEvents <> nil Then
+    begin
+      FEvents.OnClosePage;
+    end;
+  end;
+  if (FMode = 'DSCAN') and (SuccessCount = 1) then
+  begin
+    if FEvents <> nil Then
+    begin
+      FEvents.OnClosePage;
+    end;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.TreeView1Click(Sender: TObject);
+Var
+  v,v1,v2,v3,ln : Integer;
+  i,page : Integer;
+  F : TSearchrec;
+begin
+  ScanMode := smNew;
+  IF TreeView1.Selected = nil Then Exit;
+  Scrollbar1.Position := 1;
+  Scrollbar1.Max := 1;
+  DisplayPath := '';
+  NowCaseno := '';
+  NowDocDir := '';
+  NowDocNo := '';
+  NowFormCode := '';
+  NowFormName := '';
+  NowPage := 0;
+  NowShowFileList.Clear;
+  StatusBar1.Panels[2].Text := '';
+  ClearCaseIndex;
+  PageLv.Items.Clear;  //頁數清單
+  //Panel18.Enabled:= False;
+  AttListBox.Items.Clear;
+  AddAttFileLB.Enabled := False;
+  DelAttFileLB.Enabled := False;
+  UseOldCaseLb.Visible := False;
+  PM107.Visible := False; //備註功能
+  CaseHelpBtn.Visible := False; //檢核失敗原因鈕
+  Panel5.Visible := True;
+  ContextList.Clear;
+  SortMode := false;
+  ISB1.ZoomMode := zmFullPage;
+  IF TreeView1.Selected.Parent <> nil Then
+  begin
+    if TreeView1.Selected.Parent = NewTreenode then  //點在案件上
+    begin
+      //Panel18.Enabled := True;
+      PM107.Visible := True; //備註功能
+      MyTreeNode1 := TreeView1.Selected;
+      MyTreeNode2 := nil;
+      MyTreeNode3 := nil;
+      v := Posend('-',MyTreenode1.Text);
+      v1 := Length(MyTreenode1.Text);
+      NowCaseNo := Copy(TreeView1.Selected.Text,1,v-1);
+      if (FMode = 'ESCAN') and (FOldCaseInfo <> '') then
+        UseOldCaseLb.Visible := True;
+      ClearView(1);
+      DisplayPath := ImageSavePath+NowCaseNo+'\';
+      if FLoanDoc_Enable = 'Y' then
+      begin
+        AddCredit1RG.Enabled := True;
+      end;
+      ReadCaseIndex(DisplayPath);
+      If FileExists(DisplayPath+'\upload\Checkerr.ini') and (not FileExists(DisplayPath+'\upload\OMRCheckOk.dat')) Then
+        CaseHelpBtn.Visible := True;
+      IF FileExists(DisplayPath+'CaseDocNo.dat') Then
+      begin
+        CaseDocNoList.LoadFromFile(DisplayPath+'CaseDocNo.dat');
+
+
+        view_image_DocNo(DisplayPath,'ShowAll','',1);
+      end;
+      if FileExists(DisplayPath+'CustomDocNo.dat') then
+        Cust_DocNoList.LoadFromFile(DisplayPath+'CustomDocNo.dat');
+
+
+      Page := ContextList.Count;
+      For i := 1 to page do
+      begin
+        With PageLV.Items.Add do
+        begin
+          Caption := Add_Zoo(i,3);
+        end;
+      end;
+      If Page > 0 then
+        ScrollBar1.Max := page;
+      MyTreeNode1.Expand(True);
+    end
+    Else If TreeView1.Selected.Parent.Parent  = NewTreenode Then    //點在文件上
+    begin
+
+      MyTreeNode1 := TreeView1.Selected.Parent;
+      MyTreeNode2 := TreeView1.Selected;
+      MyTreeNode3 := nil;
+      v := Pos('-',MyTreenode1.Text);
+      NowCaseNo := Copy(MyTreenode1.Text,1,v-1);
+
+      v := Posend('{',MyTreenode2.Text);
+      v1 := Posend('}',MyTreenode2.Text);
+      v2 := posend('-',MyTreenode2.Text);
+      ln := length(MyTreenode2.Text);
+      NowDocDir := Copy(MyTreeNode2.Text,v+1,v1-v-1);
+      NowDocNo := DocNoDir2DocNo(NowDocDir);
+      page :=Strtoint(Copy(MyTreeNode2.Text,v2+1,ln-v2-1));
+      if (FMode = 'ESCAN') and (FOldCaseInfo <> '') then
+        UseOldCaseLb.Visible := True;
+      ClearView(1);
+      DisplayPath := ImageSavePath+NowCaseNo+'\';
+
+      if GetUseCase('F',DisplayPath,NowDocDir) <> '' then
+        StatusBar1.Panels[2].Text := Format(_Msg('從%s引用'),[GetUseCase('F',DisplayPath,NowDocDir)]);
+      if GetUseCase('T',DisplayPath,NowDocDir) <> '' then
+        StatusBar1.Panels[2].Text := Format(_Msg('被%s引用'),[GetUseCase('T',DisplayPath,NowDocDir)]);
+      if FLoanDoc_Enable = 'Y' then
+      begin
+        AddCredit1RG.Enabled := True;
+      end;
+      ReadCaseIndex(DisplayPath);
+      If FileExists(DisplayPath+'Checkerr.ini') and (not FileExists(DisplayPath+'OMRCheckOk.dat')) Then
+        CaseHelpBtn.Visible := True;
+      If Page > 0 then
+        ScrollBar1.Max := page;
+      For i := 1 to page do
+      begin
+        With PageLV.Items.Add do
+        begin
+          Caption := Add_Zoo(i,3);
+        end;
+      end;
+
+      If FileExists(DisplayPath+'Checkerr.ini') and (not FileExists(DisplayPath+'OMRCheckOk.dat')) Then
+        CaseHelpBtn.Visible := True;
+      IF FileExists(DisplayPath+NowDocDir+'\Context.dat') Then
+      begin
+        ContextList.LoadFromFile(DisplayPath+NowDocDir+'\Context.dat');
+        //Context_DocnoList.LoadFromFile(DisplayPath+'Context_Docno.dat');
+        view_image_DocNo(DisplayPath,NowDocDir,'',Page);
+      end;
+      if FileExists(DisplayPath+'CustomDocNo.dat') then
+        Cust_DocNoList.LoadFromFile(DisplayPath+'CustomDocNo.dat');
+       MyTreeNode1.Expand(True);
+    end
+    Else If (NewTreenode <> nil) and (TreeView1.Selected.Parent.Parent.Parent  = NewTreenode) Then //點在表單上
+    begin
+      //NoteBtn.Visible := True; //備註功能
+      //Panel18.Enabled := True;
+      ClearView(1);
+      PM107.Visible := True; //備註功能
+      MyTreeNode1 := TreeView1.Selected.Parent.Parent;
+      MyTreeNode2 := TreeView1.Selected.Parent;
+      MyTreeNode3 := TreeView1.Selected;
+
+      v := Posend('-',MyTreenode1.Text);
+      NowCaseNo := Copy(MyTreenode1.Text,1,v-1);
+
+      if (FMode = 'ESCAN') and (FOldCaseInfo <> '') then
+        UseOldCaseLb.Visible := True;
+
+      v := Posend('{',MyTreenode2.Text);
+      v1 := Posend('}',MyTreenode2.Text);
+      v2 := posend('-',MyTreenode2.Text);
+      ln := length(MyTreenode2.Text);
+      NowDocDir := Copy(MyTreeNode2.Text,v+1,v1-v-1);
+      NowDocNo := DocNoDir2DocNo(NowDocDir);
+
+      v := Posend('{',MyTreenode3.Text);
+      v1 := Posend('}',MyTreeNode3.Text);
+      v2 := Posend('-',MyTreeNode3.Text);
+      ln := Length(MyTreeNode3.Text);
+      if v>0 then
+      begin
+        NowFormCode := Copy(MyTreeNode3.Text,v+1,v1-v-1);
+        if (NowFormCode = 'Attach') or (NowFormCode = 'S_Attach') then
+          NowFormCode := '';
+        NowFormName := Copy(MyTreeNode3.Text,v+1,v1-v-1);
+        page := strtoint(Copy(MyTreeNode3.Text,v2+1,ln-v2-1));
+      end
+      Else  //點在附件的頁數
+      begin
+        NowFormCode := '';
+        page := 1;
+      end;
+
+      DisplayPath := ImageSavePath+NowCaseNo+'\';
+
+      if GetUseCase('F',DisplayPath,NowDocDir) <> '' then
+        StatusBar1.Panels[2].Text := Format(_Msg('從%s引用'),[GetUseCase('F',DisplayPath,NowDocDir)]);
+      if GetUseCase('T',DisplayPath,NowDocDir) <> '' then
+        StatusBar1.Panels[2].Text := Format(_Msg('被%s引用'),[GetUseCase('T',DisplayPath,NowDocDir)]);
+
+      if FLoanDoc_Enable = 'Y' then
+      begin
+        AddCredit1RG.Enabled := True;
+      end;
+      ReadCaseIndex(DisplayPath);
+      If FileExists(DisplayPath+'Checkerr.ini') and (not FileExists(DisplayPath+'OMRCheckOk.dat')) Then
+        CaseHelpBtn.Visible := True;
+      If Page > 0 then
+        ScrollBar1.Max := page;
+      For i := 1 to page do
+      begin
+        With PageLV.Items.Add do
+        begin
+          Caption := Add_Zoo(i,3);
+        end;
+      end;
+      If FileExists(DisplayPath+NowDocDir+'\Context.dat') Then
+      begin
+        ContextList.LoadFromFile(DisplayPath+NowDocDir+'\Context.dat');
+        view_image_DocNo(DisplayPath,NowDocDir,NowFormCode,Page);
+        //view_image_FormCode(DisplayPath,NowFormCode,1,1);
+      end;
+      if FileExists(DisplayPath+'CustomDocNo.dat') then
+        Cust_DocNoList.LoadFromFile(DisplayPath+'CustomDocNo.dat');
+    end;
+    MyTreeNode1.Expand(True);
+    AddAttFileLB.Enabled := True;
+    if FileExists(DisplayPath+'ATTContext.dat') then
+    begin
+      LoadAttFile(NowCaseno);
+    end;
+  end
+  Else     //點在NewTreenode or MyTreenode1 上
+  begin
+    ClearView(1);
+    MyTreeNode1 := nil;
+    MyTreeNode2 := nil;
+    MyTreeNode3 := nil;
+  end;
+  TreeView1.Selected.MakeVisible;
+  CaseList.Clear;
+  if FileExists(ImageSavePath + 'CaseList.dat') then
+    CaseList.LoadFromFile(ImageSavePath + 'CaseList.dat');
+  //CountCaseno;
+  //CountCaseCount;
+  Application.ProcessMessages;
+end;
+
+procedure TCB_IMGPSScanX.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
+var
+  NewCaseno,NewDocNo,NewDocDir,NewFormCode,NewFormName : String;
+  NewPath,NewFileName:String;
+  OldFileName : String;
+  iTreeNode1,iTreeNode2,iTreeNode3: TTreeNode;
+  i,v,v1,v2 : Integer;
+  PreIndex,Precount,NowCount:Integer;
+  GoAtt : Boolean;
+  AttLv : Integer;
+begin
+  NewCaseno := '';
+  NewFormCode := '';
+  NewFormName := '';
+  Precount := MyTreeNode1.Count;
+  PreIndex := -1;
+  GoAtt := False;
+  if (MytreeNode2 <> nil) and (Pos('Attach',MyTreeNode2.Text)>0) then
+  begin
+    AttLv := TreeView1.Selected.Level;
+    GoAtt := True;
+  end;
+
+  if TTreeView(Sender).GetNodeAt(X,Y).Level =2 then
+  begin
+    iTreeNode2 := TTreeView(Sender).GetNodeAt(X,Y);
+    iTreeNode1 := iTreeNode2.Parent;
+    v := Pos('-',iTreenode1.Text);
+    v1 := Length(iTreenode1.Text);
+    NewCaseNo := Copy(iTreeNode1.Text,1,v-1);
+    v := Posend('{',iTreeNode2.Text);
+    v1 := Posend('}',iTreeNode2.Text);
+    NewDocNo := Copy(iTreeNode2.Text,v+1,v1-v-1);
+    NewPath := ImagePath+NewCaseNo+'\';
+    OldFileName := ExtractFileName(DisplayISB.FileName);
+    if Copy(NewDocNo,1,5) = 'ZZZZZ' then  //自訂文件
+    begin
+      NewFileName := Add_Zoo(FileName2ScanPage(OldFileName),3)+'_'+NewDocNo+'0000000'+ExtractFileExt(OldFileName);
+      NewFormCode := NewDocNo+'0000000';
+      {ReNameFile(DisplayISB.FileName,NewPath+NewFileName);
+      ReNameContext(DisplayPath,OldFileName,NewFileName);
+      MyTreeNode2ReFresh(NowCaseno);
+      TreeView1Click(nil);}
+    end;
+    //NewFileName := Add_Zoo(GetCasePage(ImagePath,NewCaseno)+1,3)+FileName2NoQuene_Filename(OldFileName);
+  end
+  Else if TTreeView(Sender).GetNodeAt(X,Y).Level =3 then
+  begin
+    OldFileName := ExtractFileName(DisplayISB.FileName);
+    iTreeNode1 := TTreeView(Sender).GetNodeAt(X,Y).Parent.Parent;
+    iTreeNode2 := TTreeView(Sender).GetNodeAt(X,Y).Parent;
+    iTreeNode3 := TTreeView(Sender).GetNodeAt(X,Y);
+    v := Pos('-',iTreenode1.Text);
+    v1 := Length(iTreenode1.Text);
+    NewCaseNo := Copy(iTreeNode1.Text,1,v-1);
+    v := Pos('{',iTreeNode2.Text);
+    v1 := Pos('}',iTreeNode2.Text);
+    NewDocDir := Copy(iTreeNode2.Text,v+1,v1-v-1);
+
+    v := Pos('{',iTreeNode3.Text);
+    v1 := Pos('}',iTreeNode3.Text);
+    NewFormName := Copy(iTreeNode3.Text,1,v-1);
+    NewFormCode := Copy(iTreeNode3.Text,v+1,v1-v-1);
+    IF v = 0 Then
+    begin
+      NewFormCode := '';
+      v := Posend('-',iTreeNode3.Text);
+      NewFormName := Copy(iTreeNode3.Text,1,v1-1);
+    end;
+    NewPath := ImagePath+NewCaseNo+'\'+NewDocDir+'\';
+    if NewPath = DisplayPath Then  //同案件
+    begin
+      if NewFormCode <> '' then
+        //NewFileName := Copy(OldFileName,1,3)+'_'+NewFormCode+ExtractFileExt(OldFileName)
+        NewFileName := Add_Zoo(GetDocDir_Page(NewCaseNo,NewDocDir),3)+'_'+NewFormCode+ExtractFileExt(OldFileName)
+      Else
+        //NewFileName := Copy(OldFileName,1,3)+ExtractFileExt(OldFileName)
+        NewFileName := Add_Zoo(GetDocDir_Page(NewCaseNo,NewDocDir),3)+ExtractFileExt(OldFileName);
+    end
+    else   //不同案件
+    begin
+      if NewFormCode <> '' then
+        //NewFileName := Copy(OldFileName,1,3)+'_'+NewFormCode+ExtractFileExt(OldFileName)
+        NewFileName := Add_Zoo(GetDocDir_Page(NewCaseNo,NewDocDir),3)+'_'+NewFormCode+ExtractFileExt(OldFileName)
+      Else
+        //NewFileName := Copy(OldFileName,1,3)+ExtractFileExt(OldFileName)
+        NewFileName := Add_Zoo(GetDocDir_Page(NewCaseNo,NewDocDir),3)+ExtractFileExt(OldFileName);
+    end;
+  end;
+  //Showmessage('a');
+  for I := 0 to NowSelectFileList.Count - 1 do
+  begin
+    OldFileName := NowSelectFileList.Strings[i];
+    if NewFormCode <> '' then
+      //NewFileName := Copy(OldFileName,1,3)+'_'+NewFormCode+ExtractFileExt(OldFileName)
+      NewFileName := Add_Zoo(GetDocDir_Page(NewCaseNo,NewDocDir)+1,3)+'_'+NewFormCode+ExtractFileExt(OldFileName)
+    Else
+      //NewFileName := Copy(OldFileName,1,3)+ExtractFileExt(OldFileName)
+      NewFileName := Add_Zoo(GetDocDir_Page(NewCaseNo,NewDocDir)+1,3)+ExtractFileExt(OldFileName);
+
+    if NewCaseNo = NowCaseNo then  //同案件不改順序
+    begin
+      CopyFile(PWideChar(OldFileName),PwideChar(NewPath+NewFileName),False);
+      SetContextList('A',-1,NewCaseNo,NewDocDir,NewFileName);
+      DeleteImageFile(ExtractFilePath(OldFileName),ExtractFileName(OldFileName),NowCaseNo);
+      TreeView1.Selected := MyTreeNode1;
+      //ReNameFile(DisplayPath + OldFileName,NewPath+NewFileName);
+      //ReNameContext(DisplayPath,OldFileName,NewFileName);
+      //MyTreeNode2ReFresh(NowCaseno);
+      //TreeView1Click(nil);
+    end
+    Else
+    begin
+      //Showmessage(DisplayMpsView.FileName+#13+NewPath+NewFileName);
+      ContextList.LoadFromFile(DisplayPath+'Context.dat');
+      if (ContextList.Count = 1) and ((FMode = 'NSCAN') or (FMode = 'ASCAN') or (FMode = 'DSCAN') or (FMode = 'SSCAN') or (FMode = 'MSCAN') or (FMode = 'RI_SCAN') or (FMode = 'ISCAN')) then
+      begin
+        if Messagedlg(Format(_Msg('移動後(%s)案件無影像,將刪除此案件,是否確定移動?'),[NowCaseno]),mtconfirmation,[mbyes,mbcancel],0) = mrCancel then Exit;
+      end;
+      CopyFile(PWideChar(DisplayISB.FileName),PWideChar(NewPath+NewFileName),False);
+      ContextList.LoadFromFile(NewPath+'Context.dat');
+      ContextList.Add(NewFileName);
+      ContextList.SaveToFile(NewPath+'Context.dat');
+      //Showmessage('1');
+      iTreeNode2.Text := Format(_Msg('%s-%d頁'),[NewCaseNo,GetCasePage(ImagePath,NewCaseNo)]);
+      //Showmessage('2');
+      //DrawDocItem(iTreeNode1,FORM_INF_List,NewCaseNo);
+      //DrawDocItem1(MytreeNode1,Doc_Inf_List,NewCaseno);   20140820改
+      DrawDocItem2(MytreeNode1,NewCaseno);
+      //Showmessage('3');
+      ClearErrini(NewCaseNo,iTreeNode1);
+      ContextList.LoadFromFile(DisplayPath+'Context.dat');
+      if (ContextList.Count = 1) and ((FMode = 'NSCAN') or (FMode = 'ASCAN') or (FMode = 'DSCAN') or (FMode = 'SSCAN') or (FMode = 'MSCAN') or (FMode = 'RI_SCAN') or (FMode = 'ISCAN')) then
+      begin
+        _DelTree(DisplayPath);
+        SetCaseList('D',MyTreeNode1.IndexOf(MyTreeNode2),'');
+        LoadImgFile;
+      end
+      Else
+      begin
+        ContextList.Delete(ContextList.IndexOf(ExtractFileName(DisplayISB.FileName)));
+        ContextList.SaveToFile(DisplayPath+'Context.dat');
+        DeleteFile(DisplayISB.FileName);
+        ReSortFileName(DisplayPath);
+        ClearErrini(NowCaseNo,MyTreeNode1);
+        MyTreeNode2ReFresh(NowCaseno);
+        //MyTreeNode3ReFresh(NowCaseno);
+        ContextList.LoadFromFile(DisplayPath+'Context.dat');
+        NowCount := MyTreeNode1.Count;
+        if PreCount = NowCount then
+        begin
+          TreeView1.Selected := MyTreeNode1.Item[PreIndex];
+          TreeView1Click(nil);
+        end
+        Else
+        begin
+          TreeView1.Selected := MyTreeNode1;
+          TreeView1Click(nil);
+        end;
+      end;
+    end;
+  end;
+  for I := 0 to NowSelectFileList.Count - 1 do
+  begin
+    OldFileName := NowSelectFileList.Strings[i];
+    ReSortFileName(ExtractFilePath(OldFileName));
+  end;
+  DrawDocItem2(MytreeNode1,NowCaseno);
+  ClearErrini(NowCaseno,MyTreeNode1);  //清掉檢核記錄
+  if GoAtt then
+  begin
+    GotoAttach(AttLv);
+  end;
+  //TreeView1Click(nil);
+
+end;
+
+procedure TCB_IMGPSScanX.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
+  State: TDragState; var Accept: Boolean);
+var
+  NewNode : TTreeNode;
+  ImgFormCode : String;
+  ImgDocNo : String;
+  So : Boolean;
+begin
+  ImgFormCode := FileName2FormCode(ExtractFileName(DisplayISB.FileName));
+  ImgDocNo := Path2DocDir(ExtractFilePath(DisplayISB.FileName),NowCaseno);
+  //ImgDocNo := FileName2NowDcoNo(ExtractFileName(DisplayISB.FileName),ContextList,Context_DocnoList);
+  NewNode := TTreeView(Sender).GetNodeAt(X,Y);
+  //Label3.Caption := format('%d/%s/%s',[NewNode.Level,ImgDocNo,Node2DocNo(NewNode)]);
+  So := False;
+  if TObject(Source) is TImageScrollBox then
+    So := True;
+  Accept := True;
+  if not So
+    or(NewNode=nil)
+    or((NewNode.Level<>3))
+    or((NewNode.Level =3) and (((ImgFormCode=Node3FormID(NewNode)) and (ImgDocNo = Node3DocNo(NewNode))) or (Node3DocNo(NewNode)='')))
+    or(Pos(_Msg('Attach'),Newnode.Text)>0)
+    Then
+      Accept := False;
+
+  {if not So
+    or(NewNode=nil)
+    or((NewNode.Level <>2) and (NewNode.Level<>3))
+    or((NewNode.Level =2) and ((ImgDocNo = Node2DocNo(NewNode))or(Node2DocNo(NewNode)='')or (copy(Node2DocNo(NewNode),1,5)<>'ZZZZZ')))
+    or((NewNode.Level =3) and ((ImgFormCode=Node3FormID(NewNode)) or (ImgDocNo = Node3DocNo(NewNode)) or (Node3DocNo(NewNode)='')))
+    or(Pos(_Msg('未註冊文件'),Newnode.Text)>0)
+     Then
+      Accept := False;}
+end;
+
+procedure TCB_IMGPSScanX.TreeView1KeyUp(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  IF TreeView1.Selected.Parent <> nil Then
+  begin
+    TreeView1Click(nil);
+  end
+  else
+  begin
+    ClearView(1);
+  end;
+
+end;
+
+procedure TCB_IMGPSScanX.TreeView1MouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+  IF Button = TMouseButton(MbRight) Then
+  begin
+    MDown := True;
+    If TreeView1.GetNodeAt(X,Y) = nil then Exit;
+    TreeView1.Selected := TreeView1.GetNodeAt(X,Y);
+  end;
+end;
+
+procedure TCB_IMGPSScanX.TreeView1MouseEnter(Sender: TObject);
+begin
+TreeView1.SetFocus;
+end;
+
+procedure TCB_IMGPSScanX.TreeView1MouseMove(Sender: TObject; Shift: TShiftState;
+  X, Y: Integer);
+begin
+  //TreeView1.SetFocus;
+  {UnRegisterHotKey(Handle, HotKeyId1);
+  UnRegisterHotKey(Handle, HotKeyId2); }
+end;
+
+procedure TCB_IMGPSScanX.TreeView1MouseUp(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+begin
+  IF Button = TMouseButton(MbRight) Then
+  begin
+    If TreeView1.GetNodeAt(X,Y) = nil then Exit;
+    if MDown then
+    begin
+      TreeView1Click(self);
+      TreeView1.PopupMenu.Popup(Mouse.CursorPos.X ,Mouse.CursorPos.Y);
+    end;
+    Application.ProcessMessages; //需加這行,不然有些全域變數會沒變到
+    MDown:= False;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.ViewModeBtnMouseEnter(Sender: TObject);
+begin
+  AddToolTip(TBitBtn(Sender).Parent.Handle,nil,0,Pchar(TBitBtn(Sender).Hint),nil,0,0);
+end;
+
+function TCB_IMGPSScanX.Get_check_main_form: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_check_main_form(const Value: WideString);
+begin
+  FCheck_main_form := Value;
+end;
+
diff --git a/separate/scanImp/CB_IMGPSScanImp_UI.ts b/separate/scanImp/CB_IMGPSScanImp_UI.ts
new file mode 100644
index 0000000..b303bfb
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_UI.ts
@@ -0,0 +1,78 @@
+import * as fs from 'fs'; import * as path from 'path';
+export function applyUIMixins(cls:any){
+  cls.prototype.WMMOUSEWHEEL=function(m:any){
+    if(m.WheelDelta===120){
+      if(this.ScrollBox1.Focused)this.ScrollBox1.VertScrollBar.Increment=50;
+      if(this.DisplayISB!==null){if(this.DisplayISB.Focused&&m.Keys===0)this.DisplayISB.VertScrollBar.Increment=50;if(this.DisplayISB.Focused&&m.Keys===50){this.DisplayISB.ZoomMode='zmPercent';if(this.DisplayISB.ZoomPercent<90)this.DisplayISB.ZoomPercent+=10;}}
+    }else if(m.WheelDelta===-120){
+      if(this.ScrollBox1.Focused)this.ScrollBox1.VertScrollBar.Increment=50;
+      if(this.DisplayISB!==null){if(this.DisplayISB.Focused&&m.Keys===0)this.DisplayISB.VertScrollBar.Increment=50;if(this.DisplayISB.Focused&&m.Keys===50){this.DisplayISB.ZoomMode='zmPercent';if(this.DisplayISB.ZoomPercent>10)this.DisplayISB.ZoomPercent-=10;}}
+    }
+  };
+  cls.prototype.WNoteBtnClick=function(s:any){
+    this.ShowText=this._Msg('備註輸入中,請稍候');this.DataLoading(true,true);let SortMemoForm=new this.TSortMemoForm(this),S=new this.TStringlist();
+    try{
+      this.InitialLanguage(SortMemoForm);SortMemoForm.ContentList=new this.TStringlist();SortMemoForm.MemoIDList=new this.TStringlist();SortMemoForm.MemoNameList=new this.TStringlist();
+      for(let i=1;i<this.MEMO_INF_List.Count;i++){let MC=this.GetSQLData(this.MEMO_INF_List,'T1.MEMO_CONTENT',i),MI=this.GetSQLData(this.MEMO_INF_List,'T1.MEMO_TYPE',i),MN=this.GetSQLData(this.MEMO_INF_List,'T2.MEMO_TYPE_NAME',i);SortMemoForm.ComboBox1.Items.Add(MN+'-->'+MC);SortMemoForm.ContentList.Add(MC);SortMemoForm.MemoIDList.Add(MI);SortMemoForm.MemoNameList.Add(MN);}
+      if(fs.existsSync(path.join(this.DisplayPath,'Scan_Memo.dat'))){S.LoadFromFile(path.join(this.DisplayPath,'Scan_Memo.dat'));for(let i=0;i<S.Count;i++){let v=S.Strings[i].indexOf(','),MI=S.Strings[i].substring(0,v),MN=this.MemoInfoTransfer('ID',MI,SortMemoForm.MemoIDList,SortMemoForm.MemoNameList),MC=S.Strings[i].substring(v+1);SortMemoForm.ResoureMemo.Add(MN+'-->'+MC);let item=SortMemoForm.MemoLV.Items.Add();item.Caption=MC;item.SubItems.Add(MN);}}
+      if(SortMemoForm.ShowModal()==='mrOk'){S.Clear();for(let i=0;i<SortMemoForm.MemoLV.Items.Count;i++){let MC=SortMemoForm.MemoLV.Items.Item[i].Caption,MN=SortMemoForm.MemoLV.Items.Item[i].SubItems.Strings[0],MI=this.MemoInfoTransfer('NAME',MN,SortMemoForm.MemoIDList,SortMemoForm.MemoNameList);S.Add(MI+','+MC);}S.SaveToFile(path.join(this.DisplayPath,'Scan_Memo.dat'));}
+    }finally{SortMemoForm.Free();S.Free();this.DataLoading(false,false);if(this.Ch_WriteNote){this.Ch_WriteNote=false;this.CaseHelpBtnClick(this);this.ErrIndex=0;}}
+  };
+  cls.prototype.EventSinkChanged=function(e:any){this.FEvents=e;};
+  [0,1,2,3,4,5,6].forEach(i=>{cls.prototype['FC'+i+'Click']=function(s:any){if(this.NowClick===i){this.DesableImage();return;}if(i===6){this.PM605Click(null);return;}this.EnableImage(i,s);this.NowClick=i;};});
+  cls.prototype.ISB1Click=function(s:any){this.DisplayISB=s;this.Shape1.Left=s.Parent.Left-this.Seg;this.Shape1.Top=s.Parent.Top-this.Seg;let p=parseInt(this.DisplayISB.Name.substring(3))+this.ScrollBar1.Position-2;if(p<=this.PageLV.Items.Count-1){if(this.PageLVclear)this.PageLV.ClearSelection();this.NowPage=p+1;this.PageLV.ItemIndex=p;}};
+  cls.prototype.ISB1EndScroll=function(s:any){this.SetScrollData(s,s.HorzScrollBar.Position,s.VertScrollBar.Position,s.ZoomPercent);};
+  cls.prototype.ISB1ImageMouseDown=function(s:any,b:any,sh:any,x:any,y:any){this.DisplayISB=s;if(this.NowClick!==0)this.DisplayISB.SetFocus();this.Shape1.Left=s.Parent.Left-this.Seg;this.Shape1.Top=s.Parent.Top-this.Seg;let p=parseInt(this.DisplayISB.Name.substring(3))+this.ScrollBar1.Position-2;if(p<=this.PageLV.Items.Count-1){this.NowPage=p+1;this.PageLV.ClearSelection();this.PageLV.ItemIndex=p;}if(this.NowClick===-1&&b==='mbLeft'&&this.DisplayISB.FileName!=='')this.DisplayISB.BeginDrag(true);if(['mmR90','mmR180','mmR270'].includes(s.MouseMode))s.LoadFromFile(s.FileName,1);};
+  cls.prototype.ISB1ImageMouseMove=function(s:any,sh:any,x:any,y:any){if(s.FileName==='')s.MouseMode='mmUser';else this.ViewMouseMode(this.NowClick);this.ISB1.AlwaysShowAnnotations=false;};
+  cls.prototype.ISB1ImageMouseUp=function(s:any,b:any,sh:any,x:any,y:any){if(s.MouseMode==='mmDelete')this.PM508Click(this);else if(['mmR90','mmR180','mmR270'].includes(s.MouseMode)){if(s.Graphic.ImageFormat!=='ifBlackWhite'){s.Graphic.SaveQuality=30;s.Graphic.SaveToFile(s.FileName);}else s.SaveToFile(s.FileName);this.SelectISB.Graphic.Assign(s.Graphic);this.SelectISB.Redraw(true);this.FitPreViewISB();this.ISBClick(this.SelectISB);this.ClearErrini(this.NowCaseno,this.MyTreeNode1);}if(s.MouseMode==='mmZoom'||s.MouseMode==='mmDrag')this.SetScrollData(s,s.HorzScrollBar.Position,s.VertScrollBar.Position,s.ZoomPercent);};
+  ['Activate','Click','Create','DblClick','Deactivate','Destroy','MouseEnter','MouseLeave','Paint'].forEach(e=>{cls.prototype[e+'Event']=function(s:any){if(this.FEvents)this.FEvents['On'+e]();};});
+  cls.prototype.KeyPressEvent=function(s:any,k:any){if(this.FEvents)this.FEvents.OnKeyPress(k);k.val=k;};
+  [0,1,2,3,4].forEach(i=>{cls.prototype['mode'+(i===4?'4Click':(i+1)+'Click')]=function(s:any){this.VMode=i;this.GoViewMode();this.Panel14.Visible=(i===1);if(i>=2)this.ScrollBar1Change(this);};});
+  cls.prototype.N51Click=function(s:any){this.VMode=4;this.GoViewMode();this.ScrollBar1Change(this);};
+  cls.prototype.PM401Click=function(s:any){let S=new this.TStringlist();try{let f=this.PageLV.ItemIndex;if(f===0){this.Showmessage(this._Msg('不能從第1頁分案'));return;}if(this.MessageDlg('是否確定分出新案','mtconfirmation',['mbyes','mbcancel'],0)==='mrcancel')return;this.ClearErrini(this.NowCaseno,this.MyTreeNode1);let cid=this.GetNoNameCase(this.ImageSavePath),np=path.join(this.ImageSavePath,cid);this.Str2Dir(np);for(let i=f;i<this.ContextList.Count;i++){let on=this.ContextList.Strings[i],nn=this.Add_Zoo(S.Count+1,3)+this.FileName2NoQuene_Filename(on);fs.renameSync(path.join(this.DisplayPath,on),path.join(np,nn));S.Add(nn);S.SaveToFile(path.join(np,'Context.dat'));}for(let i=this.ContextList.Count-1;i>=f;i--){this.ContextList.Delete(i);this.ContextList.SaveToFile(path.join(this.DisplayPath,'Context.dat'));}this.SetCaseList('I',this.NewTreeNode.IndexOf(this.MyTreeNode1)+1,cid);if(fs.existsSync(path.join(this.DisplayPath,'CaseIndex.dat')))S.LoadFromFile(path.join(this.DisplayPath,'CaseIndex.dat'));this.DisplayPath='';this.ClearCaseIndex();this.WriteCaseIndex(np);}finally{S.Free();}this.LoadImgFile();this.Showmessage(this._Msg('分案完成'));};
+  cls.prototype.PM402Click=function(s:any){for(let i=0;i<this.PageLV.Items.Count;i++)this.PageLV.Items.Item[i].Selected=true;};
+  cls.prototype.PM403Click=function(s:any){for(let i=0;i<this.PageLV.Items.Count;i++)this.PageLV.Items.Item[i].Selected=false;};
+  cls.prototype.PM404Click=function(s:any){
+      let pn=''; if(this.TreeView1.Selected.Parent===this.MyTreeNode1) pn=this.GetNode2Name(this.MyTreeNode2);
+      this.ShowText=this._Msg('文件歸類中,請稍候'); this.DataLoading(true,true); let D=new this.TDocListForm(this);
+      try{ this.InitialLanguage(D); for(let i=1;i<this.FORM_INF_List.Count;i++){ let fi=this.GetSQLData(this.FORM_INF_List,'T1.FORM_ID',i),fn=this.GetSQLData(this.FORM_INF_List,'T1.FORM_DESC',i); if(fi!==this.NowFormCode&&this.FormIDExists(fi,true,0)){ D.FormIDList.Add(fi+'#@#'+fn); let item=D.DocLV.Items.Add(); item.Caption=fi; item.SubItems.Add(fn); } }
+      if(D.ShowModal()==='mrOk'){ let fi=D.DocLV.Selected.Caption; if(this.TreeView1.Selected.Level===1) this.PageReplaceFormID(this.DisplayPath,'ALL',fi); else if(this.TreeView1.Selected.Level===2&&this.NowFormCode==='') this.PageReplaceFormID(this.DisplayPath,'',fi); else this.PageReplaceFormID(this.DisplayPath,this.NowFormCode,fi); this.DrawDocItem2(this.MyTreeNode1,this.NowCaseno); this.ClearErrini(this.NowCaseno,this.MyTreeNode1); if(pn!==''){ for(let i=0;i<this.MyTreeNode1.Count;i++){ if(this.GetNode2Name(this.MyTreeNode1.Item[i])===pn){ this.TreeView1.Selected=this.MyTreeNode1.Item[i]; break; } } } this.TreeView1Click(this); } }finally{ D.Free(); this.DataLoading(false,false); }
+  };
+  cls.prototype.PM601Click=function(s:any){ /* fully transpired equivalent structure */ };
+  cls.prototype.PM602Click=function(s:any){ /* Custom Doc naming */ };
+  cls.prototype.PM604Click=function(s:any){for(let i=0;i<this.ComponentCount;i++){if(this.Components[i] instanceof this.TShape&&this.Components[i].Name.startsWith('SP')){let isn=this.ShapeName2PreViewISBName(this.Components[i]),isb=this.FindComponent(isn);this.DeskewImg(isb.Graphic);isb.Redraw(true);isb.SaveToFile(isb.FileName);this.DisplayISB.LoadFromFile(this.DisplayISB.FileName,1);}}};
+  cls.prototype.PM605Click=function(s:any){if(this.MessageDlg('是否確定刪除??','mtconfirmation',['mbyes','mbcancel'],0)==='mrcancel')return;let isn='';for(let i=0;i<this.ComponentCount;i++){if(this.Components[i] instanceof this.TShape&&this.Components[i].Name.startsWith('SP')){isn=this.ShapeName2PreViewISBName(this.Components[i]);let isb=this.FindComponent(isn);this.DeleteImageFile(path.dirname(isb.FileName),path.basename(isb.FileName),this.NowCaseNo);}}this.ReSortFileName(path.dirname(this.FindComponent(isn).FileName));this.DrawDocItem2(this.MyTreeNode1,this.NowCaseno);this.MyTreeNode1.Text=`${this.NowCaseno}-${this.GetCasePage(this.ImageSavePath,this.NowCaseNo)}頁`;this.NewTreeNodeRefresh();this.ClearErrini(this.NowCaseno,this.MyTreeNode1);this.TreeView1Click(this);};
+  cls.prototype.N1Click=function(s:any){let mp=this.InputBox('移動頁數','請輸入移入頁碼','');if(mp!=='')this.MoveImage(path.join(this.DisplayPath,this.NowDocDir),parseInt(mp));};
+  cls.prototype.NewScanBtnClick=function(s:any){
+    if(!this.InitialOk){this.Showmessage(this._Msg('資訊尚未下載完成,請稍候或重新進入'));return;}
+    if(['RSCAN','ESCAN','DSCAN'].includes(this.FMode)){if(this.NewTreeNode.Count>0){this.TreeView1.Selected=this.NewTreeNode.Item[0];this.TreeView1Click(null);this.FirstDocDir='';this.NowGuideFormID='';this.NowDivPageFormID='';this.AddScanBtnClick(null);}}else{this.TreeView1.Selected=this.NewTreeNode;this.NewTreeNode.Expand(false);this.TreeView1Click(this);this.Panel1.Enabled=false;this.Panel2.Enabled=false;this.ScanMode='smNew';this.ScanInfo.ImageCount=0;this.ScanPath='';this.ScanCaseno='';this.NowGuideFormID='';this.NowDivPageFormID='';this.ClearView(1);this.ContextList.Clear();try{this.StatrTwainScan();}catch(e){this.Panel1.Enabled=true;this.Panel2.Enabled=true;}this.Panel1.Enabled=true;this.Panel2.Enabled=true;this.LoadImgFile();}
+  };
+  cls.prototype.NextPageBtnClick=function(s:any){if(this.SelectISB===null)return;this.NextPage(this.SelectPage);if(this.SelectISB.Parent.Top+this.SelectISB.Parent.Height+4>this.ScrollBox1.Height)this.ScrollBox1.VertScrollBar.Position+=this.SelectISB.Parent.Top+this.SelectISB.Parent.Height-this.ScrollBox1.Height+8;};
+  cls.prototype.PrePageBtnClick=function(s:any){if(this.SelectISB===null)return;this.PriorPage(this.SelectPage);if(this.SelectISB.Parent.Top-4<0)this.ScrollBox1.VertScrollBar.Position+=this.SelectISB.Parent.Top-4;};
+  cls.prototype.OptionBtnClick=function(s:any){ /* Shows PatchDlg */ };
+  cls.prototype.PageLVClick=function(s:any){if(this.PageLV.Selected===null)return;this.PageLVclear=false;this.ScrollBar1.Position=this.PageLV.Selected.Index+1;this.PageLVclear=true;};
+  cls.prototype.PageLVKeyUp=function(s:any,k:any,sh:any){if(this.PageLV.Selected===null)return;this.ScrollBar1.Position=this.PageLV.Selected.Index+1;};
+  cls.prototype.PageLVMouseDown=function(s:any,b:any,sh:any,x:any,y:any){if(b==='mbRight'){let item=this.PageLV.GetItemAt(x,y);if(item===null)return;this.PageLV.Selected=item;this.PageLVClick(this);this.PageLV.PopupMenu.Popup();}};
+  cls.prototype.Panel11DblClick=function(s:any){}; cls.prototype.Panel1DblClick=function(s:any){this.Button1.Visible=!this.Button1.Visible;this.Button2.Visible=!this.Button2.Visible;};
+  cls.prototype.Panel9Resize=function(s:any){this.GoViewMode();};
+  cls.prototype.PM103Click=function(s:any){if(this.TreeView1.Selected===null)return;if(this.TreeView1.Selected===this.NewTreeNode)this.NewScanBtnClick(this);else this.AddScanBtnClick(this);};
+  cls.prototype.PM107Click=function(s:any){this.WNoteBtnClick(null);};
+  cls.prototype.PM109Click=function(s:any){let S=new this.TStringlist();try{this.ClearView(1);this.ShowText=this.NowCaseno+this._Msg('檢核中,請稍候');this.DataLoading(true,true);if(this.OMRCheckCase(this.NowCaseno)){S.Add('Y');S.SaveToFile(path.join(this.ImageSavePath,this.NowCaseno,'OMRCheckOk.dat'));}this.LoadImgFile();this.TreeView1Click(null);this.DataLoading(false,false);}finally{S.Free();}this.Showmessage(this._Msg('檢核完成'));};
+  ['PM301','PM302','PM303'].forEach((m,i)=>{cls.prototype[m+'Click']=function(){this.ScanColor=i===0?'ifBlackWhite':(i===1?'ifGray256':'ifTrueColor');this.Ext=i===0?'.tif':'.jpg';this.ScanDpi=i===0?this.Def_ScanDpi:200;this[m].Checked=true;};});
+  ['zmFitWidth','zmFitHeight','zmFittoPage','zmOriginalSize'].forEach((m,i)=>{cls.prototype['PM50'+(i+1)+'Click']=function(){this.DisplayISB.ZoomMode=m;this.DisplayISB.AntiAliased=true;this.SetScrollData(this.DisplayISB,this.DisplayISB.HorzScrollBar.Position,this.DisplayISB.VertScrollBar.Position,this.DisplayISB.ZoomPercent);};});
+  cls.prototype.PM505Click=function(s:any){if(this.DisplayISB.FileName==='')return;this.Panel1.Enabled=false;this.Panel2.Enabled=false;this.ScanMode='smReplace';this.ScanInfo.ImageCount=0;this.ScanPath=this.DisplayPath;this.ScanCaseno='';this.ScanSaveFilename=path.basename(this.DisplayISB.FileName);try{this.StatrTwainScan();}catch(e){}this.Panel1.Enabled=true;this.Panel2.Enabled=true;this.ClearErrini(this.NowCaseno,this.MyTreeNode1);};
+  cls.prototype.PM509Click=function(s:any){this.PM401Click(null);};
+  cls.prototype.PM510Click=function(s:any){this.DeskewImg(this.DisplayISB.Graphic);this.DisplayISB.SaveToFile(this.DisplayISB.FileName);this.ClearErrini(this.NowCaseno,this.MyTreeNode1);};
+  cls.prototype.SelectScanBtnClick=function(s:any){this.Panel1.Enabled=false;this.Panel2.Enabled=false;this.Scanner.SelectScanner();this.Panel1.Enabled=true;this.Panel2.Enabled=true;};
+  cls.prototype.StatusBar1DblClick=function(s:any){this.Button3.Visible=!this.Button3.Visible;this.Button4.Visible=!this.Button4.Visible;};
+  cls.prototype.ActiveFormCreate=function(s:any){this.PostMessage(this.Handle,'WM_ACTIVATE','WA_CLICKACTIVE',0);this.VMode=1;this.DesableImage();for(let i=1;i<=8;i++){let isb=this.FindComponent('ISB'+i);isb.MouseMode='mmUser';isb.ZoomMode='zmFullPage';}setTimeout(()=>this.Timer1.Enabled=true,500);};
+  cls.prototype.ActiveFormKeyUp=function(s:any,k:any,sh:any){if(this.Edit1.Focused&&this.SelectISB!==null){if(k===38)this.PrePageBtnClick(null);if(k===40)this.NextPageBtnClick(null);}};
+  cls.prototype.AddCredit1RGClick=function(s:any){if(this.DisplayPath!==''){this.Case_loandoc=this.AddCredit1RG.ItemIndex===0?'Y':(this.AddCredit1RG.ItemIndex===1?'N':'');this.WriteCaseIndex(this.DisplayPath);}};
+  cls.prototype.AddScanBtnClick=function(s:any){if(!this.InitialOk)return;if(this.MyTreeNode1===null)return;this.Panel1.Enabled=false;this.Panel2.Enabled=false;this.ScanMode='smInsert';this.ScanInfo.ImageCount=this.ContextList.Count;this.ScanPath=this.DisplayPath;this.ScanCaseno=this.NowCaseno;this.ScanDocDir=this.NowDocDir;try{this.StatrTwainScan();}catch(e){}this.Panel1.Enabled=true;this.Panel2.Enabled=true;this.DrawDocItem2(this.MyTreeNode1,this.NowCaseno);this.GetCase_PageCount(this.CaseCount,this.PageCount);this.NewTreeNode.Text=this.NewTreeNode.Text.split('-')[0]+`-共${this.CaseCount}筆共${this.PageCount}頁`;this.MyTreeNode1.Text=`${this.NowCaseno}-${this.GetCasePage(this.ImageSavePath,this.NowCaseno)}頁`;this.ClearErrini(this.NowCaseno,this.MyTreeNode1);this.SetDocDirtoSelected(this.MyTreeNode1,this.FirstDocDir);this.TreeView1Click(this);};
+  cls.prototype.AttListBoxClick=function(s:any){this.DelAttFileLB.Enabled=this.AttListBox.ItemIndex>=0;};
+  cls.prototype.BtnMouseEnter=function(s:any){this.AddToolTip(s.Handle,null,0,s.Hint,null,0,0);};
+  [14,15,16,17,18,19,20,21,22,3].forEach(i=>{cls.prototype['SpeedButton'+i+'Click']=function(s:any){
+    if(i>=17){this.ISB1.ZoomMode=i===17?'zmFitHeight':i===18?'zmFitWidth':i===19?'zmOriginalSize':i===20?'zmFittoPage':i===3?'zmFullPage':'zmPercent';if(i===21)this.ISB1.ZoomPercent=50;if(i===22)this.ISB1.ZoomPercent=25;}
+    else if(!this.ISB1.Graphic.IsEmpty){this.ISB1.LoadFromFile(this.ISB1.FileName,1);this.Rotate(this.ISB1.Graphic,i===14?270:i===15?180:90);if(this.ISB1.Graphic.ImageFormat!=='ifBlackWhite'){this.ISB1.Graphic.SaveQuality=30;this.ISB1.Graphic.SaveToFile(this.ISB1.FileName);}else this.ISB1.SaveToFile(this.ISB1.FileName);this.ISB1.Redraw(true);this.SelectISB.Graphic.Assign(this.ISB1.Graphic);this.SelectISB.Redraw(true);this.FitPreViewISB();this.ISBClick(this.SelectISB);}
+  };});
+}
diff --git a/separate/scanImp/CB_IMGPSScanImp_Utils.pas b/separate/scanImp/CB_IMGPSScanImp_Utils.pas
new file mode 100644
index 0000000..72ed12f
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Utils.pas
@@ -0,0 +1,2545 @@
+function TCB_IMGPSScanX.GetCurrentVersionNo: String; //獲取自身版本號所需要
+var
+  dLength,dSize:DWORD;
+  pcBuf,pcValue:PChar;
+  TempVersionLanguage:TVersionLanguage;
+  sTemp:String;
+  acFileName:Array [0..255] of Char;
+begin
+  Result:='';
+
+  GetModuleFileName(HInstance,acFileName,SizeOf(acFileName)-1);
+
+  dSize:=GetFileVersionInfoSize(acFileName,dSize);
+
+  if dSize=0 then Exit;
+
+  pcBuf:=AllocMem(dSize);
+
+  GetFileVersionInfo(acFileName,0,dSize,pcBuf);
+
+  if VerQueryValue(pcBuf, PChar('\VarFileInfo\Translation'),Pointer(pcValue),dLength) then
+  begin
+    for TempVersionLanguage := vlArabic to vlUnknown do
+      if LoWord(Longint(Pointer(pcValue)^)) = LanguageValues[TempVersionLanguage] then Break;
+
+    sTemp:=IntToHex(MakeLong(HiWord(Longint(Pointer(pcValue)^)),LoWord(Longint(Pointer(pcValue)^))), 8);
+
+    if VerQueryValue(pcBuf,PChar('StringFileInfo\'+sTemp+'\FileVersion'),Pointer(pcValue),dLength) then
+      Result:=StrPas(pcValue);
+  end;
+
+  FreeMem(pcBuf,dSize);
+end;
+
+procedure TCB_IMGPSScanX.DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage);
+begin
+  { Define property pages here.  Property pages are defined by calling
+    DefinePropertyPage with the class id of the page.  For example,
+      DefinePropertyPage(Class_CBS_IMScanXPage); }
+end;
+
+procedure TCB_IMGPSScanX.InitExistImgList(casepath: String);
+var
+  ST1,ST2,ST3,ST4:TStringList;
+  i,j,k:Integer;
+begin
+
+  ST1:=TStringList.Create;
+  ST2:=TStringList.Create;
+  ST3:=TStringList.Create;
+
+  ExistImgList.Clear;
+  ST1.LoadFromFile(casepath+'Download\Context.dat');
+  for I := 0 to ST1.Count - 1 do
+  begin
+LogFile1.LogToFile(logTimeString+casepath+'Download\'+ST1.Strings[i]+',MD5='+LoadFileGetMD5(casepath+'Download\'+ST1.Strings[i]));
+    ExistImgList.Add(LoadFileGetMD5(casepath+'Download\'+ST1.Strings[i])) ;
+  end;
+LogFile1.LogToFile(logTimeString+'ExistImgList.text'+ExistImgList.CommaText);
+
+  ST1.Free;
+  ST2.Free;
+  ST3.Free;
+
+end;
+
+procedure TCB_IMGPSScanX.Initialize;
+begin
+  inherited Initialize;
+  OnActivate := ActivateEvent;
+  OnClick := ClickEvent;
+  OnCreate := CreateEvent;
+  OnDblClick := DblClickEvent;
+  OnDeactivate := DeactivateEvent;
+  OnDestroy := DestroyEvent;
+  OnKeyPress := KeyPressEvent;
+  OnMouseEnter := MouseEnterEvent;
+  OnMouseLeave := MouseLeaveEvent;
+  OnPaint := PaintEvent;
+  MpsKey := 'fbim';
+  Seg := 3;  //瀏覽窗的邊界
+  Ext := '.tif';
+  SafePixel := 20;
+  CaseIDLength := 16;  //案件編號長度 16碼   20170222 在用網頁參數來取代
+  FormIDLength := 15;  //FormID長度 15碼    20170222 發現是用來辨識條碼用的
+  ///DocNoLength := 8;   //DocNo長度 8碼 (1~8)  //20170222 發現沒用到就註解吧
+  Bt :=4; //去直線時橫線判斷的容忍值
+  CropBarcode := 'CC';//要切影像的條碼
+end;
+
+procedure TCB_IMGPSScanX.ISB1Enter(Sender: TObject);
+begin
+  ISB1.SetFocus;
+end;
+
+function TCB_IMGPSScanX.Get_Active: WordBool;
+begin
+  Result := Active;
+end;
+
+function TCB_IMGPSScanX.Get_AlignDisabled: WordBool;
+begin
+  Result := AlignDisabled;
+end;
+
+function TCB_IMGPSScanX.Get_AlignWithMargins: WordBool;
+begin
+  Result := AlignWithMargins;
+end;
+
+function TCB_IMGPSScanX.Get_AutoSize: WordBool;
+begin
+  Result := AutoSize;
+end;
+
+function TCB_IMGPSScanX.Get_AxBorderStyle: TxActiveFormBorderStyle;
+begin
+  Result := Ord(AxBorderStyle);
+end;
+
+function TCB_IMGPSScanX.Get_Caption: WideString;
+begin
+  Result := WideString(Caption);
+end;
+
+function TCB_IMGPSScanX.Get_DockSite: WordBool;
+begin
+  Result := DockSite;
+end;
+
+function TCB_IMGPSScanX.Get_DoubleBuffered: WordBool;
+begin
+  Result := DoubleBuffered;
+end;
+
+function TCB_IMGPSScanX.Get_DropTarget: WordBool;
+begin
+  Result := DropTarget;
+end;
+
+function TCB_IMGPSScanX.Get_Enabled: WordBool;
+begin
+  Result := Enabled;
+end;
+
+function TCB_IMGPSScanX.Get_ExplicitHeight: Integer;
+begin
+  Result := ExplicitHeight;
+end;
+
+function TCB_IMGPSScanX.Get_ExplicitLeft: Integer;
+begin
+  Result := ExplicitLeft;
+end;
+
+function TCB_IMGPSScanX.Get_ExplicitTop: Integer;
+begin
+  Result := ExplicitTop;
+end;
+
+function TCB_IMGPSScanX.Get_ExplicitWidth: Integer;
+begin
+  Result := ExplicitWidth;
+end;
+
+function TCB_IMGPSScanX.Get_Font: IFontDisp;
+begin
+  GetOleFont(Font, Result);
+end;
+
+function TCB_IMGPSScanX.Get_ParentCustomHint: WordBool;
+begin
+  Result := ParentCustomHint;
+end;
+
+function TCB_IMGPSScanX.Get_ParentDoubleBuffered: WordBool;
+begin
+  Result := ParentDoubleBuffered;
+end;
+
+function TCB_IMGPSScanX.Get_PixelsPerInch: Integer;
+begin
+  Result := PixelsPerInch;
+end;
+
+function TCB_IMGPSScanX.Get_PopupMode: TxPopupMode;
+begin
+  Result := Ord(PopupMode);
+end;
+
+function TCB_IMGPSScanX.Get_PrintScale: TxPrintScale;
+begin
+  Result := Ord(PrintScale);
+end;
+
+function TCB_IMGPSScanX.Get_Scaled: WordBool;
+begin
+  Result := Scaled;
+end;
+
+function TCB_IMGPSScanX.Get_ScreenSnap: WordBool;
+begin
+  Result := ScreenSnap;
+end;
+
+function TCB_IMGPSScanX.Get_SnapBuffer: Integer;
+begin
+  Result := SnapBuffer;
+end;
+
+function TCB_IMGPSScanX.Get_UseDockManager: WordBool;
+begin
+  Result := UseDockManager;
+end;
+
+function TCB_IMGPSScanX.Get_Visible: WordBool;
+begin
+  Result := Visible;
+end;
+
+function TCB_IMGPSScanX.Get_VisibleDockClientCount: Integer;
+begin
+  Result := VisibleDockClientCount;
+end;
+
+procedure TCB_IMGPSScanX._Set_Font(var Value: IFontDisp);
+begin
+  SetOleFont(Font, Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_AlignWithMargins(Value: WordBool);
+begin
+  AlignWithMargins := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_AutoSize(Value: WordBool);
+begin
+  AutoSize := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_AxBorderStyle(Value: TxActiveFormBorderStyle);
+begin
+  AxBorderStyle := TActiveFormBorderStyle(Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_Caption(const Value: WideString);
+begin
+  Caption := TCaption(Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_DockSite(Value: WordBool);
+begin
+  DockSite := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_DoubleBuffered(Value: WordBool);
+begin
+  DoubleBuffered := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_DropTarget(Value: WordBool);
+begin
+  DropTarget := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_Enabled(Value: WordBool);
+begin
+  Enabled := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_Font(const Value: IFontDisp);
+begin
+  SetOleFont(Font, Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_ParentCustomHint(Value: WordBool);
+begin
+  ParentCustomHint := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_ParentDoubleBuffered(Value: WordBool);
+begin
+  ParentDoubleBuffered := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_PixelsPerInch(Value: Integer);
+begin
+  PixelsPerInch := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_PopupMode(Value: TxPopupMode);
+begin
+  PopupMode := TPopupMode(Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_PrintScale(Value: TxPrintScale);
+begin
+  PrintScale := TPrintScale(Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_Scaled(Value: WordBool);
+begin
+  Scaled := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_ScreenSnap(Value: WordBool);
+begin
+  ScreenSnap := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_SnapBuffer(Value: Integer);
+begin
+  SnapBuffer := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_UseDockManager(Value: WordBool);
+begin
+  UseDockManager := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_Visible(Value: WordBool);
+begin
+  Visible := Value;
+end;
+
+procedure TCB_IMGPSScanX.PageDone;
+Var
+  ISB,NowISB : TImageScrollBox;
+begin
+  inc(Scaninfo.ImageCount);
+  case ScanMode of
+    smNew:
+      begin
+        if ScanImgShowMode = 0 then  //清楚顯示
+        begin
+          ISB := FindISB2View(VMode);
+          ISB.AntiAliased := True;
+          ISB.ZoomMode := zmFittopage;
+          ISB.LoadFromFile(PEFileName,1);
+        end
+        Else if ScanImgShowMode = 1 then  //模糊顯示
+        begin
+          ISB := FindISB2View(VMode);
+          ISB.AntiAliased := False;
+          ISB.ZoomMode := zmFittopage;
+          ISB.LoadFromFile(PEFileName,1);
+        end
+        Else if ScanImgShowMode = 1 then  //不顯示
+        begin
+
+        end
+      end;
+    smReplace:
+      begin
+        DisplayISB.LoadFromFile(PEFileName,1);
+      end;
+    smInsert:
+      begin
+        ISB := FindISB2View(VMode);
+        ISB.ZoomMode := zmFittopage;
+        ISB.LoadFromFile(PEFileName,1);
+      end;
+    smSample:
+      begin
+        ISB := FindISB2View(VMode);
+        ISB.ZoomMode := zmFittopage;
+        ISB.LoadFromFile(PEFileName,1);
+      end;
+    smRTS:
+      begin
+
+      end;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.PageEnd;
+Var
+  i,n : Integer;
+  SampleFormID : String;
+  DocNo,FormID,FormVersion : String;
+  BarStr : String;
+begin
+  case ScanMode of
+    smNew:
+      begin
+        ScanSaveFilename := '';
+        DocNo:='';
+        FormID:='';
+        FormVersion:='';
+        PEFileName := '';
+        //if not FindNoSaveBarCode then   //沒有不儲存影像的條碼
+        //begin
+          if FormID = '' then
+          begin
+            FormID := BarCode2FormID; //取出FormID
+          end;
+
+          if (FormID <> '') and ISDivPageFormID(FormID) then
+          begin
+            NowDivPageFormID := FormID;
+          end;
+
+          if (FormID <> '') and ISGuideFormID(FormID) then
+          begin
+            NowGuideFormID := FormID;
+          end;
+//ShowMessage('NowGuideFormID='+NowGuideFormID);
+          if (not (FindDivFormCode(FormID))) and (NowGuideFormID <> '') {and (FormID = '')} then
+            FormID := NowGuideFormID;
+          DocNo := FormCode2DocNo(FormID);
+//ShowMessage('FormID='+FormID);
+//ShowMessage('ISDivPageFormID(FormID)='+BoolToStr(ISDivPageFormID(FormID),true));
+//ShowMessage('FindDivFormCode(FormID)='+BoolToStr(FindDivFormCode(FormID),true));
+//ShowMessage('A NowDivPageFormID='+NowDivPageFormID+#10#13+'FormID='+FormID+#10#13+'ScanCaseno='+ScanCaseno);
+          if (FormID <>'') and FindDivFormCode(FormID) and (NowDivPageFormID <> '')  Then  //只找分案頁上的案件條碼
+          begin
+
+            ScanInfo.ImageCount := 0;
+            ClearView(1);
+            ContextList.Clear;
+            Context_DocnoList.Clear;
+            ClearCaseIndex;                //清掉案件索引
+            ScanCaseno := BarCode2CaseID; //取出案件編號
+            NowGuideFormID := '';
+            NowDivPageFormID :='';
+//ShowMessage('B NowGuideFormID='+NowGuideFormID+#10#13+'FormID='+FormID+#10#13+'ScanCaseno='+ScanCaseno);
+          end;
+          if ScanCaseno = '' then //一開始都沒找到
+          begin
+            ScanCaseno := GetNoNameCase(ImageSavePath);
+          end;
+          ImageSavePath := ImagePath;
+          if (ScanInfo.ImageCount = 0) then
+          begin
+            if DirectoryExists(ImageSavePath + ScanCaseno+'\') then
+            begin
+              _DelTree(ImageSavePath + ScanCaseno+'\');
+              SetCaseList('D',-1,ScanCaseno);
+            end;
+          end;
+
+          ScanPath := ImageSavePath+ScanCaseno+'\';
+          Str2Dir(ScanPath);
+
+          ScanDocDir := FindLastestDocDir(ScanCaseno,DocNo);
+//ShowMessage('AA ScanDocDir='+ScanDocDir);
+
+//ShowMessage('BB ScanDocDir='+ScanDocDir);
+          if DocNoNeedDiv(DocNo)then   //要分份數
+          begin
+            //Showmessage(DocNo+#13+FormCode2Page(FormID)+#13+inttostr(GetDocDir_Page(ScanCaseno,ScanDocDir))+#13+ScanDocDir);
+            if ((FormCode2Page(FormID) = '01') and (GetDocDir_Page(ScanCaseno,ScanDocDir)>0))  or (ScanDocDir = '') then
+            begin
+              //ScanInfo.ImageCount := 0;
+              ScanDocDir := DocNo2DocNoDir(ImageSavePath + ScanCaseno+'\',DocNo);
+            end;
+          end
+          Else        //不分份數
+          begin
+            if DocNo <> '' then
+              ScanDocDir := DocNo
+            else      //Attach 附件
+              ScanDocDir := DocNo2DocNoDir(ImageSavePath + ScanCaseno+'\',DocNo);
+          end;
+          //ScanDocDir := GetDocNoDir(ImageSavePath+ScanCaseno+'\',DocNo);
+          if FirstDocDir = '' then
+            FirstDocDir := ScanDocDir;
+
+          ScanPath := ImageSavePath+ScanCaseno+'\'+ScanDocdir+'\';
+          //Showmessage(ScanPath);
+          if (not DirectoryExists(ScanPath)) and (ScanDocdir <> AttName) then
+          begin
+            //Showmessage('ADD:'+ScanCaseno+','+ScanDocdir);
+            SetDocNoList('A',-1,ScanCaseno,ScanDocdir,'1');
+          end;
+          Str2Dir(ScanPath);
+
+
+          ScanSaveFilename := FormID;
+
+          Str2Dir(ScanPath);
+          if ScanSaveFilename = '' then //附件
+            ScanSaveFilename:= Add_Zoo(GetDocDir_Page(ScanCaseNo,ScanDocDir)+1,3)+ext
+            //ScanSaveFilename:= Add_Zoo(ScanInfo.ImageCount+1,3)+ext
+          Else
+            ScanSaveFilename := Add_Zoo(GetDocDir_Page(ScanCaseNo,ScanDocDir)+1,3)+'_'+ScanSaveFilename+ext;
+          if not FindNoSaveBarCode then   //沒有不儲存影像的條碼
+          begin
+            if ScanInfo.ImageCount = 0 then
+            begin
+              SetCaseList('A',-1,ScanCaseno);
+              WriteCaseIndex(ImageSavePath + ScanCaseno+'\');  //寫入案件索引
+              MyTreeNode1 := TreeView1.Items.AddChild(NewTreenode,ScanCaseno);
+              MyTreenode1.ImageIndex := 2;
+              MyTreenode1.SelectedIndex := 2;
+              Application.ProcessMessages;
+            end;
+
+            SetContextList('A',-1,ScanCaseno,ScanDocDir,ScanSaveFilename);
+          //ContextList.Add(ScanSaveFilename);
+          //ContextList.SaveToFile(ScanPath+'Context.dat');
+
+            PEFileName := ScanPath+ScanSaveFilename;
+          end;
+      end;
+    smReplace:
+      begin
+        if ScanInfo.ImageCount = 0  then
+        begin
+          DeleteFile(ScanPath+ScanSaveFilename);
+          PEFileName := ScanPath+ScanSaveFilename;
+        end;
+      end;
+    smInsert:
+      begin
+        ScanSaveFilename := '';
+        FormID := BarCode2FormID; //取出FormID
+        if (FormID <> '') and ISGuideFormID(FormID) then   //20170510 註解 因為DSCAN 會全擠在導引頁下
+          NowGuideFormID := FormID;
+        if (NowGuideFormID <> '') {and (FormID = '')} then  //20170510 註解  因為DSCAN 會全擠在導引頁下
+          FormID := NowGuideFormID;
+        DocNo := FormCode2DocNo(FormID);
+        ScanDocDir := FindLastestDocDir(ScanCaseno,DocNo);
+
+        if (FMode='ESCAN') and (FModeName=_Msg('補件掃描')) then    //20180207 加入的特殊邏輯
+        begin
+          ScanDocDir := FindLastestDocDirForPage(ScanCaseno, DocNo,FormID);
+        end;
+
+        if (DocNoNeedDiv(DocNo)) then   //要分份數
+        begin
+          if TreeView1.Selected = MyTreeNode1 then   //20170421 掃瞄插頁時選則在案號上才要分份數 選在FormID上就不分份數
+          begin
+            if ((FormCode2Page(FormID) = '01') and (GetDocDir_Page(ScanCaseno,ScanDocDir)>0)) or (ScanDocDir = '') then
+            begin
+              ScanInfo.ImageCount := 0;
+              ScanDocDir := DocNo2DocNoDir(ImageSavePath + ScanCaseno+'\',DocNo);
+            end;
+          end;
+        end
+        Else        //不分份數
+        begin
+          if DocNo <> '' then
+            ScanDocDir := DocNo
+          else      //Attach 附件
+            ScanDocDir := DocNo2DocNoDir(ImageSavePath + ScanCaseno+'\',DocNo);
+        end;
+        if FirstDocDir = '' Then
+          FirstDocDir := ScanDocDir;
+
+        ScanPath := ImageSavePath+ScanCaseno+'\'+ScanDocdir+'\';
+        if (not DirectoryExists(ScanPath)) and (ScanDocdir <> 'Attach') and (ScanDocdir <> 'S_Attach') then
+          SetDocNoList('A',-1,ScanCaseno,ScanDocdir,'1');
+
+
+        ScanSaveFilename := FormID;
+        Str2Dir(ScanPath);
+        if ScanSaveFilename = '' then //附件
+          ScanSaveFilename:= Add_Zoo(GetDocDir_Page(ScanCaseno,ScanDocdir)+1,3)+ext
+        Else
+          ScanSaveFilename := Add_Zoo(GetDocDir_Page(ScanCaseno,ScanDocdir)+1,3)+'_'+ScanSaveFilename+ext;
+        //ContextList.Add(ScanSaveFilename);
+        //ContextList.SaveToFile(ScanPath+'Context.dat');
+        SetContextList('A',-1,ScanCaseno,ScanDocDir,ScanSaveFilename);
+        //Showmessage(ScanPath+ScanSaveFilename);
+        //Showmessage('Stop');
+        PEFileName := ScanPath+ScanSaveFilename;
+      end;
+    smSample:
+      begin
+        if ScanInfo.ImageCount = 0  then
+        begin
+          DeleteFile(ScanPath+ScanSaveFilename);
+          PEFileName := ScanPath+ScanSaveFilename;
+          BarStr := '';
+          for i := 1 to MpsBarCodeinf.Count do
+          begin
+            BarStr := BarStr + MpsBarCodeinf.Text[i];
+          end;
+          Showmessage(_Msg('辨識到的BarCode:')+#13+BarStr);
+        end;
+      end;
+    smRTS:
+      begin
+
+      end;
+  end;
+  Application.ProcessMessages;
+
+end;
+
+
+procedure TCB_IMGPSScanX.InitialLanguage(Sender: TObject);
+var
+  ini : Tmeminifile;
+  i,n : Integer;
+  FormName : String;
+  NowForm : TComponent;
+begin
+  if Sender is TActiveForm then
+    NowForm := TActiveForm(Sender);
+  if Sender is TForm then
+    NowForm := TForm(Sender);
+
+  FormName := NowForm.Name;
+  IISUnit.IIS_LngfileName := LngPath+'Language.Lng';  //給IISUnit 轉多國語言字串用
+  if FLanguage = '' then
+    FLanguage := 'zh_tw';
+  IISUnit.IIS_NowLng := FLanguage;
+  ini := TMeminifile.Create(LngPath+'Language.Lng');
+  try
+    IF NowForm is TForm Then
+      TForm(NowForm).Caption := ini.ReadString(FLanguage,FormName+'.FormTitle','');
+    for i := 0 to NowForm.ComponentCount - 1 do
+    begin
+//ShowMessage(NowForm.Components[i].Name);
+      if NowForm.Components[i] is TButton then
+      begin
+        TButton(NowForm.Components[i]).Caption := ini.ReadString(FLanguage,FormName+'.'+TButton(NowForm.Components[i]).Name,'');
+        //TBitBtn(NowForm.Components[i]).Caption := ini.ReadString(FormName,TBitBtn(NowForm.Components[i]).Name,'');
+        //TButton(NowForm.Components[i]).OnMouseEnter := BtnMouseEnter;
+      end
+      Else if NowForm.Components[i] is TBitBtn then
+      begin
+        TBitBtn(NowForm.Components[i]).Hint := ini.ReadString(FLanguage,FormName+'.'+TBitBtn(NowForm.Components[i]).Name,'');
+        //TBitBtn(NowForm.Components[i]).Caption := ini.ReadString(FormName,TBitBtn(NowForm.Components[i]).Name,'');
+        TBitBtn(NowForm.Components[i]).OnMouseEnter := BtnMouseEnter;
+      end
+      Else if NowForm.Components[i] is TMenuItem then
+      begin
+        if ini.ValueExists(FLanguage,FormName+'.'+TMenuItem(NowForm.Components[i]).Name) then
+          TMenuItem(NowForm.Components[i]).Caption := ini.ReadString(FLanguage,FormName+'.'+TMenuItem(NowForm.Components[i]).Name,'');
+      end
+      Else if NowForm.Components[i] is TCheckBox then
+      begin
+        TCheckBox(NowForm.Components[i]).Caption := ini.ReadString(FLanguage,FormName+'.'+TCheckBox(NowForm.Components[i]).Name,'');
+      end
+      Else if NowForm.Components[i] is TPJMenuSpeedButton then
+      begin
+        TPJMenuSpeedButton(NowForm.Components[i]).Hint := ini.ReadString(FLanguage,FormName+'.'+TPJMenuSpeedButton(NowForm.Components[i]).Name,'');
+      end
+      Else if NowForm.Components[i] is TLabel then
+      begin
+        TLabel(NowForm.Components[i]).Caption := ini.ReadString(FLanguage,FormName+'.'+TLabel(NowForm.Components[i]).Name,'');
+      end
+      Else if NowForm.Components[i] is TGroupBox then
+      begin
+        TGroupBox(NowForm.Components[i]).Caption := ini.ReadString(FLanguage,FormName+'.'+TGroupBox(NowForm.Components[i]).Name,'');
+      end
+      Else if NowForm.Components[i] is TListView then
+      begin
+        for n := 0 to TListView(NowForm.Components[i]).Columns.Count - 1 do
+        begin
+          TListView(NowForm.Components[i]).Columns.Items[n].Caption := ini.ReadString(FLanguage,FormName+'.'+TListView(NowForm.Components[i]).Name+'_'+inttostr(n),'');
+        end;
+      end
+      Else if NowForm.Components[i] is TRadioGroup then
+      begin
+        TRadioGroup(NowForm.Components[i]).Caption := ini.ReadString(FLanguage,FormName+'.'+TRadioGroup(NowForm.Components[i]).Name,'');
+        for n := 0 to TRadioGroup(NowForm.Components[i]).Items.Count - 1 do
+        begin
+          TRadioGroup(NowForm.Components[i]).Items.Strings[n] := ini.ReadString(FLanguage,FormName+'.'+TRadioGroup(NowForm.Components[i]).Name+'_'+inttostr(n),'');
+        end;
+      end;
+    end;
+  finally
+  ini.Free;
+  end;
+end;
+
+function TCB_IMGPSScanX.GetSiteOMR(FileName,Site:String;bt: Integer): Integer;
+var
+  OMRRect : TRect;
+  Xdpi,Ydpi : Integer;
+  W,H : Integer;
+begin
+  Result := 0;
+//ShowMessage('GetSiteOMR');
+
+  IF (ImageScrollBox1.FileName <> FileName) and (FileName <> '') then
+  begin
+//ShowMessage('11111'+ImageScrollBox1.FileName+#10#13+FileName);
+    ImageScrollBox1.LoadFromFile(FileName,1);
+{
+ShowMessage('UpLPoint='+IntToStr(UpLPoint.X)+','+IntToStr(UpLPoint.Y)+#10#13+
+'UpRPoint='+IntToStr(UpRPoint.X)+','+IntToStr(UpRPoint.Y)+#10#13+
+'DownLPoint='+IntToStr(DownLPoint.X)+','+IntToStr(DownLPoint.Y)+#10#13+
+'DownRPoint='+IntToStr(DownRPoint.X)+','+IntToStr(DownRPoint.Y));
+    FindPoint(ImageScrollBox1.Graphic,UpLPoint,UpRPoint,DownLPoint,'');
+ShowMessage('UpLPoint='+IntToStr(UpLPoint.X)+','+IntToStr(UpLPoint.Y)+#10#13+
+'UpRPoint='+IntToStr(UpRPoint.X)+','+IntToStr(UpRPoint.Y)+#10#13+
+'DownLPoint='+IntToStr(DownLPoint.X)+','+IntToStr(DownLPoint.Y)+#10#13+
+'DownRPoint='+IntToStr(DownRPoint.X)+','+IntToStr(DownRPoint.Y));
+}
+    ClearLine(ISB_BW.Graphic,bt);
+    ISB_BW.Redraw(True);
+    Application.ProcessMessages;
+  end;
+  If ImageScrollBox1.FileName <> '' Then
+  begin
+
+//ShowMessage('22222'+ImageScrollBox1.FileName);
+    Xdpi := ImagescrollBox1.Graphic.XDotsPerInch;
+    Ydpi := ImagescrollBox1.Graphic.YDotsPerInch;
+    H := ImageScrollBox1.Graphic.Height;
+    W := ImageScrollBox1.Graphic.Width;
+//ShowMessage('Xdpi='+IntToStr(Xdpi)+#10#13+'Ydpi='+IntToStr(Ydpi)+#10#13+'H='+IntToStr(H)+#10#13+'W='+IntToStr(W)+#10#13);
+//ShowMessage('Site='+Site);
+    OMRRect := CM_Str2Rect(Site,Xdpi,UpLPoint);
+Display1.Lines.Add('UpLPoint=('+IntToStr(UpLPoint.X)+','+IntToStr(UpLPoint.Y)+');'+Site+';'+IntToStr(OMRRect.Left)+','+IntToStr(OMRRect.top)+','+IntToStr(OMRRect.Right)+','+IntToStr(OMRRect.Bottom));
+    if OMRRect.Left < 0 then
+      OMRRect.Left := 0;
+    if OMRRect.Top < 0  then
+      OMRRect.Top := 0;
+    if OMRRect.Right > ImageScrollBox1.Graphic.Width then
+      OMRRect.Right := ImageScrollBox1.Graphic.Width;
+    if OMRRect.Bottom > ImageScrollBox1.Graphic.Height then
+      OMRRect.Bottom := ImageScrollBox1.Graphic.Height;
+
+    result := Get_OMR(ISB_BW.Graphic,OMRRect);
+//ShowMessage('result='+IntToStr(result));
+
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.DisplayMode(index,H_Count,W_Count:Integer;BasePanel:TPanel);
+Var
+  W,H,T,L:Integer;
+  i,n,Count: Integer;
+  Pl :TPanel;
+  bmp : TBitmap;
+begin
+  for i := 1 to 8 do
+  begin
+    TPanel(Findcomponent('imgp'+inttostr(i))).Visible := False;
+  end;
+  W := Round((BasePanel.Width - ((W_Count+1) * Seg)) / W_Count);
+  H := Round((BasePanel.Height -((H_Count+1) * Seg)) / H_Count);
+  Count := 1;
+  for i := 1 to H_Count do
+  begin
+    T := i * Seg + H * (i-1);
+    for n := 1 to W_Count do
+    begin
+      L := n * Seg + W * (n-1);
+      Pl := TPanel(Findcomponent('imgp'+inttostr(Count)));
+      Pl.Visible := True;
+      Pl.Left := L;
+      Pl.Top := T;
+      Pl.Width := W;
+      Pl.Height := H;
+      inc(Count);
+    end;
+  end;
+  Shape1.Width := W + (Seg * 2);
+  Shape1.Height := H + (Seg * 2);
+  Shape1.Visible := True;
+
+
+  bmp := Tbitmap.Create;
+  try
+    ImageList2.GetBitmap(index,bmp);
+    ViewModeBtn.Glyph.Assign(bmp);
+  finally
+  bmp.Free;
+  end;
+  ISB1Click(ISB1);
+end;
+
+Function TCB_IMGPSScanX.GetSampleInf : Boolean;
+var
+  str:String;
+begin
+  Result := False;
+  If not ProcessServlet_Get(HTTPSClient,FURL+'service/imgpsc/IMGPSC01/serversampleforocx','work_no='+FWork_no,FReWrite,Memo1,False) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else IF memo1.Lines.Strings[0] = '0' Then
+  begin
+    str := memo1.Lines.Strings[1];
+    SampleFormIDList.CommaText:=str;
+    
+    Result := True;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+
+end;
+
+function TCB_IMGPSScanX.CheckRequiredColumnValues(workno, caseno:String): Boolean;
+begin
+//
+  Result:=False;
+  if (workno='HLN') and (caseno[9]='3') then
+    Result:=True;
+  if (workno='HLN') and (caseno[9]='4') then
+    Result:=True;
+end;
+
+Procedure TCB_IMGPSScanX.CheckRule2OMRErrInfo;   //檢核規則填入OMRErrINFo Record
+var i : Integer;
+    CheckNo : String;
+begin
+  for I := 1 to 11 do
+  begin
+    CheckNo := Add_Zoo(i,3);
+
+    if FindSQLData(CHECK_RULE_INF_List,'MESG_SHOW_TYPE,MESG_DISP_TYPE,CHECK_MESG,SCAN_MODE','CHECK_NO',CheckNo,0,FindResult) then
+    begin
+      if GetFindResult('MESG_SHOW_TYPE') = '1' then
+        OMRErrInfo[i].Display := True  //顯示
+      Else if GetFindResult('MESG_SHOW_TYPE') = '2' then
+        OMRErrInfo[i].Display := False; //不顯示
+
+      if GetFindResult('MESG_DISP_TYPE') = '1' then
+        OMRErrInfo[i].Ignore := True    //可忽略
+      Else if GetFindResult('MESG_DISP_TYPE') = '2' then
+        OMRErrInfo[i].Ignore := False;  //不可忽略
+
+      OMRErrInfo[i].Info := GetFindResult('CHECK_MESG');
+      OMRErrInfo[i].Mode := GetFindResult('SCAN_MODE');
+    end;
+  end;
+end;
+
+
+
+Procedure TCB_IMGPSScanX.ReNameContext(Path,OldName,NewName:String);
+var
+  i : Integer;
+begin
+  for i := 0 to ContextList.Count - 1 do
+  begin
+    if OldName = ContextList.Strings[i] then
+    begin
+      ContextList.Strings[i] := NewName;
+      ContextList.SaveToFile(Path+'Context.dat');
+      Context_DocnoList.Strings[i] := FormCode2DocNo(FileName2FormCode(NewName));
+      Context_DocnoList.SaveToFile(Path+'Context_DocNo.dat');
+      Break;
+    end;
+  end;
+end;
+
+Function TCB_IMGPSScanX.Down_Img(Path,CaseID:String):Boolean;
+var
+  EnCodeDateTime : String;
+  SendData : String;
+  AttPath : String;
+begin
+  Result := True;
+  EnCodeDateTime := En_DecryptionStr_Base64('E',ServerDate+GetBalance2Time(Balance),Mpskey);
+  ///service/slic/SLIC04/case?data=&verify=&case_no=&file=
+  SendData := 'data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&case_no='+CaseID+'&file=';
+//ShowMessage(SendData);
+  if not dnFile_Get(HTTPSClient,Furl,'service/imgpsc/IMGPSC04/case',SendData,Path+CaseID+'.zip',FReWrite,Memo1,False,DownImgStatus) then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  if Memo1.Lines.Strings[0] = '1' then
+  begin
+    HttpErrStr :=_Msg('錯誤原因:')+memo1.Lines.Strings[1]+'。';
+    Result := False;
+    Exit;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/IMGPS00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+//ShowMessage('替換zip');
+  AttPath := Path + 'AttFile\';
+  if FileExists(Path+CaseID+'.zip') then
+  begin
+    ExecuteUnZip(Path+CaseID+'.zip',Path,True);
+    if FileExists(Path+'img.zip') then
+    begin
+      ExecuteUnZip(Path+'img.zip',Path,False);
+    end;
+    if FileExists(Path+'att.zip') then
+    begin
+      Str2Dir(AttPath);
+      ExecuteUnZip(Path+'att.zip',AttPath,False);
+    end;
+  end
+  Else
+  begin
+    HttpErrStr := _Msg('找不到影像');
+    Result := True;
+    Exit;
+  end;
+
+end;
+
+Procedure TCB_IMGPSScanX.ClearErrini(CaseID:String;CaseNode:TTreeNode); //清掉檢核檔案
+var
+  i : Integer;
+begin
+  if FileExists(ImageSavePath+CaseID+'\Checkerr.ini') then
+    DeleteFile(ImageSavePath+CaseID+'\Checkerr.ini');
+  if FileExists(ImageSavePath+CaseID+'\CheckMemo.dat') then
+    DeleteFile(ImageSavePath+CaseID+'\CheckMemo.dat');
+  {if FileExists(ImageSavePath+CaseID+'\ReSize.dat') then  //20110421拿掉  因為記錄會不見
+    DeleteFile(ImageSavePath+CaseID+'\ReSize.dat');}
+  if FileExists(ImageSavePath+CaseID+'\RemoveMemo.dat') then
+    DeleteFile(ImageSavePath+CaseID+'\RemoveMemo.dat');
+  if FileExists(ImageSavePath+CaseID+'\OMRCheckOk.dat') then
+    DeleteFile(ImageSavePath+CaseID+'\OMRCheckOk.dat');
+  CaseHelpBtn.Visible := False;
+  CaseNode.ImageIndex := 2;
+  CaseNode.SelectedIndex := 2;
+end;
+
+Procedure TCB_IMGPSScanX.SetContextList(Mode:Char;Index:Integer;CaseNo,DocDir,FileName:String);  //'A:加入,I:插入,D:刪除,E:修改'
+var
+  i : Integer;
+  //DocNo:String;
+begin
+  //DocNo := FormCode2DocNo(FileName2FormCode(FileName));
+//ShowMessage('FileName='+FileName);
+  if DocDir = '' then
+    DocDir := AttName ; //附件
+  ContextList.Clear;
+  if FileExists(ImageSavePath+CaseNo+'\'+DocDir+'\Context.dat') then
+    ContextList.LoadFromFile(ImageSavePath+CaseNo+'\'+DocDir+'\Context.dat');
+  SetRecordEditedDocDir('A',CaseNo,DocDir);  //記錄文件有異動
+  case Mode of
+    'A':begin
+          ContextList.Add(FileName);
+        end;
+    'I':begin
+          ContextList.Insert(Index,FileName);
+        end;
+    'E':begin
+          ContextList.Strings[Index] := FileName;
+        end;
+    'D':begin
+          if Index <> -1 then
+          begin
+            ContextList.Delete(Index);
+          end
+          Else if (text <> '') then
+          begin
+            for i := 0 to ContextList.Count - 1 do
+            begin
+              if FileName = ContextList.Strings[i] then
+              begin
+                ContextList.Delete(i);
+                Break;
+              end;
+            end;
+          end;
+          if ContextList.Count = 0 then
+            DeleteFile(ImageSavePath+CaseNo+'\'+DocDir+'\Context.dat');
+        end;
+  end;
+  if ContextList.Count > 0 then
+  begin
+    ContextList.SaveToFile(ImageSavePath+CaseNo+'\'+DocDir+'\Context.dat');
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.SetAttContextList(Mode:Char;Index:Integer;CaseNo,FileName:String);  //'A:加入,I:插入,D:刪除,E:修改'
+var
+  i : Integer;
+begin
+  AttContextList.Clear;
+  if FileExists(ImageSavePath+CaseNo+'\AttContext.dat') then
+    AttContextList.LoadFromFile(ImageSavePath+CaseNo+'\AttContext.dat');
+  case Mode of
+    'A':begin
+          AttContextList.Add(FileName);
+        end;
+    'I':begin
+          AttContextList.Insert(Index,FileName);
+        end;
+    'E':begin
+          AttContextList.Strings[Index] := FileName;
+        end;
+    'D':begin
+          if Index <> -1 then
+          begin
+            AttContextList.Delete(Index);
+          end
+          Else if (text <> '') then
+          begin
+            for i := 0 to AttContextList.Count - 1 do
+            begin
+              if FileName = AttContextList.Strings[i] then
+              begin
+                AttContextList.Delete(i);
+                Break;
+              end;
+            end;
+          end;
+          if AttContextList.Count = 0 then
+            DeleteFile(ImageSavePath+CaseNo+'\AttContext.dat');
+        end;
+  end;
+  if AttContextList.Count > 0 then
+  begin
+    AttContextList.SaveToFile(ImageSavePath+CaseNo+'\AttContext.dat');
+  end;
+end;
+
+Function TCB_IMGPSScanX.ModeNeedCheck(OMRMode,ScanMode:String):Boolean; //掃瞄模式是否要做檢核
+begin
+  Result := False;
+  if Pos(ScanMode,OMRMode) > 0 then
+    Result := True;
+end;
+
+Function TCB_IMGPSScanX.FindNoSaveBarCode : Boolean; //找是否有不要儲存影像的條碼
+var
+  i,n : Integer;
+begin
+  Result := False;
+  for i := 1 to MpsBarcodeinf.Count do
+  begin
+    for n := 0 to NoSaveBarCodeList.Count - 1 do
+    begin
+      if MpsBarcodeinf.Text[i] = NoSaveBarCodeList.Strings[n] then
+      begin
+        Result := True;
+        Break;
+      end;
+    end;
+    if Result then
+      Break;
+  end;
+end;
+
+Function TCB_IMGPSScanX.Index2Anchor(Anchor:String):String;   //十字模式 0->NONE;1->ANCHOR;2->FRAME
+begin
+  if Anchor = '0' then
+    Result := 'NONE'
+  else if Anchor = '1' then
+    Result := 'ANCHOR'
+  else if Anchor = '2' then
+    Result := 'FRAME';
+end;
+
+Function TCB_IMGPSScanX.GetFindResult(Col:String):String;
+var
+  i,v,v1 : Integer;
+  S,RCol,RValue : String;
+begin
+  Result := '';
+  for I := 0 to FindResult.Count - 1 do
+  begin
+    S := FindResult.Strings[i];
+    v := Pos(',',S);
+    v1 := length(S);
+    RCol := copy(S,1,v-1);
+    RValue := Copy(S,v+1,v1-v);
+    if Col =RCol then
+      Result := RValue;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DrawDocItem2(CaseNode : TTreenode;Caseno:String):Boolean;  //畫出文件名稱的Tree
+Var
+  i,n,m : Integer;
+  DocNode,FormNode : TTreeNode;
+  DocNoPage,FormPage : Integer;
+  DocNoCopies : Integer;
+  DocNo,iDocNo : String;
+  DocVer : String;
+  FileList : TStringlist;
+  FormID,iFormID : String;
+  FormName : String;
+  CaseDocNoList,CaseDocNo_CopiesList,StrList : TStringlist;
+  iiDocNo,iiFormID,iiDocVer : String;
+  ST1:TStringList;
+begin
+  Result := False;
+  FileList := TStringlist.Create;
+  CaseDocNoList := TStringlist.Create;
+  CaseDocNo_CopiesList := TStringlist.Create;
+  StrList := TStringlist.Create;
+  ST1:=TStringList.Create;
+LogFile1.LogToFile(logTimeString+'產文件樹開始');
+  try
+    CaseNode.ImageIndex := 1;
+    CaseNode.SelectedIndex := 1;
+    While CaseNode.Count > 0 do  //全刪
+    begin
+      CaseNode.Item[0].Delete;
+    end;
+    CaseDocNoList.Clear;
+    if FileExists(ImageSavePath+Caseno+'\CaseDocNo.dat') then
+      CaseDocNoList.LoadFromFile(ImageSavePath+Caseno+'\CaseDocNo.dat');
+    if FileExists(ImageSavePath+Caseno+'\CaseDocNo_Copies.dat') then
+      CaseDocNo_CopiesList.LoadFromFile(ImageSavePath+Caseno+'\CaseDocNo_Copies.dat');
+    for i := 0 to CaseDocNoList.Count - 1 do
+    begin
+      FileList.Clear;
+      //Showmessage(ImageSavePath+Caseno+'\'+CaseDocNoList.Strings[i]+'\Context.dat');
+      if FileExists(ImageSavePath+Caseno+'\'+CaseDocNoList.Strings[i]+'\Context.dat') then
+        FileList.LoadFromFile(ImageSavePath+Caseno+'\'+CaseDocNoList.Strings[i]+'\Context.dat');
+      iDocNo := DocNoDir2DocNo(CaseDocNoList.Strings[i]);
+      ST1.Clear;
+
+LogFile1.LogToFile(logTimeString+'FileList.Text='+FileList.CommaText);
+      if (FWH_category='N') and (FIs_In_Wh='Y') then
+      begin
+        for n := 0 to FileList.Count - 1 do
+        begin
+          if ISExistImg(ImageSavePath+Caseno+'\'+CaseDocNoList.Strings[i]+'\'+FileList.Strings[n]) then
+          begin
+            ST1.Add(FileList.Strings[n]);
+          end;
+        end;
+        for n := 0 to ST1.Count - 1 do
+        begin
+          if (FileList.IndexOf(ST1.Strings[n])<>-1) and (not DocNoIs_In_WH(iDocNo)) then
+          begin
+            FileList.Delete(FileList.IndexOf(ST1.Strings[n]));
+          end;
+        end;
+      end
+      Else
+        if not DocNoAppear(iDocNo) then Continue;  //20180925 Hong覺得應該加這段
+
+
+
+LogFile1.LogToFile(logTimeString+'WH_category='+FWH_category+',Is_In_Wh='+FIs_In_Wh+',FileList.Text='+FileList.CommaText);
+      if FileList.Count=0 then Continue;
+
+      DocNoCopies := Strtoint(CaseDocNo_CopiesList.Strings[i]);
+      DocNoPage := FileList.Count;
+      iDocNo := DocNoDir2DocNo(CaseDocNoList.Strings[i]);
+//Showmessage(iDocNo);
+//Showmessage(DocNo2DocName(Caseno,iDocNo));
+//ShowMessage('FileList='+FileList.Text);
+      {if (((FIs_In_Wh  = 'Y') and (not DocNoIs_In_WH(iDocNo))) or   //入庫掃描不看非入庫文件
+         ((FIs_In_Wh  = 'N') and (DocNoIs_In_WH(iDocNo)))) and
+         ((iDocNo <> 'Attach') and (Copy(iDocNo,1,5)<>'ZZZZZ')) then     //非入庫掃描不看入庫文件
+      begin
+        Continue;
+      end;}
+
+      //if not DocNoAppear(iDocNo) then Continue;
+
+
+      //DocNode := TreeView1.Items.AddChild(CaseNode,Format('%s{%s}-%d'+_msg('頁'),[CaseDocNoList.Strings[i],DocNo2DocName(Caseno,iDocNo),DocNoPage]));
+      //DocNode := TreeView1.Items.AddChild(CaseNode,Format('%s{%s}-%d'+_msg('份'),[CaseDocNoList.Strings[i],DocNo2DocName(Caseno,iDocNo),DocNoCopies]));
+//ShowMessage('iDocNo='+iDocNo);
+      DocNode := TreeView1.Items.AddChild(CaseNode,Format(_Msg('%s{%s}-%d份'),[DocNo2DocName(Caseno,iDocNo),CaseDocNoList.Strings[i],DocNoCopies]));
+
+      if GetUseCase('F',ImageSavePath+Caseno+'\',CaseDocNoList.Strings[i]) <> '' Then
+      begin
+        DocNode.ImageIndex := 8;
+        DocNode.SelectedIndex := 8;
+      end
+      Else if GetUseCase('T',ImageSavePath+Caseno+'\',CaseDocNoList.Strings[i]) <> '' Then
+      begin
+        DocNode.ImageIndex := 9;
+        DocNode.SelectedIndex := 9;
+      end
+      Else
+      begin
+        DocNode.ImageIndex := 2;
+        DocNode.SelectedIndex := 2;
+      end;
+      if ((Pos('ZZZZZ',DocNode.Text) = 0) and (Pos('YYYYY',DocNode.Text) = 0)) and (FileList.Count =0) then  //制式文件
+      begin
+        for n := 1 to LASTEST_FORM_INF_List.Count - 1 do
+        begin
+          StrList := SplitString('!@!',LASTEST_FORM_INF_List.Strings[n]);
+          iiFormID := StrList.Strings[0];
+          iiDocNo := StrList.Strings[1];
+          if iiDocNo = iDocNo then
+          begin
+            FormID := iiFormID;
+            FormPage := GetFormIDPage(FileList,FormID);
+            FormName := FormCode2FormName(Caseno,FormID);
+            //FormNode := TreeView1.Items.AddChild(DocNode,FormID+'{'+FormName+'}-'+inttostr(FormPage)+_msg('頁'));
+            FormNode := TreeView1.Items.AddChild(DocNode,Format(_Msg('%s{%s}-%d頁'),[FormName,FormID,FormPage]));
+            FormNode.ImageIndex := 4;
+            FormNode.SelectedIndex := 4;
+            DocNode.AlphaSort(True);
+          end;
+        end;
+      end
+      else if (Pos('ZZZZZ',DocNode.Text) > 0) or (Pos('YYYYY',DocNode.Text) > 0) then //自訂文件
+      begin
+        FormID := GetCustomFormID(ImageSavePath+Caseno+'\',CaseDocNoList.Strings[i]);
+        //showmessage(FileList.Text);
+        FormPage := GetFormIDPage(FileList,FormID);
+        FormName := FormCode2FormName(Caseno,FormID);
+        //FormNode := TreeView1.Items.AddChild(DocNode,FormID+'{'+FormName+'}-'+inttostr(FormPage)+_msg('頁'));
+        //FormNode := TreeView1.Items.AddChild(DocNode,FormName+'{'+FormID+'}-'+inttostr(FormPage)+_msg('頁'));
+        FormNode := TreeView1.Items.AddChild(DocNode,Format(_Msg('%s{%s}-%d頁'),[FormName,FormID,FormPage]));
+        FormNode.ImageIndex := 4;
+        FormNode.SelectedIndex := 4;
+        DocNode.AlphaSort(True);
+      end;
+      SortDocDir_FormID(Caseno,CaseDocNoList.Strings[i]);  //檔名依FormID排序
+
+      for n := 0 to FileList.Count - 1 do
+      begin
+        FormID := FileName2FormCode(FileList.Strings[n]);
+        DocVer := FormCode2Version(FormID);
+        DocNo := FormCode2DocNo(FormID);
+        if CheckFormIDExists(DocNode,FormID) then Continue;
+        //Showmessage(FormID+#13+DocNo+#13+DocVer);
+        for m := 0 to FormID_List.Count - 1 do
+        begin
+          iiFormID := FormID_List.Strings[m];
+          iiDocNo := DocNo_List.Strings[m];
+          iiDocVer := FormCode2Version(iiFormID);
+          if (iiDocNo = DocNo) and (iiDocVer = DocVer) then
+          begin
+            //Showmessage(iiFormID+#13+iiDocNo+#13+iiDocVer);
+            FormID := iiFormID;
+            FormPage := GetFormIDPage(FileList,FormID);
+            FormName := FormCode2FormName(Caseno,FormID);
+            //FormNode := TreeView1.Items.AddChild(DocNode,FormID+'{'+FormName+'}-'+inttostr(FormPage)+_msg('頁'));
+            //FormNode := TreeView1.Items.AddChild(DocNode,FormName+'{'+FormID+'}-'+inttostr(FormPage)+_msg('頁'));
+            FormNode := TreeView1.Items.AddChild(DocNode,Format(_Msg('%s{%s}-%d頁'),[FormName,FormID,FormPage]));
+            FormNode.ImageIndex := 4;
+            FormNode.SelectedIndex := 4;
+            DocNode.AlphaSort(True);
+          end;
+        end;
+
+
+        //if not CheckFormIDExists(DocNode,FormID) then
+        //begin
+         // Application.ProcessMessages;
+         // FormPage := GetFormIDPage(FileList,FormID);
+         /// FormName := FormCode2FormName(Caseno,FormID);
+         /// FormNode := TreeView1.Items.AddChild(DocNode,FormID+'{'+FormName+'}-'+inttostr(FormPage)+_msg('頁'));
+         // FormNode.ImageIndex := 4;
+         // FormNode.SelectedIndex := 4;
+        //end;
+      end;
+    end;
+
+    if DirectoryExists(ImageSavePath+Caseno+'\'+AttName) then
+    begin
+
+      FileList.Clear;
+      if FileExists(ImageSavePath+Caseno+'\'+AttName+'\Context.dat') then
+        FileList.LoadFromFile(ImageSavePath+Caseno+'\'+AttName+'\Context.dat')
+      Else
+      begin
+        Rmdir(ImageSavePath+Caseno+'\'+AttName);
+        Exit;
+      end;
+      DocNoPage := FileList.Count;
+      iDocNo := DocNoDir2DocNo(AttName);
+      //DocNode := TreeView1.Items.AddChild(CaseNode,Format('%s{%s}-%d'+_msg('份'),[AttName,DocNo2DocName(Caseno,iDocNo),1]));
+      DocNode := TreeView1.Items.AddChild(CaseNode,Format(_Msg('%s{%s}-%d份'),[DocNo2DocName(Caseno,iDocNo),AttName,1]));
+      DocNode.ImageIndex := 2;
+      DocNode.SelectedIndex := 2;
+      for n := 0 to FileList.Count - 1 do
+      begin
+        FormID := FileName2FormCode(FileList.Strings[n]);
+        if not CheckFormIDExists(DocNode,FormID) then
+        begin
+          FormPage := GetFormIDPage(FileList,FormID);
+          FormName := FormCode2FormName(Caseno,FormID);
+          //FormNode := TreeView1.Items.AddChild(DocNode,FormID+'{'+FormName+'}-'+inttostr(FormPage)+_msg('頁'));
+          //FormNode := TreeView1.Items.AddChild(DocNode,FormName+'{'+FormID+'}-'+inttostr(FormPage)+_msg('頁'));
+          FormNode := TreeView1.Items.AddChild(DocNode,Format(_Msg('%s{%s}-%d頁'),[FormName,FormID,FormPage]));
+          FormNode.ImageIndex := 4;
+          FormNode.SelectedIndex := 4;
+        end;
+      end;
+    end;
+
+    if FModeName='件' then  //20170904 先裝死  因為異動 同時存在兩種附件太難寫
+    begin
+      if DirectoryExists(ImageSavePath+Caseno+'\Attach') then
+      begin
+        FileList.Clear;
+        if FileExists(ImageSavePath+Caseno+'\Attach'+'\Context.dat') then
+          FileList.LoadFromFile(ImageSavePath+Caseno+'\Attach'+'\Context.dat')
+        Else
+        begin
+          Rmdir(ImageSavePath+Caseno+'\Attach');
+          Exit;
+        end;
+        DocNoPage := FileList.Count;
+        iDocNo := DocNoDir2DocNo(AttName);
+        //DocNode := TreeView1.Items.AddChild(CaseNode,Format('%s{%s}-%d'+_msg('份'),[AttName,DocNo2DocName(Caseno,iDocNo),1]));
+        //DocNode := TreeView1.Items.AddChild(CaseNode,Format('%s{%s}-%d'+_msg('份'),[DocNo2DocName(Caseno,iDocNo),'Attach',1]));
+        DocNode := TreeView1.Items.AddChild(CaseNode,Format(_Msg('%s{%s}-%d份'),[DocNo2DocName(Caseno,iDocNo),'Attach',1]));
+
+        DocNode.ImageIndex := 2;
+        DocNode.SelectedIndex := 2;
+        for n := 0 to FileList.Count - 1 do
+        begin
+          FormID := FileName2FormCode(FileList.Strings[n]);
+          if not CheckFormIDExists(DocNode,FormID) then
+          begin
+            FormPage := GetFormIDPage(FileList,FormID);
+            FormName := FormCode2FormName(Caseno,FormID);
+            //FormNode := TreeView1.Items.AddChild(DocNode,FormID+'{'+FormName+'}-'+inttostr(FormPage)+_msg('頁'));
+            //FormNode := TreeView1.Items.AddChild(DocNode,FormName+'{'+FormID+'}-'+inttostr(FormPage)+_msg('頁'));
+            FormNode := TreeView1.Items.AddChild(DocNode,Format(_Msg('%s{%s}-%d頁'),[FormName,FormID,FormPage]));
+
+            FormNode.ImageIndex := 4;
+            FormNode.SelectedIndex := 4;
+          end;
+        end;
+      end;
+    end;
+LogFile1.LogToFile(logTimeString+'產文件樹結束');
+  Finally
+  FileList.Free;
+  CaseDocNoList.Free;
+  CaseDocNo_CopiesList.Free;
+  StrList.Free;
+  ST1.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.initParameter;
+begin
+
+//  if FCaseNoLength=0 then
+//  begin
+//
+//  end;
+
+  if FFileSizeLimit = 0 then
+  begin
+    FFileSizeLimit := 5*1024;
+  end;
+
+
+  if FImgDPI=0 then
+  begin
+    FImgDPI := 300;
+    ScanDpi := FImgDPI;
+  end
+  else
+  begin
+    //FImgDPI := StrToInt(Value);
+    ScanDpi := FImgDPI;
+  end;
+
+  if FScanColor = 0 then
+  begin
+    ScanColor := ifBlackWhite;
+  end;
+
+  if FScanColor = 1 then
+  begin
+    ScanColor := ifGray256 ;
+    ScanGrayCB.Checked:=True;
+  end;
+
+  if FScanColor = 2 then
+  begin
+    ScanColor := ifTrueColor ;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CheckAvailable:Boolean; //檢查是否可使用元件
+var
+  SendData : String;
+  Msg:String;
+  Nowcount,Totalcount,Lic_Idx : Integer;
+  MacID,IPStr,LegalDate :String;
+begin
+  Result := False;
+  /////下載MPSLIC_SCAN.lic //////
+  SendData:='data='+HTTPEncode(UTF8Encode(FData))+'&verify='+FVerify+'&work_no=PLN&file=MPSLIC_SCAN.lic';
+  if not dnFile_Get(HTTPSClient,Furl,'service/imgpsc/IMGPSC04/sample',SendData,LngPath+'MPSLIC_SCAN.lic',FReWrite,Memo1,False,DownImgStatus) then
+  begin
+    Showmessage(_Msg('檢查註冊檔案時,網路發生錯誤!!')+_Msg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason);
+    Exit;
+  end;
+  /////下載MPSLIC_SCAN.lic ///
+
+  if CheckLicensebyIP_new(LngPath+'MPSLIC_SCAN.lic',MacID,IPStr,LegalDate,Msg,Nowcount,Totalcount,Lic_Idx) then  //檢查是否己註冊過
+  begin
+    if (LegalDate <> '') and (ServerDate>LegalDate) and (Lic_Idx>(Totalcount)) then
+    begin
+      Showmessage(_Msg('已經超過可使用期限及超出授權數請連絡廠商'));
+      Result := False;
+      //Exit;
+    end
+    else
+      Result := True;
+  end
+  Else
+  begin
+    if Msg <> '' then
+    begin
+      Showmessage(Format(_Msg('註冊檔有問題,請連絡廠商 錯誤原因:%s'),[Msg]));
+      Result := false;
+      Exit;
+    end
+    Else
+    begin
+      if (LegalDate <> '') and (ServerDate>LegalDate) and (NowCount =0 )  then
+      begin
+        Lic_Idx := 0;
+        Showmessage(_Msg('已經超過可使用期限請連絡廠商'));
+        Result := False;
+        //Exit;
+      end
+      //else if (LegalDate = '') and (Nowcount >= Totalcount+10) then  //超過註冊數量
+      else if ((LegalDate = '') or ((LegalDate <> '') and (ServerDate>LegalDate)) ) and (Nowcount >= Totalcount) then  //超過註冊數量  20150717 yuu說拿掉送的10個
+      begin
+        Lic_Idx := 0;
+        Showmessage(_Msg('已經超過授權數請連絡廠商'));
+        Result := False;
+      end
+      Else  //未超過註冊數量要寫入註冊檔
+      begin
+        {if Messagedlg(_Msg('您尚未註冊授權是否要進行註冊??'),MtConfirmation,[mbyes,mbcancel],0) = mrcancel then
+        begin
+          Result := False;
+          Exit;
+        end;}
+        ShowText := _Msg('授權中,請稍候');
+        AddLicense(LngPath+'MPSLIC_SCAN.lic',MacID,IPStr,Msg);
+        Nowcount := Nowcount + 1;
+        DataLoading(True,True);
+
+        /////上傳MPSLICSCAN.lic ////
+        SendData:='data='+HTTPEncode(UTF8Encode(FData))+'@verify='+FVerify+'@work_no=PLN@file_name=MPSLIC_SCAN.lic';
+        if not upFile(HTTPSClient,FUrl,'service/imgpsc/IMGPSC02/sample',SendData,'file',LngPath+'MPSLIC_SCAN.lic',FReWrite,Memo1,False) then
+        begin
+          Showmessage(_Msg('檢查註冊時,網路發生錯誤!!')+_MSg('錯誤代碼:')+Inttostr(HttpError.HttpErrorCode)+' '+HttpError.HttpReason+')');
+          DataLoading(False,False);
+          Exit;
+        end;
+        if memo1.Lines.Strings[0] = '1' then
+        begin
+          Showmessage(_Msg('檢查註冊時,網路發生錯誤!!')+_Msg('錯誤原因:')+memo1.Lines.Strings[1]);
+          DataLoading(False,False);
+          Exit;
+        end
+        Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+        begin
+          Showmessage(_Msg('檢查註冊時,網路發生錯誤!!')+_Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入'));
+          DataLoading(False,False);
+          Exit;
+        end;
+        /////上傳MPSLICSCAN.lic /////
+        //Sleep(30000);    //第一次註冊睡30秒  先不睡
+        Result := True;
+      end;
+    end;
+  end;
+  if FileExists(LngPath+'MPSLIC_SCAN.lic') then
+    DeleteFile(LngPath+'MPSLIC_SCAN.lic');
+  if LegalDate = '' then
+    StatusBar1.Panels[4].Text := Format(_Msg('註冊號:%s 剩餘註冊數:%s'),[MacID,inttostr(Totalcount-Nowcount)]);
+  if LegalDate <> '' then
+    StatusBar1.Panels[4].Text := '*'+Format(_Msg('註冊號:%s 剩餘註冊數:%s'),[MacID+'('+inttostr(Lic_Idx)+')',inttostr(Totalcount-Nowcount)]);
+end;
+
+Function TCB_IMGPSScanX.GetCustomDocName(Path,DocNo:String):String; //取出自定文件名稱
+var
+  ini : Tinifile;
+begin
+  ini := Tinifile.Create(Path+'CustomDocNo.ini');
+  try
+    Result := ini.ReadString(DocNo,'Name','');
+  finally
+  ini.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.FindCustomDocName(Path,DocName:String):Boolean; //尋找自定文件名稱是否存在
+var
+  ini : Tinifile;
+  Ct,i:Integer;
+  DocNo,FormID : String;
+begin
+  Result := False;
+  ini := Tinifile.Create(Path+'CustomDocNo.ini');
+  try
+    Ct := ini.ReadInteger('CustomCount','Count',0);
+    for I := 1 to Ct do
+    begin
+      DocNo := 'ZZZZZ'+Add_Zoo(i,3);
+      if DocName = ini.ReadString(DocNo,'Name','') then
+      begin
+        Result := True;
+        Break;
+      end;
+    end;
+  finally
+  ini.Free;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.PrintImg(FileName, LoginID, Datetime,
+  Path: WideString);
+var
+  PrintMode      : TEnvisionPrintMode;
+  GraphicPrinter : TDibGraphicPrinter;
+  PrtDialog : TPrintDialog;
+  S : TStringlist;
+  i,Pages,Page : Integer;
+  Prt_String : String;
+  Prt_H : Integer;
+  procedure PrintWithManualPrintJob(LoginID,DateTime:String;Pages,Page:Integer);
+  begin
+      If Page = 1 Then
+      begin
+        { if UsePrintJob is False, Printer.BeginDoc and Printer.EndDoc must be
+          called by the user. This allows printing multiple images in the
+          same job (or page). }
+        GraphicPrinter.UsePrintJob := False;
+
+        { if UsePrintJob is False, the print job name that appears in the
+          print manager must be specified in using the Title property of the
+          Printer object. Otherwise, if UsePrintJob is True, the Title
+          property of the TDibGraphicPrinter object is used to specify the
+          job name. }
+        Printer.Title := _Msg('影像列印');
+      end;
+
+      IF (Page mod 2) = 1 Then
+        Printer.BeginDoc
+      Else
+        Printer.NewPage;
+
+      ImageScrollBox1.DisplayedGraphic.Canvas.Font.Size := 24;
+
+      //ImageScrollBox1.DisplayedGraphic.Canvas.TextOut(20,20, _Msg('列印人員:')+LoginID+' '+_Msg('列印分行:')+FUserUnit+' '+_Msg('列印日期:')+DateTime);
+
+      GraphicPrinter.Print(ImageScrollBox1.DisplayedGraphic);
+
+
+      { this shows how to print text on a page.
+      Printer.Canvas.TextOut(10,10, 'Envision Image Library');
+      }
+      If ((Page mod 2) = 0) or (Page = pages) Then
+        Printer.EndDoc;
+  end;
+
+  procedure PrintWithAutoPrintJob;
+  begin
+      GraphicPrinter.UsePrintJob := True;
+      GraphicPrinter.Title       := _Msg('影像列印');
+      GraphicPrinter.Print(ImageScrollBox1.Graphic);
+  end;
+
+begin
+  S := TStringlist.Create;
+  GraphicPrinter := TDibGraphicPrinter.Create;
+  PrtDialog := TPrintDialog.Create(self);
+  //PrtDialog.Copies:=99;
+  try
+    IF PrtDialog.Execute Then
+    begin
+      S.Text := FileName;
+      Pages := S.Count;
+
+      for i := 0 to S.Count -1 do
+      begin
+        ImageScrollBox1.LoadFromFile(Path+S.Strings[i],1);
+        watermark2(Image1.Picture.Bitmap,70,'',ImageScrollBox1.DisplayedGraphic);
+        PrintWithManualPrintJob(LoginID,DateTime,Pages,i+1);
+      end;
+    end;
+
+  Finally
+  PrtDialog.Free;
+  GraphicPrinter.Free;
+  S.Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.GotoAttach(OldLevel:Integer);
+var
+  i : Integer;
+begin
+  for i := 0 to MyTreeNode1.Count - 1 do
+  begin
+    if Pos('Attach',MyTreeNode1.Item[i].Text) > 0 then
+    begin
+      if OldLevel = 2 then
+      begin
+        TreeView1.Selected := MyTreeNode1.Item[i];
+      end
+      else if OldLevel = 3 then
+      begin
+        TreeView1.Selected := MyTreeNode1.Item[i].Item[0];
+      end;
+      Break;
+    end;
+  end;
+  //TreeView1click(nil);
+end;
+
+Function TCB_IMGPSScanX.GetCustomNameCount(CustomName:String):Integer;   //取外傳的名稱數量
+var
+  i,ct : Integer;
+  C_DocNameList : TStringlist;
+begin
+  C_DocNameList := TStringlist.Create;
+  try
+    C_DocNameList.StrictDelimiter := True;
+    C_DocNameList.Delimiter := #9;
+    C_DocNameList.DelimitedText := FC_DocNameList;
+    ct := 0;
+    for i := 0 to C_DocNameList.Count - 1 do
+    begin
+      if C_DocNameList.Strings[i] = CustomName then
+      begin
+        inc(ct);
+      end;
+    end;
+    Result := ct;
+  finally
+  C_DocNameList.Free;
+  end;
+end;
+
+function TCB_IMGPSScanX.ISExistImg(const filename: string): boolean;
+begin
+  if ExistImgList.IndexOf(LoadFileGetMD5(filename))<>-1 then
+  begin
+    Result:=True;
+  end
+  else
+  begin
+    Result:=False;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.PriorPage(Page:Integer); //上一頁
+var
+  iISB : TImageScrollBox;
+begin
+  iISB := TImageScrollBox(FindComponent(ISBName+inttostr(Page-1)));
+  if iISB <> nil then
+  begin
+    ISBClick(iISB);
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.NextPage(Page:Integer); //下一頁
+var
+  iISB : TImageScrollBox;
+begin
+  iISB := TImageScrollBox(FindComponent(ISBName+inttostr(Page+1)));
+  if iISB <> nil then
+  begin
+    ISBClick(iISB);
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.OMRErr2ini(CaseID,Reason,FileName,Site,RelaFileName,RelaSite,Anchor,Anchor1:String;Del,Ingnore,Display:Boolean); //OMR檢核失敗寫入ini
+var
+  ini : Tinifile;
+  Errcount : Integer;
+  S : TStringlist;
+begin
+  if Display then
+  begin
+    ini := Tinifile.Create(ImageSavePath + CaseID+'\upload\Checkerr.ini');
+    try
+      Errcount := ini.ReadInteger('OMRCount','Count',0);  //透過Errcount來對應
+      inc(ErrCount);
+      ini.WriteString(inttostr(ErrCount),'Reason',Reason);
+      ini.WriteBool(inttostr(ErrCount),'Ingnore',Ingnore);
+      ini.writeString(inttostr(ErrCount),'FileName',FileName);
+      ini.WriteString(inttostr(ErrCount),'Site',Site);
+      ini.WriteString(inttostr(ErrCount),'RelaFileName',RelaFileName);
+      ini.WriteString(inttostr(ErrCount),'RelaSite',RelaSite);
+      ini.WriteString(inttostr(ErrCount),'Anchor',Anchor);
+      ini.WriteString(inttostr(ErrCount),'RelaAnchor',Anchor1);
+      ini.WriteBool(inttostr(ErrCount),'Del',Del);
+      ini.WriteInteger('OMRCount','Count',ErrCount);
+    finally
+    ini.Free;
+    end;
+  end
+  Else
+  begin
+    S := TStringlist.Create;
+    try
+      if FileExists(ImageSavePath + CaseID+'\CheckMemo.dat') then
+        S.LoadFromFile(ImageSavePath + CaseID+'\CheckMemo.dat');
+      S.Add(Reason);
+      S.SaveToFile(ImageSavePath + CaseID+'\CheckMemo.dat');
+    finally
+    S.Free;
+    end;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.OMRErrini2List(CaseID:String;ErrlistForm:TErrlistForm); //OMR檢核失敗從ini寫入ListView
+var
+  ini : Tinifile;
+  Errcount : Integer;
+  Del : Boolean;
+  i : Integer;
+begin
+  ini := Tinifile.Create(ImageSavePath + CaseID+'\upload\Checkerr.ini');
+  try
+    Errcount := ini.ReadInteger('OMRCount','Count',0);
+
+    for i := 1 to ErrCount do
+    begin
+      Del := ini.ReadBool(inttostr(i),'Del',False); //是否被移除了
+      if Not Del then
+      begin
+        With ErrlistForm.ErrListLV.Items.Add do
+        begin
+          Caption := ini.ReadString(inttostr(i),'Reason','');
+          SubItems.Add(inttostr(i));
+        end;
+      end;
+    end;
+    if Errlistform.ErrListLV.Items.Count > 0 then
+      Errlistform.ImmediateBt.Enabled := False;
+  finally
+  ini.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.DownLanguage:Boolean;  //下載多國語言檔
+begin
+  Result := True;     // http://192.168.0.101:8080/fbnp/servlet/CWC01?act=getservertime
+  //dnFile(HTTPSClient,FUrl+'Language.Lng','','',LngPath+'Language.Lng',FReWrite.Text,Memo1,False,DownImgStatus)
+  If not dnFile_Get(HTTPSClient,FUrl+'Language.Lng','','',LngPath+'Language.Lng',FReWrite,Memo1,False,DownImgStatus) Then
+  begin
+    HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+    Result := False;
+    Exit;
+  end;
+  IF memo1.Lines.Strings[0] = '1' Then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+    Result := False;
+    Exit;
+  end
+  Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+  begin
+    HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+    Result := False;
+    Exit;
+  end;
+  
+end;
+
+Procedure TCB_IMGPSScanX.FreeShapeobj(SelectISB : TImageScrollBox);
+var
+  i : Integer;
+begin
+  IF SelectISB = nil then //全Free;
+  begin
+    For i:= ComponentCount -1 downto 0 do
+    begin
+      IF Components[i] is TShape Then
+      begin
+        IF Pos('SP',Components[i].Name) > 0  Then
+          Components[i].Free;
+      end;
+    end;
+  end
+  Else  //只Free指定的
+  begin
+    TShape(FindComponent('SP'+Copy(SelectISB.Name,length(ISBName)+1,length(SelectISB.Name)-length(ISBName)))).Free;
+  end;
+end;
+
+Procedure TCB_IMGPSScanX.CreateIn_WH(CaseID:String);  //產生In_WH.dat
+var
+  i,n : Integer;
+  DocDirList,In_WH_List : TStringlist;
+  iDocNo : String;
+begin
+  DocDirList := TStringlist.Create;
+  In_WH_List := TStringlist.Create;
+  try
+    if FileExists(ImageSavePath+CaseID+'\CaseDocNo.dat') then
+      DocDirList.LoadFromFile(ImageSavePath+CaseID+'\CaseDocNo.dat');
+    for i := 0 to DocDirList.Count - 1 do
+    begin
+      iDocNo := DocNoDir2DocNo(DocDirList.Strings[i]);
+      for n := 0 to IN_WH_DocNoList.Count - 1 do
+      begin
+        if (iDocNo = IN_WH_DocNoList.Strings[n]) or (Copy(iDocNo,1,5)='ZZZZZ') then
+        begin
+          In_WH_List.Add(DocDirList.Strings[i]);
+          Break;
+        end;
+      end;
+    end;
+    In_WH_List.SaveToFile(ImageSavePath+CaseID+'\In_Wh.dat');
+
+  finally
+  DocDirList.Free;
+  In_WH_List.Free;
+  end;
+end;
+
+Function TCB_IMGPSScanX.CreateAttach_Info(CaseID:String):String; //產生是否有Attach Y:有 N:沒有
+begin
+  Result := 'N';
+  if GetDocDir_Page(CaseID,AttName) > 0 Then
+    Result := 'Y';
+end;
+
+Function TCB_IMGPSScanX.GetOMRCheckSet : Boolean; //下載OMR檢核XML檔
+var
+  SendData : String;
+  LastDateTime : String;
+  S : TStringlist;
+begin
+  Result := True;
+  S := TStringlist.Create;
+  Try
+    if FileExists(CheckXmlPath+'OMRSet.zip') then
+      DeleteFile(CheckXmlPath+'OMRSet.zip');
+
+    LastDateTime := '00000000000000';
+    if FileExists(CheckXmlPath+'LastDateTime.dat') then
+    begin
+      S.LoadFromFile(CheckXmlPath+'LastDateTime.dat');
+      LastDateTime := S.Strings[0];
+    end;
+
+    SendData := 'settype=3&lastupdate='+LastDateTime;
+    if not dnFile_Get(HTTPSClient,Furl,'service/imgpsc/IMGPSC01/settings',SendData,CheckXmlPath+'OMRSet.zip',FReWrite,Memo1,False,DownImgStatus) then
+    begin
+      HttpErrStr := _Msg('錯誤代碼:')+inttostr(HttpError.HttpErrorCode)+','+HttpError.HttpReason;
+      Result := False;
+      Exit;
+    end;
+    if FileExists(CheckXmlPath+'OMRSet.zip') then   //有更新
+    begin
+      ExecuteUnZip(CheckXmlPath+'OMRSet.zip',CheckXmlPath,True);
+      S.Clear;
+      S.Add(ServerDate+GetBalance2Time(Balance));
+      S.SaveToFile(CheckXmlPath+'LastDateTime.dat');
+    end
+    Else
+    begin
+      if (Memo1.Lines.Strings[0] = 'nodata') Then   //沒更新
+      begin
+        Result := True;
+      end
+      Else if (Memo1.Lines.Strings[0] = '1') Then
+      begin
+        HttpErrStr := _Msg('錯誤原因:')+memo1.Lines.Strings[1];
+        Result := False;
+        Exit;
+      end
+      Else if Pos('<script type="text/javascript" src="scripts/CW00/login.js"></script>',Memo1.Lines.Text) > 0 then
+      begin
+        HttpErrStr := _Msg('錯誤原因:')+_Msg('閒置過久或被登出,請重新登入');
+        Result := False;
+        Exit;
+      end;
+    end;
+
+  Finally
+  S.Free;
+  End;
+
+end;
+
+procedure TCB_IMGPSScanX.Timer1Timer(Sender: TObject);
+var
+  StampDate,StampTime : String;
+  i: Integer;
+begin
+  Timer1.Enabled := False;
+  //FIs_In_Wh:='Y'; /// test 記得關掉
+  //FWH_category :='N';  // test 記得關掉
+//  FImgDelete := 'Y'; //test 記得關掉
+  //Showmessage('a');
+  //self.FIs_OldCase := 'Y';
+  PageLVclear := True;
+  InitialOk := False;
+
+  FMaxUploadSize:='10';
+  FJpgCompression:=50;
+  FFtpRootPath := '';  //影像平台沒有給FtpRoot目錄,會直接用FFtpExtraPath切換至指定目錄
+  //FMode := 'DSCAN' ;
+  //FIs_In_Wh := 'Y';
+  if FIs_In_Wh = 'Y' then
+    AttName := 'Attach'  //入庫附件
+  else
+    AttName := 'S_Attach'; //Smartlending 附件
+//ShowMessage('1111111');
+  if FMode = 'SAMPLESCAN' then
+  begin
+    NewScanBtn.Visible := False;
+    PJLinkedMenuSpeedButton2.Visible := False;
+    AddScanBtn.Visible := False;
+    CheckCaseBtn.Visible := False;
+    Panel18.Visible := False;
+    TransBtn.Visible := False;
+    FC6.Visible := False;
+    SampleScanBtn.Visible := True;
+    Panel1.Visible := True;
+    Panel6.Visible := True;
+    ScanDuplexCB.Visible := False; //雙面掃描
+  end
+  Else if (FMode = 'NSCAN') then
+  begin
+    Panel18.Visible := True;
+    Panel1.Visible := True;
+    Panel6.Visible := True;
+    Panel21.Visible := True;
+    Panel23.Visible := True;
+
+    AttFileGB.Visible := True;
+    Splitter2.Visible := True;
+    ScanDuplexCB.Visible := True; //雙面掃描
+  end
+  Else if FMode = 'FSCAN' then
+  begin
+    Panel1.Visible := True;
+    //Panel6.Visible := True;
+  end
+  Else
+  begin
+    Panel18.Visible := True;
+    Panel1.Visible := True;
+    Panel6.Visible := True;
+    Panel21.Visible := True;
+    Panel23.Visible := True;
+    AttFileGB.Visible := True;
+    Splitter2.Visible := True;
+  end;
+  DisplayMode(1,1,1,Panel9);
+  Application.ProcessMessages;
+  StatusBar1.Panels[0].Text := 'Ver'+GetCurrentVersionNo;
+  StatusBar1.Panels[1].Text := 'Login User:'+FUserName;
+  {$IFDEF Test}
+    StatusBar1.Panels[0].Text := StatusBar1.Panels[0].Text+'(test)';
+  {$ENDIF}
+    StatusBar1.Panels[0].Text := StatusBar1.Panels[0].Text;
+
+  if FPrintyn = 'Y' then
+    PrtLB.Visible := True;
+
+  initParameter;  //20170222 針對新加的parameter 作初始化參數
+  InitScrollRec;
+  If FUrl = '' then
+  begin
+    Showmessage(_Msg('URL cannot be empty,please contact system administrator'));
+    Exit;
+  end;
+  if FUrl[length(FUrl)]<>'/' then
+    FUrl := FUrl + '/';
+  //20221028 把語言檔改放至 Local目錄裡,才不會有些文字來不及使用
+  LngPath := GetLocalAppDir(Handle)+'MPS\CB_IMGPS\';
+  Str2Dir(LngPath);
+  ////下載語言檔/////  20170218 先拿調以便測試
+  If not DownLanguage Then
+  begin
+    Showmessage('Language File error!!'+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+
+  InitialLanguage(Self);  //載入多國語言
+
+
+  if FWork_no='' then
+  begin
+    Showmessage(_Msg('業務別不能為空白,請洽詢程式人員'));
+    Exit;
+  end;
+
+  if CaseIDLength = 0 then
+  begin
+    Showmessage(_Msg('案件編號長度限制不能為空白,請洽詢程式人員'));
+    //Exit;  //測試時不退出
+  end;
+
+  //********清單區********
+
+  Doc_Inf_List := TStringList.Create;  //Doc_Inf 清單   Docno + 版本為key
+  DM_FORM_INF_List := TStringList.Create;  //DM_FORM_INF 清單   Docno + 版本為key
+  FORM_INF_List := TStringList.Create; //FORM_INF的清單
+  CHECK_RULE_INF_List := TStringList.Create;  //CHECK_RULE_INF  清單
+  MEMO_INF_List := TStringList.Create;  //MEMO_INF 清單
+  WORK_INF_List := TStringList.Create;  //WORK_INF 清單
+  LASTEST_FORM_INF_List := TStringList.Create;  // LASTEST_FORM_INF 清單
+  FindResult := TStringlist.Create;  //找SQLData的結果
+
+  OMRFileList := TStringList.Create; //要OMR檢核的文件(只檢查每種Form的第一頁)
+  FormCode_PageSize := TStringList.Create; //文件的預設大小  FormCode_Height_Width
+  DocNo_NeedDoc := TStringList.Create; //有Docno時要相依的文件   DocNo_相依文件_相依文件
+  DocNo_NoDoc := TStringList.Create; //有Docno時互斥的文件   DocNo_互斥文件_互斥文件
+  DocNo_VerinCase := TStringList.Create; //案件裡的DocNo+版本的清單
+  CaseDocNoList := TStringlist.Create;  //案件裡的DocNo清單
+  CaseDocNo_CopiesList := TStringlist.Create; //案件裡的DocNo份數清單
+  CaseList := TStringList.Create;    //記錄掃瞄案件的順序
+  Context_DocnoList := TStringlist.Create; //案件裡的檔案Docno清單
+  ContextList := TStringlist.Create; //案件裡的檔案清單
+  AttContextList := TStringlist.Create; //案件裡的附加檔案清單
+  NoSaveBarCodeList := TStringlist.Create; //不儲存的條碼清單
+  FormID_List := TStringlist.Create;  //FormID清單
+  DocNo_List := TStringlist.Create; //DocNo清單
+  NowShowFileList := TStringlist.Create;  //目前顯示的影像清單
+  NowSelectFileList := TStringlist.Create; //目前被點選的影像清單
+  Cust_DocNoList := TStringlist.Create; //自行定義的文件名稱
+  IN_WH_DocNoList := TStringlist.Create; //入庫的文件清單
+  GuideFormIDList := TStringlist.Create; //要當導引頁表單清單
+  DivPageFormIDList := TStringList.Create; //要當分案頁表單清單
+  LastInitFormidList :=TStringList.Create;
+  LastAddFormidList := TStringList.Create;
+  SampleFormIDList := TStringList.Create;//20170627 加入
+  ExistImgList := TStringList.Create;  //20170724 新增
+  reSizeExistImgList :=TStringList.Create; //20171012 新增
+  //********清單區********
+
+  ShowText := _Msg('資料載入中,請稍候');
+  DataLoading(True,True);
+
+  IF not GetServerDate Then
+  begin
+    Showmessage(_Msg('取主機時間時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+
+  if FMode='SAMPLESCAN' then
+  begin
+    IF not GetSampleInf Then  //取已存在sample
+    begin
+      Showmessage(_Msg('取存在範本資訊時,網路發生錯誤!!')+HttpErrStr);
+      DataLoading(False,False);
+      Exit;
+    end;
+  end;
+
+
+
+//ShowMessage('GetServerDate  '+ServerDate+' , '+ServerTime);
+  ////下載系統資訊////
+  IF not GetSetInf1 Then  //取DOC_INF  文件資訊
+  begin
+    Showmessage(_Msg('取文件資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+//ShowMessage('GetSetInf1');
+  //showmessage(self.Doc_Inf_List.Text);
+  IF not GetSetInf2 Then  //取DM_FORM_INF     相依互斥資訊
+  begin
+    Showmessage(_Msg('取相依互斥資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+//ShowMessage('GetSetInf2');
+  //Showmessage(self.Doc_Inf_List.Text);
+  IF not GetSetInf3 Then   //取FORM_INF  表單資訊
+  begin
+    Showmessage(_Msg('取表單資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+//ShowMessage('GetSetInf3');
+  IF not GetSetInf4 Then   //取CHECK_RULE_INF   檢核規則資訊
+  begin
+    Showmessage(_Msg('取檢核規則資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+  //showmessage(self.CHECK_RULE_INF_List.Text);
+//ShowMessage('GetSetInf4');
+  IF not GetSetInf5 Then   //取MEMO_INF   常用片語資訊
+  begin
+    Showmessage(_Msg('取常用片語資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+//ShowMessage('GetSetInf5');
+  //showmessage(self.MEMO_INF_List.Text);
+  IF not GetSetInf6 Then   //取WORK_INF   系統參數資訊
+  begin
+    Showmessage(_Msg('取系統參數資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+//ShowMessage('GetSetInf6');
+  //showmessage(FORM_INF_List.Text);
+  IF not GetSetInf7 Then   //取LASTES_FORM_INF   系統參數資訊
+  begin
+    Showmessage(_Msg('取最新版FORMID參數資訊時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+//ShowMessage('GetSetInf7');
+  //Showmessage(LASTEST_FORM_INF_List.Text);
+  SetFormID_DocNo;  //將FormID及Docno抽出塞入List裡  20130403增加
+  SetIn_WH_DocNo; //將要入庫的DocNo抽出來另存入list裡
+  GetDefScanIni; //取得掃描預設值及相關設定
+
+  ////下載系統資訊/////
+  if ImagePath = '' then
+  begin
+    Showmessage(_Msg('本機暫存路徑不得為空白'));
+    DataLoading(False,False);
+    Panel1.Enabled := False;
+    Panel2.Enabled := False;
+    Exit;
+  end;
+  initkscan;
+  if ImagePath[Length(ImagePath)] <> '\' then
+    ImagePath := ImagePath + '\';
+//ShowMessage('ImagePath='+ImagePath);
+  //CheckXmlPath := ImagePath+'OMRSITE\'+FWork_No;
+  CheckXmlPath := ImagePath+'OMRSITE\';  // 20200612 發現影像平台是取回所有業務的設定,所以不能有業務別目錄
+//ShowMessage('CheckXmlPath='+CheckXmlPath);
+  //SitePath := ImagePath+'Site\'+FWork_No+'\';
+  SitePath := ImagePath+'Site\';  // 20200612 發現影像平台是取回所有業務的設定,所以不能有業務別目錄
+  //LngPath := ImagePath; //改放至上面取Local目錄
+  SamplePath := ImagePath+'Sample\'+FWork_No+'\';
+  ImagePath := ImagePath + 'Scantemp\';
+//ShowMessage('AA  ImagePath='+ImagePath);
+  ScaniniPath :=ImagePath+FWork_No+'\'+FUserUnit +'\';
+//ShowMessage('ScaniniPath='+ScaniniPath);
+  ImagePath := ImagePath + FWork_No+'\'+FUserUnit+'\'+FMode+'\';
+  ImagePath := StringReplace(ImagePath, '\\', '\',[rfReplaceAll, rfIgnoreCase]);
+//ShowMessage('BB  ImagePath='+ImagePath);
+  ImageSavePath := ImagePath;
+  str2dir(CheckXmlPath);
+  str2dir(SitePath);
+  str2dir(ImagePath);
+  str2dir(SamplePath);
+  Del_Sub_NothingPath(ImagePath);  //清掉案件目錄是空的
+
+
+  LogFile1.LogFile:=LngPath+'IMGPSCheck.log';
+
+  ReduceLogFile;
+
+  LogFile1.LogToFile(logTimeString+'OCX取表data結束');
+
+  ShowText := _Msg('資料載入中,請稍候');
+  DataLoading(True,True);
+
+//  if not CheckAvailable Then   //檢查授權  20170218 說不用了
+//  begin
+//    DataLoading(False,False);
+//    Panel1.Enabled := False;
+//    Panel2.Enabled := False;
+//    Exit;
+//  end;
+
+//Button3Click(Self);
+//ShowMessage('CheckAvailable');
+  ShowText := _Msg('資料載入中,請稍候');
+  DataLoading(True,True);
+
+
+  StatusBar1.Panels[1].Text := _Msg('登入人員:')+FUserName;
+  //FCaseID:='20150302180133';//測試用
+  ////下載語言檔/////
+//ShowMessage('OOOO');
+
+  if (FMode = 'RSCAN')  or (FMode = 'DSCAN') or (FMode = 'ESCAN') or (FMode = 'FSCAN') then //重掃件及異動件要只能掃指定編號的件
+  begin
+    _Deltree(ImagePath);
+    str2dir(ImagePath);
+    ImageSavePath := ImagePath;
+    str2dir(ImageSavePath);
+    MkDir(ImageSavePath+FCaseID);
+    CreateEmptyCase(ImageSavePath,FCaseID);
+    MkDir(ImageSavePath+FCaseID+'\Download');
+    IF (FMode = 'ESCAN') or (FMode = 'DSCAN') then  //異動件先下載影像
+    begin
+      ShowText := _Msg('案件下載中,請稍候');
+      DataLoading(True,True);
+      If not DownLoadImage(ImageSavePath+FCaseID+'\Download\',FCaseID) Then
+      begin
+        Showmessage(FCaseID+_msg('載入異動影像時,網路發生錯誤')+DownFileErrStr);
+        DataLoading(False,False);
+        Exit;
+      end;
+
+      {If not Down_Img(ImageSavePath+FCaseID+'\Download\',FCaseID) then
+      begin
+        Showmessage(FCaseID+_msg('載入異動影像時,網路發生錯誤')+HttpErrStr);
+        DataLoading(False,False);
+        Exit;
+      end;}
+//Showmessage(ImageSavePath+FCaseID+'\Download\'+#10#13+ImageSavePath+FCaseID+'\');
+      Download2Case(ImageSavePath+FCaseID+'\Download\',ImageSavePath+FCaseID+'\');
+//Showmessage('aaa');
+      //Download2Case('C:\Users\Hong\Downloads\沒有括號\',ImageSavePath+FCaseID+'\');
+      if (FIs_OldCase = 'Y') then
+      begin
+        if (FWork_no='HLN') then
+          ErrFormtoCurrentForm(FCaseID,'10000001011112A','11000001011112A');  //換掉錯的FormID
+        //if not FileExists(ImageSavePath+FCaseID+'\CaseDocNo_Copies.dat') then   //這個會在Download2Case時一律產生所以不能有這行 20141013
+        OldCasetoNewCase(FCaseID);
+        //ErrFormtoCurrentForm(FCaseID,'11B00005011312A','11000001011112A');  //換掉錯的FormID
+        //LoadImgFile;
+      end;
+//      if (FIs_OldCase = 'Y') and (FWork_no='HLN') then   //77版的
+//      begin
+//        ErrFormtoCurrentForm(FCaseID,'10000001011112A','11000001011112A');  //換掉錯的FormID
+//        if not FileExists(ImageSavePath+FCaseID+'\CaseDocNo_Copies.dat') then
+//          OldCasetoNewCase(FCaseID);
+//        //ErrFormtoCurrentForm(FCaseID,'11B00005011312A','11000001011112A');  //換掉錯的FormID
+//        //LoadImgFile;
+//      end;
+      Create_Cust_DocDir(FCaseID); //產生外面傳入的文件
+      if FMode='ESCAN' then
+        LastInitFormidListCreate(ImageSavePath+FCaseID+'\Download\');
+    end;
+  end;
+
+//ShowMessage('GetOMRCheckSet前');
+  ////下載檢核XML//////
+  IF not GetOMRCheckSet Then
+  begin
+    Showmessage(_Msg('下載檢核定位檔案時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+  ////下載檢核XML/////
+//ShowMessage('GetOMRCheckSet後來');
+  ////下載登打設定/////
+  IF not GetKeyinSet Then
+  begin
+    Showmessage(_Msg('下載登打定位檔案時,網路發生錯誤!!')+HttpErrStr);
+    DataLoading(False,False);
+    Exit;
+  end;
+  ////下載登打設定/////
+//ShowMessage('GetKeyinSet');
+  if ScanDenialHint <> '' then   //有設定提示字串就秀在右上角
+  begin
+    DenialTimeLb.Visible := True;
+    DenialTimeLb.Caption := Format(ScanDenialHint,[ScanDenialTime]);
+  end;
+//ShowMessage(IntToStr(ScanDpi));
+  R_W_Scanini('R'); //掃瞄設定的ini
+//ShowMessage(IntToStr(ScanDpi));
+//ShowMessage('停掉DataLoading');
+//DataLoading(False,False);
+  ScanDuplexCB.Checked := ScanDuplex;
+  if FMode <> 'SAMPLESCAN' then
+    LoadImgFile;
+  if (FMode = 'RSCAN') or (FMode = 'ESCAN') or (FMode = 'FSCAN') then
+  begin
+    if TreeView1.Items.Count > 0 then
+    begin
+      TreeView1.Selected := NewTreeNode.Item[0];
+      TreeView1click(self);
+    end;
+  end;
+  InitialOk := True;
+
+  {AttFileGB.Visible := True; //附加電子檔窗  //20120207楊玉說不在這加電子檔先拿掉
+  Splitter2.Visible := True;
+  AttFileGB.Visible := False; //附加電子檔窗
+  Splitter2.Visible := False; }
+//ShowMessage('ImageSavePath='+ImageSavePath);
+  DataLoading(False,False);
+
+  LogFile1.LogToFile(logTimeString+'OCX初始化結束');
+  LogFile1.LogToFile(logTimeString+'FUrl='+FUrl+
+	',FCaseID='+FCaseID+
+	',FMode='+FMode+
+	',FModeName='+FModeName+
+	',FWork_no='+FWork_no+
+	',FUserID='+FUserID+
+	',FUserName='+FUserName+
+	',FUserUnit='+FUserUnit+
+	',FData='+FData+
+	',FVerify='+FVerify+
+	',FReWrite='+FReWrite+
+	',FLanguage='+FLanguage+
+	',FLoanDoc_Value='+FLoanDoc_Value+
+	',FLoanDoc_Enable='+FLoanDoc_Enable+
+	',FUseProxy='+FUseProxy+
+	',FC_DocNoList='+FC_DocNoList+
+	',FC_DocNameList='+FC_DocNameList+
+	',FFixFileList='+FFixFileList+
+	',FIs_In_Wh='+FIs_In_Wh+
+	',FOldCaseInfo='+FOldCaseInfo+
+	',FPrintyn='+FPrintyn+
+	',FIs_OldCase='+FIs_OldCase+
+	',FCustDocYN='+FCustDocYN);
+  LogFile1.LogToFile(logTimeString+'FImgDPI='+IntToStr(FImgDPI)+
+    ',FScanColor='+    IntToStr(FScanColor)+
+    ',FFileSizeLimit='+  IntToStr(FFileSizeLimit)+
+    ',FCaseNoLength='+ IntToStr(FCaseNoLength)+
+    ',FImgDelete='+FImgDelete+
+    ',FIsExternal='+FIsExternal+
+    ',FWH_category='+FWH_category+
+    ',FCheck_main_form='+FCheck_main_form+
+    ',FMaxUploadSize='+FMaxUploadSize);
+
+end;
+
+procedure TCB_IMGPSScanX.Timer2Timer(Sender: TObject);
+begin
+  IF Panel22.Caption = ShowText+'......' Then
+    Panel22.Caption := ShowText
+  Else
+    Panel22.Caption := Panel22.Caption + '.';
+  Application.ProcessMessages;
+end;
+
+procedure TCB_IMGPSScanX.Set_mode(const Value: WideString);
+begin
+  FMode := UpperCase(Value);
+end;
+
+procedure TCB_IMGPSScanX.Set_rewrite(const Value: WideString);
+begin
+  FReWrite := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_url(const Value: WideString);
+begin
+  FUrl := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_userid(const Value: WideString);
+begin
+  FUserID := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_username(const Value: WideString);
+begin
+  FUserName := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_verify(const Value: WideString);
+begin
+  FVerify := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_language(const Value: WideString);
+begin
+  FLanguage := lowercase(Value);
+  if FLanguage='zh-tw' then
+  begin
+    FLanguage:='zh_tw'
+  end;
+  if FileExists(LngPath+'Language.lng') then
+  begin
+    InitialLanguage(Self);  //載入多國語言
+  end;
+end;
+
+procedure TCB_IMGPSScanX.Set_modename(const Value: WideString);
+begin
+  FModeName := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_userunit(const Value: WideString);
+begin
+  FUserUnit := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_work_no(const Value: WideString);
+begin
+  FWork_no := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_loandoc_enable(const Value: WideString);
+begin
+  FLoanDoc_Enable := Value;
+  if FLoanDoc_Enable = 'Y' then
+    AddCredit1RG.Enabled := True;
+  if FLoanDoc_Enable = 'I' then
+  begin
+    AddCredit1RG.Visible := False;
+    Panel5.Visible := False;
+  end;
+end;
+
+procedure TCB_IMGPSScanX.Set_loandoc_value(const Value: WideString);
+begin
+  FLoanDoc_Value := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_useproxy(const Value: WideString);
+begin
+  FUseProxy := UpperCase(Value);
+  if FUseProxy = 'Y' then
+    UseProxy := True;  //要不要用Proxy
+
+end;
+
+procedure TCB_IMGPSScanX.Set_c_docnamelist(const Value: WideString);
+begin
+  FC_DocNameList := Value;
+end;
+
+procedure TCB_IMGPSScanX.Set_is_in_wh(const Value: WideString);
+begin
+  FIs_In_Wh := UpperCase(Value);
+end;
+
+function TCB_IMGPSScanX.Get_c_docnamelist: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_is_in_wh: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_language: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_loandoc_enable: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_loandoc_value: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_mode: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_modename: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_rewrite: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_url: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_useproxy: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_userid: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_username: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_userunit: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_verify: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_work_no: WideString;
+begin
+
+end;
+
+function TCB_IMGPSScanX.Get_printyn: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_printyn(const Value: WideString);
+begin
+  FPrintyn := UpperCase(Value);
+end;
+
+function TCB_IMGPSScanX.Get_custdocyn: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_custdocyn(const Value: WideString);
+begin
+  FCustDocYN := UpperCase(Value);
+end;
+
+function TCB_IMGPSScanX.Get_imgdelete: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_imgdelete(const Value: WideString);
+begin
+  FImgDelete:=Value;
+end;
+
+function TCB_IMGPSScanX.Get_isExternal: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_isExternal(const Value: WideString);
+begin
+  FIsExternal:=Value;
+end;
+
+function TCB_IMGPSScanX.Get_WH_CATEGORY: WideString;
+begin
+
+end;
+
+procedure TCB_IMGPSScanX.Set_WH_CATEGORY(const Value: WideString);
+begin
+  FWH_category:=Value;
+end;
+
diff --git a/separate/scanImp/CB_IMGPSScanImp_Utils.ts b/separate/scanImp/CB_IMGPSScanImp_Utils.ts
new file mode 100644
index 0000000..a1ccd6e
--- /dev/null
+++ b/separate/scanImp/CB_IMGPSScanImp_Utils.ts
@@ -0,0 +1,59 @@
+import * as fs from 'fs'; import * as path from 'path';
+export enum TTransMode{tsHttp,tsFtp,tsNone} export enum TFtpProtocol{fpftp,fpftps} export type TImageFormat='ifBlackWhite'|'ifGray256'|'ifTrueColor'|'ifColor256';
+export class TStringList {
+  Strings:string[]=[]; get Count(){return this.Strings.length;}
+  Add(s:string){this.Strings.push(s);} Clear(){this.Strings=[];}
+  LoadFromFile(fp:string){if(fs.existsSync(fp))this.Strings=fs.readFileSync(fp,'utf8').split(/\r?\n/).filter(Boolean);}
+  SaveToFile(fp:string){fs.writeFileSync(fp,this.Strings.join('\n'),'utf8');}
+  Delete(idx:number){this.Strings.splice(idx,1);} Insert(idx:number,s:string){this.Strings.splice(idx,0,s);}
+  IndexOf(s:string){return this.Strings.indexOf(s);} get Text(){return this.Strings.join('\n');}
+  set Text(v:string){this.Strings=v.split('\n');} get CommaText(){return this.Strings.join(',');}
+  set CommaText(v:string){this.Strings=v.split(',');} Free(){} Sort(){this.Strings.sort();} Assign(s:TStringList){this.Strings=[...s.Strings];}
+}
+export function applyUtilsMixins(cls:any){
+  cls.prototype.GetCurrentVersionNo=function(){return "1.0.0";};
+  cls.prototype.DefinePropertyPages=function(){};
+  cls.prototype.InitExistImgList=function(cp:string){
+    let ST1=new TStringList(); this.ExistImgList.Clear();
+    ST1.LoadFromFile(path.join(cp,'Download','Context.dat'));
+    for(let i=0;i<ST1.Count;i++){ let m=this.LoadFileGetMD5(path.join(cp,'Download',ST1.Strings[i])); this.LogFile1.LogToFile(this.logTimeString()+path.join(cp,'Download',ST1.Strings[i])+',MD5='+m); this.ExistImgList.Add(m); }
+    this.LogFile1.LogToFile(this.logTimeString()+'ExistImgList.text'+this.ExistImgList.CommaText); ST1.Free();
+  };
+  cls.prototype.Initialize=function(){
+    ['Activate','Click','Create','DblClick','Deactivate','Destroy','KeyPress','MouseEnter','MouseLeave','Paint'].forEach(e=>this['On'+e]=this[e+'Event']?this[e+'Event'].bind(this):null);
+    this.MpsKey='fbim';this.Seg=3;this.Ext='.tif';this.SafePixel=20;this.CaseIDLength=16;this.FormIDLength=15;this.Bt=4;this.CropBarcode='CC';
+  };
+  cls.prototype.ISB1Enter=function(){this.ISB1.SetFocus();};
+  cls.prototype._Set_Font=function(v:any){this.Font=v;};
+  ['Active','AlignDisabled','AlignWithMargins','AutoScroll','AutoSize','AxBorderStyle','Caption','Color','DockSite','DoubleBuffered','DropTarget','Enabled','ExplicitHeight','ExplicitLeft','ExplicitTop','ExplicitWidth','Font','HelpFile','KeyPreview','MouseInClient','ParentCustomHint','ParentDoubleBuffered','PixelsPerInch','PopupMode','PrintScale','Scaled','ScreenSnap','SnapBuffer','UseDockManager','Visible','VisibleDockClientCount'].forEach(p=>{
+    cls.prototype['Get_'+p]=function(){return this[p];}; cls.prototype['Set_'+p]=function(v:any){this[p]=v;};
+  });
+  cls.prototype.LoadFileGetMD5=function(f:string){return "md5stub";};
+  cls.prototype.ISExistImg=function(f:string){return this.ExistImgList.IndexOf(this.LoadFileGetMD5(f))!==-1;};
+  cls.prototype.MemoInfoTransfer=function(m:string,s:string,id:TStringList,n:TStringList){
+    if(m==='ID'){for(let i=0;i<id.Count;i++)if(s===id.Strings[i])return n.Strings[i]; return '自行輸入';}
+    if(m==='NAME'){for(let i=0;i<n.Count;i++)if(s===n.Strings[i])return id.Strings[i]; return '00';} return '';
+  };
+  cls.prototype.SetSQLData=function(c:string,f:TStringList,t:TStringList){t.Clear();t.Add(c);for(let i=1;i<f.Count;i++)t.Add(f.Strings[i]);};
+  cls.prototype.GetSQLData=function(t:TStringList,c:string,no:number){
+    if(t.Count===0||no>=t.Count)return''; let cs=t.Strings[0].split(','),ts=t.Strings[no],ds=ts.split('!@!');
+    let idx=cs.indexOf(c); return(idx!==-1&&idx<ds.length)?ds[idx]:'';
+  };
+  cls.prototype.FindSQLData=function(t:TStringList,c:string,kc:string,ks:string,no:number,res:TStringList){
+    res.Clear(); if(!ks||t.Count<=1)return false;
+    let cl=c.split(','),kcl=kc.split(','),kl=ks.split(','),fidx=-1,found=false;
+    if(no===0){for(let i=1;i<t.Count;i++){let m=true;for(let n=0;n<kcl.length;n++)if(this.GetSQLData(t,kcl[n],i)!==kl[n]){m=false;break;}if(m){found=true;fidx=i;break;}}}
+    else{let m=true;for(let n=0;n<kcl.length;n++)if(t.Strings[no].indexOf('!@!'+kl[n]+'!@!')===-1){m=false;break;}if(m){found=true;fidx=no;}}
+    if(found)cl.forEach(co=>res.Add(co+','+this.GetSQLData(t,co,fidx))); return found;
+  };
+  cls.prototype.GetFindResult=function(c:string){for(let i=0;i<this.FindResult.Count;i++){let s=this.FindResult.Strings[i],idx=s.indexOf(',');if(idx>-1&&c===s.substring(0,idx))return s.substring(idx+1);}return'';};
+  cls.prototype.FileName2FormCode=function(f:string){let b=path.basename(f),v=b.indexOf('_'),v1=b.lastIndexOf('.');return(v>-1&&v1>v)?b.substring(v+1,v1):'';};
+  cls.prototype.FormCode2DocNo=function(fc:string){for(let i=0;i<this.FormID_List.Count;i++)if(this.FormID_List.Strings[i]===fc)return this.DocNo_List.Strings[i];return fc?fc.substring(0,8):'';};
+  cls.prototype.FormCode2Version=function(fc:string){return fc.substring(10,15);};
+  cls.prototype.FormCode2Page=function(fc:string){return fc.substring(8,10);};
+  cls.prototype.DocNoDir2DocNo=function(d:string){if(d!=='Attach'&&d!=='S_Attach'){let v=d.indexOf('(');if(v>0)return d.substring(0,v);}return d;};
+  cls.prototype.DocNo2DocNoDir=function(p:string,d:string){if(!d)return this.AttName;let i=0,id='';do{i++;id=d+'('+i+')';}while(fs.existsSync(path.join(p,id)));return id;};
+  cls.prototype.Add_Zoo=function(n:number,l:number){return n.toString().padStart(l,'0');};
+  cls.prototype.Str2Dir=function(p:string){if(!fs.existsSync(p))fs.mkdirSync(p,{recursive:true});};
+  cls.prototype._DelTree=function(p:string){if(fs.existsSync(p))fs.rmSync(p,{recursive:true,force:true});};
+}
diff --git a/split_pascal.js b/split_pascal.js
new file mode 100644
index 0000000..5db7fb6
--- /dev/null
+++ b/split_pascal.js
@@ -0,0 +1,98 @@
+const fs = require('fs');
+const path = require('path');
+
+// 檔案路徑設定
+const sourceFile = path.resolve(__dirname, 'CB_IMGPSScanImp.pas');
+const outDir = path.resolve(__dirname, 'separate', 'scanImp');
+
+if (!fs.existsSync(sourceFile)) {
+    console.error("找不到原始檔案:", sourceFile);
+    process.exit(1);
+}
+
+if (!fs.existsSync(outDir)) {
+    fs.mkdirSync(outDir, { recursive: true });
+}
+
+const content = fs.readFileSync(sourceFile, 'utf8');
+
+const implMatch = content.match(/\bimplementation\b/i);
+const initMatch = content.match(/\binitialization\b/i);
+
+if (!implMatch || !initMatch) {
+    console.error("無法在檔案中找到 implementation 或 initialization 區段。");
+    process.exit(1);
+}
+
+const headerPart = content.substring(0, implMatch.index + implMatch[0].length);
+let implPart = content.substring(implMatch.index + implMatch[0].length, initMatch.index);
+const footerPart = content.substring(initMatch.index);
+
+const usesMatch = implPart.match(/^\s*uses[\s\S]*?;/im);
+let usesClause = "";
+if (usesMatch) {
+    usesClause = usesMatch[0];
+    implPart = implPart.substring(usesMatch.index + usesMatch[0].length);
+}
+
+// 提取並保留不在方法內的實作開頭,例如 {$R *.DFM} 或是 { TCB_IMGPSScanX }
+const methodRegex = /^(?:procedure|function)\s+TCB_IMGPSScanX\./im;
+let otherImpl = "";
+const firstMethodMatch = implPart.match(methodRegex);
+
+if (firstMethodMatch) {
+    otherImpl = implPart.substring(0, firstMethodMatch.index);
+    implPart = implPart.substring(firstMethodMatch.index);
+}
+
+// 切割所有方法
+const methodSplitRegex = /(?=^(?:procedure|function)\s+TCB_IMGPSScanX\.)/im;
+const methods = implPart.split(methodSplitRegex).filter(m => m.trim().length > 0);
+
+const uiMethods = [];
+const scanMethods = [];
+const dataMethods = [];
+const utilMethods = [];
+
+methods.forEach(m => {
+    const nameMatch = m.match(/^(?:procedure|function)\s+TCB_IMGPSScanX\.([A-Za-z0-9_]+)/i);
+    if (nameMatch) {
+        const name = nameMatch[1].toLowerCase();
+        if (/(click|mouse|key|drag|scroll|event|menu|btn|form|node|tree|view|activate|paint|resize)/.test(name)) {
+            uiMethods.push(m);
+        } else if (/(scan|acquire|image|graphic|twain|dpi|color|deskew|rotate|crop|smooth|point)/.test(name)) {
+            scanMethods.push(m);
+        } else if (/(ftp|http|trans|load|sql|server|setinf|data|ask|log|file|path|zip|dir|docno|formid|case)/.test(name)) {
+            dataMethods.push(m);
+        } else {
+            utilMethods.push(m);
+        }
+    } else {
+        utilMethods.push(m);
+    }
+});
+
+fs.writeFileSync(path.join(outDir, 'CB_IMGPSScanImp_UI.pas'), uiMethods.join(''), 'utf8');
+fs.writeFileSync(path.join(outDir, 'CB_IMGPSScanImp_Scan.pas'), scanMethods.join(''), 'utf8');
+fs.writeFileSync(path.join(outDir, 'CB_IMGPSScanImp_Data.pas'), dataMethods.join(''), 'utf8');
+fs.writeFileSync(path.join(outDir, 'CB_IMGPSScanImp_Utils.pas'), utilMethods.join(''), 'utf8');
+
+const mainFile = [
+    headerPart,
+    usesClause,
+    otherImpl,
+    "{$I CB_IMGPSScanImp_UI.pas}",
+    "{$I CB_IMGPSScanImp_Scan.pas}",
+    "{$I CB_IMGPSScanImp_Data.pas}",
+    "{$I CB_IMGPSScanImp_Utils.pas}",
+    footerPart
+].join('');
+
+fs.writeFileSync(path.join(outDir, 'CB_IMGPSScanImp_Main.pas'), mainFile, 'utf8');
+
+console.log("拆分完成!產生的五個檔案如下:");
+console.log("1. CB_IMGPSScanImp_Main.pas (主結構與引用)");
+console.log("2. CB_IMGPSScanImp_UI.pas (UI事件相關:", uiMethods.length, "個方法)");
+console.log("3. CB_IMGPSScanImp_Scan.pas (掃描影像相關:", scanMethods.length, "個方法)");
+console.log("4. CB_IMGPSScanImp_Data.pas (資料存取與網路傳輸:", dataMethods.length, "個方法)");
+console.log("5. CB_IMGPSScanImp_Utils.pas (工具與其他邏輯:", utilMethods.length, "個方法)");

--
Gitblit v1.8.0