MainFragment.java
package cz.adaptech.tesseract4android.sample.ui.main;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import java.io.File;
import java.io.FileOutputStream;
import cz.adaptech.tesseract4android.sample.Assets;
import cz.adaptech.tesseract4android.sample.Config;
import cz.adaptech.tesseract4android.sample.databinding.FragmentMainBinding;
import com.googlecode.tesseract.android.TessBaseAPI;
public class MainFragment extends Fragment {
private static final int PICK_IMAGE = 1; // 打开相册的请求码
private FragmentMainBinding binding;
private MainViewModel viewModel;
private TessBaseAPI tessBaseAPI;
public static MainFragment newInstance() {
return new MainFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
// Copy sample image and language data to storage
Assets.extractAssets(requireContext());
if (!viewModel.isInitialized()) {
String dataPath = Assets.getTessDataPath(requireContext());
viewModel.initTesseract(dataPath, Config.TESS_LANG, Config.TESS_ENGINE);
}
// Initialize Tesseract
tessBaseAPI = new TessBaseAPI();
String dataPath = Assets.getTessDataPath(requireContext());
tessBaseAPI.init(dataPath, Config.TESS_LANG);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentMainBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.image.setImageBitmap(Assets.getImageBitmap(requireContext()));
// 选择图片按钮点击事件
assert binding.openGalleryButton != null;
binding.openGalleryButton.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, PICK_IMAGE);
});
binding.start.setOnClickListener(v -> {
// 开始识别,之前需要设置好图片
Bitmap bitmap = Assets.getImageBitmap(requireContext());
assert bitmap != null;
viewModel.recognizeImage(bitmap);
//OCR 识别操作放入新的线程中以防止 UI 卡顿
new Thread(() -> {
tessBaseAPI.setImage(bitmap);
String recognizedText = tessBaseAPI.getUTF8Text(); // 执行OCR识别
requireActivity().runOnUiThread(() -> binding.text.setText(recognizedText)); // 显示识别结果
}).start();
});
binding.stop.setOnClickListener(v -> {
tessBaseAPI.stop(); // 停止识别
viewModel.stop();
});
assert binding.copyButton != null;
binding.copyButton.setOnClickListener(v -> copyToClipboard(binding.text.getText().toString())); // 复制文本
assert binding.shareButton != null;
binding.shareButton.setOnClickListener(v -> shareText(binding.text.getText().toString())); // 分享文本
binding.text.setMovementMethod(new ScrollingMovementMethod());
// 观察处理状态
viewModel.getProcessing().observe(getViewLifecycleOwner(), processing -> {
binding.start.setEnabled(!processing);
binding.stop.setEnabled(processing);
});
viewModel.getProgress().observe(getViewLifecycleOwner(), progress -> {
binding.status.setText(progress);
});
viewModel.getResult().observe(getViewLifecycleOwner(), result -> {
binding.text.setText(result);
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK && data != null) {
Uri selectedImageUri = data.getData();
Bitmap bitmap;
try {
// 使用异步任务或线程来加载和处理图像
bitmap = MediaStore.Images.Media.getBitmap(requireActivity().getContentResolver(), selectedImageUri);
// 缩放图像以减少内存使用,例如每次只加载部分
bitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / 2, bitmap.getHeight() / 2, true);
binding.image.setImageBitmap(bitmap); // 设置选中的图片到ImageView
// 将选中的bitmap保存为文件(如果需要)
File imageFile = Assets.getImageFile(requireContext());
FileOutputStream fos = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
// 设置Tesseract的输入图像
tessBaseAPI.setImage(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (tessBaseAPI != null) {
tessBaseAPI.recycle(); // 释放资源
}
}
// 复制到剪贴板的方法
private void copyToClipboard(String text) {
ClipboardManager clipboard = (ClipboardManager) requireContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("OCR Result", text);
clipboard.setPrimaryClip(clip);
Toast.makeText(requireContext(), "文本已复制到剪贴板", Toast.LENGTH_SHORT).show();
}
// 分享文本的方法
private void shareText(String text) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, "分享文本"));
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.main.MainFragment">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAlignment="center"
android:textStyle="bold"
tools:text="Status" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop" />
</LinearLayout>
<!-- 添加打开相册按钮 -->
<Button
android:id="@+id/openGalleryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="打开相册" />
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="16dp"
android:scrollbars="vertical"
android:text="" />
<!-- 新增的复制按钮 -->
<Button
android:id="@+id/copyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="复制文本"
android:layout_gravity="center" />
<!-- 新增的分享按钮 -->
<Button
android:id="@+id/shareButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="分享文本"
android:layout_gravity="center" />
</LinearLayout>
参考github
adaptech-czTesseract4Android