Skip to content

Commit 0d2baed

Browse files
committed
feat(examples): 添加交互式示例页面与实时代码执行功能
- 创建新示例页面,展示所有 libvips_ffi 操作的代码示例 - 添加交互式"试一试"区域,实现实时图像处理 - 实现开发者工具页面,组织测试和诊断工具 - 更新 README 文档,扩展文档内容和快速入门部分 - 重组主页导航,提升用户体验 Signed-off-by: Caijinglong <[email protected]>
1 parent 6847db2 commit 0d2baed

File tree

5 files changed

+1209
-47
lines changed

5 files changed

+1209
-47
lines changed

libvips_ffi/README.md

Lines changed: 114 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ dependencies:
3838
path: libvips_ffi
3939
```
4040
41-
## Usage
41+
## Quick Start
42+
43+
### Basic Usage (Sync API)
4244
4345
```dart
4446
import 'package:libvips_ffi/libvips_ffi.dart';
@@ -52,25 +54,127 @@ void main() {
5254

5355
// Load an image
5456
final image = VipsImageWrapper.fromFile('/path/to/image.jpg');
55-
56-
// Get image info
5757
print('Size: ${image.width}x${image.height}');
58-
print('Bands: ${image.bands}');
5958

60-
// Save to a different format
61-
image.writeToFile('/path/to/output.png');
59+
// Process image
60+
final resized = image.resize(0.5); // 50% size
61+
final blurred = resized.gaussianBlur(3.0);
6262

63-
// Or get as bytes
64-
final pngBytes = image.writeToBuffer('.png');
63+
// Save result
64+
blurred.writeToFile('/path/to/output.jpg');
6565

66-
// Don't forget to dispose
66+
// Always dispose when done (in reverse order)
67+
blurred.dispose();
68+
resized.dispose();
6769
image.dispose();
6870

69-
// Shutdown when done (optional)
7071
shutdownVips();
7172
}
7273
```
7374

75+
### Flutter Usage (Async API - Recommended)
76+
77+
**Important:** Use the async API in Flutter to avoid blocking the UI thread.
78+
79+
```dart
80+
import 'package:libvips_ffi/libvips_ffi.dart';
81+
82+
// Simple one-off operations using VipsCompute
83+
Future<void> processImage() async {
84+
// Resize image (runs in isolate, doesn't block UI)
85+
final result = await VipsCompute.resizeFile('input.jpg', 0.5);
86+
87+
// result.data contains the processed image bytes
88+
// result.width, result.height contain dimensions
89+
90+
// Display in Flutter
91+
Image.memory(result.data);
92+
}
93+
94+
// More operations
95+
Future<void> moreExamples() async {
96+
// Thumbnail (most efficient for previews)
97+
final thumb = await VipsCompute.thumbnailFile('input.jpg', 200);
98+
99+
// Rotate
100+
final rotated = await VipsCompute.rotateFile('input.jpg', 90);
101+
102+
// Blur
103+
final blurred = await VipsCompute.blurFile('input.jpg', 5.0);
104+
105+
// Custom operation chain
106+
final custom = await VipsCompute.processFile('input.jpg', (img) {
107+
final step1 = img.resize(0.5);
108+
final step2 = step1.gaussianBlur(2.0);
109+
step1.dispose(); // Clean up intermediate
110+
return step2;
111+
});
112+
}
113+
```
114+
115+
### Common Operations
116+
117+
```dart
118+
// Resize by scale factor
119+
final resized = image.resize(0.5); // 50% of original
120+
121+
// Create thumbnail (maintains aspect ratio)
122+
final thumb = image.thumbnail(200); // 200px width
123+
124+
// Rotate by angle
125+
final rotated = image.rotate(90); // 90 degrees
126+
127+
// Crop region
128+
final cropped = image.crop(100, 100, 200, 200); // left, top, width, height
129+
130+
// Flip
131+
final flippedH = image.flip(VipsDirection.horizontal);
132+
final flippedV = image.flip(VipsDirection.vertical);
133+
134+
// Blur
135+
final blurred = image.gaussianBlur(5.0); // sigma value
136+
137+
// Sharpen
138+
final sharpened = image.sharpen();
139+
140+
// Adjust brightness (1.0 = no change, >1 = brighter)
141+
final brighter = image.brightness(1.3);
142+
143+
// Adjust contrast
144+
final highContrast = image.contrast(1.5);
145+
146+
// Convert to grayscale
147+
final gray = image.colourspace(VipsInterpretation.bw);
148+
149+
// Smart crop (focus on interesting area)
150+
final smartCropped = image.smartCrop(300, 300);
151+
152+
// Auto-rotate based on EXIF
153+
final autoRotated = image.autoRotate();
154+
```
155+
156+
### Memory Management
157+
158+
```dart
159+
// Always dispose images when done
160+
final image = VipsImageWrapper.fromFile('input.jpg');
161+
try {
162+
final result = image.resize(0.5);
163+
try {
164+
result.writeToFile('output.jpg');
165+
} finally {
166+
result.dispose();
167+
}
168+
} finally {
169+
image.dispose();
170+
}
171+
172+
// Check for memory leaks (development only)
173+
if (VipsPointerManager.instance.hasLeaks) {
174+
print(VipsPointerManager.instance.getLeakReport());
175+
}
176+
```
177+
74178
## Advanced Usage
75179

76180
For advanced users who need direct access to libvips functions:

libvips_ffi/README_CN.md

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ dependencies:
3838
path: libvips_ffi
3939
```
4040
41-
## 使用示例
41+
## 快速开始
42+
43+
### 基础用法(同步 API)
4244
4345
```dart
4446
import 'package:libvips_ffi/libvips_ffi.dart';
@@ -52,25 +54,127 @@ void main() {
5254

5355
// 加载图片
5456
final image = VipsImageWrapper.fromFile('/path/to/image.jpg');
57+
print('尺寸: ${image.width}x${image.height}');
5558

56-
// 获取图片信息
57-
print('Size: ${image.width}x${image.height}');
58-
print('Bands: ${image.bands}');
59-
60-
// 保存为其他格式
61-
image.writeToFile('/path/to/output.png');
59+
// 处理图片
60+
final resized = image.resize(0.5); // 缩小到 50%
61+
final blurred = resized.gaussianBlur(3.0);
6262

63-
// 或导出为字节数据
64-
final pngBytes = image.writeToBuffer('.png');
63+
// 保存结果
64+
blurred.writeToFile('/path/to/output.jpg');
6565

66-
// 使用完记得释放资源
66+
// 使用完记得释放资源(按逆序释放)
67+
blurred.dispose();
68+
resized.dispose();
6769
image.dispose();
6870

69-
// 全部处理完成后(可选)关闭 libvips
7071
shutdownVips();
7172
}
7273
```
7374

