or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mderror-handling.mdimage-processing.mdindex.mdupload.mdutilities.md

utilities.mddocs/

0

# Utilities

1

2

Helper functions for image compression, base64 encoding, and upload configuration management.

3

4

## Capabilities

5

6

### Image Compression

7

8

Client-side image compression to reduce file sizes before upload.

9

10

```typescript { .api }

11

/**

12

* Compress an image file on the client side

13

* @param file - Image file to compress

14

* @param options - Compression configuration

15

* @returns Promise with compressed image and metadata

16

*/

17

function compressImage(file: File, options: CompressOptions): Promise<CompressResult>;

18

19

interface CompressOptions {

20

/** Output quality (0-1), defaults to 0.92 */

21

quality?: number;

22

/** Don't compress if result is larger than original */

23

noCompressIfLarger?: boolean;

24

/** Maximum width constraint in pixels */

25

maxWidth?: number;

26

/** Maximum height constraint in pixels */

27

maxHeight?: number;

28

}

29

30

interface CompressResult {

31

/** Compressed image as Blob or original File */

32

dist: Blob | File;

33

/** Final width in pixels */

34

width: number;

35

/** Final height in pixels */

36

height: number;

37

}

38

```

39

40

**Usage Examples:**

41

42

```typescript

43

import { compressImage } from "qiniu-js";

44

45

// Basic compression

46

const fileInput = document.getElementById('imageInput') as HTMLInputElement;

47

const originalFile = fileInput.files[0];

48

49

try {

50

const compressed = await compressImage(originalFile, {

51

quality: 0.8,

52

maxWidth: 1920,

53

maxHeight: 1080,

54

noCompressIfLarger: true

55

});

56

57

console.log(`Original: ${originalFile.size} bytes`);

58

console.log(`Compressed: ${compressed.dist.size} bytes`);

59

console.log(`Dimensions: ${compressed.width}x${compressed.height}`);

60

61

// Use compressed image for upload

62

const subscription = upload(compressed.dist, 'compressed-image.jpg', token);

63

64

} catch (error) {

65

console.error('Compression failed:', error);

66

}

67

68

// Aggressive compression for thumbnails

69

async function createThumbnail(file: File): Promise<Blob> {

70

const result = await compressImage(file, {

71

quality: 0.7,

72

maxWidth: 300,

73

maxHeight: 300

74

});

75

76

return result.dist as Blob;

77

}

78

79

// Quality comparison

80

async function compressByQuality(file: File) {

81

const qualities = [0.5, 0.7, 0.9];

82

83

for (const quality of qualities) {

84

const result = await compressImage(file, { quality });

85

console.log(`Quality ${quality}: ${result.dist.size} bytes`);

86

}

87

}

88

```

89

90

### Base64 Encoding

91

92

URL-safe base64 encoding and decoding functions for Qiniu API compatibility.

93

94

```typescript { .api }

95

/**

96

* Encode data to URL-safe base64 format used by Qiniu APIs

97

* @param v - Data to encode (string or other)

98

* @returns URL-safe base64 encoded string

99

*/

100

function urlSafeBase64Encode(v: any): string;

101

102

/**

103

* Decode URL-safe base64 data

104

* @param v - URL-safe base64 encoded string

105

* @returns Decoded string

106

*/

107

function urlSafeBase64Decode(v: any): string;

108

```

109

110

**Usage Examples:**

111

112

```typescript

113

import { urlSafeBase64Encode, urlSafeBase64Decode } from "qiniu-js";

114

115

// Encode text for watermarks

116

const watermarkText = "© 2024 My Company";

117

const encodedText = urlSafeBase64Encode(watermarkText);

118

console.log('Encoded:', encodedText); // Safe for URLs

119

120

// Encode image URLs for watermarks

121

const logoUrl = "https://example.com/logo.png";

122

const encodedLogoUrl = urlSafeBase64Encode(logoUrl);

123

124

// Use in watermark operations

125

const watermarkUrl = `watermark/1/image/${encodedLogoUrl}/dissolve/80`;

126

127

// Decode data

128

const decodedText = urlSafeBase64Decode(encodedText);

129

console.log('Decoded:', decodedText); // "© 2024 My Company"

130

131

// Handle Chinese and Unicode text

132

const chineseText = "七牛云存储";

133

const encodedChinese = urlSafeBase64Encode(chineseText);

134

const decodedChinese = urlSafeBase64Decode(encodedChinese);

135

console.log('Chinese text preserved:', decodedChinese === chineseText);

136

```

