【前端】如何直接选中复制图片中的文字:前端OCR实现指南

如何直接选中复制图片中的文字:前端OCR实现指南

在现代Web开发中,从图片中提取文字是一个常见需求。无论是处理扫描的文档图片,还是用户上传的图片,通过OCR (光学字符识别) 技术,我们可以实现从图像中提取文字的功能。本文将详细介绍如何使用JavaScript(借助Tesseract.js库)从图片中提取,并可供复制的文字。

实现效果参考微信图片的图片文字识别。

第一步:页面布局与样式定义

我们的HTML页面包含基本的文件上传控件、进度条显示、以及用于展示图片和文字覆盖的容器。CSS用于简单设定进度条及图片展示的样式。

html 复制代码
<input type="file" id="upload" accept="image/*">
<div id="progressContainer">
    <div id="progressBar"></div>
</div>
<div id="textOverlays" style="position:relative;">
    <img id="display" src="" alt="Uploaded Image" style="position: absolute;">
    <canvas id="canvas" style="display:none;"></canvas>
</div>

第二步:文件上传与图像预处理

当用户选择文件后,我们通过FileReader对象将上传的图片文件转换为数据URL,然后使用<canvas>元素来对图片进行预处理。预处理的目的是调整图像的亮度阈值,以优化后续的文字识别过程。

javascript 复制代码
document.getElementById('upload').addEventListener('change', function (event) {
    var file = event.target.files[0];
    var reader = new FileReader();
    reader.onload = function (e) {
        var img = new Image();
        img.onload = function () {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext('2d');
            canvas.width = img.width;
            canvas.height = img.height;
            ctx.drawImage(img, 0, 0);
            /* 灰度与二值化过程 */
            var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var data = imageData.data;
            for (var i = 0; i < data.length; i += 4) {
                var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
                var threshold = brightness < 128 ? 0 : 255;
                data[i] = data[i + 1] = data[i + 2] = threshold;
            }
            ctx.putImageData(imageData, 0, 0);
            document.getElementById('display').src = e.target.result;
        };
        img.src = e.target.result;
    };
    reader.readAsDataURL(file);
});

第三步:文字识别与展示

我们使用Tesseract.js库对处理后的图像进行OCR识别。识别过程中,实时更新进度条,并在识别完成后将识别的文字以覆盖在原图上的形式展示。这里我们动态创建<span>元素,绝对定位到原图对应文字的位置。

javascript 复制代码
Tesseract.recognize(
    canvas,
    'chi_sim', // 指定中文简体进行识别
    {
        logger: m => {
            console.log(m);
            if (m.status === 'recognizing text') {
                var progress = Math.floor(m.progress * 100);
                document.getElementById('progressBar').style.width = progress + '%';
            }
        }
    }
).then(({ data: { text, words } }) => {
    for (let word of words) {
        const el = document.createElement("span");
        el.style.position = "absolute";
        el.style.left = `${word.bbox.x0}px`;
        el.style.top = `${word.bbox.y0}px`;
        el.style.color = "red";
        el.style.fontSize = `${word.font_size}px`;
        el.textContent = word.text;
        document.getElementById('textOverlays').appendChild(el);
    }
});

完整代码实现

这里的代码可以直接复制到一个html文件中使用

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IMG to Text OCR</title>
    <style>
        #progressBar {
            width: 0%;
            height: 20px;
            background-color: green;
        }
        #progressContainer {
            width: 100%;
            background-color: #ddd;
        }
    </style>
</head>

<body>
    <input type="file" id="upload" accept="image/*">
    <div id="progressContainer">
        <div id="progressBar"></div>
    </div>
    <div id="textOverlays" style="position:relative;">
        <img id="display" src="" alt="Uploaded Image" style="position: absolute;user-select:none;">
        <canvas id="canvas" style="display:none;"></canvas>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/tesseract.js@2"></script>
    <script>
        document.getElementById('upload').addEventListener('change', function (event) {
            var file = event.target.files[0];
            var reader = new FileReader();
            reader.onload = function (e) {
                var img = new Image();
                img.onload = function () {
                    var canvas = document.getElementById('canvas');
                    var ctx = canvas.getContext('2d');
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0);
                    var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                    var data = imageData.data;
                    for (var i = 0; i < data.length; i += 4) {
                        var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
                        var threshold = brightness < 128 ? 0 : 255;
                        data[i] = data[i + 1] = data[i + 2] = threshold;
                    }
                    ctx.putImageData(imageData, 0, 0);
                    document.getElementById('display').src = e.target.result; // Display the original image
                    Tesseract.recognize(
                        canvas,
                        'chi_sim',
                        {
                            logger: m => {
                                console.log(m);
                                if (m.status === 'recognizing text') {
                                    var progress = Math.floor(m.progress * 100);
                                    document.getElementById('progressBar').style.width = progress + '%';
                                }
                            }
                        }
                    ).then(({ data: { text, words } }) => {
                        for (let word of words) {
                            const el = document.createElement("span");
                            el.style.position = "absolute";
                            el.style.left = `${word.bbox.x0}px`;
                            el.style.top = `${word.bbox.y0}px`;
                            el.style.color = `rgba(0,0,0,0)`;
                            el.style.fontSize = `${((word.bbox.y1 - word.bbox.y0) + (word.bbox.x1 - word.bbox.x0))/2}px`;
                            el.textContent = word.text;
                            document.getElementById('textOverlays').appendChild(el);
                        }
                    });
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);
        });
    </script>
</body>

</html>

效果

1 选择一张本地图片,等待进度条完成

2 用鼠标选中文字区域

会发现图片中的文字已经被识别出来,并且定位到图片位置了。现在我们可以直接再图片上选中,并且复制文字

小结

通过这样的步骤,我们可以实现一个可以识别图片中文字并进行展示的Web应用。用户上传图片后,应用不仅显示文字识别的进程,更可以直接在图片上查看到识别后的文字,甚至可以支持选择和复制。这种技术可以广泛应用于文档管理系统、数据入库等多种场景。

相关推荐
ekskef_sef39 分钟前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6411 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻1 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云1 小时前
npm淘宝镜像
前端·npm·node.js
dz88i81 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr2 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook
顾平安3 小时前
Promise/A+ 规范 - 中文版本
前端
聚名网3 小时前
域名和服务器是什么?域名和服务器是什么关系?
服务器·前端
桃园码工3 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
不是鱼3 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js