75+
### Flutter 用法(异步 API - 推荐)
76+
77+
**重要:** 在 Flutter 中请使用异步 API,避免阻塞 UI 线程。
78+
79+
```dart
80+
import 'package:libvips_ffi/libvips_ffi.dart';
81+
82+
// 使用 VipsCompute 进行简单的一次性操作
83+
Future<void> processImage() async {
84+
// 调整图片大小(在 isolate 中运行,不阻塞 UI)
85+
final result = await VipsCompute.resizeFile('input.jpg', 0.5);
86+
87+
// result.data 包含处理后的图片字节数据
88+
// result.width, result.height 包含尺寸信息
89+
90+
// 在 Flutter 中显示
91+
Image.memory(result.data);
92+
}
93+
94+
// 更多操作示例
95+
Future<void> moreExamples() async {
96+
// 缩略图(预览图最高效的方式)
97+
final thumb = await VipsCompute.thumbnailFile('input.jpg', 200);
98+
99+
// 旋转
100+
final rotated = await VipsCompute.rotateFile('input.jpg', 90);
101+
102+
// 模糊
103+
final blurred = await VipsCompute.blurFile('input.jpg', 5.0);
104+
105+
// 自定义操作链
106+
final custom = await VipsCompute.processFile('input.jpg', (img) {
107+
final step1 = img.resize(0.5);
108+
final step2 = step1.gaussianBlur(2.0);
109+
step1.dispose(); // 清理中间结果
110+
return step2;
111+
});
112+
}
113+
```
114+
115+
### 常用操作
116+
117+
```dart
118+
// 按比例缩放
119+
final resized = image.resize(0.5); // 原图的 50%
120+
121+
// 创建缩略图(保持宽高比)
122+
final thumb = image.thumbnail(200); // 宽度 200px
123+
124+
// 按角度旋转
125+
final rotated = image.rotate(90); // 90 度
126+
127+
// 裁剪区域
128+
final cropped = image.crop(100, 100, 200, 200); // left, top, width, height
129+
130+
// 翻转
131+
final flippedH = image.flip(VipsDirection.horizontal); // 水平翻转
132+
final flippedV = image.flip(VipsDirection.vertical); // 垂直翻转
133+
134+
// 模糊
135+
final blurred = image.gaussianBlur(5.0); // sigma 值
136+
137+
// 锐化
138+
final sharpened = image.sharpen();
139+
140+
// 调整亮度(1.0 = 不变,>1 = 更亮)
141+
final brighter = image.brightness(1.3);
142+
143+
// 调整对比度
144+
final highContrast = image.contrast(1.5);
145+
146+
// 转换为灰度
147+
final gray = image.colourspace(VipsInterpretation.bw);
148+
149+
// 智能裁剪(聚焦于有趣的区域)
150+
final smartCropped = image.smartCrop(300, 300);
151+
152+
// 根据 EXIF 自动旋转
153+
final autoRotated = image.autoRotate();
154+
```
155+
156+
### 内存管理
157+
158+
```dart
159+
// 使用完图片后务必释放
160+
final image = VipsImageWrapper.fromFile('input.jpg');
161+
try {
162+
final result = image.resize(0.5);
163+
try {
164+
result.writeToFile('output.jpg');
165+
} finally {
166+
result.dispose();
167+
}
168+
} finally {
169+
image.dispose();
170+
}
171+
172+
// 检查内存泄漏(仅开发阶段使用)
173+
if (VipsPointerManager.instance.hasLeaks) {
174+
print(VipsPointerManager.instance.getLeakReport());
175+
}
176+
```
177+
74178
## 高级用法
75179