137

138

### HTTP Headers Generation

139

140

Generate properly formatted headers for different types of upload requests.

141

142

```typescript { .api }

143

/**

144

* Generate headers for final file creation requests

145

* @param token - Upload token

146

* @returns Headers object with authorization and content-type

147

*/

148

function getHeadersForMkFile(token: string): { [key: string]: string };

149

150

/**

151

* Generate headers for chunk upload requests

152

* @param token - Upload token

153

* @returns Headers object with authorization and content-type

154

*/

155

function getHeadersForChunkUpload(token: string): { [key: string]: string };

156

```

157

158

**Usage Examples:**

159

160

```typescript

161

import { getHeadersForMkFile, getHeadersForChunkUpload } from "qiniu-js";

162

163

// Get headers for file completion

164

const token = "your-upload-token";

165

const mkFileHeaders = getHeadersForMkFile(token);

166

console.log(mkFileHeaders);

167

// Output: {

168

// "Authorization": "UpToken your-upload-token",

169

// "content-type": "application/json"

170

// }

171

172

// Get headers for chunk uploads

173

const chunkHeaders = getHeadersForChunkUpload(token);

174

console.log(chunkHeaders);

175

// Output: {

176

// "Authorization": "UpToken your-upload-token",

177

// "content-type": "application/octet-stream"

178

// }

179

180

// Use in custom HTTP requests

181

async function customChunkUpload(chunkData: Blob, uploadUrl: string, token: string) {

182

const headers = getHeadersForChunkUpload(token);

183

184

const response = await fetch(uploadUrl, {

185

method: 'PUT',

186

headers: {

187

...headers,

188

'Content-MD5': await calculateMD5(chunkData)

189

},

190

body: chunkData

191

});

192

193

return response.json();

194

}

195

```

196

197

## Advanced Utilities

198

199

### Image Compression Advanced Usage

200

201

Handle different scenarios and edge cases with image compression.

202

203

```typescript

204

import { compressImage, QiniuError, QiniuErrorName } from "qiniu-js";

205

206

async function smartCompress(file: File): Promise<File | Blob> {

207

// Skip compression for very small images

208

if (file.size < 100 * 1024) { // Less than 100KB

209

console.log('File too small, skipping compression');

210

return file;

211

}

212

213

// Skip compression for non-image files

214

if (!file.type.startsWith('image/')) {

215

console.log('Not an image file, skipping compression');

216

return file;

217

}

218

219

try {

220

// Try aggressive compression first

221

let result = await compressImage(file, {

222

quality: 0.7,

223

maxWidth: 1920,

224

maxHeight: 1080,

225

noCompressIfLarger: true

226

});

227

228

// If still too large, try more aggressive compression

229

if (result.dist.size > 2 * 1024 * 1024) { // > 2MB

230

result = await compressImage(file, {

231

quality: 0.5,

232

maxWidth: 1280,

233

maxHeight: 720,

234

noCompressIfLarger: true

235

});

236

}

237

238

console.log(`Compression ratio: ${(result.dist.size / file.size * 100).toFixed(1)}%`);

239

return result.dist;

240

241

} catch (error) {

242

if (error instanceof QiniuError) {

243

if (error.name === QiniuErrorName.UnsupportedFileType) {

244

console.log('Unsupported image format, using original');

245

return file;

246

} else if (error.name === QiniuErrorName.GetCanvasContextFailed) {

247

console.log('Canvas not available, using original');

248

return file;

249

}

250

}

251

252

console.error('Compression failed, using original:', error);

253

return file;

254

}

255

}

256

257

// Batch compression with progress

258

async function compressBatch(files: File[], onProgress?: (index: number, total: number) => void): Promise<(File | Blob)[]> {

259

const results: (File | Blob)[] = [];

260

261

for (let i = 0; i < files.length; i++) {

262

const compressed = await smartCompress(files[i]);

263

results.push(compressed);

264

265

if (onProgress) {

266

onProgress(i + 1, files.length);

267

}

268

}

269

270

return results;

271

}

272

```

