diff --git a/src/main/java/net/micode/notes/tool/AIService.java b/src/main/java/net/micode/notes/tool/AIService.java
new file mode 100644
index 0000000..c2a0e93
--- /dev/null
+++ b/src/main/java/net/micode/notes/tool/AIService.java
@@ -0,0 +1,409 @@
+package net.micode.notes.tool;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.Base64;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * AIService - AI服务类
+ *
+ * 用于处理与AI相关的服务调用,如豆包API
+ *
+ */
+public class AIService {
+ private static final String TAG = "AIService";
+ private static final String DOUBAO_API_URL = "https://ark.cn-beijing.volces.com/api/v3/responses";
+ private static final String API_KEY = "ee5fb4c7-ea14-4481-ac23-4b0e82907850";
+ private static final String SECRET_ACCESS_KEY = "";
+
+ /**
+ * 提取图片内容
+ * @param bitmap 图片bitmap
+ * @param callback 回调接口
+ */
+ public static void extractImageContent(final Bitmap bitmap, final ExtractImageContentCallback callback) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Log.d(TAG, "Starting image content extraction...");
+
+ // 检查bitmap
+ if (bitmap == null) {
+ Log.e(TAG, "Bitmap is null");
+ callback.onFailure("Bitmap is null");
+ return;
+ }
+
+ Log.d(TAG, "Bitmap width: " + bitmap.getWidth() + ", height: " + bitmap.getHeight());
+
+ // 将bitmap转换为Base64
+ Log.d(TAG, "Converting bitmap to base64...");
+ String base64Image = bitmapToBase64(bitmap);
+ if (base64Image == null) {
+ Log.e(TAG, "Failed to convert bitmap to base64");
+ callback.onFailure("Failed to convert bitmap to base64");
+ return;
+ }
+ Log.d(TAG, "Base64 conversion successful, length: " + base64Image.length());
+
+ // 构建请求体
+ Log.d(TAG, "Building request body...");
+ JSONObject requestBody = new JSONObject();
+ requestBody.put("model", "ep-20260127214554-frsrr"); // 新的推理接入点ID
+
+ // 创建input数组
+ org.json.JSONArray input = new org.json.JSONArray();
+
+ // 创建user input
+ JSONObject userInput = new JSONObject();
+ userInput.put("role", "user");
+
+ // 创建content数组
+ org.json.JSONArray contentArray = new org.json.JSONArray();
+
+ // 添加图片部分
+ JSONObject imageContent = new JSONObject();
+ imageContent.put("type", "input_image");
+ imageContent.put("image_url", "data:image/jpeg;base64," + base64Image);
+ contentArray.put(imageContent);
+
+ // 添加文本部分
+ JSONObject textContent = new JSONObject();
+ textContent.put("type", "input_text");
+ textContent.put("text", "请提取这张图片中的所有文字和结构化数据,包括表格、列表等信息,清晰准确地格式化提取的内容。");
+ contentArray.put(textContent);
+
+ userInput.put("content", contentArray);
+ input.put(userInput);
+
+ requestBody.put("input", input);
+
+ // 发送请求
+ String requestBodyString = requestBody.toString();
+ Log.d(TAG, "Request body length: " + requestBodyString.length());
+ Log.d(TAG, "Request body (first 1000 chars): " + (requestBodyString.length() > 1000 ? requestBodyString.substring(0, 1000) + "..." : requestBodyString));
+
+ Log.d(TAG, "Sending POST request to: " + DOUBAO_API_URL);
+ String response = sendPostRequest(DOUBAO_API_URL, requestBodyString);
+
+ if (response == null) {
+ Log.e(TAG, "Failed to get response from Doubao API");
+ callback.onFailure("Failed to get response from Doubao API");
+ return;
+ }
+
+ Log.d(TAG, "Got response from Doubao API, length: " + response.length());
+ Log.d(TAG, "Response content: " + response);
+
+ // 解析响应
+ Log.d(TAG, "Parsing response...");
+ JSONObject responseJson = new JSONObject(response);
+
+ // 检查响应格式
+ if (responseJson.has("output")) {
+ Log.d(TAG, "Response has output field");
+ try {
+ // 尝试作为数组处理(新格式)
+ org.json.JSONArray outputArray = responseJson.getJSONArray("output");
+ Log.d(TAG, "Output is an array, length: " + outputArray.length());
+
+ // 遍历数组找到包含文本的message
+ String extractedText = "";
+ for (int i = 0; i < outputArray.length(); i++) {
+ JSONObject item = outputArray.getJSONObject(i);
+ Log.d(TAG, "Output item " + i + ": " + item.toString());
+
+ // 检查是否是message类型
+ if (item.has("type") && "message".equals(item.getString("type"))) {
+ Log.d(TAG, "Found message item");
+ if (item.has("content")) {
+ org.json.JSONArray messageContentArray = item.getJSONArray("content");
+ for (int j = 0; j < messageContentArray.length(); j++) {
+ JSONObject contentItem = messageContentArray.getJSONObject(j);
+ if (contentItem.has("type") && "output_text".equals(contentItem.getString("type"))) {
+ extractedText = contentItem.getString("text");
+ Log.d(TAG, "Got text from response: " + extractedText);
+ callback.onSuccess(extractedText);
+ return;
+ }
+ }
+ }
+ }
+ // 检查是否有role字段为assistant
+ else if (item.has("role") && "assistant".equals(item.getString("role"))) {
+ Log.d(TAG, "Found assistant item");
+ if (item.has("content")) {
+ org.json.JSONArray assistantContentArray = item.getJSONArray("content");
+ for (int j = 0; j < assistantContentArray.length(); j++) {
+ JSONObject contentItem = assistantContentArray.getJSONObject(j);
+ if (contentItem.has("type") && "output_text".equals(contentItem.getString("type"))) {
+ extractedText = contentItem.getString("text");
+ Log.d(TAG, "Got text from assistant response: " + extractedText);
+ callback.onSuccess(extractedText);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // 如果没有找到文本,尝试其他方式
+ if (extractedText.isEmpty()) {
+ Log.e(TAG, "No text found in output array");
+ callback.onFailure("No text found in output array");
+ }
+ } catch (JSONException e) {
+ // 如果不是数组,尝试作为对象处理(旧格式)
+ Log.d(TAG, "Output is not an array, trying as object: " + e.getMessage());
+ try {
+ JSONObject outputObj = responseJson.getJSONObject("output");
+ if (outputObj.has("text")) {
+ String content = outputObj.getString("text");
+ Log.d(TAG, "Got text from response object: " + content);
+ callback.onSuccess(content);
+ } else if (outputObj.has("content")) {
+ String content = outputObj.getString("content");
+ Log.d(TAG, "Got content from response object: " + content);
+ callback.onSuccess(content);
+ } else {
+ Log.e(TAG, "No text or content in response object: " + outputObj.toString());
+ callback.onFailure("No text or content in response");
+ }
+ } catch (JSONException ex) {
+ Log.e(TAG, "Error parsing output: " + ex.getMessage());
+ callback.onFailure("Error parsing output: " + ex.getMessage());
+ }
+ }
+ } else if (responseJson.has("choices")) {
+ // 兼容旧格式
+ Log.d(TAG, "Response has choices field");
+ org.json.JSONArray choices = responseJson.getJSONArray("choices");
+ if (choices.length() > 0) {
+ JSONObject choice = choices.getJSONObject(0);
+ if (choice.has("message")) {
+ JSONObject message = choice.getJSONObject("message");
+ if (message.has("content")) {
+ String content = message.getString("content");
+ Log.d(TAG, "Got content from choices: " + content);
+ callback.onSuccess(content);
+ } else {
+ Log.e(TAG, "No content in message: " + message.toString());
+ callback.onFailure("No content in message");
+ }
+ } else {
+ Log.e(TAG, "No message in choice: " + choice.toString());
+ callback.onFailure("No message in choice");
+ }
+ } else {
+ Log.e(TAG, "No choices in response");
+ callback.onFailure("No choices in response");
+ }
+ } else if (responseJson.has("error")) {
+ // 处理错误响应
+ Log.e(TAG, "API returned error: " + responseJson.toString());
+ JSONObject error = responseJson.getJSONObject("error");
+ String errorMessage = error.getString("message");
+ callback.onFailure("API error: " + errorMessage);
+ } else {
+ Log.e(TAG, "Unexpected response format: " + responseJson.toString());
+ callback.onFailure("Unexpected response format: " + responseJson.toString());
+ }
+
+ } catch (JSONException e) {
+ Log.e(TAG, "JSONException: " + e.getMessage());
+ e.printStackTrace();
+ callback.onFailure("JSON error: " + e.getMessage());
+ } catch (Exception e) {
+ Log.e(TAG, "Exception: " + e.getMessage());
+ e.printStackTrace();
+ callback.onFailure("Error: " + e.getMessage());
+ }
+ }
+ }).start();
+ }
+
+ /**
+ * 将Bitmap转换为Base64字符串
+ * @param bitmap 图片bitmap
+ * @return Base64字符串
+ */
+ private static String bitmapToBase64(Bitmap bitmap) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream);
+ byte[] byteArray = byteArrayOutputStream.toByteArray();
+ try {
+ byteArrayOutputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return Base64.encodeToString(byteArray, Base64.NO_WRAP);
+ }
+
+ /**
+ * 发送POST请求
+ * @param urlString URL字符串
+ * @param requestBody 请求体
+ * @return 响应字符串
+ */
+ private static String sendPostRequest(String urlString, String requestBody) {
+ try {
+ Log.d(TAG, "Sending POST request to: " + urlString);
+ Log.d(TAG, "Request body length: " + requestBody.length());
+ Log.d(TAG, "Request body (first 500 chars): " + (requestBody.length() > 500 ? requestBody.substring(0, 500) + "..." : requestBody));
+
+ URL url = new URL(urlString);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("POST");
+ // 设置请求头
+ connection.setRequestProperty("Content-Type", "application/json");
+ connection.setRequestProperty("Authorization", "Bearer " + API_KEY);
+ connection.setRequestProperty("X-TT-LOGID", System.currentTimeMillis() + "");
+ connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
+ connection.setDoOutput(true);
+ connection.setConnectTimeout(30000); // 设置连接超时为30秒
+ connection.setReadTimeout(30000); // 设置读取超时为30秒
+
+ // 写入请求体
+ Log.d(TAG, "Writing request body...");
+ OutputStream outputStream = connection.getOutputStream();
+ outputStream.write(requestBody.getBytes(StandardCharsets.UTF_8));
+ outputStream.flush();
+ outputStream.close();
+ Log.d(TAG, "Request body written successfully");
+
+ // 读取响应
+ Log.d(TAG, "Reading response...");
+ int responseCode = connection.getResponseCode();
+ Log.d(TAG, "HTTP response code: " + responseCode);
+
+ // 读取所有响应头
+ Log.d(TAG, "Response headers:");
+ java.util.Map> headers = connection.getHeaderFields();
+ for (String key : headers.keySet()) {
+ if (key != null) {
+ Log.d(TAG, key + ": " + headers.get(key));
+ }
+ }
+
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+ Log.d(TAG, "HTTP OK, reading response body...");
+ InputStream inputStream = connection.getInputStream();
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
+ responseStream.write(buffer, 0, bytesRead);
+ }
+ String responseString = responseStream.toString(StandardCharsets.UTF_8.name());
+ responseStream.close();
+ inputStream.close();
+ connection.disconnect();
+ Log.d(TAG, "API response length: " + responseString.length());
+ Log.d(TAG, "API response (first 500 chars): " + (responseString.length() > 500 ? responseString.substring(0, 500) + "..." : responseString));
+ return responseString;
+ } else {
+ // 读取错误响应
+ Log.e(TAG, "HTTP error, reading error response...");
+ InputStream errorStream = connection.getErrorStream();
+ if (errorStream != null) {
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ ByteArrayOutputStream errorResponseStream = new ByteArrayOutputStream();
+ while ((bytesRead = errorStream.read(buffer)) != -1) {
+ errorResponseStream.write(buffer, 0, bytesRead);
+ }
+ String errorResponse = errorResponseStream.toString(StandardCharsets.UTF_8.name());
+ errorResponseStream.close();
+ errorStream.close();
+ Log.e(TAG, "HTTP error: " + responseCode + ", Error response: " + errorResponse);
+ } else {
+ Log.e(TAG, "HTTP error code: " + responseCode + ", No error stream available");
+ }
+ connection.disconnect();
+ return null;
+ }
+ } catch (java.net.SocketTimeoutException e) {
+ Log.e(TAG, "Socket timeout error: " + e.getMessage());
+ e.printStackTrace();
+ return null;
+ } catch (java.net.ConnectException e) {
+ Log.e(TAG, "Connection error: " + e.getMessage());
+ e.printStackTrace();
+ return null;
+ } catch (java.io.IOException e) {
+ Log.e(TAG, "IO error: " + e.getMessage());
+ e.printStackTrace();
+ return null;
+ } catch (Exception e) {
+ Log.e(TAG, "Error sending POST request: " + e.getMessage());
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * 提取图片内容回调接口
+ */
+ public interface ExtractImageContentCallback {
+ void onSuccess(String extractedContent);
+ void onFailure(String errorMessage);
+ }
+
+ /**
+ * 测试API连接
+ */
+ public static void testApiConnection(final ExtractImageContentCallback callback) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // 构建测试请求体
+ JSONObject requestBody = new JSONObject();
+ requestBody.put("model", "ep-20260127214554-frsrr");
+
+ org.json.JSONArray input = new org.json.JSONArray();
+ JSONObject userInput = new JSONObject();
+ userInput.put("role", "user");
+
+ org.json.JSONArray contentArray = new org.json.JSONArray();
+ JSONObject textContent = new JSONObject();
+ textContent.put("type", "input_text");
+ textContent.put("text", "Hello, test connection");
+ contentArray.put(textContent);
+
+ userInput.put("content", contentArray);
+ input.put(userInput);
+
+ requestBody.put("input", input);
+
+ Log.d(TAG, "Testing API connection...");
+ String response = sendPostRequest(DOUBAO_API_URL, requestBody.toString());
+
+ if (response != null) {
+ Log.d(TAG, "API connection test successful: " + response);
+ callback.onSuccess("API connection test successful");
+ } else {
+ Log.e(TAG, "API connection test failed");
+ callback.onFailure("API connection test failed");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error testing API connection: " + e.getMessage());
+ callback.onFailure("Error testing API connection: " + e.getMessage());
+ }
+ }
+ }).start();
+ }
+}
diff --git a/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/main/java/net/micode/notes/ui/NoteEditActivity.java
index 013726d..bf69f19 100644
--- a/src/main/java/net/micode/notes/ui/NoteEditActivity.java
+++ b/src/main/java/net/micode/notes/ui/NoteEditActivity.java
@@ -119,6 +119,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public ImageButton ibRedo; // 重做按钮
public ImageView ibSetBgColor; // 设置背景色按钮
public ImageButton ibInsertImage; // 插入图片按钮
+ public ImageButton ibExtractImage; // 提取图片内容按钮
public TextView tvTitleHint; // 标题提示文字
public EditText etTitle; // 标题输入框
public TextView tvTitleCount; // 字符数提示
@@ -594,6 +595,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
mNoteHeaderHolder.ibInsertImage = (ImageButton) findViewById(R.id.add_img_btn);
mNoteHeaderHolder.ibInsertImage.setOnClickListener(this);
+ mNoteHeaderHolder.ibExtractImage = (ImageButton) findViewById(R.id.extract_img_btn);
+ mNoteHeaderHolder.ibExtractImage.setOnClickListener(this);
mNoteHeaderHolder.tvTitleHint = (TextView) findViewById(R.id.tv_title_hint);
mNoteHeaderHolder.etTitle = (EditText) findViewById(R.id.et_title);
mNoteHeaderHolder.etTitle.addTextChangedListener(new TextWatcher() {
@@ -795,6 +798,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mFontSizeSelector.setVisibility(View.GONE);
} else if (id == R.id.add_img_btn) {
insertImage();
+ } else if (id == R.id.extract_img_btn) {
+ extractImageContent();
} else if (id == R.id.btn_bold) {
// 处理加粗按钮点击
mNoteEditor.toggleBold();
@@ -1981,4 +1986,143 @@ public class NoteEditActivity extends Activity implements OnClickListener,
showToast(R.string.error_out_of_memory);
}
}
+
+ /**
+ * 提取图片内容
+ */
+ private void extractImageContent() {
+ // 检查当前笔记中是否有图片
+ String content = mNoteEditor.getText().toString();
+ if (!content.contains("[IMAGE:")) {
+ showToast(R.string.error_no_image_in_note);
+ return;
+ }
+
+ // 提取所有图片路径
+ final java.util.List imagePaths = new java.util.ArrayList<>();
+ int startIndex = 0;
+ while (true) {
+ int imageStart = content.indexOf("[IMAGE:", startIndex);
+ if (imageStart == -1) {
+ break;
+ }
+ int imageEnd = content.indexOf("]", imageStart);
+ if (imageEnd == -1) {
+ break;
+ }
+ String imagePath = content.substring(imageStart + 7, imageEnd);
+ imagePaths.add(imagePath);
+ startIndex = imageEnd + 1;
+ }
+
+ if (imagePaths.isEmpty()) {
+ showToast(R.string.error_no_image_in_note);
+ return;
+ }
+
+ // 如果只有一张图片,直接提取
+ if (imagePaths.size() == 1) {
+ extractImageContentFromPath(imagePaths.get(0));
+ return;
+ }
+
+ // 如果有多张图片,让用户选择
+ final String[] imageOptions = new String[imagePaths.size()];
+ for (int i = 0; i < imagePaths.size(); i++) {
+ imageOptions[i] = "Image " + (i + 1);
+ }
+
+ new android.app.AlertDialog.Builder(this)
+ .setTitle("Select Image")
+ .setItems(imageOptions, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String selectedImagePath = imagePaths.get(which);
+ extractImageContentFromPath(selectedImagePath);
+ }
+ })
+ .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ })
+ .show();
+ }
+
+ /**
+ * 从指定路径提取图片内容
+ */
+ private void extractImageContentFromPath(final String imagePath) {
+ // 显示加载提示
+ final android.app.AlertDialog loadingDialog = new android.app.AlertDialog.Builder(this)
+ .setTitle("Loading")
+ .setMessage("Extracting image content...")
+ .setCancelable(false)
+ .create();
+ loadingDialog.show();
+
+ // 加载图片
+ ImageHelper imageHelper = new ImageHelper(this);
+ final Bitmap bitmap = imageHelper.loadImage(imagePath);
+
+ if (bitmap == null) {
+ loadingDialog.dismiss();
+ showToast(R.string.error_failed_to_load_image);
+ return;
+ }
+
+ // 调用AI服务提取图片内容
+ net.micode.notes.tool.AIService.extractImageContent(bitmap, new net.micode.notes.tool.AIService.ExtractImageContentCallback() {
+ @Override
+ public void onSuccess(final String extractedContent) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ loadingDialog.dismiss();
+
+ // 显示提取结果对话框
+ new android.app.AlertDialog.Builder(NoteEditActivity.this)
+ .setTitle(R.string.dialog_title_extracted_content)
+ .setMessage(extractedContent)
+ .setPositiveButton(R.string.dialog_button_insert, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // 将提取的内容插入到笔记中
+ int cursorPosition = mNoteEditor.getSelectionStart();
+ Editable editable = mNoteEditor.getEditableText();
+ editable.insert(cursorPosition, "\n" + extractedContent + "\n");
+ mNoteEditor.setSelection(cursorPosition + extractedContent.length() + 2);
+
+ // 更新WorkingNote的内容
+ getWorkingText();
+ updateWordCount();
+
+ showToast(R.string.info_content_inserted);
+ }
+ })
+ .setNegativeButton(R.string.dialog_button_cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ })
+ .show();
+ }
+ });
+ }
+
+ @Override
+ public void onFailure(final String errorMessage) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ loadingDialog.dismiss();
+ showToast(R.string.error_extract_image_content_failed);
+ Log.e(TAG, "Extract image content failed: " + errorMessage);
+ }
+ });
+ }
+ });
+ }
}
diff --git a/src/main/java/net/micode/notes/ui/NotesListActivity.java b/src/main/java/net/micode/notes/ui/NotesListActivity.java
index 64dfc2f..3d3c90f 100644
--- a/src/main/java/net/micode/notes/ui/NotesListActivity.java
+++ b/src/main/java/net/micode/notes/ui/NotesListActivity.java
@@ -28,6 +28,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
@@ -83,6 +84,8 @@ import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -218,13 +221,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
// 处理从相册选择图片的结果
if (data != null && data.getData() != null) {
try {
- // 保存图片路径
- mCurrentBackgroundType = BACKGROUND_TYPE_ALBUM;
- mCurrentBackgroundPath = data.getData().toString();
- // 更新背景
- updateBackground();
- // 保存设置
- saveBackgroundSetting();
+ // 将相册图片复制到应用内部存储
+ String internalPath = saveImageToInternalStorage(data.getData());
+ if (!TextUtils.isEmpty(internalPath)) {
+ // 保存内部存储路径
+ mCurrentBackgroundType = BACKGROUND_TYPE_ALBUM;
+ mCurrentBackgroundPath = internalPath;
+ // 更新背景
+ updateBackground();
+ // 保存设置
+ saveBackgroundSetting();
+ } else {
+ Toast.makeText(this, "图片保存失败", Toast.LENGTH_SHORT).show();
+ }
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "图片加载失败", Toast.LENGTH_SHORT).show();
@@ -1640,8 +1649,17 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else if (BACKGROUND_TYPE_ALBUM.equals(mCurrentBackgroundType) && !TextUtils.isEmpty(mCurrentBackgroundPath)) {
// 使用相册图片作为背景
try {
- android.graphics.Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(
- getContentResolver().openInputStream(android.net.Uri.parse(mCurrentBackgroundPath)));
+ android.graphics.Bitmap bitmap = null;
+ // 检查路径类型
+ if (mCurrentBackgroundPath.startsWith("content://")) {
+ // 如果是URI字符串
+ bitmap = android.graphics.BitmapFactory.decodeStream(
+ getContentResolver().openInputStream(android.net.Uri.parse(mCurrentBackgroundPath)));
+ } else {
+ // 如果是内部存储路径
+ bitmap = android.graphics.BitmapFactory.decodeFile(mCurrentBackgroundPath);
+ }
+
if (bitmap != null) {
// 计算屏幕尺寸
android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics();
@@ -1750,4 +1768,42 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
});
}
+
+ /**
+ * 将图片保存到应用内部存储
+ * @param uri 图片的URI
+ * @return 保存后的内部存储路径
+ */
+ private String saveImageToInternalStorage(Uri uri) {
+ try {
+ // 创建内部存储目录
+ File directory = new File(getFilesDir(), "backgrounds");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ // 创建输出文件
+ String fileName = "background_" + System.currentTimeMillis() + ".jpg";
+ File outputFile = new File(directory, fileName);
+
+ // 复制图片
+ InputStream inputStream = getContentResolver().openInputStream(uri);
+ FileOutputStream outputStream = new FileOutputStream(outputFile);
+
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = inputStream.read(buffer)) > 0) {
+ outputStream.write(buffer, 0, length);
+ }
+
+ inputStream.close();
+ outputStream.close();
+
+ // 返回文件路径
+ return outputFile.getAbsolutePath();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
}
diff --git a/src/main/res/layout/note_edit.xml b/src/main/res/layout/note_edit.xml
index b529e4d..849137d 100644
--- a/src/main/res/layout/note_edit.xml
+++ b/src/main/res/layout/note_edit.xml
@@ -94,6 +94,16 @@
android:background="@drawable/bg_btn_insert_image"
android:contentDescription="@string/menu_insert_image"
android:padding="12dp" />
+
Word count large
Word count too large
+
+ No image found in the note
+ Loading
+ Extracting image content...
+ Failed to load image
+ Extracted Content
+ Insert
+ Cancel
+ Content inserted successfully
+ Failed to extract image content
+