76180
对于需要直接访问 libvips 原生函数的高级用户,可以直接使用底层绑定:

libvips_ffi/example/lib/main.dart

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import 'package:flutter/material.dart';
22
import 'package:libvips_ffi/libvips_ffi.dart';
33

4-
import 'pages/all_tests_page.dart';
5-
import 'pages/benchmark_page.dart';
6-
import 'pages/memory_diagnostics_page.dart';
4+
import 'pages/developer_tools_page.dart';
5+
import 'pages/examples_page.dart';
76

87
void main() {
98
runApp(const MyApp());
@@ -111,43 +110,33 @@ class _HomePageState extends State<HomePage> {
111110

112111
// Navigation Buttons
113112
Text(
114-
'Select a test mode:',
113+
'Get Started / 开始使用',
115114
style: Theme.of(context).textTheme.titleMedium,
116115
),
117116
const SizedBox(height: 16),
118117

119118
_buildNavButton(
120119
context,
121-
title: 'All Tests',
122-
subtitle: 'Test all image operations with async API',
123-
icon: Icons.science,
120+
title: 'Examples / 示例',
121+
subtitle: 'Learn with code examples and try them live',
122+
icon: Icons.code,
123+
color: Colors.green,
124124
onTap: () => Navigator.push(
125125
context,
126-
MaterialPageRoute(builder: (_) => const AllTestsPage()),
126+
MaterialPageRoute(builder: (_) => const ExamplesPage()),
127127
),
128128
),
129129
const SizedBox(height: 12),
130130

131131
_buildNavButton(
132132
context,
133-
title: 'Benchmark',
134-
subtitle: 'Compare sync vs async performance',
135-
icon: Icons.speed,
133+
title: 'Developer Tools / 开发者工具',
134+
subtitle: 'Testing, benchmarking, and diagnostics',
135+
icon: Icons.developer_mode,
136+
color: Colors.orange,
136137
onTap: () => Navigator.push(
137138
context,
138-
MaterialPageRoute(builder: (_) => const BenchmarkPage()),
139-
),
140-
),
141-
const SizedBox(height: 12),
142-
143-
_buildNavButton(
144-
context,
145-
title: 'Memory Diagnostics',
146-
subtitle: 'Monitor pointer usage and detect leaks',
147-
icon: Icons.memory,
148-
onTap: () => Navigator.push(
149-
context,
150-
MaterialPageRoute(builder: (_) => const MemoryDiagnosticsPage()),
139+
MaterialPageRoute(builder: (_) => const DeveloperToolsPage()),
151140
),
152141
),
153142

@@ -198,6 +187,7 @@ class _HomePageState extends State<HomePage> {
198187
required String subtitle,
199188
required IconData icon,
200189
required VoidCallback onTap,
190+
Color color = Colors.blue,
201191
}) {
202192
return Card(
203193
clipBehavior: Clip.antiAlias,
@@ -210,10 +200,10 @@ class _HomePageState extends State<HomePage> {
210200
Container(
211201
padding: const EdgeInsets.all(12),
212202
decoration: BoxDecoration(
213-
color: Colors.blue.shade100,
203+
color: color.withOpacity(0.15),
214204
borderRadius: BorderRadius.circular(12),
215205
),
216-
child: Icon(icon, size: 32, color: Colors.blue.shade700),
206+
child: Icon(icon, size: 32, color: color),
217207
),
218208
const SizedBox(width: 16),
219209
Expanded(

0 commit comments

Comments
 (0)