API jembatan JavaScript
Pemindai QR dan barcode
Layar pemindai Google dari satu promise, AppMint.scanCode() - tanpa izin kamera, dan URL, Wi-Fi, telepon, atau kontak yang sudah diurai untuk kode QR umum.
AppMint.scanCode helper#
AppMint.scanCode(options)
Contoh
Membuka layar pemindai kode QR dan barcode Google dan memberi Anda hasil pindaiannya. Satu panggilan - tanpa izin kamera, tanpa <video>, tanpa UI buatan sendiri.
Mengembalikan: sebuah Promise yang selalu selesai: {ok: true, value, displayValue, format, type, …} atau {ok: false, code, message}. Memerlukan: tidak ada yang perlu diaktifkan. Ponsel memerlukan layanan Google Play.
Kode apa pun:
async function scan() {
if (!(window.AppMint && AppMint.scanCode)) { alert('Open this page in the app to scan'); return; }
var r = await AppMint.scanCode();
if (!r.ok) {
if (r.code === 'cancelled') return; // the user closed the scanner
if (r.code === 'unavailable') alert('The scanner is not available on this phone');
else if (r.code === 'busy') alert('A scan is already open');
else alert('Scan failed: ' + r.message); // 'failed'
return;
}
console.log(r.value, r.format, r.type); // "TICKET-4821", "qr_code", "text"
}Hanya beberapa format, dan opsi "ketik sendiri" untuk label yang rusak:
var r = await AppMint.scanCode({
formats: ['ean_13', 'ean_8', 'upc_a', 'upc_e'], // shop barcodes
manualInput: true, // lets the user type the code
autoZoom: true // default true
});
if (r.ok) lookUpProduct(r.value);Bagian siap pakai - hanya bagian yang cocok dengan r.type yang ada:
var r = await AppMint.scanCode({ formats: ['qr_code'] });
if (r.ok) {
if (r.type === 'url') openLink(r.url.url); // url: { url, title }
if (r.type === 'wifi') showWifi(r.wifi.ssid, r.wifi.password, r.wifi.encryption); // 'wpa'|'wep'|'open'
if (r.type === 'phone') callNumber(r.phone); // a string
if (r.type === 'email') writeMail(r.email.address, r.email.subject, r.email.body);
if (r.type === 'sms') writeSms(r.sms.phoneNumber, r.sms.message);
if (r.type === 'geo') showMap(r.geo.lat, r.geo.lng);
if (r.type === 'contact') addContact(r.contact.name, r.contact.organization, r.contact.phones, r.contact.emails);
}Catatan: Nama format: qr_code, aztec, codabar, code_39, code_93, code_128, data_matrix, ean_8, ean_13, itf, pdf417, upc_a, upc_e (nama yang tidak dikenal diabaikan; kosong = semua format). type adalah salah satu dari url, wifi, text, phone, email, sms, geo, contact, calendar, isbn, product, driver_license, unknown. Kode kesalahan: cancelled (ditutup, termasuk dengan Kembali), unavailable (tanpa layanan Play, atau pemindai tidak dapat diunduh), busy (pemindaian sudah terbuka), failed. Pemindaian pertama di sebuah ponsel bisa memakan beberapa detik saat layanan Play mengunduh pemindai. Aplikasi buatan AI memakai scanCode() dari @/lib/appmintNative, yang juga memindai di web.
AppMint.textRecognition helper#
AppMint.textRecognition.recognize(image, {script}) / prepare(script, onProgress)
Contoh
Membaca teks dalam skrip selain Latin: Devanagari (Hindi, Marathi, Nepali …), Mandarin, Jepang, dan Korea - atau 'auto', yang mencoba setiap skrip dan mempertahankan hasil bacaan dengan karakter terbanyak. Opsi yang sama berlaku pada detektor standar: new TextDetector({ script: 'devanagari' }). Tanpa opsi, semuanya dibaca sebagai Latin persis seperti sebelumnya.
Mengembalikan: recognize() → sebuah Promise berisi {script, text, blocks: [{text, box, corners, lines}]} (script = yang digunakan); ditolak dengan DOMException - NotSupportedError untuk skrip tidak dikenal atau tanpa layanan Google Play, OperationError selain itu. prepare() → sebuah Promise berisi {script, status: 'ready'}. Memerlukan: layanan Google Play. Pengenal tiap skrip adalah unduhan layanan Play: skrip yang disebut kode Anda dipasang bersama aplikasi, skrip lain saat pertama digunakan.
Teks Hindi dari foto:
document.getElementById('photo').addEventListener('change', async function (e) {
var file = e.target.files[0];
if (!file || !(window.AppMint && AppMint.textRecognition)) return;
try {
var r = await AppMint.textRecognition.recognize(file, { script: 'devanagari' });
document.getElementById('out').textContent = r.text;
} catch (err) {
alert('Could not read the photo: ' + err.name);
}
});Unduh model sebuah skrip lebih dulu, dengan progres - penggunaan pertama di ponsel jika tidak harus menunggu unduhan:
async function getReady() {
var bar = document.getElementById('model-progress');
await AppMint.textRecognition.prepare('japanese', function (s) {
if (s.progress != null) bar.value = s.progress; // 0..1 while 'downloading'
});
bar.hidden = true;
}
// The same states arrive as events, also when a recognize() call starts a download:
window.addEventListener('appmint:ocr-model', function (e) {
console.log(e.detail.script, e.detail.status, e.detail.progress); // 'downloading' | 'ready' | 'failed'
});Dokumen campuran - biarkan aplikasi memilih di antara skrip yang Anda harapkan:
var r = await AppMint.textRecognition.recognize(img, { script: 'auto', scripts: ['latin', 'chinese', 'korean'] });
console.log('read as ' + r.script + ': ' + r.text);
var lines = await new TextDetector({ script: 'korean' }).detect(img); // standard shape, one entry per lineCatatan: scripts adalah daftar AppMint: latin, devanagari, chinese, japanese, korean. Arab, Sirilik, Thai, dan Ibrani tidak memiliki pengenal di perangkat. WebToApk.__ocrRecognizeWith(requestId, base64, optionsJson) adalah transportasi internal; gunakan helper.
__ocrAvailable jembatan#
window.WebToApk.__ocrAvailable(): Boolean
TextDetector / recognizeText(): layanan Google Play ada di sini (rumah modul OCR).
Contoh
Transportasi internal di balik TextDetector: apakah layanan Google Play (tempat pengenal berasal) ada di ponsel ini. Halaman memakai API standar; jangan pernah memanggil ini langsung - metode __ bisa berubah tanpa pemberitahuan.
Mengembalikan: true atau false. Saat false, TextDetector sama sekali tidak terpasang. Memerlukan: tidak ada.
Gunakan API publik:
if ('TextDetector' in window) scanButton.hidden = false;Pilih antara alur pemindaian dan formulir ketik sekali saja, saat mulai. Saat ponsel tidak memiliki layanan Google Play, detektor memang tidak ada, jadi halaman harus menawarkan jalan lain:
function setUpReceiptEntry() {
var canScan = typeof window.TextDetector === 'function';
document.getElementById('scan-receipt').hidden = !canScan;
document.getElementById('type-receipt').hidden = canScan;
if (!canScan) document.getElementById('entry-hint').textContent =
'Text scanning is not available on this phone. Type the total below.';
}
document.addEventListener('DOMContentLoaded', setUpReceiptEntry);Detektor yang ada tetap bisa menjawab bahwa pengenalan tidak tersedia pada saat panggilan. Bedakan kedua kegagalan itu dari nama kesalahannya:
async function readLabel(img) {
if (typeof window.TextDetector !== 'function') return null;
try {
var lines = await new TextDetector().detect(img);
return lines.map(function (l) { return l.rawValue; }).join('\n');
} catch (e) {
if (e.name === 'NotSupportedError') showMessage('Text recognition is not available right now.');
else showMessage('Could not read the label: ' + e.message);
return null;
}
}Catatan: Diimplementasikan di shell aplikasi (TextRecognitionBridge.kt).
__ocrRecognize jembatan#
window.WebToApk.__ocrRecognize(requestId: String, base64: String)
Mengenali teks dalam [base64] (PNG/JPEG); jawabannya tiba sebagai `appmint:ocr {requestId, blocks|error}`.
Contoh
Transportasi internal di balik TextDetector.detect(): mengenali teks dalam PNG/JPEG. Halaman memakai API standar; jangan pernah memanggil ini langsung - metode __ bisa berubah tanpa pemberitahuan.
Mengembalikan: tidak ada; jawabannya tiba sebagai peristiwa appmint:ocr {requestId, blocks:[{text, box, corners, lines}]} atau {requestId, error} (unavailable, bad-image, failed: …). Memerlukan: tidak ada.
Gunakan API publik:
const lines = await new TextDetector().detect(document.getElementById('receipt'));
console.log(lines.map((l) => l.rawValue));Baca teks dari foto yang dipilih pengguna. detect() menerima Blob/File serta <img>, <canvas> atau ImageData:
<input type="file" id="doc" accept="image/*" capture="environment">
<pre id="out"></pre>
<script>
document.getElementById('doc').addEventListener('change', async function (e) {
var file = e.target.files[0];
if (!file || typeof window.TextDetector !== 'function') return;
try {
var lines = await new TextDetector().detect(file);
document.getElementById('out').textContent = lines.map(function (l) { return l.rawValue; }).join('\n');
} catch (err) {
document.getElementById('out').textContent = 'Could not read the photo (' + err.name + ')';
}
});
</script>Gambar garis besar setiap baris yang dikenali di atas gambar. boundingBox menggunakan piksel gambar itu sendiri, jadi skalakan ke ukuran yang ditampilkan. Gambar harus sudah selesai dimuat, atau detect() ditolak dengan InvalidStateError:
async function highlightLines(img, overlay) {
if (!img.complete) await new Promise(function (r) { img.onload = r; });
var lines = await new TextDetector().detect(img);
var sx = img.clientWidth / img.naturalWidth, sy = img.clientHeight / img.naturalHeight;
overlay.innerHTML = '';
lines.forEach(function (l) {
var b = l.boundingBox, box = document.createElement('div');
box.className = 'ocr-box';
box.title = l.rawValue;
box.style.cssText = 'position:absolute;left:' + b.x * sx + 'px;top:' + b.y * sy +
'px;width:' + b.width * sx + 'px;height:' + b.height * sy + 'px';
overlay.appendChild(box);
});
}Ambil nominal dari sebuah struk. Gambar lintas-origin yang mencemari canvas ditolak dengan SecurityError, jadi sajikan gambar dari origin aplikasi sendiri:
async function findTotal(img) {
try {
var lines = await new TextDetector().detect(img);
var hit = lines.find(function (l) { return /total/i.test(l.rawValue); });
var m = hit && hit.rawValue.match(/(\d+[.,]\d{2})/);
return m ? parseFloat(m[1].replace(',', '.')) : null;
} catch (e) {
if (e.name === 'SecurityError') console.warn('Image is from another origin; load it from the app instead.');
else console.warn('OCR failed:', e.name, e.message);
return null;
}
}Catatan: Diimplementasikan di shell aplikasi (TextRecognitionBridge.kt).
__ocrRecognizeWith jembatan#
window.WebToApk.__ocrRecognizeWith(requestId: String, base64: String, optionsJson: String)
[__ocrRecognize] dengan opsi [optionsJson] `{script: 'latin'|'devanagari'|'chinese'|'japanese'|'korean'|'auto', scripts?}`; jawaban `appmint:ocr` juga menyebut `script` yang digunakan.
Contoh
Didokumentasikan bersama AppMint.textRecognition - contoh di sana menunjukkan yang ini juga.
Membaca teks dalam skrip selain Latin: Devanagari (Hindi, Marathi, Nepali …), Mandarin, Jepang, dan Korea - atau 'auto', yang mencoba setiap skrip dan mempertahankan hasil bacaan dengan karakter terbanyak. Opsi yang sama berlaku pada detektor standar: new TextDetector({ script: 'devanagari' }). Tanpa opsi, semuanya dibaca sebagai Latin persis seperti sebelumnya.
Mengembalikan: recognize() → sebuah Promise berisi {script, text, blocks: [{text, box, corners, lines}]} (script = yang digunakan); ditolak dengan DOMException - NotSupportedError untuk skrip tidak dikenal atau tanpa layanan Google Play, OperationError selain itu. prepare() → sebuah Promise berisi {script, status: 'ready'}. Memerlukan: layanan Google Play. Pengenal tiap skrip adalah unduhan layanan Play: skrip yang disebut kode Anda dipasang bersama aplikasi, skrip lain saat pertama digunakan.
Teks Hindi dari foto:
document.getElementById('photo').addEventListener('change', async function (e) {
var file = e.target.files[0];
if (!file || !(window.AppMint && AppMint.textRecognition)) return;
try {
var r = await AppMint.textRecognition.recognize(file, { script: 'devanagari' });
document.getElementById('out').textContent = r.text;
} catch (err) {
alert('Could not read the photo: ' + err.name);
}
});Unduh model sebuah skrip lebih dulu, dengan progres - penggunaan pertama di ponsel jika tidak harus menunggu unduhan:
async function getReady() {
var bar = document.getElementById('model-progress');
await AppMint.textRecognition.prepare('japanese', function (s) {
if (s.progress != null) bar.value = s.progress; // 0..1 while 'downloading'
});
bar.hidden = true;
}
// The same states arrive as events, also when a recognize() call starts a download:
window.addEventListener('appmint:ocr-model', function (e) {
console.log(e.detail.script, e.detail.status, e.detail.progress); // 'downloading' | 'ready' | 'failed'
});Dokumen campuran - biarkan aplikasi memilih di antara skrip yang Anda harapkan:
var r = await AppMint.textRecognition.recognize(img, { script: 'auto', scripts: ['latin', 'chinese', 'korean'] });
console.log('read as ' + r.script + ': ' + r.text);
var lines = await new TextDetector({ script: 'korean' }).detect(img); // standard shape, one entry per lineCatatan: scripts adalah daftar AppMint: latin, devanagari, chinese, japanese, korean. Arab, Sirilik, Thai, dan Ibrani tidak memiliki pengenal di perangkat. WebToApk.__ocrRecognizeWith(requestId, base64, optionsJson) adalah transportasi internal; gunakan helper.
prepareTextRecognition jembatan#
window.WebToApk.prepareTextRecognition(script: String): String
Mengunduh pengenal teks untuk [script] sebelum digunakan. Mengembalikan "checking" (lalu `appmint:ocr-model {script, status: 'downloading'|'ready'|'failed', progress?}`), "unsupported-script" atau "unavailable" (tanpa layanan Google Play).
Contoh
Mengunduh pengenal teks di perangkat untuk satu skrip sebelum digunakan, sehingga recognize() pertama tidak perlu menunggu. Halaman biasanya memanggil AppMint.textRecognition.prepare(script), yang membungkus ini.
Mengembalikan: sebuah string seketika - "checking" (hasilnya menyusul sebagai peristiwa appmint:ocr-model {script, status: 'downloading' | 'ready' | 'failed', progress?, error?}), "unsupported-script" atau "unavailable" (tanpa layanan Google Play). 'auto' menyiapkan semua skrip. Memerlukan: layanan Google Play.
if (window.WebToApk && typeof window.WebToApk.prepareTextRecognition === 'function') {
window.addEventListener('appmint:ocr-model', function (e) {
if (e.detail.script !== 'chinese') return;
if (e.detail.status === 'downloading') console.log('downloading', Math.round((e.detail.progress || 0) * 100) + '%');
if (e.detail.status === 'ready') document.getElementById('scan').disabled = false;
if (e.detail.status === 'failed') console.warn(e.detail.error);
});
var state = window.WebToApk.prepareTextRecognition('chinese');
if (state !== 'checking') console.warn('Chinese text recognition: ' + state);
}Siapkan, lalu pindai melalui wrapper:
async function readSign(canvas) {
if (!(window.AppMint && AppMint.textRecognition)) return null;
try {
await AppMint.textRecognition.prepare('japanese');
return await AppMint.textRecognition.recognize(canvas, { script: 'japanese' });
} catch (err) {
console.warn('Text recognition:', err.name, err.message); // e.g. NotSupportedError without Play services
return null;
}
}Skrip yang tidak didukung dan layanan Play yang hilang dilaporkan dalam nilai kembalian:
const W = window.WebToApk;
if (W && typeof W.prepareTextRecognition === 'function') {
const state = W.prepareTextRecognition('arabic');
if (state === 'unsupported-script') showMessage('Arabic text cannot be read on the phone.');
else if (state === 'unavailable') showMessage('Text recognition needs Google Play services.');
}Catatan: Skrip: latin, devanagari, chinese, japanese, korean, auto. Skrip yang sudah ada di ponsel langsung dijawab ready.
scanCode jembatan#
window.WebToApk.scanCode(optionsJson: String, callbackId: String)
Membuka pemindai kode Google; [optionsJson] `{formats?, autoZoom?, manualInput?}`. Menyelesaikan promise AppMint.scanCode [callbackId].
Contoh
Mekanisme internal di balik AppMint.scanCode() - halaman memakai helper Promise itu, yang membuka pemindai QR/barcode Google dan menyelesaikan dengan hasilnya.
Mengembalikan: tidak ada secara langsung; hasilnya menyelesaikan promise AppMint.scanCode(). Memerlukan: tidak ada yang perlu diaktifkan (tanpa izin kamera). Ponsel memerlukan layanan Google Play.
API publik:
async function scanTicket() {
if (!(window.AppMint && AppMint.scanCode)) { alert('Open this page in the app to scan'); return; }
var r = await AppMint.scanCode({ formats: ['qr_code'] });
if (r.ok) checkTicket(r.value); // r.format, r.type, r.displayValue…
else if (r.code !== 'cancelled') alert('Scan failed (' + r.code + ')');
}Bergabung ke jaringan Wi-Fi dari kode QR cetak. Kode Wi-Fi kembali dengan type: 'wifi' dan objek wifi:
async function scanWifi() {
if (!(window.AppMint && AppMint.scanCode)) return;
var r = await AppMint.scanCode({ formats: ['qr_code'] });
if (!r.ok) { if (r.code !== 'cancelled') alert('Scan failed (' + r.code + ')'); return; }
if (r.type !== 'wifi') { alert('That is not a Wi-Fi code.'); return; }
showWifiCard(r.wifi.ssid, r.wifi.password, r.wifi.encryption); // encryption: 'wpa' | 'wep' | 'open'
}Cari produk dari barcode tokonya, dan biarkan pengguna mengetik angkanya saat label rusak (manualInput). Pemindaian pertama di ponsel mungkin mengunduh pemindai, yang gagal dengan unavailable saat offline:
async function scanProduct() {
if (!(window.AppMint && AppMint.scanCode)) { showManualEntry(); return; }
var r = await AppMint.scanCode({ formats: ['ean_13', 'ean_8', 'upc_a', 'upc_e'], manualInput: true });
if (r.ok) return lookUpProduct(r.value, r.format); // e.g. '4006381333931', 'ean_13'
if (r.code === 'busy') return; // a scan is already open
if (r.code === 'unavailable') alert('The scanner is not available: ' + r.message);
else if (r.code !== 'cancelled') alert('Scan failed (' + r.code + ')');
}Buka apa pun yang ditunjuk kode QR, berdasarkan hasil dekodenya type:
async function scanAndOpen() {
var r = await AppMint.scanCode({ formats: ['qr_code'], autoZoom: true });
if (!r.ok) return;
if (r.type === 'url') location.href = r.url.url;
else if (r.type === 'phone') location.href = 'tel:' + r.phone;
else if (r.type === 'email') location.href = 'mailto:' + r.email.address;
else if (r.type === 'geo') showOnMap(r.geo.lat, r.geo.lng);
else if (r.type === 'contact') saveContact(r.contact.name, r.contact.phones, r.contact.emails);
else showText(r.displayValue);
}Catatan: Metode mentah menerima optionsJson ({formats?, autoZoom?, manualInput?} sebagai string JSON) dan sebuah callbackId; jawabannya dikirim ke tabel balasan internal helper, jadi halaman yang memanggilnya langsung tidak mendapat jawaban. Hanya satu pemindaian berjalan pada satu waktu - panggilan kedua dijawab code: 'busy'. Lihat AppMint.scanCode untuk semua field hasil dan kode kesalahan.