UNPKG

ndlkotenocr-lite-worker

Version:
1,012 lines (1,011 loc) 39.8 kB
import { c as Z, g as f, d as R, b as W, a as k, l as G, p as v } from "./chunks/model-loader-ByxdVp3K.js"; class h { constructor() { this.worker = null, this.taskQueue = /* @__PURE__ */ new Map(), this.currentTaskId = null, this.isWorkerBusy = !1, this.eventListeners = /* @__PURE__ */ new Map(); } /** * Workerの初期化 */ async initializeWorker() { this.worker && this.terminateWorker(); try { return this.worker = new Worker( new URL( /* @vite-ignore */ "/assets/ocr-worker-CWCweuCe.js", import.meta.url ), { type: "module" } ), this.setupWorkerEventHandlers(), await this.sendMessage({ type: "INITIALIZE" }), console.log("Worker initialized successfully"), !0; } catch (e) { throw console.error("Failed to initialize worker:", e), e; } } /** * Workerイベントハンドラーの設定 */ setupWorkerEventHandlers() { this.worker.onmessage = (e) => { this.handleWorkerMessage(e.data); }, this.worker.onerror = (e) => { console.error("Worker error:", e), this.emit("error", { type: "worker_error", error: e.message, filename: e.filename, lineno: e.lineno }); }, this.worker.onmessageerror = (e) => { console.error("Worker message error:", e), this.emit("error", { type: "worker_message_error", error: e.message }); }; } /** * Workerからのメッセージ処理 */ handleWorkerMessage(e) { const { type: t, id: s, ...i } = e; switch (t) { case "OCR_PROGRESS": this.emit("progress", { id: s, ...i }); break; case "OCR_COMPLETE": this.handleTaskComplete(s, i); break; case "OCR_ERROR": this.handleTaskError(s, i); break; default: console.warn("Unknown worker message type:", t); } } /** * タスク完了の処理 */ handleTaskComplete(e, t) { const s = this.taskQueue.get(e); s && (s.resolve(t), this.taskQueue.delete(e)), this.isWorkerBusy = !1, this.currentTaskId = null, this.emit("complete", { id: e, result: t }), this.processNextTask(); } /** * タスクエラーの処理 */ handleTaskError(e, t) { const s = this.taskQueue.get(e); s && (s.reject(new Error(t.error || "OCR processing failed")), this.taskQueue.delete(e)), this.isWorkerBusy = !1, this.currentTaskId = null, this.emit("error", { id: e, ...t }), this.processNextTask(); } /** * OCR処理タスクの追加 */ async processOCR(e, t = {}) { return new Promise((s, i) => { const g = this.generateTaskId(), n = { id: g, type: "OCR_PROCESS", imageData: e, config: t, resolve: s, reject: i, timestamp: Date.now() }; this.taskQueue.set(g, n), this.isWorkerBusy || this.processNextTask(); }); } /** * 次のタスクを処理 */ processNextTask() { if (this.isWorkerBusy || this.taskQueue.size === 0) return; const e = Array.from(this.taskQueue.values()).sort( (t, s) => t.timestamp - s.timestamp )[0]; e && (this.isWorkerBusy = !0, this.currentTaskId = e.id, this.sendMessage({ type: e.type, id: e.id, imageData: e.imageData, config: e.config })); } /** * Workerにメッセージを送信 */ sendMessage(e) { if (!this.worker) throw new Error("Worker not initialized"); return new Promise((t, s) => { try { this.worker.postMessage(e), t(); } catch (i) { s(i); } }); } /** * タスクIDの生成 */ generateTaskId() { return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * 現在のタスクをキャンセル */ cancelCurrentTask() { if (this.currentTaskId) { const e = this.taskQueue.get(this.currentTaskId); e && (e.reject(new Error("Task cancelled")), this.taskQueue.delete(this.currentTaskId)), this.isWorkerBusy = !1, this.currentTaskId = null, this.terminateWorker(), this.initializeWorker(); } } /** * 全タスクをキャンセル */ cancelAllTasks() { for (const e of this.taskQueue.values()) e.reject(new Error("All tasks cancelled")); this.taskQueue.clear(), this.isWorkerBusy = !1, this.currentTaskId = null, this.terminateWorker(), this.initializeWorker(); } /** * キューの状態を取得 */ getQueueStatus() { return { queueSize: this.taskQueue.size, isWorkerBusy: this.isWorkerBusy, currentTaskId: this.currentTaskId, totalTasks: this.taskQueue.size + (this.isWorkerBusy ? 1 : 0) }; } /** * イベントリスナーの追加 */ on(e, t) { this.eventListeners.has(e) || this.eventListeners.set(e, []), this.eventListeners.get(e).push(t); } /** * イベントリスナーの削除 */ off(e, t) { const s = this.eventListeners.get(e); if (s) { const i = s.indexOf(t); i > -1 && s.splice(i, 1); } } /** * イベントの発火 */ emit(e, t) { const s = this.eventListeners.get(e); s && s.forEach((i) => { try { i(t); } catch (g) { console.error("Error in event listener:", g); } }); } /** * Workerの終了 */ terminateWorker() { this.worker && (this.worker.terminate(), this.worker = null); for (const e of this.taskQueue.values()) e.reject(new Error("Worker terminated")); this.taskQueue.clear(), this.isWorkerBusy = !1, this.currentTaskId = null; } /** * リソースのクリーンアップ */ dispose() { this.terminateWorker(), this.eventListeners.clear(); } } const m = new h(); class p { constructor() { this.eventListeners = /* @__PURE__ */ new Map(), this.acceptedTypes = [ "image/jpeg", "image/jpg", "image/png", "image/gif", "image/bmp" ], this.maxFileSize = 50 * 1024 * 1024, this.setupElements(); } /** * DOM要素の設定 */ setupElements() { this.fileInput = document.getElementById("file-input"), this.dropZone = document.getElementById("drop-zone"), this.fileInfo = document.getElementById("file-info"), this.fileInput && this.setupFileInput(), this.dropZone && this.setupDropZone(); } /** * ファイル入力の設定 */ setupFileInput() { this.fileInput.addEventListener("change", (e) => { const t = e.target.files[0]; t && this.handleFile(t); }), this.fileInput.accept = this.acceptedTypes.join(","); } /** * ドロップゾーンの設定 */ setupDropZone() { ["dragenter", "dragover", "dragleave", "drop"].forEach( (e) => { this.dropZone.addEventListener( e, this.preventDefaults, !1 ), document.body.addEventListener( e, this.preventDefaults, !1 ); } ), ["dragenter", "dragover"].forEach((e) => { this.dropZone.addEventListener(e, () => { this.dropZone.classList.add("drag-over"); }); }), ["dragleave", "drop"].forEach((e) => { this.dropZone.addEventListener(e, () => { this.dropZone.classList.remove("drag-over"); }); }), this.dropZone.addEventListener("drop", (e) => { const t = e.dataTransfer.files; t.length > 0 && this.handleFile(t[0]); }), this.dropZone.addEventListener("click", () => { this.fileInput && !this.fileInput.disabled && this.fileInput.click(); }); } /** * デフォルト動作の防止 */ preventDefaults(e) { e.preventDefault(), e.stopPropagation(); } /** * ファイル処理 */ handleFile(e) { console.log( "File selected:", e.name, e.type, e.size ); const t = this.validateFile(e); if (!t.isValid) { this.showError(t.error); return; } this.displayFileInfo(e), this.showImagePreview(e), this.emit("fileSelected", e); } /** * ファイル検証 */ validateFile(e) { return this.acceptedTypes.includes(e.type) ? e.size > this.maxFileSize ? { isValid: !1, error: `ファイルサイズが大きすぎます。最大サイズ: ${Math.round( this.maxFileSize / 1048576 )}MB` } : { isValid: !0 } : { isValid: !1, error: `サポートされていないファイル形式です。対応形式: ${this.acceptedTypes.join( ", " )}` }; } /** * ファイル情報の表示 */ displayFileInfo(e) { if (!this.fileInfo) return; const t = Math.round(e.size / 1024), s = t > 1024 ? `${Math.round(t / 1024 * 10) / 10}MB` : `${t}KB`; this.fileInfo.innerHTML = ` <div class="file-info-item"> <strong>ファイル名:</strong> ${this.escapeHtml( e.name )} </div> <div class="file-info-item"> <strong>ファイルサイズ:</strong> ${s} </div> <div class="file-info-item"> <strong>ファイルタイプ:</strong> ${e.type} </div> <div class="file-info-item"> <strong>最終更新:</strong> ${new Date( e.lastModified ).toLocaleString()} </div> `, this.fileInfo.classList.remove("hidden"); } /** * HTMLエスケープ */ escapeHtml(e) { const t = document.createElement("div"); return t.textContent = e, t.innerHTML; } /** * エラー表示 */ showError(e) { console.error("File handler error:", e), this.emit("error", { message: e }); const t = document.getElementById( "message-display" ); t && (t.textContent = e, t.className = "message message-error", t.classList.remove("hidden"), setTimeout(() => { t.classList.add("hidden"); }, 5e3)); } /** * ファイル情報をクリア */ clearFileInfo() { this.fileInfo && (this.fileInfo.classList.add("hidden"), this.fileInfo.innerHTML = ""), this.fileInput && (this.fileInput.value = ""), this.clearPreview(); } /** * ドロップゾーンの状態設定 */ setEnabled(e) { this.dropZone && (e ? this.dropZone.classList.remove("disabled") : this.dropZone.classList.add("disabled")), this.fileInput && (this.fileInput.disabled = !e); } /** * 画像プレビューの表示 */ showImagePreview(e) { const t = document.getElementById("image-preview"); if (!t) return; const s = new FileReader(); s.onload = (i) => { t.innerHTML = ` <img src="${i.target.result}" alt="プレビュー" style="max-width: 100%; max-height: 250px; object-fit: contain;"> `, t.classList.remove("hidden"); }, s.readAsDataURL(e); } /** * プレビューをクリア */ clearPreview() { const e = document.getElementById("image-preview"); e && (e.innerHTML = "", e.classList.add("hidden")); } /** * 複数ファイルの処理(将来の拡張用) */ handleMultipleFiles(e) { const t = [], s = []; for (const i of e) { const g = this.validateFile(i); g.isValid ? t.push(i) : s.push({ file: i.name, error: g.error }); } s.length > 0 && console.warn("Some files were rejected:", s), t.length > 0 && this.emit("filesSelected", t); } /** * イベントリスナーの追加 */ on(e, t) { this.eventListeners.has(e) || this.eventListeners.set(e, []), this.eventListeners.get(e).push(t); } /** * イベントリスナーの削除 */ off(e, t) { const s = this.eventListeners.get(e); if (s) { const i = s.indexOf(t); i > -1 && s.splice(i, 1); } } /** * イベントの発火 */ emit(e, t) { const s = this.eventListeners.get(e); s && s.forEach((i) => { try { i(t); } catch (g) { console.error( "Error in file handler event listener:", g ); } }); } /** * サンプル画像を読み込み */ async loadSampleImage() { try { const t = await fetch("./sample.png"); if (!t.ok) throw new Error("サンプル画像が見つかりません"); const s = await t.blob(), i = new File([s], "sample.png", { type: "image/png", lastModified: Date.now() }); this.handleFile(i), console.log("Sample image loaded successfully"); } catch (e) { console.error("Failed to load sample image:", e), this.showError( "サンプル画像の読み込みに失敗しました: " + e.message ); } } /** * リソースのクリーンアップ */ dispose() { this.clearFileInfo(), this.clearPreview(), this.eventListeners.clear(); } } class b { constructor() { this.currentResults = null, this.originalImageData = null, this.setupElements(); } /** * DOM要素の設定 */ setupElements() { this.resultContainer = document.getElementById( "result-container" ), this.resultTabs = document.getElementById("result-tabs"), this.resultContent = document.getElementById( "result-content" ), this.downloadSection = document.getElementById( "download-section" ), this.setupTabHandlers(), this.setupDownloadHandlers(); } /** * タブハンドラーの設定 */ setupTabHandlers() { this.resultTabs && this.resultTabs.addEventListener("click", (e) => { if (e.target.classList.contains("tab-button")) { const t = e.target.dataset.tab; this.switchTab(t); } }); } /** * ダウンロードハンドラーの設定 */ setupDownloadHandlers() { document.querySelectorAll( "[data-download]" ).forEach((t) => { t.addEventListener("click", (s) => { const i = s.target.dataset.download; this.downloadResult(i); }); }); } /** * 結果の表示 */ displayResults(e) { if (console.log("Displaying OCR results:", e), console.log("Results.txt:", e.txt), console.log("Results.textBlocks:", e.textBlocks), this.currentResults = e, !this.resultContainer) { console.error("Result container not found"); return; } this.resultContainer.classList.remove("hidden"), this.displayStatistics(e), this.displayTextBlocks(e.textBlocks || []), this.displayImageWithBboxes(e.textBlocks || []), this.displayFormattedResults(e), this.enableDownloadButtons(), this.switchTab("text"); } /** * 統計情報の表示 */ displayStatistics(e) { const t = document.getElementById( "result-statistics" ); if (!t) return; const { totalRegions: s = 0, successfulRecognitions: i = 0, processingTime: g = 0 } = e; t.innerHTML = ` <div class="stat-item"> <span class="stat-label">検出された領域数:</span> <span class="stat-value">${s}</span> </div> <div class="stat-item"> <span class="stat-label">認識成功数:</span> <span class="stat-value">${i}</span> </div> <div class="stat-item"> <span class="stat-label">処理時間:</span> <span class="stat-value">${(g / 1e3).toFixed(2)}秒</span> </div> `; } /** * テキストブロックの表示 */ displayTextBlocks(e) { const t = document.getElementById("text-blocks"); if (!t) return; if (e.length === 0) { t.innerHTML = '<p class="no-results">テキストが認識されませんでした。</p>'; return; } const s = e.map((i, g) => { const n = i.text?.text || "", r = Math.round( (i.confidence || 0) * 100 ); return ` <div class="text-block" data-block="${g}"> <div class="block-header"> <span class="block-number">#${i.readingOrder || g + 1}</span> <span class="block-position">位置: (${i.x}, ${i.y})</span> <span class="block-size">サイズ: ${i.width}×${i.height}</span> <span class="block-confidence">信頼度: ${r}%</span> </div> <div class="block-text">${this.escapeHtml( n )}</div> </div> `; }).join(""); t.innerHTML = s; } /** * フォーマット済み結果の表示 */ displayFormattedResults(e) { this.displayTextResult(e), e.json && this.displayJSONResult(e.json), e.xml && this.displayXMLResult(e.xml); } /** * テキスト形式の表示 */ displayTextResult(e) { const t = document.getElementById("result-text"); if (!t) return; let s = ""; e.txt ? s = e.txt : e.textBlocks && (s = e.textBlocks.filter((i) => i.text?.text).map((i) => i.text.text).join(` `)), t.innerHTML = ` <pre class="result-content-text">${this.escapeHtml( s )}</pre> `; } /** * JSON形式の表示 */ displayJSONResult(e) { const t = document.getElementById("result-json"); if (!t) return; const s = JSON.stringify(e, null, 2); t.innerHTML = ` <pre class="result-content-json"><code>${this.escapeHtml( s )}</code></pre> `; } /** * XML形式の表示 */ displayXMLResult(e) { const t = document.getElementById("result-xml"); if (!t) return; const s = this.formatXML(e); t.innerHTML = ` <pre class="result-content-xml"><code>${this.escapeHtml( s )}</code></pre> `; } /** * XMLの整形 */ formatXML(e) { try { const s = new DOMParser().parseFromString( e, "application/xml" ); let g = new XMLSerializer().serializeToString(s); return g = g.replace(/></g, `> <`), g; } catch (t) { return console.warn("XML formatting failed:", t), e; } } /** * タブの切り替え */ switchTab(e) { if (!this.resultTabs || !this.resultContent) return; this.resultTabs.querySelectorAll(".tab-button").forEach((i) => { i.dataset.tab === e ? i.classList.add("active") : i.classList.remove("active"); }), this.resultContent.querySelectorAll(".tab-content").forEach((i) => { i.id === `result-${e}` ? i.classList.remove("hidden") : i.classList.add("hidden"); }); } /** * 結果のダウンロード */ downloadResult(e) { if (!this.currentResults) { console.warn("No results to download"); return; } let t = "", s = "", i = ""; switch (e) { case "txt": t = this.generateTextContent(), s = "ocr_result.txt", i = "text/plain"; break; case "json": t = JSON.stringify( this.currentResults.json || this.currentResults, null, 2 ), s = "ocr_result.json", i = "application/json"; break; case "xml": t = this.currentResults.xml || this.generateXMLContent(), s = "ocr_result.xml", i = "application/xml"; break; default: console.warn("Unknown download format:", e); return; } this.downloadFile(t, s, i); } /** * テキストコンテンツの生成 */ generateTextContent() { return this.currentResults.txt ? this.currentResults.txt : this.currentResults.textBlocks ? this.currentResults.textBlocks.filter((e) => e.text?.text).map((e) => e.text.text).join(` `) : ""; } /** * XMLコンテンツの生成(フォールバック) */ generateXMLContent() { if (!this.currentResults.textBlocks) return ""; let e = `<?xml version="1.0" encoding="UTF-8"?> <document> `; return this.currentResults.textBlocks.forEach( (t, s) => { e += ` <textblock id="${s}" x="${t.x}" y="${t.y}" width="${t.width}" height="${t.height}" confidence="${t.confidence}"> `, e += ` <text>${this.escapeXML( t.text?.text || "" )}</text> `, e += ` </textblock> `; } ), e += "</document>", e; } /** * ファイルのダウンロード */ downloadFile(e, t, s) { try { const i = new Blob([e], { type: s }), g = URL.createObjectURL(i), n = document.createElement("a"); n.href = g, n.download = t, document.body.appendChild(n), n.click(), document.body.removeChild(n), URL.revokeObjectURL(g), console.log(`Downloaded: ${t}`); } catch (i) { console.error("Download failed:", i); } } /** * ダウンロードボタンの有効化 */ enableDownloadButtons() { document.querySelectorAll( "[data-download]" ).forEach((t) => { const s = t.dataset.download; let i = !1; switch (s) { case "txt": i = !0; break; case "json": i = !!(this.currentResults?.json || this.currentResults?.textBlocks); break; case "xml": i = !!(this.currentResults?.xml || this.currentResults?.textBlocks); break; } t.disabled = !i; }); } /** * HTMLエスケープ */ escapeHtml(e) { if (typeof e != "string") return ""; const t = document.createElement("div"); return t.textContent = e, t.innerHTML; } /** * XMLエスケープ */ escapeXML(e) { return typeof e != "string" ? "" : e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;"); } /** * 結果のクリア */ clear() { this.currentResults = null, this.originalImageData = null, this.resultContainer && this.resultContainer.classList.add("hidden"), [ "result-statistics", "text-blocks", "result-text", "result-json", "result-xml", "bbox-image-container" ].forEach((s) => { const i = document.getElementById(s); i && (i.innerHTML = ""); }), document.querySelectorAll( "[data-download]" ).forEach((s) => { s.disabled = !0; }); } /** * 結果のエクスポート(他の形式への変換) */ exportResults(e) { if (!this.currentResults) return null; switch (e) { case "csv": return this.generateCSV(); case "tsv": return this.generateTSV(); default: return null; } } /** * CSV形式の生成 */ generateCSV() { if (!this.currentResults?.textBlocks) return ""; const t = [[ "読み順", "X座標", "Y座標", "幅", "高さ", "信頼度", "テキスト" ].join(",")]; return this.currentResults.textBlocks.forEach((s) => { const i = [ s.readingOrder || "", s.x || "", s.y || "", s.width || "", s.height || "", s.confidence || "", `"${(s.text?.text || "").replace(/"/g, '""')}"` ]; t.push(i.join(",")); }), t.join(` `); } /** * TSV形式の生成 */ generateTSV() { if (!this.currentResults?.textBlocks) return ""; const t = [[ "読み順", "X座標", "Y座標", "幅", "高さ", "信頼度", "テキスト" ].join(" ")]; return this.currentResults.textBlocks.forEach((s) => { const i = [ s.readingOrder || "", s.x || "", s.y || "", s.width || "", s.height || "", s.confidence || "", (s.text?.text || "").replace(/\t/g, " ") ]; t.push(i.join(" ")); }), t.join(` `); } /** * 元画像データの設定 */ setOriginalImageData(e) { this.originalImageData = e; } /** * bbox描画画像の表示 */ displayImageWithBboxes(e) { if (console.log("displayImageWithBboxes called with:", { hasOriginalImageData: !!this.originalImageData, textBlocksLength: e.length, textBlocks: e }), !this.originalImageData) { const t = document.getElementById( "bbox-image-container" ); t && (t.innerHTML = "<p>bbox描画画像を生成できませんでした(元画像データがありません)</p>"), console.warn("Original image data is missing"); return; } if (e.length === 0) { const t = document.getElementById( "bbox-image-container" ); t && (t.innerHTML = "<p>bbox描画画像を生成できませんでした(テキストブロックが見つかりませんでした)</p>"), console.warn("No text blocks found for bbox drawing"); return; } try { const s = this.drawBoundingBoxes( this.originalImageData, e ).toDataURL(), i = document.getElementById( "bbox-image-container" ); i && (i.innerHTML = ` <img src="${s}" alt="bbox描画結果" /> `); } catch (t) { console.error("Error drawing bounding boxes:", t); const s = document.getElementById( "bbox-image-container" ); s && (s.innerHTML = "<p>bbox描画中にエラーが発生しました</p>"); } } /** * Canvas上にbboxを描画 */ drawBoundingBoxes(e, t) { const s = document.createElement("canvas"), i = s.getContext("2d"); return s.width = e.width, s.height = e.height, i.putImageData(e, 0, 0), i.strokeStyle = "#FF0000", i.lineWidth = 2, i.font = "12px Arial", i.fillStyle = "#FF0000", i.textBaseline = "top", t.forEach((g, n) => { const { x: r, y: l, width: I, height: C } = g; i.strokeRect(r, l, I, C); const o = `${n + 1}`, c = r, d = Math.max(0, l - 15), A = i.measureText(o).width; i.fillStyle = "#FF0000", i.fillRect(c, d, A + 4, 14), i.fillStyle = "#FFFFFF", i.fillText(o, c + 2, d), i.fillStyle = "#FF0000"; }), s; } /** * リソースのクリーンアップ */ dispose() { this.clear(); } } function u() { return new URL("data:text/javascript;base64,LyoqCiAqIE5ETEtvdGVuT0NSIFdlYiBXb3JrZXIKICogT0NS5Yem55CG44KS44OQ44OD44Kv44Kw44Op44Km44Oz44OJ44Gn5a6f6KGMCiAqLwoKaW1wb3J0IHsgbG9hZE1vZGVsIH0gZnJvbSAnLi4vdXRpbHMvbW9kZWwtbG9hZGVyLmpzJzsKaW1wb3J0IHsgTGF5b3V0RGV0ZWN0b3IgfSBmcm9tICcuL2xheW91dC1kZXRlY3Rvci5qcyc7CmltcG9ydCB7IFRleHRSZWNvZ25pemVyIH0gZnJvbSAnLi90ZXh0LXJlY29nbml6ZXIuanMnOwppbXBvcnQgeyBSZWFkaW5nT3JkZXJQcm9jZXNzb3IgfSBmcm9tICcuL3JlYWRpbmctb3JkZXIuanMnOwppbXBvcnQgJy4vb25ueC1jb25maWcuanMnOyAvLyBPTk5YIFJ1bnRpbWUgV2ViIOOBruioreWumuOCkuiqreOBv+i+vOOBvwoKY2xhc3MgT0NSV29ya2VyIHsKICBjb25zdHJ1Y3RvcigpIHsKICAgIHRoaXMubGF5b3V0RGV0ZWN0b3IgPSBudWxsOwogICAgdGhpcy50ZXh0UmVjb2duaXplciA9IG51bGw7CiAgICB0aGlzLnJlYWRpbmdPcmRlclByb2Nlc3NvciA9CiAgICAgIG5ldyBSZWFkaW5nT3JkZXJQcm9jZXNzb3IoKTsKICAgIHRoaXMuaXNJbml0aWFsaXplZCA9IGZhbHNlOwogIH0KCiAgLyoqCiAgICog44Ov44O844Kr44O844Gu5Yid5pyf5YyWCiAgICovCiAgYXN5bmMgaW5pdGlhbGl6ZSgpIHsKICAgIGlmICh0aGlzLmlzSW5pdGlhbGl6ZWQpIHJldHVybjsKCiAgICB0cnkgewogICAgICB0aGlzLnBvc3RNZXNzYWdlKHsKICAgICAgICB0eXBlOiAnT0NSX1BST0dSRVNTJywKICAgICAgICBzdGFnZTogJ2luaXRpYWxpemluZycsCiAgICAgICAgcHJvZ3Jlc3M6IDAuMSwKICAgICAgICBtZXNzYWdlOiAnSW5pdGlhbGl6aW5nIE9DUiBXb3JrZXIuLi4nLAogICAgICB9KTsKCiAgICAgIC8vIOODouODh+ODq+OBruiqreOBv+i+vOOBvwogICAgICBjb25zdCBsYXlvdXRNb2RlbERhdGEgPSBhd2FpdCBsb2FkTW9kZWwoCiAgICAgICAgJ2xheW91dCcsCiAgICAgICAgKHByb2dyZXNzKSA9PiB7CiAgICAgICAgICB0aGlzLnBvc3RNZXNzYWdlKHsKICAgICAgICAgICAgdHlwZTogJ09DUl9QUk9HUkVTUycsCiAgICAgICAgICAgIHN0YWdlOiAnbG9hZGluZ19sYXlvdXRfbW9kZWwnLAogICAgICAgICAgICBwcm9ncmVzczogMC4xICsgcHJvZ3Jlc3MgKiAwLjQsCiAgICAgICAgICAgIG1lc3NhZ2U6IGBMb2FkaW5nIGxheW91dCBkZXRlY3Rpb24gbW9kZWwuLi4gJHtNYXRoLnJvdW5kKAogICAgICAgICAgICAgIHByb2dyZXNzICogMTAwCiAgICAgICAgICAgICl9JWAsCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICk7CgogICAgICBjb25zdCByZWNvZ25pdGlvbk1vZGVsRGF0YSA9IGF3YWl0IGxvYWRNb2RlbCgKICAgICAgICAncmVjb2duaXRpb24nLAogICAgICAgIChwcm9ncmVzcykgPT4gewogICAgICAgICAgdGhpcy5wb3N0TWVzc2FnZSh7CiAgICAgICAgICAgIHR5cGU6ICdPQ1JfUFJPR1JFU1MnLAogICAgICAgICAgICBzdGFnZTogJ2xvYWRpbmdfcmVjb2duaXRpb25fbW9kZWwnLAogICAgICAgICAgICBwcm9ncmVzczogMC41ICsgcHJvZ3Jlc3MgKiAwLjQsCiAgICAgICAgICAgIG1lc3NhZ2U6IGBMb2FkaW5nIHRleHQgcmVjb2duaXRpb24gbW9kZWwuLi4gJHtNYXRoLnJvdW5kKAogICAgICAgICAgICAgIHByb2dyZXNzICogMTAwCiAgICAgICAgICAgICl9JWAsCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICk7CgogICAgICAvLyDmpJzlh7rlmajjgajjg6rjgrPjgrDjg4rjgqTjgrbjg7zjga7liJ3mnJ/ljJYKICAgICAgdGhpcy5sYXlvdXREZXRlY3RvciA9IG5ldyBMYXlvdXREZXRlY3RvcigpOwogICAgICBhd2FpdCB0aGlzLmxheW91dERldGVjdG9yLmluaXRpYWxpemUobGF5b3V0TW9kZWxEYXRhKTsKCiAgICAgIHRoaXMudGV4dFJlY29nbml6ZXIgPSBuZXcgVGV4dFJlY29nbml6ZXIoKTsKICAgICAgYXdhaXQgdGhpcy50ZXh0UmVjb2duaXplci5pbml0aWFsaXplKAogICAgICAgIHJlY29nbml0aW9uTW9kZWxEYXRhCiAgICAgICk7CgogICAgICB0aGlzLmlzSW5pdGlhbGl6ZWQgPSB0cnVlOwoKICAgICAgdGhpcy5wb3N0TWVzc2FnZSh7CiAgICAgICAgdHlwZTogJ09DUl9QUk9HUkVTUycsCiAgICAgICAgc3RhZ2U6ICdpbml0aWFsaXplZCcsCiAgICAgICAgcHJvZ3Jlc3M6IDEuMCwKICAgICAgICBtZXNzYWdlOiAnT0NSIFdvcmtlciBpbml0aWFsaXplZCBzdWNjZXNzZnVsbHknLAogICAgICB9KTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgIHRoaXMucG9zdE1lc3NhZ2UoewogICAgICAgIHR5cGU6ICdPQ1JfRVJST1InLAogICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlLAogICAgICAgIHN0YWdlOiAnaW5pdGlhbGl6YXRpb24nLAogICAgICB9KTsKICAgIH0KICB9CgogIC8qKgogICAqIE9DUuWHpueQhuOBruWun+ihjAogICAqLwogIGFzeW5jIHByb2Nlc3NPQ1IoZGF0YSkgewogICAgY29uc3QgeyBpZCwgaW1hZ2VEYXRhLCBjb25maWcgPSB7fSB9ID0gZGF0YTsKCiAgICB0cnkgewogICAgICBpZiAoIXRoaXMuaXNJbml0aWFsaXplZCkgewogICAgICAgIGF3YWl0IHRoaXMuaW5pdGlhbGl6ZSgpOwogICAgICB9CgogICAgICAvLyBTdGFnZSAxOiDjg6zjgqTjgqLjgqbjg4jmpJzlh7oKICAgICAgdGhpcy5wb3N0TWVzc2FnZSh7CiAgICAgICAgdHlwZTogJ09DUl9QUk9HUkVTUycsCiAgICAgICAgaWQsCiAgICAgICAgc3RhZ2U6ICdsYXlvdXRfZGV0ZWN0aW9uJywKICAgICAgICBwcm9ncmVzczogMC4xLAogICAgICAgIG1lc3NhZ2U6ICdEZXRlY3RpbmcgdGV4dCByZWdpb25zLi4uJywKICAgICAgfSk7CgogICAgICBjb25zdCB0ZXh0UmVnaW9ucyA9IGF3YWl0IHRoaXMubGF5b3V0RGV0ZWN0b3IuZGV0ZWN0KAogICAgICAgIGltYWdlRGF0YSwKICAgICAgICAocHJvZ3Jlc3MpID0+IHsKICAgICAgICAgIHRoaXMucG9zdE1lc3NhZ2UoewogICAgICAgICAgICB0eXBlOiAnT0NSX1BST0dSRVNTJywKICAgICAgICAgICAgaWQsCiAgICAgICAgICAgIHN0YWdlOiAnbGF5b3V0X2RldGVjdGlvbicsCiAgICAgICAgICAgIHByb2dyZXNzOiAwLjEgKyBwcm9ncmVzcyAqIDAuMywKICAgICAgICAgICAgbWVzc2FnZTogYERldGVjdGluZyB0ZXh0IHJlZ2lvbnMuLi4gJHtNYXRoLnJvdW5kKAogICAgICAgICAgICAgIHByb2dyZXNzICogMTAwCiAgICAgICAgICAgICl9JWAsCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICk7CiAgICAgIGNvbnNvbGUubG9nKCfmpJzlh7rjgZXjgozjgZ/jg4bjgq3jgrnjg4jpoJjln586JywgdGV4dFJlZ2lvbnMpOwoKICAgICAgLy8gU3RhZ2UgMjog5paH5a2X6KqN6K2YCiAgICAgIHRoaXMucG9zdE1lc3NhZ2UoewogICAgICAgIHR5cGU6ICdPQ1JfUFJPR1JFU1MnLAogICAgICAgIGlkLAogICAgICAgIHN0YWdlOiAndGV4dF9yZWNvZ25pdGlvbicsCiAgICAgICAgcHJvZ3Jlc3M6IDAuNCwKICAgICAgICBtZXNzYWdlOiBgUmVjb2duaXppbmcgdGV4dCBpbiAke3RleHRSZWdpb25zLmxlbmd0aH0gcmVnaW9ucy4uLmAsCiAgICAgIH0pOwoKICAgICAgY29uc3QgcmVjb2duaXRpb25SZXN1bHRzID0gW107CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGV4dFJlZ2lvbnMubGVuZ3RoOyBpKyspIHsKICAgICAgICBjb25zdCByZWdpb24gPSB0ZXh0UmVnaW9uc1tpXTsKICAgICAgICBjb25zdCBjb25maWRlbmNlID0gcmVnaW9uLmNvbmZpZGVuY2UgfHwgMC4wOwogICAgICAgIGNvbnN0IHRleHQgPSBhd2FpdCB0aGlzLnRleHRSZWNvZ25pemVyLnJlY29nbml6ZSgKICAgICAgICAgIGltYWdlRGF0YSwKICAgICAgICAgIHJlZ2lvbgogICAgICAgICk7CgogICAgICAgIHJlY29nbml0aW9uUmVzdWx0cy5wdXNoKHsKICAgICAgICAgIC4uLnJlZ2lvbiwKICAgICAgICAgIHRleHQsCiAgICAgICAgICBjb25maWRlbmNlLAogICAgICAgIH0pOwoKICAgICAgICB0aGlzLnBvc3RNZXNzYWdlKHsKICAgICAgICAgIHR5cGU6ICdPQ1JfUFJPR1JFU1MnLAogICAgICAgICAgaWQsCiAgICAgICAgICBzdGFnZTogJ3RleHRfcmVjb2duaXRpb24nLAogICAgICAgICAgcHJvZ3Jlc3M6CiAgICAgICAgICAgIDAuNCArICgoaSArIDEpIC8gdGV4dFJlZ2lvbnMubGVuZ3RoKSAqIDAuNCwKICAgICAgICAgIG1lc3NhZ2U6IGBSZWNvZ25pemVkICR7aSArIDF9LyR7CiAgICAgICAgICAgIHRleHRSZWdpb25zLmxlbmd0aAogICAgICAgICAgfSByZWdpb25zYCwKICAgICAgICB9KTsKICAgICAgfQogICAgICBjb25zb2xlLmxvZygn6KqN6K2Y57WQ5p6c44GZ44G544GmOicsIHJlY29nbml0aW9uUmVzdWx0cyk7CgogICAgICAvLyBTdGFnZSAzOiDoqq3jgb/poIblh6bnkIYKICAgICAgdGhpcy5wb3N0TWVzc2FnZSh7CiAgICAgICAgdHlwZTogJ09DUl9QUk9HUkVTUycsCiAgICAgICAgaWQsCiAgICAgICAgc3RhZ2U6ICdyZWFkaW5nX29yZGVyJywKICAgICAgICBwcm9ncmVzczogMC44LAogICAgICAgIG1lc3NhZ2U6ICdQcm9jZXNzaW5nIHJlYWRpbmcgb3JkZXIuLi4nLAogICAgICB9KTsKCiAgICAgIGNvbnN0IG9yZGVyZWRSZXN1bHRzID0KICAgICAgICB0aGlzLnJlYWRpbmdPcmRlclByb2Nlc3Nvci5wcm9jZXNzKAogICAgICAgICAgcmVjb2duaXRpb25SZXN1bHRzCiAgICAgICAgKTsKICAgICAgY29uc29sZS5sb2coJ+iqreOBv+mghuWHpueQhuW+jOOBrue1kOaenDonLCBvcmRlcmVkUmVzdWx0cyk7CgogICAgICAvLyBTdGFnZSA0OiDntZDmnpzjga7nlJ/miJAKICAgICAgdGhpcy5wb3N0TWVzc2FnZSh7CiAgICAgICAgdHlwZTogJ09DUl9QUk9HUkVTUycsCiAgICAgICAgaWQsCiAgICAgICAgc3RhZ2U6ICdnZW5lcmF0aW5nX291dHB1dCcsCiAgICAgICAgcHJvZ3Jlc3M6IDAuOSwKICAgICAgICBtZXNzYWdlOiAnR2VuZXJhdGluZyBvdXRwdXQuLi4nLAogICAgICB9KTsKCiAgICAgIGNvbnN0IHJlc3VsdCA9IHsKICAgICAgICB0ZXh0QmxvY2tzOiBvcmRlcmVkUmVzdWx0cywKICAgICAgICB0b3RhbFJlZ2lvbnM6IHRleHRSZWdpb25zLmxlbmd0aCwKICAgICAgICBzdWNjZXNzZnVsUmVjb2duaXRpb25zOiByZWNvZ25pdGlvblJlc3VsdHMuZmlsdGVyKAogICAgICAgICAgKHIpID0+IHIudGV4dCAmJiByLnRleHQudGV4dAogICAgICAgICkubGVuZ3RoLAogICAgICAgIHByb2Nlc3NpbmdUaW1lOiBEYXRlLm5vdygpIC0gZGF0YS5zdGFydFRpbWUsCiAgICAgIH07CiAgICAgIGNvbnNvbGUubG9nKCfmnIDntYLntZDmnpw6JywgcmVzdWx0KTsKCiAgICAgIC8vIOODhuOCreOCueODiOWHuuWKm+OBr+W4uOOBq+eUn+aIkO+8iFVJ44Gn5b+F6KaB44Gq44Gf44KB77yJCiAgICAgIHJlc3VsdC50eHQgPSB0aGlzLmdlbmVyYXRlVGV4dE91dHB1dChvcmRlcmVkUmVzdWx0cyk7CgogICAgICAvLyDjgZ3jga7ku5bjga7lh7rlipvlvaLlvI/jga7nlJ/miJAKICAgICAgaWYgKGNvbmZpZy5vdXRwdXRGb3JtYXRzKSB7CiAgICAgICAgaWYgKGNvbmZpZy5vdXRwdXRGb3JtYXRzLmluY2x1ZGVzKCd4bWwnKSkgewogICAgICAgICAgcmVzdWx0LnhtbCA9CiAgICAgICAgICAgIHRoaXMuZ2VuZXJhdGVYTUxPdXRwdXQob3JkZXJlZFJlc3VsdHMpOwogICAgICAgIH0KICAgICAgICBpZiAoY29uZmlnLm91dHB1dEZvcm1hdHMuaW5jbHVkZXMoJ2pzb24nKSkgewogICAgICAgICAgcmVzdWx0Lmpzb24gPQogICAgICAgICAgICB0aGlzLmdlbmVyYXRlSlNPTk91dHB1dChvcmRlcmVkUmVzdWx0cyk7CiAgICAgICAgfQogICAgICB9CgogICAgICB0aGlzLnBvc3RNZXNzYWdlKHsKICAgICAgICB0eXBlOiAnT0NSX0NPTVBMRVRFJywKICAgICAgICBpZCwKICAgICAgICAuLi5yZXN1bHQsCiAgICAgIH0pOwogICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgdGhpcy5wb3N0TWVzc2FnZSh7CiAgICAgICAgdHlwZTogJ09DUl9FUlJPUicsCiAgICAgICAgaWQsCiAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UsCiAgICAgICAgc3RhY2s6IGVycm9yLnN0YWNrLAogICAgICB9KTsKICAgIH0KICB9CgogIC8qKgogICAqIFhNTOW9ouW8j+OBruWHuuWKm+eUn+aIkAogICAqLwogIGdlbmVyYXRlWE1MT3V0cHV0KHRleHRCbG9ja3MpIHsKICAgIGxldCB4bWwgPSAnPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz5cbic7CiAgICB4bWwgKz0gJzxkb2N1bWVudD5cbic7CgogICAgdGV4dEJsb2Nrcy5mb3JFYWNoKChibG9jaywgaW5kZXgpID0+IHsKICAgICAgeG1sICs9IGAgIDx0ZXh0YmxvY2sgaWQ9IiR7aW5kZXh9IiB4PSIke2Jsb2NrLnh9IiB5PSIke2Jsb2NrLnl9IiB3aWR0aD0iJHtibG9jay53aWR0aH0iIGhlaWdodD0iJHtibG9jay5oZWlnaHR9IiBjb25maWRlbmNlPSIke2Jsb2NrLmNvbmZpZGVuY2V9Ij5cbmA7CiAgICAgIHhtbCArPSBgICAgIDx0ZXh0PiR7dGhpcy5lc2NhcGVYTUwoCiAgICAgICAgYmxvY2sudGV4dD8udGV4dCB8fCAnJwogICAgICApfTwvdGV4dD5cbmA7CiAgICAgIHhtbCArPSAnICA8L3RleHRibG9jaz5cbic7CiAgICB9KTsKCiAgICB4bWwgKz0gJzwvZG9jdW1lbnQ+JzsKICAgIHJldHVybiB4bWw7CiAgfQoKICAvKioKICAgKiBKU09O5b2i5byP44Gu5Ye65Yqb55Sf5oiQCiAgICovCiAgZ2VuZXJhdGVKU09OT3V0cHV0KHRleHRCbG9ja3MpIHsKICAgIHJldHVybiB7CiAgICAgIGRvY3VtZW50OiB7CiAgICAgICAgdGV4dEJsb2NrczogdGV4dEJsb2Nrcy5tYXAoKGJsb2NrLCBpbmRleCkgPT4gKHsKICAgICAgICAgIGlkOiBpbmRleCwKICAgICAgICAgIHg6IGJsb2NrLngsCiAgICAgICAgICB5OiBibG9jay55LAogICAgICAgICAgd2lkdGg6IGJsb2NrLndpZHRoLAogICAgICAgICAgaGVpZ2h0OiBibG9jay5oZWlnaHQsCiAgICAgICAgICBjb25maWRlbmNlOiBibG9jay5jb25maWRlbmNlLAogICAgICAgICAgdGV4dDogYmxvY2sudGV4dD8udGV4dCB8fCAnJywKICAgICAgICB9KSksCiAgICAgIH0sCiAgICB9OwogIH0KCiAgLyoqCiAgICog44OG44Kt44K544OI5b2i5byP44Gu5Ye65Yqb55Sf5oiQCiAgICovCiAgZ2VuZXJhdGVUZXh0T3V0cHV0KHRleHRCbG9ja3MpIHsKICAgIHJldHVybiB0ZXh0QmxvY2tzCiAgICAgIC5maWx0ZXIoKGJsb2NrKSA9PiBibG9jay50ZXh0Py50ZXh0KQogICAgICAubWFwKChibG9jaykgPT4gYmxvY2sudGV4dC50ZXh0KQogICAgICAuam9pbignXG4nKTsKICB9CgogIC8qKgogICAqIFhNTCDjgqjjgrnjgrHjg7zjg5cKICAgKi8KICBlc2NhcGVYTUwodGV4dCkgewogICAgcmV0dXJuIHRleHQKICAgICAgLnJlcGxhY2UoLyYvZywgJyZhbXA7JykKICAgICAgLnJlcGxhY2UoLzwvZywgJyZsdDsnKQogICAgICAucmVwbGFjZSgvPi9nLCAnJmd0OycpCiAgICAgIC5yZXBsYWNlKC8iL2csICcmcXVvdDsnKQogICAgICAucmVwbGFjZSgvJy9nLCAnJiMzOTsnKTsKICB9CgogIC8qKgogICAqIOODoeODg+OCu+ODvOOCuOOBrumAgeS/oQogICAqLwogIHBvc3RNZXNzYWdlKG1lc3NhZ2UpIHsKICAgIHNlbGYucG9zdE1lc3NhZ2UobWVzc2FnZSk7CiAgfQp9CgovLyDjg6/jg7zjgqvjg7zjgqTjg7Pjgrnjgr/jg7PjgrkKY29uc3Qgb2NyV29ya2VyID0gbmV3IE9DUldvcmtlcigpOwoKLy8g44Oh44Kk44Oz44K544Os44OD44OJ44GL44KJ44Gu44Oh44OD44K744O844K45Yem55CGCnNlbGYub25tZXNzYWdlID0gYXN5bmMgZnVuY3Rpb24gKGV2ZW50KSB7CiAgY29uc3QgeyB0eXBlLCAuLi5kYXRhIH0gPSBldmVudC5kYXRhOwoKICBzd2l0Y2ggKHR5cGUpIHsKICAgIGNhc2UgJ0lOSVRJQUxJWkUnOgogICAgICBhd2FpdCBvY3JXb3JrZXIuaW5pdGlhbGl6ZSgpOwogICAgICBicmVhazsKCiAgICBjYXNlICdPQ1JfUFJPQ0VTUyc6CiAgICAgIGF3YWl0IG9jcldvcmtlci5wcm9jZXNzT0NSKHsKICAgICAgICAuLi5kYXRhLAogICAgICAgIHN0YXJ0VGltZTogRGF0ZS5ub3coKSwKICAgICAgfSk7CiAgICAgIGJyZWFrOwoKICAgIGNhc2UgJ1RFUk1JTkFURSc6CiAgICAgIHNlbGYuY2xvc2UoKTsKICAgICAgYnJlYWs7CgogICAgZGVmYXVsdDoKICAgICAgY29uc29sZS53YXJuKCdVbmtub3duIG1lc3NhZ2UgdHlwZTonLCB0eXBlKTsKICB9Cn07CgovLyDjgqjjg6njg7zjg4/jg7Pjg4njg6rjg7PjgrAKc2VsZi5vbmVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7CiAgc2VsZi5wb3N0TWVzc2FnZSh7CiAgICB0eXBlOiAnT0NSX0VSUk9SJywKICAgIGVycm9yOiBlcnJvci5tZXNzYWdlLAogICAgZmlsZW5hbWU6IGVycm9yLmZpbGVuYW1lLAogICAgbGluZW5vOiBlcnJvci5saW5lbm8sCiAgfSk7Cn07Cg==", import.meta.url); } class w { constructor() { this.worker = null, this.initialized = !1; } /** * WebWorkerを初期化 */ async initialize() { if (!this.initialized) return this.worker = new Worker(u(), { type: "module" }), new Promise((e, t) => { const s = setTimeout(() => { t(new Error("Worker initialization timeout")); }, 3e4); this.worker.onmessage = (i) => { const { type: g } = i.data; g === "WORKER_READY" ? (clearTimeout(s), this.initialized = !0, e()) : g === "WORKER_ERROR" && (clearTimeout(s), t(new Error(i.data.error))); }, this.worker.onerror = (i) => { clearTimeout(s), t(i); }, this.worker.postMessage({ type: "INITIALIZE" }); }); } /** * OCR処理を実行 * @param {ImageData|HTMLImageElement|File} imageInput - 画像データ * @param {Object} options - 処理オプション * @returns {Promise<Object>} OCR結果 */ async processImage(e, t = {}) { this.initialized || await this.initialize(); const s = await this._convertToImageData( e ); return new Promise((i, g) => { const n = Date.now().toString(), r = (l) => { const { type: I, id: C, ...o } = l.data; if (C === n) switch (I) { case "OCR_PROGRESS": t.onProgress && t.onProgress(o); break; case "OCR_COMPLETE": this.worker.removeEventListener( "message", r ), i(o); break; case "OCR_ERROR": this.worker.removeEventListener( "message", r ), g(new Error(o.error)); break; } }; this.worker.addEventListener( "message", r ), this.worker.postMessage({ type: "OCR_PROCESS", id: n, imageData: s, config: { outputFormats: t.outputFormats || ["txt"], ...t } }); }); } /** * 画像入力をImageDataに変換 */ async _convertToImageData(e) { if (e instanceof ImageData) return e; const t = document.createElement("canvas"), s = t.getContext("2d"); if (e instanceof File) { const i = new Image(); return new Promise((g, n) => { i.onload = () => { t.width = i.width, t.height = i.height, s.drawImage(i, 0, 0), g( s.getImageData( 0, 0, t.width, t.height ) ); }, i.onerror = n, i.src = URL.createObjectURL(e); }); } if (e instanceof HTMLImageElement) return t.width = e.width, t.height = e.height, s.drawImage(e, 0, 0), s.getImageData( 0, 0, t.width, t.height ); throw new Error("Unsupported image input type"); } /** * WebWorkerを終了 */ terminate() { this.worker && (this.worker.terminate(), this.worker = null, this.initialized = !1); } } export { p as FileHandler, w as NDLKotenOCR, b as ResultDisplay, Z as clearCache, w as default, f as getCachedModels, R as getModelUrl, W as getModelUrls, u as getWorkerUrl, k as loadConfig, G as loadModel, v as preloadAllModels, m as workerMessageHandler };