Photo editor SDK
People photograph passports and ID cards at an angle, with a thumb in the corner, under a lamp. Read as they are, those photos give worse OCR results. The Vanguard SDK puts a photo editor in your own page — the one our portal uses — so a picture is cropped, turned straight and brightened before it leaves the phone:
- Crop with handles, on the exact shape of an ID card, a passport data page or an A4 page — or free.
- Rotate in quarter turns, straighten a few degrees, mirror.
- Enhance: one-tap auto levels, brightness, contrast, colour, sharpness.
- Filters: black & white, and a “document” look that makes print stand off the paper.
It speaks Lao, Thai and English, works on phones and computers, and runs entirely in the browser: editing is free and nothing is sent anywhere until you send it. One script, about 30 KB.
Quick start
Add the script, then attach the editor to your file input:
<script src="https://ai.vanguardinitiative.com/sdk/v1/vanguard.js"></script>
<input type="file" id="passport" accept="image/*" />
<script>
// Opens the editor whenever one photo is picked. The input then holds the
// edited photo, and its change event fires again for your own code.
Vanguard.photoEditor.attach('#passport', { preset: 'document', aspect: 'passport', locale: 'lo' });
</script>That is all a plain form needs: when a person picks one photo, the editor opens; when they press Apply & continue, the input holds the edited photo and your form sends it as before. If they cancel, the input is cleared.
In your own code
With a framework, or when you send the picture yourself, call open() in your change handler. It resolves to the edited File, the original (the person chose Use original, changed nothing, or the browser cannot decode the type), or null when they cancelled.
const input = document.querySelector('#passport');
input.addEventListener('change', async () => {
const file = await Vanguard.photoEditor.open(input.files[0], {
preset: 'document',
aspect: 'passport'
});
if (!file) return; // the person cancelled
// To YOUR server, which calls Vanguard with your API key.
const result = await Vanguard.upload(file, {
endpoint: '/api/scan-passport',
fields: { type: 'PASSPORT' }
});
console.log(result.data);
});Vanguard.photoEditor.open(file, options) — options
preset document | photo | avatar | icon | What kind of picture it is: the shapes, size and format follow. document: OCR and identity papers (JPEG, 2048 px). photo: a person. avatar: square, 1024 px. icon: square, 512 px. Default: document. |
aspects string[] | The shapes offered: free, id-card (ID card, driving licence, bank card), passport (the data page), a4, square, 3:4, 35:45. Default: the preset’s. |
aspect string | The shape selected when the editor opens. |
maxEdge number | The long edge of the edited picture, at most 4096. A smaller picture is never enlarged. |
format auto | image/jpeg | image/png | image/webp | auto keeps a PNG a PNG and makes the rest JPEG. Default: the preset’s. |
quality number | JPEG/WebP quality, 0.5–1. Default: 0.92. |
locale lo | th | en | The editor’s language. Default: your page’s lang attribute, then the browser’s language. |
labels object | Your own words for any label, e.g. a title. |
title, subtitle string | The heading at the top of the editor. |
allowSkip boolean | Offer “Use original”. Default: true. |
Vanguard.photoEditor.attach(input, options) takes the same options plus onChange(file), and returns a function that detaches it. Vanguard.photoEditor.canEdit(file) says whether the editor would open for a file.
Sending the picture to your server
Vanguard.upload(file, options) posts the picture as multipart/form-data to your endpoint and resolves to the response (JSON when it is JSON). A failed request throws a Vanguard.UploadError with status and body.
Vanguard.upload(file, options) — options
endpoint * string | Your own server’s URL. Never Vanguard’s API with a key: a key in the browser is refused. |
fieldName string | The form field for the picture. Default: image (what /v1/ocr/scan reads). |
fields object | Other form fields, e.g. a document type. |
headers object | Request headers, e.g. your own CSRF token. |
credentials string | fetch credentials. Default: same-origin (your session cookie goes along). |
Your server then calls the API with your key — for example POST /v1/ocr/scan, field image, optional type:
// Express + multer. Your own login check runs first: every scan spends your credits.
import express from 'express';
import multer from 'multer';
const app = express();
const upload = multer({ limits: { fileSize: 15 * 1024 * 1024 } });
app.post('/api/scan-passport', requireLogin, upload.single('image'), async (req, res) => {
const form = new FormData();
form.append('image', new Blob([req.file.buffer], { type: req.file.mimetype }), req.file.originalname);
if (req.body.type) form.append('type', req.body.type);
const r = await fetch('https://ai-api.vanguardinitiative.com/v1/ocr/scan', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.VANGUARD_API_KEY}` },
body: form
});
res.status(r.status).json(await r.json());
});<?php
// POST /api/scan-passport — check your own login first: every scan spends your credits.
$ch = curl_init('https://ai-api.vanguardinitiative.com/v1/ocr/scan');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('VANGUARD_API_KEY')],
CURLOPT_POSTFIELDS => [
'image' => new CURLFile($_FILES['image']['tmp_name'], $_FILES['image']['type'], $_FILES['image']['name']),
'type' => $_POST['type'] ?? 'PASSPORT',
],
CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($ch);
http_response_code(curl_getinfo($ch, CURLINFO_HTTP_CODE));
header('Content-Type: application/json');
echo $body;Look and language
The editor sits in its own shadow root, so your page’s CSS does not change it and its CSS does not touch your page. To match your brand, set its colours on the vanguard-photo-editor element: --vg-pe-accent, --vg-pe-bg, --vg-pe-fg, --vg-pe-border, --vg-pe-muted-fg, --vg-pe-subtle, --vg-pe-stage, --vg-pe-radius and --vg-pe-font.
The language follows your page’s lang attribute (lo, th, otherwise English), or the locale option.
Good to know
- Picture types. JPEG, PNG, WebP and BMP everywhere; HEIC where the browser can open it (Safari on iPhone and Mac). PDF, GIF and anything else go through untouched.
- Large photos. A 50-megapixel phone photo works: the editor holds at most 4096 px and the result is
maxEdgeon its long side. - Privacy. The edited picture carries no EXIF data — no GPS position, no camera details. Nothing leaves the browser until you upload it.
- Content Security Policy. If your site sends one, allow
https://ai.vanguardinitiative.cominscript-src, and keep'unsafe-inline'instyle-src(the editor writes its styles into its shadow root). - Versions. Everything under
/sdk/v1/stays compatible: options are only ever added. A change that could break your page would ship as/sdk/v2/.