Go's native support for concurrency is one of its standout features, making it an excellent choice for building web servers capable of handling multiple requests simultaneously and efficiently. In this article, we'll guide you through the creation of a web application designed to decode multiple barcode images uploaded by users. The barcode detection logic will be implemented on the web server side using Go, while the client-side application will handle image picking, file uploading, and result display.
Prerequisites
HTML & JavaScript for Image Picking, Uploading, and Displaying Results
The user interface (UI) for the web application includes an input element, a button element, an image element, a canvas element, and a textarea element.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Dynamsoft Vision SDKs</title>
</head>
<body>
<h1>1D/2D Barcode Reader</h1>
<div id="loading-indicator" class="loading-indicator">
<div class="spinner"></div>
</div>
<div class="container" id="file_container">
<div>
<input type="file" id="pick_file" accept="image/*" />
<button onclick="detect()">Detect</button>
</div>
<div class="row">
<div class="imageview">
<img id="image_file" src="default.png" />
<canvas id="overlay_canvas" class="overlay"></canvas>
</div>
</div>
<div class="row">
<div>
<textarea id="detection_result"></textarea>
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
- The input element allows users to select an image file.
- The image element displays the selected image file.
- The button element initiates the upload of the image to the server for barcode detection.
- The canvas element is utilized to draw the contours of the detected barcode.
- The textarea element presents the decoded barcode data.
Picking an Image File from the File System and Clipboard
We utilize an Image
element to load the selected image file and initialize a canvas element to match the size of the image.
let imageFile = document.getElementById('image_file');
let overlayCanvas = document.getElementById('overlay_canvas');
let img = new Image();
function loadImage2Canvas(base64Image) {
imageFile.src = base64Image;
img.src = base64Image;
img.onload = function () {
let width = img.width;
let height = img.height;
overlayCanvas.width = width;
overlayCanvas.height = height;
detect();
};
}
There are three methods provided for users to add an image to the image element:
-
Clicking the input element to select an image file.
document.getElementById("pick_file").addEventListener("change", function () { let currentFile = this.files[0]; if (currentFile == null) { return; } var fr = new FileReader(); fr.onload = function () { loadImage2Canvas(fr.result); } fr.readAsDataURL(currentFile); });
-
Listening for the drag-and-drop event to load an image file.
let overlayCanvas = document.getElementById('overlay_canvas'); overlayCanvas.addEventListener('dragover', function (event) { event.preventDefault(); event.dataTransfer.dropEffect = 'copy'; }, false); overlayCanvas.addEventListener('drop', function (event) { event.preventDefault(); if (event.dataTransfer.files.length > 0) { let file = event.dataTransfer.files[0]; if (file.type.match('image.*')) { let reader = new FileReader(); reader.onload = function (e) { loadImage2Canvas(e.target.result); }; reader.readAsDataURL(file); } else { alert("Please drop an image file."); } } }, false);
-
Copying and pasting an image from the clipboard.
document.addEventListener('paste', (event) => { const items = (event.clipboardData || event.originalEvent.clipboardData).items; for (index in items) { const item = items[index]; if (item.kind === 'file') { const blob = item.getAsFile(); const reader = new FileReader(); reader.onload = (event) => { loadImage2Canvas(event.target.result); }; reader.readAsDataURL(blob); } } });
Uploading an Image File as a Base64 String
When the user clicks the "Detect
" button, the image file is uploaded to the server as a base64 string using the Fetch API
.
const base64Image = img.src;
const requestBody = {
image: base64Image
};
const response = await fetch('/upload', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
Displaying the Decoded Barcode Data
The server returns the decoded barcode data as a JSON object. The client-side application first parses the JSON object, then draws contours of the detected barcode on the canvas element, and displays the barcode data in the textarea.
const barcodes = await response.json();
detection_result.value = `Found ${barcodes.length} barcode(s)\n`;
barcodes.forEach(barcode => {
detection_result.value += `\nText: ${barcode.Text}, Format: ${barcode.Format}`;
detection_result.value += `\nCoordinates: (${barcode.X1}, ${barcode.Y1}), (${barcode.X2}, ${barcode.Y2}), (${barcode.X3}, ${barcode.Y3}), (${barcode.X4}, ${barcode.Y4})`;
detection_result.value += "\n--------------";
// Draw overlay
context.beginPath();
context.strokeStyle = '#ff0000';
context.lineWidth = 2;
context.moveTo(barcode.X1, barcode.Y1);
context.lineTo(barcode.X2, barcode.Y2);
context.lineTo(barcode.X3, barcode.Y3);
context.lineTo(barcode.X4, barcode.Y4);
context.lineTo(barcode.X1, barcode.Y1);
context.stroke();
context.font = '18px Verdana';
context.fillStyle = '#ff0000';
let x = [barcode.X1, barcode.X2, barcode.X3, barcode.X4];
let y = [barcode.Y1, barcode.Y2, barcode.Y3, barcode.Y4];
x.sort(function (a, b) {
return a - b;
});
y.sort(function (a, b) {
return b - a;
});
let left = x[0];
let top = y[0];
context.fillText(barcode.Text, left, top + 50);
});
Building the Web Server in Go
We utilize Go to host the web server, managing the upload of image files, detecting barcodes, and generating responses.
Serving Static Content
Organize your project's directory structure to include index.html
within the static folder, along with your CSS, JavaScript, and other assets.
/project
/static
styles.css
main.js
index.html
Adjust your server setup to serve all static content using http.FileServer
.
func main() {
fs := http.FileServer(http.Dir("./static"))
http.Handle("/", fs)
...
}
Handling Upload Requests for Barcode Detection
Create an endpoint /upload
to manage the upload of image files. The server extracts the base64-encoded image string from the request body, decodes it, and utilizes the Dynamsoft Barcode Reader SDK to detect barcodes.
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/yushulx/goBarcodeQrSDK"
)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
return
}
var data struct {
Image string `json:"image"` // Field where the base64 image data will be stored
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
http.Error(w, "Error decoding JSON body", http.StatusBadRequest)
return
}
imgData, err := base64.StdEncoding.DecodeString(data.Image[strings.IndexByte(data.Image, ',')+1:])
if err != nil {
http.Error(w, "Error decoding base64 image", http.StatusBadRequest)
return
}
obj := goBarcodeQrSDK.CreateBarcodeReader()
startTime := time.Now()
ret, barcodes := obj.DecodeStream(imgData)
elapsed := time.Since(startTime)
fmt.Println("DecodeStream() time cost: ", elapsed)
if ret != 0 {
fmt.Printf(`DecodeStream() = %d`, ret)
}
defer goBarcodeQrSDK.DestroyBarcodeReader(obj)
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(barcodes); err != nil {
// Handle error
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func main() {
license := "LICENSE-KEY"
ret, errMsg := goBarcodeQrSDK.InitLicense(license)
if ret != 0 {
fmt.Println(`initLicense(): `, ret)
fmt.Println(errMsg)
return
}
fs := http.FileServer(http.Dir("./static"))
http.Handle("/", fs)
http.HandleFunc("/upload", uploadHandler)
log.Println("Listening on :2024...")
http.ListenAndServe(":2024", nil)
}
Ensure to substitute LICENSE-KEY
with your actual Dynamsoft Barcode Reader SDK license key.
Source Code
https://github.com/yushulx/goBarcodeQrSDK/tree/main/example/web