or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

canvas.mdcore-framework.mddevice.mddom-query.mdindex.mdlocation.mdmedia.mdnavigation.mdnetwork.mdstorage.mdsystem-info.mdui-interactions.md

media.mddocs/

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

```