当前位置: 首页 > news >正文

Android开发:通过Tesseract第三方库实现OCR

一、引言

        什么是OCR?OCR(Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程。简单地说,OCR是一种技术,该项技术采用光学的方式将纸质文档中的文字转换为黑白点阵图像,然后通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工。

        什么是Tesseract?Tesseract was originally developed at Hewlett-Packard Laboratories Bristol UK and at Hewlett-Packard Co, Greeley Colorado USA between 1985 and 1994, with some more changes made in 1996 to port to Windows, and some C++izing in 1998. In 2005 Tesseract was open sourced by HP. From 2006 until November 2018 it was developed by Google.Tesseract最初是在英国布里斯托尔的惠普实验室和美国科罗拉多州格里利的惠普公司于1985年至1994年间开发的,1996年做了一些更改以移植到Windows,并在1998年进行了一些c++化。2005年,Tesseract被惠普开源。从2006年到2018年11月,它由谷歌开发。简单地说,Tesseract 就是上面OCR所说的“识别软件”的具体实现。

        OCR的识别对象(输入)是一张图片,而识别结果(输出)是计算机文字。在Android手机端主要存在两种图片的获取方式,一种是从相册中选择一个,另一个是直接拍照获得。因此,本文将实现最简单的OCR思路:首先从手机中获得一张图片,然后将其输入到Tesseract库,最后通过该库输出识别结果。由于只是学习该库的使用方式,所以博主忽略了其它辅助性的功能,比如拍照识别。

二、Android通过Tesseract实现OCR

1、在Module的build.gradle文件中添加以下依赖

implementation 'com.rmtheis:tess-two:9.1.0'

2、在AndroidManifest.xml文件中添加以下权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3、在MainActivity中申请权限

        建议在onCreate方法中执行下面的checkPermission方法

    // 检查应用所需的权限,如不满足则发出权限请求private void checkPermission() {if (ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 120);}if (ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 121);}}

4、从assets中读取一张读片

        既用于显示,又用于识别

    // 从assets中读取一张Bitmap类型的图片private Bitmap getBitmapFromAssets(Context context, String filename) {Bitmap bitmap = null;AssetManager assetManager = context.getAssets();try {InputStream is = assetManager.open(filename);bitmap = BitmapFactory.decodeStream(is);is.close();Log.i(TAG, "图片读取成功。");Toast.makeText(getApplicationContext(), "图片读取成功。", Toast.LENGTH_SHORT).show();} catch (IOException e) {Log.i(TAG, "图片读取失败。");Toast.makeText(getApplicationContext(), "图片读取失败。", Toast.LENGTH_SHORT).show();e.printStackTrace();}return bitmap;}

5、做好OCR的准备工作

        去https://github.com/tesseract-ocr/下载.traineddata语言包,然后放在项目assets目录下,并通过以下代码复制到Android文件系统中

    // 为Tesserect复制(从assets中复制过去)所需的数据private void prepareTess() {try{// 先创建必须的目录File dir = getExternalFilesDir(TESS_DATA);if(!dir.exists()){if (!dir.mkdir()) {Toast.makeText(getApplicationContext(), "目录" + dir.getPath() + "没有创建成功", Toast.LENGTH_SHORT).show();}}// 从assets中复制必须的数据String pathToDataFile = dir + "/" + DATA_FILENAME;if (!(new File(pathToDataFile)).exists()) {InputStream in = getAssets().open(DATA_FILENAME);OutputStream out = new FileOutputStream(pathToDataFile);byte[] buff = new byte[1024];int len;while ((len = in.read(buff)) > 0) {out.write(buff, 0, len);}in.close();out.close();}} catch (Exception e) {Log.e(TAG, e.getMessage());}}

6、点击按钮后调用以下方法,执行OCR识别

    // OCR识别的主程序private void mainProgram() {// 从assets中获取一张Bitmap图片Bitmap bitmap = getBitmapFromAssets(MainActivity.this, TARGET_FILENAME);// 同时显示在界面main_iv_image.setImageBitmap(bitmap);if (bitmap != null) {// 准备工作:创建路径和Tesserect的数据prepareTess();// 初始化TesserectTessBaseAPI tessBaseAPI = new TessBaseAPI();String dataPath = getExternalFilesDir("/").getPath() + "/";tessBaseAPI.init(dataPath, "eng");// 识别并显示结果String result = getOCRResult(tessBaseAPI, bitmap);main_tv_result.setText(result);}}// 进行OCR并返回识别结果private String getOCRResult(TessBaseAPI tessBaseAPI, Bitmap bitmap) {tessBaseAPI.setImage(bitmap);String result = "-";try{result = tessBaseAPI.getUTF8Text();}catch (Exception e){Log.e(TAG, e.getMessage());}tessBaseAPI.end();return result;}

7、编译运行,效果如图

        个人感觉识别率不是很准,一般般。

8、源代码贴一下

        MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import com.googlecode.tesseract.android.TessBaseAPI;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public class MainActivity extends AppCompatActivity {public static final String TESS_DATA = "/tessdata";private static final String TARGET_FILENAME = "vin_demo.png";private static final String DATA_FILENAME = "eng.traineddata";private static final String TAG = MainActivity.class.getSimpleName();private Button main_bt_recognize;private TextView main_tv_result;private ImageView main_iv_image;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 设置布局文件setContentView(R.layout.activity_main);// 检查并请求应用所需权限checkPermission();// 获取控件对象initView();// 设置控件的监听器setListener();}private void setListener() {// 设置识别按钮的监听器main_bt_recognize.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {// 识别之前需要再次检查一遍权限checkPermission();// 点击后的主程序mainProgram();}});}// 获得界面需要交互的控件private void initView() {main_bt_recognize = findViewById(R.id.main_bt_recognize);main_tv_result = findViewById(R.id.main_tv_result);main_iv_image = findViewById(R.id.main_iv_image);}// 检查应用所需的权限,如不满足则发出权限请求private void checkPermission() {if (ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 120);}if (ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 121);}}// OCR识别的主程序private void mainProgram() {// 从assets中获取一张Bitmap图片Bitmap bitmap = getBitmapFromAssets(MainActivity.this, TARGET_FILENAME);// 同时显示在界面main_iv_image.setImageBitmap(bitmap);if (bitmap != null) {// 准备工作:创建路径和Tesserect的数据prepareTess();// 初始化TesserectTessBaseAPI tessBaseAPI = new TessBaseAPI();String dataPath = getExternalFilesDir("/").getPath() + "/";tessBaseAPI.init(dataPath, "eng");// 识别并显示结果String result = getOCRResult(tessBaseAPI, bitmap);main_tv_result.setText(result);}}// 从assets中读取一张Bitmap类型的图片private Bitmap getBitmapFromAssets(Context context, String filename) {Bitmap bitmap = null;AssetManager assetManager = context.getAssets();try {InputStream is = assetManager.open(filename);bitmap = BitmapFactory.decodeStream(is);is.close();Log.i(TAG, "图片读取成功。");Toast.makeText(getApplicationContext(), "图片读取成功。", Toast.LENGTH_SHORT).show();} catch (IOException e) {Log.i(TAG, "图片读取失败。");Toast.makeText(getApplicationContext(), "图片读取失败。", Toast.LENGTH_SHORT).show();e.printStackTrace();}return bitmap;}// 为Tesserect复制(从assets中复制过去)所需的数据private void prepareTess() {try{// 先创建必须的目录File dir = getExternalFilesDir(TESS_DATA);if(!dir.exists()){if (!dir.mkdir()) {Toast.makeText(getApplicationContext(), "目录" + dir.getPath() + "没有创建成功", Toast.LENGTH_SHORT).show();}}// 从assets中复制必须的数据String pathToDataFile = dir + "/" + DATA_FILENAME;if (!(new File(pathToDataFile)).exists()) {InputStream in = getAssets().open(DATA_FILENAME);OutputStream out = new FileOutputStream(pathToDataFile);byte[] buff = new byte[1024];int len;while ((len = in.read(buff)) > 0) {out.write(buff, 0, len);}in.close();out.close();}} catch (Exception e) {Log.e(TAG, e.getMessage());}}// 进行OCR并返回识别结果private String getOCRResult(TessBaseAPI tessBaseAPI, Bitmap bitmap) {tessBaseAPI.setImage(bitmap);String result = "-";try{result = tessBaseAPI.getUTF8Text();}catch (Exception e){Log.e(TAG, e.getMessage());}tessBaseAPI.end();return result;}
}

        layout_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><ImageViewandroid:id="@+id/main_iv_image"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"/><Buttonandroid:id="@+id/main_bt_recognize"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:layout_gravity="center_horizontal"android:text="读取一张图片并识别" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:layout_gravity="center_horizontal"android:text="识别结果:" /><TextViewandroid:id="@+id/main_tv_result"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:layout_gravity="center_horizontal" /></LinearLayout></ScrollView>
</LinearLayout>

        AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.cs.ocrdemo4csdn"><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.OCRDemo4CSDN"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest>

        build.gradle(Module)

plugins {id 'com.android.application'
}android {compileSdk 34defaultConfig {applicationId "com.cs.ocrdemo4csdn"minSdk 21targetSdk 34versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}
}dependencies {implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'com.google.android.material:material:1.3.0'implementation 'androidx.constraintlayout:constraintlayout:2.0.4'testImplementation 'junit:junit:4.+'androidTestImplementation 'androidx.test.ext:junit:1.1.2'androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'implementation 'com.rmtheis:tess-two:9.1.0'
}

        vin_demo.png

随便从网上下的图片(保证存在光学字符即可)。

        eng.traineddata

从https://github.com/tesseract-ocr/下载的,如果不行从https://github.com/raykibul/Android-OCR-Testing/tree/main下载。

三、参考资料

        1、光学字符识别

        2、GitHub - tesseract-ocr/tesseract

        3、GitHub - raykibul/Android-OCR-Testing

四、总结语

        1、跟着别人的CSDN博客捣鼓了一天多,但是没能调通,一直在报错,比如遇到“Could not initialize Tesseract API with language=eng”、“getUTF8Text导致android tesseract崩溃”等等问题。后边看了GitHub上边比较新的代码(诸位如果代码参考了我的博客还是没能调通,建议看看这份代码),然后就跑通了。目前还不知道原因是啥。

        2、我看Tesseract这个库的识别结果并不是十分准确,尤其是对于拍照出来的结果识别率很低,再从这个库的发展历史来看,好像现在都没有什么人再维护它了(最后的维护者是谷歌,而且停留在2018年),所以,对于现在(今年是2023年)而言,我感觉它已经有点属于是过时技术。大家可以寻求一些比较新的技术方案,毕竟现在大模型都搞得这么牛了,OCR这种应该搞得更好才是。

相关文章:

Android开发:通过Tesseract第三方库实现OCR

一、引言 什么是OCR&#xff1f;OCR(Optical Character Recognition&#xff0c;光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符&#xff0c;通过检测暗、亮的模式确定其形状&#xff0c;然后用字符识别方法将形状翻译成计算机文字的过程。简单地说&#…...

合并两个有序链表——力扣21

题目描述 法一 递归 class Solution { public:ListNode* mergeTwoLists(ListNode *l1, ListNode*l2){if(l1 nullptr){return l2;} else if (l2nullptr){return l1;} else if (l1->val<l2->val){l1->next mergeTwoLists(l1->next, l2);return l1;} else {l2-&g…...

企业数据,大语言模型和矢量数据库

随着ChatGPT的推出&#xff0c;通用人工智能的时代缓缓拉开序幕。我们第一次看到市场在追求人工智能开发者&#xff0c;而不是以往的开发者寻找市场。每一个企业都有大量的数据&#xff0c;私有的用户数据&#xff0c;自己积累的行业数据&#xff0c;产品数据&#xff0c;生产线…...

LabVIEW使用支持向量机对脑磁共振成像进行图像分类

LabVIEW使用支持向量机对脑磁共振成像进行图像分类 医学成像是用于创建人体解剖学图像以进行临床研究、诊断和治疗的技术和过程。它现在是医疗技术发展最快的领域之一。通常用于获得医学图像的方式是X射线&#xff0c;计算机断层扫描&#xff08;CT&#xff09;&#xff0c;磁…...

kafka面试题

kafka基本概念 Producer 生产者&#xff1a;负责将消息发送到 BrokerConsumer 消费者&#xff1a;从 Broker 接收消息Consumer Group 消费者组&#xff1a;由多个 Consumer 组成。消费者组内每个消费者负责消费不同分区的数据&#xff0c;一个分区只能由一个组内消费者消费&am…...

树的遍历(一题直接理解中序、后序、层序遍历,以及树的存储)

题目如下&#xff1a; 一个二叉树&#xff0c;树中每个节点的权值互不相同。 现在给出它的后序遍历和中序遍历&#xff0c;请你输出它的层序遍历。 输入格式 第一行包含整数 N&#xff0c;表示二叉树的节点数。 第二行包含 N 个整数&#xff0c;表示二叉树的后序遍历。 第…...

JVM系统优化实践(22):GC生产环境案例(五)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 除了Tomcat、Jetty&#xff0c;另一个常见的可能出现OOM的地方就是微服务架构下的一次RPC调用过程中。笔者曾经经历过的一次OOM就是基于Thrift框架封装出来的一个RPC框架导…...

DevOps系列文章 之GitLabCI模板库的流水线

目录结构&#xff0c;jobs目录用于存放作业模板。templates目录用于存放流水线模板。这次使用​​default-pipeline.yml​​作为所有作业的基础模板。 作业模板 作业分为Build、test、codeanalysis、artifactory、deploy部分&#xff0c;在每个作业中配置了rules功能开关&…...

spring扩展点ApplicationContextAware解释

ApplicationContextAware是Spring框架中的一个扩展接口&#xff0c;用于获取和操作应用程序上下文&#xff08;ApplicationContext&#xff09;。通过实现ApplicationContextAware接口&#xff0c;可以在Bean中获取对应用程序上下文的引用&#xff0c;并进行进一步的操作。 具…...

力扣热门100题之最大子数组和【中等】【动态规划】

题目描述 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&a…...

导出为PDF加封面且分页处理dom元素分割

文章目录 正常展示页面导出后效果代码 正常展示页面 导出后效果 代码 组件内 <template><div><div><div class"content" id"content" style"padding: 0px 20px"><div class"item"><divstyle"…...

【C++入门】浅谈类、对象和 this 指针

文章目录 一、前言二、类1. 基本概念2. 类的封装3. 使用习惯成员函数定义习惯成员变量命名习惯 三、对象1. 基本概念2. 类对象的存储规则 四、this 指针1. 基本概念2. 注意事项3. 经典习题4. 常见面试题 一、前言 在 C 语言中&#xff0c;我们用结构体来描述一个事物的多种属性…...

【Linux命令200例】indent对C语言代码进行缩进和格式化

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…...

Hive 调优集锦(1)

一、前言 1.1 概念 Hive 依赖于 HDFS 存储数据&#xff0c;Hive 将 HQL 转换成 MapReduce 执行&#xff0c;所以说 Hive 是基于Hadoop 的一个数据仓库工具&#xff0c;实质就是一款基于 HDFS 的 MapReduce 计算框架&#xff0c;对存储在HDFS 中的数据进行分析和管理。 1.2 架…...

【C++详解】——智能指针

目录 为什么需要智能指针 抛异常引发内存泄漏 内存泄漏 什么是内存泄漏&#xff0c;内存泄漏的危害 内存泄漏分类 检测内存泄漏常用工具 如何避免内存泄漏 智能指针的使用及原理 RAII 智能指针的原理 各类智能指针介绍 auto_ptr unique_ptr shared_ptr weak_ptr …...

Jmeter接口/性能测试,Jmeter使用教程(超细整理)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、线程组 线程组…...

59,综合案例-演讲比赛流程管理系统

演讲比赛流程管理系统 59.1案例描述59.1.1比赛规则59.1.2程序功能 59.2创建管理类59.3菜单功能59.3.1添加成员函数59.3.2菜单功能实现 59.4退出功能59.4.1提供功能接口59.4.2实现退出功能 59.5演讲比赛功能59.5.1创建选手类59.5.2比赛59.5.2.1成员属性添加59.5.2.2初始化属性59…...

前端JS 展示上传图片缩略图(本地图片读取)

需求&#xff1a; 点击上传图片按钮&#xff0c;选择图片以后&#xff0c;不请求后端接口&#xff0c;直接将图片展示在缩略图中。 解决方案&#xff1a; 使用 FileReader 和 FileReader 中的 readAsDataURL 方法。 第一步 从input[type“file”] (上传文件标签) 里面拿到fil…...

Vue中$route和$router的区别

$router&#xff1a;用来操作路由&#xff0c;$route&#xff1a;用来获取路由信息 $router其实就是VueRouer的实例&#xff0c;对象包括了vue-router使用的实例方法&#xff0c;还有实例属性&#xff0c;我们可以理解为$router有一个设置的含义&#xff0c;比如设置当前的跳转…...

基于多任务学习卷积神经网络的皮肤损伤联合分割与分类

文章目录 Joint segmentation and classification of skin lesions via a multi-task learning convolutional neural network摘要本文方法实验结果 Joint segmentation and classification of skin lesions via a multi-task learning convolutional neural network 摘要 在…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...