AppFlowy-IO / AppFlowy-IO/appflowy-editor

[Bug] Cannot capture AppFlowy Editor widget including images inserted as base64 encoded string

Đang mở
#1,003 2 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Dart
Star
684
Fork
329
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

### Bug Description

I want to export the image file from the current editor content. So I used Screenshot package to capture it. It’s no issue to capture a visible widget. But there is an issue only to capture an invisible widget. I have to capture an invisible widget because my contents are over the screen. The result shows the base64-encoded images to [X] mark.
If I insert images as an url or a local path, no issue for same case. It’s a problem just only for base64 encoded data.

### How to Reproduce

1. Insert an image as the base64 encoded in an editor.
2. Capture from AppFlowy Editor widget with the current document.

### Expected Behavior

Capture image show the same contents with the current editor.

### Operating System

iOS, Android

### AppFlowy Editor Version(s)

4.0.0

### Screenshots

Current AppFlowy Editor Contents
Screenshot 2024-12-26 at 4 40 07 PM

Captured Image
Screenshot 2024-12-26 at 4 39 45 PM

### Additional Context

`appflowy_editor_widget.dart`

import 'package:feasibility_markdown/appflowy_editor/save_image_page.dart';
import 'package:flutter/material.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'dart:convert';

class AppFlowyEditorWidget extends StatefulWidget {
const AppFlowyEditorWidget({super.key});

@override
State createState() => _AppFlowyEditorWidgetState();
}

class _AppFlowyEditorWidgetState extends State {
final _scaffoldKey = GlobalKey();
late EditorState _editorState;
final _localToolbarItems = [
textDecorationMobileToolbarItem,
headingMobileToolbarItem,
todoListMobileToolbarItem,
listMobileToolbarItem,
linkMobileToolbarItem,
quoteMobileToolbarItem,
codeMobileToolbarItem,
blocksMobileToolbarItem,
textDecorationMobileToolbarItemV2
];

@override
void initState() {
super.initState();
_editorState = EditorState.blank();
}

@override
void dispose() {
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('AppFlowy Editor'),
),
body: Column(children: [
Expanded(
child: AppFlowyEditor(
characterShortcutEvents: standardCharacterShortcutEvents,
editorStyle: const EditorStyle.mobile(),
editorState: _editorState)),
Padding(
padding: const EdgeInsets.all(5),
child:
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
InkWell(
child: const Icon(Icons.image),
onTap: () async {
final ImagePicker picker = ImagePicker();
final XFile? pickedImage =
await picker.pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
var imageBytes =
File(pickedImage.path).readAsBytesSync();
_editorState.insertImageNode(base64Encode(imageBytes));
}
}),
InkWell(
child: const Icon(Icons.save_alt),
onTap: () async {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) =>
SaveImagePage(editorState: _editorState)));
}),
])),
MobileToolbar(
editorState: _editorState, toolbarItems: _localToolbarItems)
]));
}
}

`save_image_page.dart`

import 'dart:io';

import 'package:appflowy_editor/appflowy_editor.dart' as appflowy;
import 'package:flutter/material.dart';
import 'package:screenshot/screenshot.dart';
import 'package:gal/gal.dart';

class SaveImagePage extends StatefulWidget {
const SaveImagePage({super.key, required this.editorState});

final appflowy.EditorState editorState;

@override
State createState() => _SaveImagePageState();
}

class _SaveImagePageState extends State {
final _scaffoldKey = GlobalKey();
late ScreenshotController _screenshotController;
late appflowy.EditorState _editorState;

@override
void initState() {
super.initState();
_editorState = appflowy.EditorState(
document:
appflowy.Document.fromJson(widget.editorState.document.toJson()));
_screenshotController = ScreenshotController();

WidgetsBinding.instance.addPostFrameCallback((_) => _saveImage());
}

Widget _captureToSaveToImageWidget() {
const physicalPixelBaseLength = 512.0;
final logicalPixelBaseLength =
physicalPixelBaseLength / MediaQuery.of(context).devicePixelRatio;

return Container(
color: Colors.white,
width: logicalPixelBaseLength,
constraints: BoxConstraints(minHeight: logicalPixelBaseLength),
child: MediaQuery(
data: const MediaQueryData(),
child: IntrinsicHeight(
child: appflowy.AppFlowyEditor(
characterShortcutEvents:
appflowy.standardCharacterShortcutEvents,
editorStyle: const appflowy.EditorStyle.mobile(),
disableKeyboardService: true,
disableSelectionService: true,
shrinkWrap: true,
editorScrollController: appflowy.EditorScrollController(
editorState: _editorState, shrinkWrap: true),
editorState: _editorState),
// )),
)),
);
}

void _saveImage() async {
_screenshotController
.captureFromLongWidget(_captureToSaveToImageWidget(),
pixelRatio: MediaQuery.of(context).devicePixelRatio,
delay: const Duration(seconds: 1))
.then((capturedImage) async {
if (!mounted) return;

final file =
await File('${Directory.systemTemp.path}/flutter_image.png').create();
await file.writeAsBytes(capturedImage);
await Gal.putImage(file.path);

Navigator.of(context).pop();
});
}

@override
void dispose() {
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
body: const SafeArea(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Saving ...",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
]),
)));
}
}

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.