FastAPI is a modern, async-ready Python web framework for building APIs. It wraps low-level ASGI (Asynchronous Server Gateway Interface) interfaces and is built on top of Starlette and Pydantic. The combination of FastAPI and Uvicorn is ideal for creating high-performance web applications. In this article, you’ll learn how to build a web-based barcode reader using FastAPI, Uvicorn, Dynamsoft Barcode Reader SDK and HTML5.
Web Barcode Reader Demo
Prerequisites
- Python 3.8 or higher
- Dynamsoft Barcode Reader license
Python Web Framework Comparison: FastAPI vs Flask vs Django
Before diving into the code, let’s briefly compare FastAPI with other popular Python web frameworks: Flask and Django.
Feature / Aspect | FastAPI | Flask | Django |
---|---|---|---|
Performance (raw speed) | ⭐ High Built on ASGI + Starlette ~2–3x faster than Flask |
Medium WSGI-based |
Low to Medium WSGI-based |
Async Support | Native async/await from the ground up | Not native, needs workarounds | Partial (via channels or async views) |
Auto-generated Docs | Swagger & ReDoc built-in | None by default | None by default |
Deployment | ASGI (e.g., Uvicorn, Hypercorn) | WSGI (e.g., Gunicorn) | WSGI (e.g., Gunicorn) |
Project Structure
The project structure is as follows:
Project├── templates│ └── index.html├── static│ ├── script.js│ └── style.css└── backend.pyProject ├── templates │ └── index.html ├── static │ ├── script.js │ └── style.css └── backend.pyProject ├── templates │ └── index.html ├── static │ ├── script.js │ └── style.css └── backend.py
Enter fullscreen mode Exit fullscreen mode
Explanation
- templates: Contains HTML templates.
- static: Contains JavaScript and CSS files.
- backend.py: The main FastAPI application file that handles the backend logic.
The Features to Implement
The web barcode reader application is capable of:
- Upload images containing barcodes.
- Detect and decode barcodes using the Dynamsoft Capture Vision Bundle.
- Display barcode details, including type and content.
- Visualize barcode locations on the uploaded image.
Steps to Build the Web Barcode Reader
In the following sections, we will walk through the steps to build the web barcode reader application using FastAPI and HTML5.
Step 1: Install Dependencies
Install the required packages using pip:
fastapi uvicorn dynamsoft-capture-vision-bundle python-multipartfastapi uvicorn dynamsoft-capture-vision-bundle python-multipartfastapi uvicorn dynamsoft-capture-vision-bundle python-multipart
Enter fullscreen mode Exit fullscreen mode
Step 2: Set Up the FastAPI Application
-
Import required libraries:
<span>from</span> <span>fastapi</span> <span>import</span> <span>FastAPI</span><span>,</span> <span>File</span><span>,</span> <span>UploadFile</span><span>from</span> <span>fastapi.responses</span> <span>import</span> <span>JSONResponse</span><span>from</span> <span>fastapi.staticfiles</span> <span>import</span> <span>StaticFiles</span><span>from</span> <span>fastapi.middleware.cors</span> <span>import</span> <span>CORSMiddleware</span><span>from</span> <span>fastapi.templating</span> <span>import</span> <span>Jinja2Templates</span><span>from</span> <span>fastapi.requests</span> <span>import</span> <span>Request</span><span>from</span> <span>dynamsoft_capture_vision_bundle</span> <span>import</span> <span>*</span><span>from</span> <span>fastapi</span> <span>import</span> <span>FastAPI</span><span>,</span> <span>File</span><span>,</span> <span>UploadFile</span> <span>from</span> <span>fastapi.responses</span> <span>import</span> <span>JSONResponse</span> <span>from</span> <span>fastapi.staticfiles</span> <span>import</span> <span>StaticFiles</span> <span>from</span> <span>fastapi.middleware.cors</span> <span>import</span> <span>CORSMiddleware</span> <span>from</span> <span>fastapi.templating</span> <span>import</span> <span>Jinja2Templates</span> <span>from</span> <span>fastapi.requests</span> <span>import</span> <span>Request</span> <span>from</span> <span>dynamsoft_capture_vision_bundle</span> <span>import</span> <span>*</span>
from fastapi import FastAPI, File, UploadFile from fastapi.responses import JSONResponse from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from fastapi.templating import Jinja2Templates from fastapi.requests import Request from dynamsoft_capture_vision_bundle import *
-
Create the FastAPI application and configure CORS and static files:
<span>app</span> <span>=</span> <span>FastAPI</span><span>()</span><span>app</span><span>.</span><span>add_middleware</span><span>(</span><span>CORSMiddleware</span><span>,</span> <span>allow_origins</span><span>=</span><span>[</span><span>"</span><span>*</span><span>"</span><span>],</span> <span>allow_methods</span><span>=</span><span>[</span><span>"</span><span>*</span><span>"</span><span>],</span> <span>allow_headers</span><span>=</span><span>[</span><span>"</span><span>*</span><span>"</span><span>],)</span><span>app</span><span>.</span><span>mount</span><span>(</span><span>"</span><span>/static</span><span>"</span><span>,</span> <span>StaticFiles</span><span>(</span><span>directory</span><span>=</span><span>"</span><span>static</span><span>"</span><span>),</span> <span>name</span><span>=</span><span>"</span><span>static</span><span>"</span><span>)</span><span>templates</span> <span>=</span> <span>Jinja2Templates</span><span>(</span><span>directory</span><span>=</span><span>"</span><span>templates</span><span>"</span><span>)</span><span>app</span> <span>=</span> <span>FastAPI</span><span>()</span> <span>app</span><span>.</span><span>add_middleware</span><span>(</span><span>CORSMiddleware</span><span>,</span> <span>allow_origins</span><span>=</span><span>[</span><span>"</span><span>*</span><span>"</span><span>],</span> <span>allow_methods</span><span>=</span><span>[</span><span>"</span><span>*</span><span>"</span><span>],</span> <span>allow_headers</span><span>=</span><span>[</span><span>"</span><span>*</span><span>"</span><span>],)</span> <span>app</span><span>.</span><span>mount</span><span>(</span><span>"</span><span>/static</span><span>"</span><span>,</span> <span>StaticFiles</span><span>(</span><span>directory</span><span>=</span><span>"</span><span>static</span><span>"</span><span>),</span> <span>name</span><span>=</span><span>"</span><span>static</span><span>"</span><span>)</span> <span>templates</span> <span>=</span> <span>Jinja2Templates</span><span>(</span><span>directory</span><span>=</span><span>"</span><span>templates</span><span>"</span><span>)</span>
app = FastAPI() app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"],) app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates")
-
Initialize the Dynamsoft Barcode Reader SDK:
<span>license_key</span> <span>=</span> <span>"</span><span>YOUR_LICENSE_KEY</span><span>"</span><span>LicenseManager</span><span>.</span><span>init_license</span><span>(</span><span>license_key</span><span>)</span><span>cvr_instance</span> <span>=</span> <span>CaptureVisionRouter</span><span>()</span><span>license_key</span> <span>=</span> <span>"</span><span>YOUR_LICENSE_KEY</span><span>"</span> <span>LicenseManager</span><span>.</span><span>init_license</span><span>(</span><span>license_key</span><span>)</span> <span>cvr_instance</span> <span>=</span> <span>CaptureVisionRouter</span><span>()</span>
license_key = "YOUR_LICENSE_KEY" LicenseManager.init_license(license_key) cvr_instance = CaptureVisionRouter()
-
Define the FastAPI routes:
<span>@app.get</span><span>(</span><span>"</span><span>/</span><span>"</span><span>)</span><span>async</span> <span>def</span> <span>upload_page</span><span>(</span><span>request</span><span>:</span> <span>Request</span><span>):</span><span>return</span> <span>templates</span><span>.</span><span>TemplateResponse</span><span>(</span><span>"</span><span>index.html</span><span>"</span><span>,</span> <span>{</span><span>"</span><span>request</span><span>"</span><span>:</span> <span>request</span><span>})</span><span>@app.post</span><span>(</span><span>"</span><span>/scan</span><span>"</span><span>)</span><span>async</span> <span>def</span> <span>scan_barcode</span><span>(</span><span>file</span><span>:</span> <span>UploadFile</span> <span>=</span> <span>File</span><span>(...)):</span><span>try</span><span>:</span><span>image_data</span> <span>=</span> <span>await</span> <span>file</span><span>.</span><span>read</span><span>()</span><span>result</span> <span>=</span> <span>cvr_instance</span><span>.</span><span>capture</span><span>(</span><span>image_data</span><span>,</span> <span>EnumPresetTemplate</span><span>.</span><span>PT_READ_BARCODES</span><span>.</span><span>value</span><span>)</span><span>if</span> <span>result</span><span>.</span><span>get_error_code</span><span>()</span> <span>!=</span> <span>EnumErrorCode</span><span>.</span><span>EC_OK</span><span>:</span><span>return</span> <span>JSONResponse</span><span>({</span><span>"</span><span>success</span><span>"</span><span>:</span> <span>False</span><span>,</span> <span>"</span><span>error</span><span>"</span><span>:</span> <span>"</span><span>No barcode detected</span><span>"</span><span>},</span> <span>status_code</span><span>=</span><span>400</span><span>)</span><span>items</span> <span>=</span> <span>result</span><span>.</span><span>get_items</span><span>()</span><span>return_items</span> <span>=</span> <span>[]</span><span>for</span> <span>item</span> <span>in</span> <span>items</span><span>:</span><span>location</span> <span>=</span> <span>item</span><span>.</span><span>get_location</span><span>()</span><span>return_items</span><span>.</span><span>append</span><span>({</span><span>"</span><span>format</span><span>"</span><span>:</span> <span>item</span><span>.</span><span>get_format_string</span><span>(),</span><span>"</span><span>text</span><span>"</span><span>:</span> <span>item</span><span>.</span><span>get_text</span><span>(),</span><span>"</span><span>location</span><span>"</span><span>:</span> <span>{</span><span>"</span><span>x1</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>0</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y1</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>0</span><span>].</span><span>y</span><span>,</span><span>"</span><span>x2</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>1</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y2</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>1</span><span>].</span><span>y</span><span>,</span><span>"</span><span>x3</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>2</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y3</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>2</span><span>].</span><span>y</span><span>,</span><span>"</span><span>x4</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>3</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y4</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>3</span><span>].</span><span>y</span><span>,</span><span>}</span><span>})</span><span>return</span> <span>{</span><span>"</span><span>success</span><span>"</span><span>:</span> <span>True</span><span>,</span> <span>"</span><span>count</span><span>"</span><span>:</span> <span>len</span><span>(</span><span>items</span><span>),</span> <span>"</span><span>items</span><span>"</span><span>:</span> <span>return_items</span><span>}</span><span>except</span> <span>Exception</span> <span>as</span> <span>e</span><span>:</span><span>return</span> <span>JSONResponse</span><span>({</span><span>"</span><span>success</span><span>"</span><span>:</span> <span>False</span><span>,</span> <span>"</span><span>error</span><span>"</span><span>:</span> <span>str</span><span>(</span><span>e</span><span>)},</span> <span>status_code</span><span>=</span><span>500</span><span>)</span><span>@app.get</span><span>(</span><span>"</span><span>/</span><span>"</span><span>)</span> <span>async</span> <span>def</span> <span>upload_page</span><span>(</span><span>request</span><span>:</span> <span>Request</span><span>):</span> <span>return</span> <span>templates</span><span>.</span><span>TemplateResponse</span><span>(</span><span>"</span><span>index.html</span><span>"</span><span>,</span> <span>{</span><span>"</span><span>request</span><span>"</span><span>:</span> <span>request</span><span>})</span> <span>@app.post</span><span>(</span><span>"</span><span>/scan</span><span>"</span><span>)</span> <span>async</span> <span>def</span> <span>scan_barcode</span><span>(</span><span>file</span><span>:</span> <span>UploadFile</span> <span>=</span> <span>File</span><span>(...)):</span> <span>try</span><span>:</span> <span>image_data</span> <span>=</span> <span>await</span> <span>file</span><span>.</span><span>read</span><span>()</span> <span>result</span> <span>=</span> <span>cvr_instance</span><span>.</span><span>capture</span><span>(</span><span>image_data</span><span>,</span> <span>EnumPresetTemplate</span><span>.</span><span>PT_READ_BARCODES</span><span>.</span><span>value</span><span>)</span> <span>if</span> <span>result</span><span>.</span><span>get_error_code</span><span>()</span> <span>!=</span> <span>EnumErrorCode</span><span>.</span><span>EC_OK</span><span>:</span> <span>return</span> <span>JSONResponse</span><span>({</span><span>"</span><span>success</span><span>"</span><span>:</span> <span>False</span><span>,</span> <span>"</span><span>error</span><span>"</span><span>:</span> <span>"</span><span>No barcode detected</span><span>"</span><span>},</span> <span>status_code</span><span>=</span><span>400</span><span>)</span> <span>items</span> <span>=</span> <span>result</span><span>.</span><span>get_items</span><span>()</span> <span>return_items</span> <span>=</span> <span>[]</span> <span>for</span> <span>item</span> <span>in</span> <span>items</span><span>:</span> <span>location</span> <span>=</span> <span>item</span><span>.</span><span>get_location</span><span>()</span> <span>return_items</span><span>.</span><span>append</span><span>({</span> <span>"</span><span>format</span><span>"</span><span>:</span> <span>item</span><span>.</span><span>get_format_string</span><span>(),</span> <span>"</span><span>text</span><span>"</span><span>:</span> <span>item</span><span>.</span><span>get_text</span><span>(),</span> <span>"</span><span>location</span><span>"</span><span>:</span> <span>{</span> <span>"</span><span>x1</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>0</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y1</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>0</span><span>].</span><span>y</span><span>,</span> <span>"</span><span>x2</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>1</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y2</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>1</span><span>].</span><span>y</span><span>,</span> <span>"</span><span>x3</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>2</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y3</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>2</span><span>].</span><span>y</span><span>,</span> <span>"</span><span>x4</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>3</span><span>].</span><span>x</span><span>,</span> <span>"</span><span>y4</span><span>"</span><span>:</span> <span>location</span><span>.</span><span>points</span><span>[</span><span>3</span><span>].</span><span>y</span><span>,</span> <span>}</span> <span>})</span> <span>return</span> <span>{</span><span>"</span><span>success</span><span>"</span><span>:</span> <span>True</span><span>,</span> <span>"</span><span>count</span><span>"</span><span>:</span> <span>len</span><span>(</span><span>items</span><span>),</span> <span>"</span><span>items</span><span>"</span><span>:</span> <span>return_items</span><span>}</span> <span>except</span> <span>Exception</span> <span>as</span> <span>e</span><span>:</span> <span>return</span> <span>JSONResponse</span><span>({</span><span>"</span><span>success</span><span>"</span><span>:</span> <span>False</span><span>,</span> <span>"</span><span>error</span><span>"</span><span>:</span> <span>str</span><span>(</span><span>e</span><span>)},</span> <span>status_code</span><span>=</span><span>500</span><span>)</span>
@app.get("/") async def upload_page(request: Request): return templates.TemplateResponse("index.html", {"request": request}) @app.post("/scan") async def scan_barcode(file: UploadFile = File(...)): try: image_data = await file.read() result = cvr_instance.capture(image_data, EnumPresetTemplate.PT_READ_BARCODES.value) if result.get_error_code() != EnumErrorCode.EC_OK: return JSONResponse({"success": False, "error": "No barcode detected"}, status_code=400) items = result.get_items() return_items = [] for item in items: location = item.get_location() return_items.append({ "format": item.get_format_string(), "text": item.get_text(), "location": { "x1": location.points[0].x, "y1": location.points[0].y, "x2": location.points[1].x, "y2": location.points[1].y, "x3": location.points[2].x, "y3": location.points[2].y, "x4": location.points[3].x, "y4": location.points[3].y, } }) return {"success": True, "count": len(items), "items": return_items} except Exception as e: return JSONResponse({"success": False, "error": str(e)}, status_code=500)
Explanation
- The
/
route serves the HTML page for uploading images. - The
/scan
route handles the image upload and barcode scanning. It reads the uploaded image, processes it using the Dynamsoft Barcode Reader SDK, and returns the barcode results in JSON format.
- The
-
Import
uvicorn
and run the FastAPI application in the main block:<span>if</span> <span>__name__</span> <span>==</span> <span>"</span><span>__main__</span><span>"</span><span>:</span><span>import</span> <span>uvicorn</span><span>uvicorn</span><span>.</span><span>run</span><span>(</span><span>app</span><span>,</span> <span>host</span><span>=</span><span>"</span><span>0.0.0.0</span><span>"</span><span>,</span> <span>port</span><span>=</span><span>8000</span><span>)</span><span>if</span> <span>__name__</span> <span>==</span> <span>"</span><span>__main__</span><span>"</span><span>:</span> <span>import</span> <span>uvicorn</span> <span>uvicorn</span><span>.</span><span>run</span><span>(</span><span>app</span><span>,</span> <span>host</span><span>=</span><span>"</span><span>0.0.0.0</span><span>"</span><span>,</span> <span>port</span><span>=</span><span>8000</span><span>)</span>
if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
Step 3: Create the Frontend
The index.html
file includes a file input for uploading images and triggering the barcode scanning, an img element to preview the uploaded image, a canvas element for drawing the barcode locations, and a section to display the results.
<span><!DOCTYPE html></span><span><html></span><span><head></span><span><title></span>Barcode Scanner<span></title></span><span><link</span> <span>rel=</span><span>"stylesheet"</span> <span>href=</span><span>"/static/style.css"</span><span>></span><span></head></span><span><body></span><span><div</span> <span>class=</span><span>"container"</span><span>></span><span><h1></span>Upload Barcode Image<span></h1></span><span><input</span> <span>type=</span><span>"file"</span> <span>id=</span><span>"fileInput"</span> <span>accept=</span><span>"image/*"</span> <span>capture=</span><span>"camera"</span><span>></span><span><div</span> <span>id=</span><span>"imageview"</span><span>></span><span><img</span> <span>id=</span><span>"preview"</span><span>></span><span><canvas</span> <span>id=</span><span>"overlay"</span><span>></canvas></span><span></div></span><span><div</span> <span>class=</span><span>"progress"</span> <span>id=</span><span>"progress"</span><span>></span>Processing...<span></div></span><span><div</span> <span>id=</span><span>"result"</span><span>></div></span><span></div></span><span><script </span><span>src=</span><span>"/static/script.js"</span><span>></script></span><span></body></span><span></html></span><span><!DOCTYPE html></span> <span><html></span> <span><head></span> <span><title></span>Barcode Scanner<span></title></span> <span><link</span> <span>rel=</span><span>"stylesheet"</span> <span>href=</span><span>"/static/style.css"</span><span>></span> <span></head></span> <span><body></span> <span><div</span> <span>class=</span><span>"container"</span><span>></span> <span><h1></span>Upload Barcode Image<span></h1></span> <span><input</span> <span>type=</span><span>"file"</span> <span>id=</span><span>"fileInput"</span> <span>accept=</span><span>"image/*"</span> <span>capture=</span><span>"camera"</span><span>></span> <span><div</span> <span>id=</span><span>"imageview"</span><span>></span> <span><img</span> <span>id=</span><span>"preview"</span><span>></span> <span><canvas</span> <span>id=</span><span>"overlay"</span><span>></canvas></span> <span></div></span> <span><div</span> <span>class=</span><span>"progress"</span> <span>id=</span><span>"progress"</span><span>></span>Processing...<span></div></span> <span><div</span> <span>id=</span><span>"result"</span><span>></div></span> <span></div></span> <span><script </span><span>src=</span><span>"/static/script.js"</span><span>></script></span> <span></body></span> <span></html></span><!DOCTYPE html> <html> <head> <title>Barcode Scanner</title> <link rel="stylesheet" href="/static/style.css"> </head> <body> <div class="container"> <h1>Upload Barcode Image</h1> <input type="file" id="fileInput" accept="image/*" capture="camera"> <div id="imageview"> <img id="preview"> <canvas id="overlay"></canvas> </div> <div class="progress" id="progress">Processing...</div> <div id="result"></div> </div> <script src="/static/script.js"></script> </body> </html>
Enter fullscreen mode Exit fullscreen mode
The style.css
file contains the CSS styles for the web page, including styles for the container, image preview and canvas overlay.
<span>.container</span> <span>{</span><span>max-width</span><span>:</span> <span>600px</span><span>;</span><span>margin</span><span>:</span> <span>2rem</span> <span>auto</span><span>;</span><span>padding</span><span>:</span> <span>2rem</span><span>;</span><span>}</span><span>#imageview</span> <span>{</span><span>position</span><span>:</span> <span>relative</span><span>;</span><span>display</span><span>:</span> <span>block</span><span>;</span><span>width</span><span>:</span> <span>100%</span><span>;</span><span>max-width</span><span>:</span> <span>80%</span><span>;</span><span>}</span><span>#imageview</span> <span>img</span> <span>{</span><span>width</span><span>:</span> <span>100%</span><span>;</span><span>height</span><span>:</span> <span>auto</span><span>;</span><span>object-fit</span><span>:</span> <span>contain</span><span>;</span><span>display</span><span>:</span> <span>block</span><span>;</span><span>}</span><span>#overlay</span> <span>{</span><span>position</span><span>:</span> <span>absolute</span><span>;</span><span>top</span><span>:</span> <span>0</span><span>;</span><span>left</span><span>:</span> <span>0</span><span>;</span><span>pointer-events</span><span>:</span> <span>none</span><span>;</span><span>width</span><span>:</span> <span>100%</span><span>;</span><span>height</span><span>:</span> <span>100%</span><span>;</span><span>}</span><span>.container</span> <span>{</span> <span>max-width</span><span>:</span> <span>600px</span><span>;</span> <span>margin</span><span>:</span> <span>2rem</span> <span>auto</span><span>;</span> <span>padding</span><span>:</span> <span>2rem</span><span>;</span> <span>}</span> <span>#imageview</span> <span>{</span> <span>position</span><span>:</span> <span>relative</span><span>;</span> <span>display</span><span>:</span> <span>block</span><span>;</span> <span>width</span><span>:</span> <span>100%</span><span>;</span> <span>max-width</span><span>:</span> <span>80%</span><span>;</span> <span>}</span> <span>#imageview</span> <span>img</span> <span>{</span> <span>width</span><span>:</span> <span>100%</span><span>;</span> <span>height</span><span>:</span> <span>auto</span><span>;</span> <span>object-fit</span><span>:</span> <span>contain</span><span>;</span> <span>display</span><span>:</span> <span>block</span><span>;</span> <span>}</span> <span>#overlay</span> <span>{</span> <span>position</span><span>:</span> <span>absolute</span><span>;</span> <span>top</span><span>:</span> <span>0</span><span>;</span> <span>left</span><span>:</span> <span>0</span><span>;</span> <span>pointer-events</span><span>:</span> <span>none</span><span>;</span> <span>width</span><span>:</span> <span>100%</span><span>;</span> <span>height</span><span>:</span> <span>100%</span><span>;</span> <span>}</span>.container { max-width: 600px; margin: 2rem auto; padding: 2rem; } #imageview { position: relative; display: block; width: 100%; max-width: 80%; } #imageview img { width: 100%; height: auto; object-fit: contain; display: block; } #overlay { position: absolute; top: 0; left: 0; pointer-events: none; width: 100%; height: 100%; }
Enter fullscreen mode Exit fullscreen mode
The script.js
file contains the JavaScript code that handles image uploads, receives barcode results, and draws the barcode locations on the canvas.
<span>const</span> <span>fileInput</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>fileInput</span><span>'</span><span>);</span><span>const</span> <span>preview</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>preview</span><span>'</span><span>);</span><span>const</span> <span>overlay</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>overlay</span><span>'</span><span>);</span><span>const</span> <span>progress</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>progress</span><span>'</span><span>);</span><span>const</span> <span>resultDiv</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>result</span><span>'</span><span>);</span><span>fileInput</span><span>.</span><span>addEventListener</span><span>(</span><span>'</span><span>change</span><span>'</span><span>,</span> <span>async </span><span>(</span><span>e</span><span>)</span> <span>=></span> <span>{</span><span>const</span> <span>file</span> <span>=</span> <span>e</span><span>.</span><span>target</span><span>.</span><span>files</span><span>[</span><span>0</span><span>];</span><span>if </span><span>(</span><span>!</span><span>file</span><span>)</span> <span>return</span><span>;</span><span>const</span> <span>imageURL</span> <span>=</span> <span>URL</span><span>.</span><span>createObjectURL</span><span>(</span><span>file</span><span>);</span><span>preview</span><span>.</span><span>src</span> <span>=</span> <span>imageURL</span><span>;</span><span>preview</span><span>.</span><span>onload</span> <span>=</span> <span>async </span><span>()</span> <span>=></span> <span>{</span><span>overlay</span><span>.</span><span>width</span> <span>=</span> <span>preview</span><span>.</span><span>naturalWidth</span><span>;</span><span>overlay</span><span>.</span><span>height</span> <span>=</span> <span>preview</span><span>.</span><span>naturalHeight</span><span>;</span><span>const</span> <span>formData</span> <span>=</span> <span>new</span> <span>FormData</span><span>();</span><span>formData</span><span>.</span><span>append</span><span>(</span><span>'</span><span>file</span><span>'</span><span>,</span> <span>file</span><span>);</span><span>progress</span><span>.</span><span>style</span><span>.</span><span>display</span> <span>=</span> <span>'</span><span>block</span><span>'</span><span>;</span><span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>''</span><span>;</span><span>const</span> <span>ctx</span> <span>=</span> <span>overlay</span><span>.</span><span>getContext</span><span>(</span><span>'</span><span>2d</span><span>'</span><span>);</span><span>ctx</span><span>.</span><span>clearRect</span><span>(</span><span>0</span><span>,</span> <span>0</span><span>,</span> <span>overlay</span><span>.</span><span>width</span><span>,</span> <span>overlay</span><span>.</span><span>height</span><span>);</span><span>try</span> <span>{</span><span>const</span> <span>response</span> <span>=</span> <span>await</span> <span>fetch</span><span>(</span><span>'</span><span>/scan</span><span>'</span><span>,</span> <span>{</span><span>method</span><span>:</span> <span>'</span><span>POST</span><span>'</span><span>,</span><span>body</span><span>:</span> <span>formData</span><span>});</span><span>const</span> <span>data</span> <span>=</span> <span>await</span> <span>response</span><span>.</span><span>json</span><span>();</span><span>if </span><span>(</span><span>data</span><span>.</span><span>success</span><span>)</span> <span>{</span><span>let</span> <span>resultHTML</span> <span>=</span> <span>`<h3>Found </span><span>${</span><span>data</span><span>.</span><span>count</span><span>}</span><span> barcode(s)</h3><div class="results-container">`</span><span>;</span><span>data</span><span>.</span><span>items</span><span>.</span><span>forEach</span><span>((</span><span>item</span><span>,</span> <span>index</span><span>)</span> <span>=></span> <span>{</span><span>const</span> <span>loc</span> <span>=</span> <span>item</span><span>.</span><span>location</span><span>;</span><span>const</span> <span>x1</span> <span>=</span> <span>loc</span><span>.</span><span>x1</span><span>;</span><span>const</span> <span>y1</span> <span>=</span> <span>loc</span><span>.</span><span>y1</span><span>;</span><span>const</span> <span>x2</span> <span>=</span> <span>loc</span><span>.</span><span>x2</span><span>;</span><span>const</span> <span>y2</span> <span>=</span> <span>loc</span><span>.</span><span>y2</span><span>;</span><span>const</span> <span>x3</span> <span>=</span> <span>loc</span><span>.</span><span>x3</span><span>;</span><span>const</span> <span>y3</span> <span>=</span> <span>loc</span><span>.</span><span>y3</span><span>;</span><span>const</span> <span>x4</span> <span>=</span> <span>loc</span><span>.</span><span>x4</span><span>;</span><span>const</span> <span>y4</span> <span>=</span> <span>loc</span><span>.</span><span>y4</span><span>;</span><span>ctx</span><span>.</span><span>beginPath</span><span>();</span><span>ctx</span><span>.</span><span>moveTo</span><span>(</span><span>x1</span><span>,</span> <span>y1</span><span>);</span><span>ctx</span><span>.</span><span>lineTo</span><span>(</span><span>x2</span><span>,</span> <span>y2</span><span>);</span><span>ctx</span><span>.</span><span>lineTo</span><span>(</span><span>x3</span><span>,</span> <span>y3</span><span>);</span><span>ctx</span><span>.</span><span>lineTo</span><span>(</span><span>x4</span><span>,</span> <span>y4</span><span>);</span><span>ctx</span><span>.</span><span>closePath</span><span>();</span><span>ctx</span><span>.</span><span>lineWidth</span> <span>=</span> <span>2</span><span>;</span><span>ctx</span><span>.</span><span>strokeStyle</span> <span>=</span> <span>'</span><span>red</span><span>'</span><span>;</span><span>ctx</span><span>.</span><span>stroke</span><span>();</span><span>ctx</span><span>.</span><span>font</span> <span>=</span> <span>'</span><span>16px Arial</span><span>'</span><span>;</span><span>ctx</span><span>.</span><span>fillStyle</span> <span>=</span> <span>'</span><span>blue</span><span>'</span><span>;</span><span>ctx</span><span>.</span><span>fillText</span><span>(</span><span>item</span><span>.</span><span>text</span><span>,</span> <span>x1</span> <span>+</span> <span>5</span><span>,</span> <span>y1</span> <span>-</span> <span>5</span><span>);</span><span>resultHTML</span> <span>+=</span> <span>` <div class="barcode-result"> <h4>Barcode #</span><span>${</span><span>index</span> <span>+</span> <span>1</span><span>}</span><span></h4> <p><strong>Type:</strong> </span><span>${</span><span>item</span><span>.</span><span>format</span><span>}</span><span></p> <p><strong>Content:</strong> </span><span>${</span><span>item</span><span>.</span><span>text</span><span>}</span><span></p> </div> `</span><span>;</span><span>});</span><span>resultHTML</span> <span>+=</span> <span>`</div>`</span><span>;</span><span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>resultHTML</span><span>;</span><span>}</span> <span>else</span> <span>{</span><span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>`Error: </span><span>${</span><span>data</span><span>.</span><span>error</span><span>}</span><span>`</span><span>;</span><span>}</span><span>}</span> <span>catch </span><span>(</span><span>err</span><span>)</span> <span>{</span><span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>'</span><span>Request failed</span><span>'</span><span>;</span><span>}</span> <span>finally</span> <span>{</span><span>progress</span><span>.</span><span>style</span><span>.</span><span>display</span> <span>=</span> <span>'</span><span>none</span><span>'</span><span>;</span><span>}</span><span>};</span><span>});</span><span>const</span> <span>fileInput</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>fileInput</span><span>'</span><span>);</span> <span>const</span> <span>preview</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>preview</span><span>'</span><span>);</span> <span>const</span> <span>overlay</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>overlay</span><span>'</span><span>);</span> <span>const</span> <span>progress</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>progress</span><span>'</span><span>);</span> <span>const</span> <span>resultDiv</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>'</span><span>result</span><span>'</span><span>);</span> <span>fileInput</span><span>.</span><span>addEventListener</span><span>(</span><span>'</span><span>change</span><span>'</span><span>,</span> <span>async </span><span>(</span><span>e</span><span>)</span> <span>=></span> <span>{</span> <span>const</span> <span>file</span> <span>=</span> <span>e</span><span>.</span><span>target</span><span>.</span><span>files</span><span>[</span><span>0</span><span>];</span> <span>if </span><span>(</span><span>!</span><span>file</span><span>)</span> <span>return</span><span>;</span> <span>const</span> <span>imageURL</span> <span>=</span> <span>URL</span><span>.</span><span>createObjectURL</span><span>(</span><span>file</span><span>);</span> <span>preview</span><span>.</span><span>src</span> <span>=</span> <span>imageURL</span><span>;</span> <span>preview</span><span>.</span><span>onload</span> <span>=</span> <span>async </span><span>()</span> <span>=></span> <span>{</span> <span>overlay</span><span>.</span><span>width</span> <span>=</span> <span>preview</span><span>.</span><span>naturalWidth</span><span>;</span> <span>overlay</span><span>.</span><span>height</span> <span>=</span> <span>preview</span><span>.</span><span>naturalHeight</span><span>;</span> <span>const</span> <span>formData</span> <span>=</span> <span>new</span> <span>FormData</span><span>();</span> <span>formData</span><span>.</span><span>append</span><span>(</span><span>'</span><span>file</span><span>'</span><span>,</span> <span>file</span><span>);</span> <span>progress</span><span>.</span><span>style</span><span>.</span><span>display</span> <span>=</span> <span>'</span><span>block</span><span>'</span><span>;</span> <span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>''</span><span>;</span> <span>const</span> <span>ctx</span> <span>=</span> <span>overlay</span><span>.</span><span>getContext</span><span>(</span><span>'</span><span>2d</span><span>'</span><span>);</span> <span>ctx</span><span>.</span><span>clearRect</span><span>(</span><span>0</span><span>,</span> <span>0</span><span>,</span> <span>overlay</span><span>.</span><span>width</span><span>,</span> <span>overlay</span><span>.</span><span>height</span><span>);</span> <span>try</span> <span>{</span> <span>const</span> <span>response</span> <span>=</span> <span>await</span> <span>fetch</span><span>(</span><span>'</span><span>/scan</span><span>'</span><span>,</span> <span>{</span> <span>method</span><span>:</span> <span>'</span><span>POST</span><span>'</span><span>,</span> <span>body</span><span>:</span> <span>formData</span> <span>});</span> <span>const</span> <span>data</span> <span>=</span> <span>await</span> <span>response</span><span>.</span><span>json</span><span>();</span> <span>if </span><span>(</span><span>data</span><span>.</span><span>success</span><span>)</span> <span>{</span> <span>let</span> <span>resultHTML</span> <span>=</span> <span>`<h3>Found </span><span>${</span><span>data</span><span>.</span><span>count</span><span>}</span><span> barcode(s)</h3><div class="results-container">`</span><span>;</span> <span>data</span><span>.</span><span>items</span><span>.</span><span>forEach</span><span>((</span><span>item</span><span>,</span> <span>index</span><span>)</span> <span>=></span> <span>{</span> <span>const</span> <span>loc</span> <span>=</span> <span>item</span><span>.</span><span>location</span><span>;</span> <span>const</span> <span>x1</span> <span>=</span> <span>loc</span><span>.</span><span>x1</span><span>;</span> <span>const</span> <span>y1</span> <span>=</span> <span>loc</span><span>.</span><span>y1</span><span>;</span> <span>const</span> <span>x2</span> <span>=</span> <span>loc</span><span>.</span><span>x2</span><span>;</span> <span>const</span> <span>y2</span> <span>=</span> <span>loc</span><span>.</span><span>y2</span><span>;</span> <span>const</span> <span>x3</span> <span>=</span> <span>loc</span><span>.</span><span>x3</span><span>;</span> <span>const</span> <span>y3</span> <span>=</span> <span>loc</span><span>.</span><span>y3</span><span>;</span> <span>const</span> <span>x4</span> <span>=</span> <span>loc</span><span>.</span><span>x4</span><span>;</span> <span>const</span> <span>y4</span> <span>=</span> <span>loc</span><span>.</span><span>y4</span><span>;</span> <span>ctx</span><span>.</span><span>beginPath</span><span>();</span> <span>ctx</span><span>.</span><span>moveTo</span><span>(</span><span>x1</span><span>,</span> <span>y1</span><span>);</span> <span>ctx</span><span>.</span><span>lineTo</span><span>(</span><span>x2</span><span>,</span> <span>y2</span><span>);</span> <span>ctx</span><span>.</span><span>lineTo</span><span>(</span><span>x3</span><span>,</span> <span>y3</span><span>);</span> <span>ctx</span><span>.</span><span>lineTo</span><span>(</span><span>x4</span><span>,</span> <span>y4</span><span>);</span> <span>ctx</span><span>.</span><span>closePath</span><span>();</span> <span>ctx</span><span>.</span><span>lineWidth</span> <span>=</span> <span>2</span><span>;</span> <span>ctx</span><span>.</span><span>strokeStyle</span> <span>=</span> <span>'</span><span>red</span><span>'</span><span>;</span> <span>ctx</span><span>.</span><span>stroke</span><span>();</span> <span>ctx</span><span>.</span><span>font</span> <span>=</span> <span>'</span><span>16px Arial</span><span>'</span><span>;</span> <span>ctx</span><span>.</span><span>fillStyle</span> <span>=</span> <span>'</span><span>blue</span><span>'</span><span>;</span> <span>ctx</span><span>.</span><span>fillText</span><span>(</span><span>item</span><span>.</span><span>text</span><span>,</span> <span>x1</span> <span>+</span> <span>5</span><span>,</span> <span>y1</span> <span>-</span> <span>5</span><span>);</span> <span>resultHTML</span> <span>+=</span> <span>` <div class="barcode-result"> <h4>Barcode #</span><span>${</span><span>index</span> <span>+</span> <span>1</span><span>}</span><span></h4> <p><strong>Type:</strong> </span><span>${</span><span>item</span><span>.</span><span>format</span><span>}</span><span></p> <p><strong>Content:</strong> </span><span>${</span><span>item</span><span>.</span><span>text</span><span>}</span><span></p> </div> `</span><span>;</span> <span>});</span> <span>resultHTML</span> <span>+=</span> <span>`</div>`</span><span>;</span> <span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>resultHTML</span><span>;</span> <span>}</span> <span>else</span> <span>{</span> <span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>`Error: </span><span>${</span><span>data</span><span>.</span><span>error</span><span>}</span><span>`</span><span>;</span> <span>}</span> <span>}</span> <span>catch </span><span>(</span><span>err</span><span>)</span> <span>{</span> <span>resultDiv</span><span>.</span><span>innerHTML</span> <span>=</span> <span>'</span><span>Request failed</span><span>'</span><span>;</span> <span>}</span> <span>finally</span> <span>{</span> <span>progress</span><span>.</span><span>style</span><span>.</span><span>display</span> <span>=</span> <span>'</span><span>none</span><span>'</span><span>;</span> <span>}</span> <span>};</span> <span>});</span>const fileInput = document.getElementById('fileInput'); const preview = document.getElementById('preview'); const overlay = document.getElementById('overlay'); const progress = document.getElementById('progress'); const resultDiv = document.getElementById('result'); fileInput.addEventListener('change', async (e) => { const file = e.target.files[0]; if (!file) return; const imageURL = URL.createObjectURL(file); preview.src = imageURL; preview.onload = async () => { overlay.width = preview.naturalWidth; overlay.height = preview.naturalHeight; const formData = new FormData(); formData.append('file', file); progress.style.display = 'block'; resultDiv.innerHTML = ''; const ctx = overlay.getContext('2d'); ctx.clearRect(0, 0, overlay.width, overlay.height); try { const response = await fetch('/scan', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { let resultHTML = `<h3>Found ${data.count} barcode(s)</h3><div class="results-container">`; data.items.forEach((item, index) => { const loc = item.location; const x1 = loc.x1; const y1 = loc.y1; const x2 = loc.x2; const y2 = loc.y2; const x3 = loc.x3; const y3 = loc.y3; const x4 = loc.x4; const y4 = loc.y4; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.lineTo(x3, y3); ctx.lineTo(x4, y4); ctx.closePath(); ctx.lineWidth = 2; ctx.strokeStyle = 'red'; ctx.stroke(); ctx.font = '16px Arial'; ctx.fillStyle = 'blue'; ctx.fillText(item.text, x1 + 5, y1 - 5); resultHTML += ` <div class="barcode-result"> <h4>Barcode #${index + 1}</h4> <p><strong>Type:</strong> ${item.format}</p> <p><strong>Content:</strong> ${item.text}</p> </div> `; }); resultHTML += `</div>`; resultDiv.innerHTML = resultHTML; } else { resultDiv.innerHTML = `Error: ${data.error}`; } } catch (err) { resultDiv.innerHTML = 'Request failed'; } finally { progress.style.display = 'none'; } }; });
Enter fullscreen mode Exit fullscreen mode
Step 4: Run the Web Barcode Reader Application
-
In your terminal, navigate to the project directory and run:
python backend.pypython backend.py
python backend.py
-
Open your browser and visit
http://localhost:8000
.
Source Code
https://github.com/yushulx/python-barcode-qrcode-sdk/tree/main/examples/official/fastapi
原文链接:How to Build a Web Barcode Reader with Python, FastAPI and HTML5
暂无评论内容