273

274

### Base64 Utilities for Complex Scenarios

275

276

Handle various encoding scenarios for API parameters.

277

278

```typescript

279

import { urlSafeBase64Encode, urlSafeBase64Decode } from "qiniu-js";

280

281

// Create complex watermark configurations

282

function createWatermarkConfig(options: {

283

text?: string;

284

imageUrl?: string;

285

fontFamily?: string;

286

color?: string;

287

}) {

288

const params: string[] = [];

289

290

if (options.text) {

291

params.push(`text/${urlSafeBase64Encode(options.text)}`);

292

}

293

294

if (options.imageUrl) {

295

params.push(`image/${urlSafeBase64Encode(options.imageUrl)}`);

296

}

297

298

if (options.fontFamily) {

299

params.push(`font/${urlSafeBase64Encode(options.fontFamily)}`);

300

}

301

302

if (options.color) {

303

params.push(`fill/${urlSafeBase64Encode(options.color)}`);

304

}

305

306

return params.join('/');

307

}

308

309

// Usage

310

const watermarkParams = createWatermarkConfig({

311

text: "版权所有 © 2024",

312

fontFamily: "微软雅黑",

313

color: "#FFFFFF"

314

});

315

316

// Parse processing URLs

317

function parseProcessingUrl(url: string): any {

318

const params = url.split('/');

319

const result: any = {};

320

321

for (let i = 0; i < params.length; i += 2) {

322

if (i + 1 < params.length) {

323

const key = params[i];

324

const value = params[i + 1];

325

326

// Decode base64 encoded values

327

if (['text', 'font', 'image', 'fill'].includes(key)) {

328

result[key] = urlSafeBase64Decode(value);

329

} else {

330

result[key] = value;

331

}

332

}

333

}

334

335

return result;

336

}

337

```

338

339

### Upload Configuration Helpers

340

341

Utility functions for managing upload configurations and validating settings.

342

343

```typescript

344

// Validation helper for custom variables

345

function validateCustomVars(customVars: { [key: string]: string }): boolean {

346

return Object.keys(customVars).every(key => key.startsWith('x:'));

347

}

348

349

// Validation helper for metadata

350

function validateMetadata(metadata: { [key: string]: string }): boolean {

351

return Object.keys(metadata).every(key => key.startsWith('x-qn-meta-'));

352

}

353

354

// Configuration builder

355

class UploadConfigBuilder {

356

private config: any = {};

357

358

region(region: string) {

359

this.config.region = region;

360

return this;

361

}

362

363

retryCount(count: number) {

364

this.config.retryCount = Math.max(0, Math.min(10, count));

365

return this;

366

}

367

368

chunkSize(sizeMB: number) {

369

this.config.chunkSize = Math.max(1, Math.min(1000, sizeMB));

370

return this;

371

}

372

373

useCdn(enabled: boolean = true) {

374

this.config.useCdnDomain = enabled;

375

return this;

376

}

377

378

forceDirect(enabled: boolean = true) {

379

this.config.forceDirect = enabled;

380

return this;

381

}

382

383

build() {

384

return { ...this.config };

385

}

386

}

387

388

// Usage

389

const config = new UploadConfigBuilder()

390

.region('z0')

391

.retryCount(5)

392

.chunkSize(8)

393

.useCdn(true)

394

.build();

395

396

console.log(config);

397

// Output: {

398

// region: 'z0',

399

// retryCount: 5,

400

// chunkSize: 8,

401

// useCdnDomain: true

402

// }

403

```