Fix mobile photo upload: resize large camera images + increase body limit

Mobile cameras produce 8-12MB photos. Now:
- Canvas-based resize to max 2000x1500 before upload
- JPEG compression at 0.7-0.85 quality
- Express body limit increased to 5MB for id-upload route
- Falls back to raw upload for small images and PDFs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
justin 2026-05-30 17:24:16 -05:00
parent 04861ccfe0
commit f60c5229ab
2 changed files with 50 additions and 7 deletions

View file

@ -69,6 +69,8 @@ app.use("/api/v1/webhooks/stripe", express.raw({ type: "application/json" }));
app.use(identityRouter); // identity webhook uses raw() internally on its specific route
// Photo ID upload needs larger body (resized images up to ~3MB as base64)
app.use("/api/v1/id-upload", express.json({ limit: "5mb" }));
app.use(express.json({ limit: "512kb" })); // 512kb for eSign signature PNG base64
// Reject non-JSON content types on POST/PUT/PATCH

View file

@ -179,16 +179,57 @@ submitBtn.addEventListener("click", function() {
return;
}
// Convert image to base64 and send
var reader2 = new FileReader();
reader2.onload = function(ev) {
// Resize image if too large, then send as base64
function resizeAndUpload(file) {
var maxWidth = 2000;
var maxHeight = 1500;
var maxBytes = 2 * 1024 * 1024; // 2MB target
var img = new Image();
img.onload = function() {
var w = img.width;
var h = img.height;
// Only resize if image is larger than limits
if (w > maxWidth || h > maxHeight || file.size > maxBytes) {
var scale = Math.min(maxWidth / w, maxHeight / h, 1);
var canvas = document.createElement("canvas");
canvas.width = Math.round(w * scale);
canvas.height = Math.round(h * scale);
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// Compress as JPEG
var quality = file.size > 5 * 1024 * 1024 ? 0.7 : 0.85;
var dataUrl = canvas.toDataURL("image/jpeg", quality);
sendUpload(dataUrl);
} else {
// Small enough — send as-is
var reader3 = new FileReader();
reader3.onload = function(e) { sendUpload(e.target.result); };
reader3.readAsDataURL(file);
}
};
img.onerror = function() {
// Not an image (PDF?) — send as-is
var reader3 = new FileReader();
reader3.onload = function(e) { sendUpload(e.target.result); };
reader3.readAsDataURL(file);
};
var reader2 = new FileReader();
reader2.onload = function(e) { img.src = e.target.result; };
reader2.readAsDataURL(file);
}
function sendUpload(dataUrl) {
fetch(API + "/api/v1/id-upload/" + uploadToken, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
image_data: ev.target.result,
image_data: dataUrl,
filename: selectedFile.name,
content_type: selectedFile.type || "image/jpeg",
content_type: "image/jpeg",
}),
})
.then(function(r) {
@ -204,8 +245,8 @@ submitBtn.addEventListener("click", function() {
errorSection.style.display = "block";
document.getElementById("error-msg").textContent = err.message;
});
};
reader2.readAsDataURL(selectedFile);
}
resizeAndUpload(selectedFile);
});
// If no order number, show error