0
# Media APIs
1
2
Comprehensive media handling capabilities including image selection, preview, information retrieval, and photo album integration for web-compatible media operations.
3
4
## Capabilities
5
6
### Image Selection APIs
7
8
File selection and camera integration for capturing or choosing images from user device.
9
10
```typescript { .api }
11
/**
12
* Select images from album or take photos using camera
13
* @deprecated Use chooseMedia interface instead for better functionality
14
* @param options - Image selection configuration options
15
* @returns Promise resolving to selected image information
16
*/
17
function chooseImage(options: ChooseImageOption): Promise<ChooseImageResult>;
18
19
interface ChooseImageOption {
20
/** Maximum number of images to select (default: 9) */
21
count?: number;
22
/** Image size type preference */
23
sizeType?: ('original' | 'compressed')[];
24
/** Image source types */
25
sourceType?: ('album' | 'camera' | 'user')[];
26
/** Success callback function */
27
success?: (result: ChooseImageResult) => void;
28
/** Failure callback function */
29
fail?: (error: any) => void;
30
/** Completion callback function */
31
complete?: (result: ChooseImageResult | any) => void;
32
}
33
34
interface ChooseImageResult {
35
/** Array of selected image file paths */
36
tempFilePaths: string[];
37
/** Detailed information about selected images */
38
tempFiles: ImageFile[];
39
/** Operation result message */
40
errMsg: string;
41
}
42
43
interface ImageFile {
44
/** Temporary file path (blob URL) */
45
path: string;
46
/** File size in bytes */
47
size: number;
48
/** File type/format */
49
type: string;
50
/** Original File object for advanced operations */
51
originalFileObj?: File;
52
}
53
```
54
55
**Usage Examples:**
56
57
```typescript
58
import { chooseImage } from "@tarojs/taro-h5";
59
60
// Basic image selection
61
const selectImages = async () => {
62
try {
63
const result = await chooseImage({
64
count: 3,
65
sizeType: ['compressed'],
66
sourceType: ['album', 'camera']
67
});
68
69
console.log('Selected images:', result.tempFilePaths);
70
71
// Display selected images
72
result.tempFilePaths.forEach((imagePath, index) => {
73
const img = document.createElement('img');
74
img.src = imagePath;
75
img.style.maxWidth = '200px';
76
img.style.margin = '10px';
77
document.body.appendChild(img);
78
});
79
80
// Get detailed file information
81
result.tempFiles.forEach((file, index) => {
82
console.log(`Image ${index + 1}:`);
83
console.log(`- Path: ${file.path}`);
84
console.log(`- Size: ${(file.size / 1024).toFixed(2)} KB`);
85
console.log(`- Type: ${file.type}`);
86
});
87
88
} catch (error) {
89
console.error('Image selection failed:', error);
90
}
91
};
92
93
// Camera-only selection
94
const takePhoto = async () => {
95
try {
96
const result = await chooseImage({
97
count: 1,
98
sourceType: ['camera'],
99
sizeType: ['original'],
100
success: (res) => {
101
console.log('Photo captured successfully');
102
},
103
fail: (error) => {
104
console.error('Camera access failed:', error);
105
}
106
});
107
108
const photoPath = result.tempFilePaths[0];
109
110
// Use the captured photo
111
const img = document.createElement('img');
112
img.src = photoPath;
113
img.style.maxWidth = '100%';
114
document.getElementById('photo-container')?.appendChild(img);
115
116
} catch (error) {
117
console.error('Photo capture failed:', error);
118
}
119
};
120
121
// Multiple image selection with validation
122
const selectValidatedImages = async () => {
123
try {
124
const result = await chooseImage({
125
count: 5,
126
sourceType: ['album'],
127
sizeType: ['compressed']
128
});
129
130
// Validate selected images
131
const validImages = result.tempFiles.filter(file => {
132
// Check file size (max 5MB)
133
if (file.size > 5 * 1024 * 1024) {
134
console.warn(`Image too large: ${file.path}`);
135
return false;
136
}
137
138
// Check file type
139
const validTypes = ['image/jpeg', 'image/png', 'image/gif'];
140
if (!validTypes.includes(file.type)) {
141
console.warn(`Invalid image type: ${file.type}`);
142
return false;
143
}
144
145
return true;
146
});
147
148
if (validImages.length === 0) {
149
throw new Error('No valid images selected');
150
}
151
152
console.log(`Selected ${validImages.length} valid images`);
153
return validImages.map(file => file.path);
154
155
} catch (error) {
156
console.error('Image validation failed:', error);
157
}
158
};
159
```
160
161
### Image Preview APIs
162
163
Full-screen image preview with swipe navigation and zoom functionality.
164
165
```typescript { .api }
166
/**
167
* Preview images in full-screen with navigation and zoom support
168
* @param options - Image preview configuration options
169
* @returns Promise resolving when preview is initialized
170
*/
171
function previewImage(options: PreviewImageOption): Promise<void>;
172
173
interface PreviewImageOption {
174
/** Current image URL to display initially */
175
current?: string | number;
176
/** Array of image URLs to preview */
177
urls: string[];
178
/** Success callback function */
179
success?: () => void;
180
/** Failure callback function */
181
fail?: (error: any) => void;
182
/** Completion callback function */
183
complete?: () => void;
184
}
185
```
186
187
**Usage Examples:**
188
189
```typescript
190
import { previewImage } from "@tarojs/taro-h5";
191
192
// Basic image preview
193
const previewGallery = async () => {
194
const imageUrls = [
195
'https://example.com/image1.jpg',
196
'https://example.com/image2.jpg',
197
'https://example.com/image3.jpg'
198
];
199
200
try {
201
await previewImage({
202
current: 0, // Start with first image
203
urls: imageUrls,
204
success: () => {
205
console.log('Image preview opened');
206
},
207
fail: (error) => {
208
console.error('Preview failed:', error);
209
}
210
});
211
} catch (error) {
212
console.error('Failed to open image preview:', error);
213
}
214
};
215
216
// Preview with specific starting image
217
const previewFromCurrent = async (currentImageUrl: string, allImages: string[]) => {
218
try {
219
await previewImage({
220
current: currentImageUrl, // Start with specific image
221
urls: allImages,
222
success: () => {
223
console.log('Preview started from:', currentImageUrl);
224
}
225
});
226
} catch (error) {
227
console.error('Preview initialization failed:', error);
228
}
229
};
230
231
// Gallery component integration
232
class ImageGallery {
233
private images: string[] = [];
234
235
constructor(imageUrls: string[]) {
236
this.images = imageUrls;
237
this.createGalleryUI();
238
}
239
240
private createGalleryUI() {
241
const container = document.createElement('div');
242
container.className = 'image-gallery';
243
container.style.cssText = 'display: flex; flex-wrap: wrap; gap: 10px; padding: 20px;';
244
245
this.images.forEach((imageUrl, index) => {
246
const thumbnail = document.createElement('img');
247
thumbnail.src = imageUrl;
248
thumbnail.style.cssText = 'width: 150px; height: 150px; object-fit: cover; cursor: pointer; border-radius: 8px;';
249
250
// Add click handler for preview
251
thumbnail.addEventListener('click', () => {
252
this.openPreview(index);
253
});
254
255
container.appendChild(thumbnail);
256
});
257
258
document.body.appendChild(container);
259
}
260
261
private async openPreview(startIndex: number) {
262
try {
263
await previewImage({
264
current: startIndex,
265
urls: this.images,
266
success: () => {
267
console.log(`Opened preview starting at image ${startIndex + 1}`);
268
}
269
});
270
} catch (error) {
271
console.error('Gallery preview failed:', error);
272
}
273
}
274
275
// Add images to gallery
276
addImages(newImages: string[]) {
277
this.images.push(...newImages);
278
// Refresh UI
279
const existingGallery = document.querySelector('.image-gallery');
280
existingGallery?.remove();
281
this.createGalleryUI();
282
}
283
}
284
285
// Usage
286
const gallery = new ImageGallery([
287
'https://example.com/photo1.jpg',
288
'https://example.com/photo2.jpg',
289
'https://example.com/photo3.jpg'
290
]);
291
```
292
293
### Image Information APIs
294
295
Retrieve detailed information about images including dimensions and format data.
296
297
```typescript { .api }
298
/**
299
* Get detailed image information including dimensions and format
300
* @param options - Image information retrieval options
301
* @returns Promise resolving to image information
302
*/
303
function getImageInfo(options: GetImageInfoOption): Promise<ImageInfoResult>;
304
305
interface GetImageInfoOption {
306
/** Image URL or path to analyze */
307
src: string;
308
/** Success callback function */
309
success?: (result: ImageInfoResult) => void;
310
/** Failure callback function */
311
fail?: (error: any) => void;
312
/** Completion callback function */
313
complete?: (result: ImageInfoResult | any) => void;
314
}
315
316
interface ImageInfoResult {
317
/** Image width in pixels */
318
width: number;
319
/** Image height in pixels */
320
height: number;
321
/** Base64 data URL or original path */
322
path: string;
323
}
324
```
325
326
**Usage Examples:**
327
328
```typescript
329
import { getImageInfo } from "@tarojs/taro-h5";
330
331
// Get basic image information
332
const analyzeImage = async (imageUrl: string) => {
333
try {
334
const info = await getImageInfo({
335
src: imageUrl,
336
success: (result) => {
337
console.log('Image analysis completed');
338
},
339
fail: (error) => {
340
console.error('Image analysis failed:', error);
341
}
342
});
343
344
console.log('Image Information:');
345
console.log(`- Dimensions: ${info.width} x ${info.height} pixels`);
346
console.log(`- Aspect Ratio: ${(info.width / info.height).toFixed(2)}`);
347
console.log(`- Data Path: ${info.path.substring(0, 50)}...`);
348
349
return info;
350
351
} catch (error) {
352
console.error('Failed to get image info:', error);
353
throw error;
354
}
355
};
356
357
// Batch image analysis
358
const analyzeBatchImages = async (imageUrls: string[]) => {
359
try {
360
const analysisPromises = imageUrls.map(async (url, index) => {
361
try {
362
const info = await getImageInfo({ src: url });
363
return {
364
index,
365
url,
366
success: true,
367
info
368
};
369
} catch (error) {
370
return {
371
index,
372
url,
373
success: false,
374
error: error.message
375
};
376
}
377
});
378
379
const results = await Promise.all(analysisPromises);
380
381
// Process results
382
const successful = results.filter(r => r.success);
383
const failed = results.filter(r => !r.success);
384
385
console.log(`Analysis completed: ${successful.length} successful, ${failed.length} failed`);
386
387
successful.forEach((result, index) => {
388
if (result.success) {
389
const { info } = result;
390
console.log(`Image ${result.index + 1}: ${info.width}x${info.height}`);
391
}
392
});
393
394
if (failed.length > 0) {
395
console.error('Failed images:', failed.map(f => f.url));
396
}
397
398
return results;
399
400
} catch (error) {
401
console.error('Batch analysis failed:', error);
402
}
403
};
404
405
// Image validation using getImageInfo
406
const validateImageDimensions = async (imageUrl: string, requirements: { minWidth?: number; minHeight?: number; maxWidth?: number; maxHeight?: number; aspectRatio?: number }) => {
407
try {
408
const info = await getImageInfo({ src: imageUrl });
409
const errors: string[] = [];
410
411
if (requirements.minWidth && info.width < requirements.minWidth) {
412
errors.push(`Width ${info.width} is less than required ${requirements.minWidth}`);
413
}
414
415
if (requirements.maxWidth && info.width > requirements.maxWidth) {
416
errors.push(`Width ${info.width} exceeds maximum ${requirements.maxWidth}`);
417
}
418
419
if (requirements.minHeight && info.height < requirements.minHeight) {
420
errors.push(`Height ${info.height} is less than required ${requirements.minHeight}`);
421
}
422
423
if (requirements.maxHeight && info.height > requirements.maxHeight) {
424
errors.push(`Height ${info.height} exceeds maximum ${requirements.maxHeight}`);
425
}
426
427
if (requirements.aspectRatio) {
428
const actualRatio = info.width / info.height;
429
const tolerance = 0.1; // 10% tolerance
430
const expectedRatio = requirements.aspectRatio;
431
432
if (Math.abs(actualRatio - expectedRatio) > tolerance) {
433
errors.push(`Aspect ratio ${actualRatio.toFixed(2)} does not match required ${expectedRatio}`);
434
}
435
}
436
437
return {
438
valid: errors.length === 0,
439
errors,
440
info
441
};
442
443
} catch (error) {
444
return {
445
valid: false,
446
errors: [`Failed to analyze image: ${error.message}`],
447
info: null
448
};
449
}
450
};
451
452
// Usage example
453
const validateProfileImage = async (imageUrl: string) => {
454
const validation = await validateImageDimensions(imageUrl, {
455
minWidth: 200,
456
minHeight: 200,
457
maxWidth: 1024,
458
maxHeight: 1024,
459
aspectRatio: 1.0 // Square images
460
});
461
462
if (validation.valid) {
463
console.log('Image meets requirements');
464
return true;
465
} else {
466
console.error('Image validation failed:', validation.errors);
467
return false;
468
}
469
};
470
```
471
472
### Photo Album Integration
473
474
Save images to device photo album with permission handling.
475
476
```typescript { .api }
477
/**
478
* Save image to device photo album
479
* @param options - Save image configuration options
480
* @returns Promise resolving when save operation completes
481
*/
482
function saveImageToPhotosAlbum(options: SaveImageOption): Promise<void>;
483
484
interface SaveImageOption {
485
/** Image file path to save */
486
filePath: string;
487
/** Success callback function */
488
success?: () => void;
489
/** Failure callback function */
490
fail?: (error: any) => void;
491
/** Completion callback function */
492
complete?: () => void;
493
}
494
```
495
496
**Usage Examples:**
497
498
```typescript
499
import { saveImageToPhotosAlbum } from "@tarojs/taro-h5";
500
501
// Save single image to photos album
502
const saveToAlbum = async (imagePath: string) => {
503
try {
504
await saveImageToPhotosAlbum({
505
filePath: imagePath,
506
success: () => {
507
console.log('Image saved to album successfully');
508
showSuccessMessage('Image saved to photos');
509
},
510
fail: (error) => {
511
console.error('Save to album failed:', error);
512
showErrorMessage('Failed to save image');
513
}
514
});
515
} catch (error) {
516
console.error('Save operation failed:', error);
517
}
518
};
519
520
// Save multiple images with progress tracking
521
const saveMultipleImages = async (imagePaths: string[]) => {
522
let savedCount = 0;
523
let failedCount = 0;
524
525
const savePromises = imagePaths.map(async (imagePath, index) => {
526
try {
527
await saveImageToPhotosAlbum({
528
filePath: imagePath,
529
success: () => {
530
savedCount++;
531
console.log(`Image ${index + 1} saved successfully`);
532
updateProgress(savedCount + failedCount, imagePaths.length);
533
},
534
fail: (error) => {
535
failedCount++;
536
console.error(`Failed to save image ${index + 1}:`, error);
537
updateProgress(savedCount + failedCount, imagePaths.length);
538
}
539
});
540
} catch (error) {
541
failedCount++;
542
console.error(`Exception saving image ${index + 1}:`, error);
543
}
544
});
545
546
try {
547
await Promise.all(savePromises);
548
549
console.log(`Save completed: ${savedCount} successful, ${failedCount} failed`);
550
551
if (savedCount > 0) {
552
showSuccessMessage(`${savedCount} images saved to album`);
553
}
554
555
if (failedCount > 0) {
556
showErrorMessage(`${failedCount} images failed to save`);
557
}
558
559
} catch (error) {
560
console.error('Batch save operation failed:', error);
561
}
562
};
563
564
// Helper functions for UI feedback
565
function updateProgress(completed: number, total: number) {
566
const percent = Math.round((completed / total) * 100);
567
console.log(`Progress: ${completed}/${total} (${percent}%)`);
568
569
// Update progress bar if available
570
const progressBar = document.getElementById('save-progress');
571
if (progressBar) {
572
progressBar.style.width = `${percent}%`;
573
}
574
}
575
576
function showSuccessMessage(message: string) {
577
// Implementation would show toast or notification
578
console.log('Success:', message);
579
}
580
581
function showErrorMessage(message: string) {
582
// Implementation would show error toast or notification
583
console.error('Error:', message);
584
}
585
```
586
587
## Implementation Status
588
589
### ✅ Fully Implemented
590
- **Image Selection**: `chooseImage` - Complete implementation with album and camera support
591
- **Image Preview**: `previewImage` - Full-screen preview with zoom and navigation
592
- **Image Information**: `getImageInfo` - Complete dimension and format analysis
593
- **Photo Album**: `saveImageToPhotosAlbum` - Full save functionality with permission handling
594
595
### ⚠️ Temporarily Not Supported
596
- **Image Processing**: `compressImage`, `editImage`, `cropImage` - Return placeholder stubs
597
- **Media Preview**: `previewMedia` - Advanced media preview functionality
598
599
### ❌ Permanently Not Supported
600
- **WeChat Specific**: `chooseMessageFile` - Platform-specific file selection not available in browsers
601
602
## Types
603
604
```typescript { .api }
605
type ImageSourceType = 'album' | 'camera' | 'user';
606
type ImageSizeType = 'original' | 'compressed';
607
608
interface MediaCapabilities {
609
/** Whether device supports camera access */
610
camera: boolean;
611
/** Whether device supports album access */
612
album: boolean;
613
/** Whether device supports photo album saving */
614
saveToAlbum: boolean;
615
}
616
617
// Get device media capabilities
618
declare function getMediaCapabilities(): MediaCapabilities;
619
```