How to Build a Web Barcode Reader with Python, FastAPI and HTML5

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 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.py
Project
├── templates
│   └── index.html
├── static
│   ├── script.js
│   └── style.css
└── backend.py
Project ├── 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-multipart
fastapi uvicorn dynamsoft-capture-vision-bundle python-multipart
fastapi uvicorn dynamsoft-capture-vision-bundle python-multipart

Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up the FastAPI Application

  1. 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 *
  2. 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")
  3. 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()
  4. 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.
  5. 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

  1. In your terminal, navigate to the project directory and run:

    python backend.py
    python backend.py
    python backend.py
  2. 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

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
Every day has not danced, all are life's disappointment.
每一个不曾起舞的日子,都是对生命的辜负
评论 抢沙发

请登录后发表评论

    暂无评论内容