@egova-mobile/app-media-utils 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,8 @@ export declare class ResizeOptions {
5
5
  }
6
6
  export declare class CompressOptions {
7
7
  photoFileSizeLimit: number;
8
- constructor(photoFileSizeLimit: number);
8
+ keepFileType: boolean;
9
+ constructor(photoFileSizeLimit: number, keepFileType?: boolean);
9
10
  }
10
11
  export declare class ImageProcessor {
11
12
  private file;
@@ -14,7 +15,11 @@ export declare class ImageProcessor {
14
15
  private compressOptions;
15
16
  constructor(file: File, resizeOptions: ResizeOptions, watermarkOptions: WatermarkOptions, compressOptions: CompressOptions);
16
17
  process(): Promise<void | File>;
17
- compress(canvas: HTMLCanvasElement, filename: string, lastModified: number, type: string, quality: number, lastCompressFileSize?: number): Promise<File>;
18
+ /**
19
+ * 根据 MIME 类型获取文件扩展名
20
+ */
21
+ private getExtensionFromMimeType;
22
+ compress(canvas: HTMLCanvasElement, filename: string, lastModified: number, type: string, quality: number, lastCompressFileSize?: number, originalFileType?: string): Promise<File>;
18
23
  /**
19
24
  * 浮点型数据比较大小
20
25
  */
@@ -33,7 +33,7 @@ export declare function canvas2Image(canvas: HTMLCanvasElement, type?: string, q
33
33
  * @param quality
34
34
  * @see {@link https://meshworld.in/convert-canvas-to-an-image-using-javascript/}
35
35
  */
36
- export declare function canvas2File(canvas: HTMLCanvasElement, fileName: string, lastModified: number, type?: string, quality?: number): Promise<File>;
36
+ export declare function canvas2File(canvas: HTMLCanvasElement, fileName: string, lastModified: number, type?: string, quality?: number, forceFileType?: string): Promise<File>;
37
37
  export type ResizeResultType = 'image' | 'canvas';
38
38
  /**
39
39
  * 缩放图片
package/dist/index.cjs.js CHANGED
@@ -1368,9 +1368,10 @@ function image2Canvas(img, type, width, height) {
1368
1368
  canvas.height = _height;
1369
1369
  const ctx = canvas.getContext("2d");
1370
1370
  if (ctx) {
1371
- ctx.fillStyle = "transparent";
1372
- if (type === "image/jpeg") {
1371
+ const needWhiteBackground = type === "image/jpeg" || type === "image/jpg" || type === "image/bmp";
1372
+ if (needWhiteBackground) {
1373
1373
  ctx.fillStyle = "#fff";
1374
+ ctx.fillRect(0, 0, _width, _height);
1374
1375
  }
1375
1376
  ctx.drawImage(img, 0, 0, _width, _height);
1376
1377
  return Promise.resolve(canvas);
@@ -1383,18 +1384,20 @@ function canvas2Image(canvas, type = "image/jpeg", quality = 0.8) {
1383
1384
  image.src = canvas.toDataURL(type, quality);
1384
1385
  return Promise.resolve(image);
1385
1386
  }
1386
- function canvas2File(canvas, fileName, lastModified, type = "image/jpeg", quality = 0.8) {
1387
+ function canvas2File(canvas, fileName, lastModified, type = "image/jpeg", quality = 0.8, forceFileType) {
1387
1388
  return new Promise((resolve, reject) => {
1389
+ const blobType = type === "image/gif" ? "image/png" : type;
1388
1390
  canvas.toBlob(
1389
1391
  (blob) => {
1390
1392
  if (!blob) {
1391
1393
  reject(new Error("canvas文件导出失败"));
1392
1394
  } else {
1393
- const file = new File([blob], fileName, { lastModified, type });
1395
+ const fileType = forceFileType || type;
1396
+ const file = new File([blob], fileName, { lastModified, type: fileType });
1394
1397
  resolve(file);
1395
1398
  }
1396
1399
  },
1397
- type,
1400
+ blobType,
1398
1401
  quality
1399
1402
  );
1400
1403
  });
@@ -1455,13 +1458,14 @@ var ResizeOptions = class {
1455
1458
  }
1456
1459
  };
1457
1460
  var CompressOptions = class {
1458
- // 图片大小限制,单位kb
1459
- constructor(photoFileSizeLimit) {
1461
+ // 是否保持原始文件类型
1462
+ constructor(photoFileSizeLimit, keepFileType = false) {
1460
1463
  if (checkIsUndefinedOrNull(photoFileSizeLimit)) {
1461
1464
  this.photoFileSizeLimit = PHOTO_FILE_SIZE_LIMIT;
1462
1465
  } else {
1463
1466
  this.photoFileSizeLimit = photoFileSizeLimit;
1464
1467
  }
1468
+ this.keepFileType = keepFileType;
1465
1469
  }
1466
1470
  };
1467
1471
  var ImageProcessor = class {
@@ -1475,12 +1479,15 @@ var ImageProcessor = class {
1475
1479
  process() {
1476
1480
  const filename = this.file.name;
1477
1481
  const { lastModified } = this.file;
1478
- let fileType = this.file.type;
1479
- if (this.file.size > this.compressOptions.photoFileSizeLimit * 1024) {
1480
- fileType = "image/jpeg";
1481
- }
1482
- if (fileType === "image/gif") {
1483
- fileType = "image/png";
1482
+ const originalFileType = this.file.type;
1483
+ let fileType = originalFileType;
1484
+ if (!this.compressOptions.keepFileType) {
1485
+ if (this.file.size > this.compressOptions.photoFileSizeLimit * 1024) {
1486
+ fileType = "image/jpeg";
1487
+ }
1488
+ if (fileType === "image/gif") {
1489
+ fileType = "image/png";
1490
+ }
1484
1491
  }
1485
1492
  return file2Image(this.file).then((img) => {
1486
1493
  return resize(img, {
@@ -1492,18 +1499,43 @@ var ImageProcessor = class {
1492
1499
  const canvas = result;
1493
1500
  return yield renderWatermark(canvas, this.watermarkOptions);
1494
1501
  })).then((canvas) => {
1495
- const exportFilename = filename.replace(/\./g, "-") + ".jpg";
1502
+ let exportFilename;
1503
+ if (this.compressOptions.keepFileType) {
1504
+ const ext = this.getExtensionFromMimeType(fileType);
1505
+ exportFilename = filename.replace(/\.[^.]+$/, "") + "." + ext;
1506
+ } else {
1507
+ exportFilename = filename.replace(/\./g, "-") + ".jpg";
1508
+ }
1496
1509
  return this.compress(
1497
1510
  canvas,
1498
1511
  exportFilename,
1499
1512
  lastModified,
1500
1513
  fileType,
1501
- DEFAULT_JPEG_QUALITY
1514
+ DEFAULT_JPEG_QUALITY,
1515
+ -1,
1516
+ originalFileType
1517
+ // 传入原始文件类型,用于GIF等特殊格式
1502
1518
  );
1503
1519
  });
1504
1520
  }
1505
- compress(canvas, filename, lastModified, type, quality, lastCompressFileSize = -1) {
1506
- return canvas2File(canvas, filename, lastModified, type, quality).then(
1521
+ /**
1522
+ * 根据 MIME 类型获取文件扩展名
1523
+ */
1524
+ getExtensionFromMimeType(mimeType) {
1525
+ const mimeToExt = {
1526
+ "image/jpeg": "jpg",
1527
+ "image/jpg": "jpg",
1528
+ "image/png": "png",
1529
+ "image/gif": "gif",
1530
+ "image/webp": "webp",
1531
+ "image/bmp": "bmp",
1532
+ "image/svg+xml": "svg"
1533
+ };
1534
+ return mimeToExt[mimeType] || "jpg";
1535
+ }
1536
+ compress(canvas, filename, lastModified, type, quality, lastCompressFileSize = -1, originalFileType) {
1537
+ const forceFileType = originalFileType === "image/gif" ? originalFileType : void 0;
1538
+ return canvas2File(canvas, filename, lastModified, type, quality, forceFileType).then(
1507
1539
  (file) => {
1508
1540
  let qualityStep = JPEG_QUALITY_STEP;
1509
1541
  if (file.size > this.compressOptions.photoFileSizeLimit * 1024) {
@@ -1523,7 +1555,8 @@ var ImageProcessor = class {
1523
1555
  lastModified,
1524
1556
  type,
1525
1557
  this.roundToDecimalPlace(nextCompressQuality, 2),
1526
- file.size
1558
+ file.size,
1559
+ originalFileType
1527
1560
  );
1528
1561
  } else {
1529
1562
  return Promise.resolve(file);
@@ -1343,9 +1343,10 @@ function image2Canvas(img, type, width, height) {
1343
1343
  canvas.height = _height;
1344
1344
  const ctx = canvas.getContext("2d");
1345
1345
  if (ctx) {
1346
- ctx.fillStyle = "transparent";
1347
- if (type === "image/jpeg") {
1346
+ const needWhiteBackground = type === "image/jpeg" || type === "image/jpg" || type === "image/bmp";
1347
+ if (needWhiteBackground) {
1348
1348
  ctx.fillStyle = "#fff";
1349
+ ctx.fillRect(0, 0, _width, _height);
1349
1350
  }
1350
1351
  ctx.drawImage(img, 0, 0, _width, _height);
1351
1352
  return Promise.resolve(canvas);
@@ -1358,18 +1359,20 @@ function canvas2Image(canvas, type = "image/jpeg", quality = 0.8) {
1358
1359
  image.src = canvas.toDataURL(type, quality);
1359
1360
  return Promise.resolve(image);
1360
1361
  }
1361
- function canvas2File(canvas, fileName, lastModified, type = "image/jpeg", quality = 0.8) {
1362
+ function canvas2File(canvas, fileName, lastModified, type = "image/jpeg", quality = 0.8, forceFileType) {
1362
1363
  return new Promise((resolve, reject) => {
1364
+ const blobType = type === "image/gif" ? "image/png" : type;
1363
1365
  canvas.toBlob(
1364
1366
  (blob) => {
1365
1367
  if (!blob) {
1366
1368
  reject(new Error("canvas文件导出失败"));
1367
1369
  } else {
1368
- const file = new File([blob], fileName, { lastModified, type });
1370
+ const fileType = forceFileType || type;
1371
+ const file = new File([blob], fileName, { lastModified, type: fileType });
1369
1372
  resolve(file);
1370
1373
  }
1371
1374
  },
1372
- type,
1375
+ blobType,
1373
1376
  quality
1374
1377
  );
1375
1378
  });
@@ -1430,13 +1433,14 @@ var ResizeOptions = class {
1430
1433
  }
1431
1434
  };
1432
1435
  var CompressOptions = class {
1433
- // 图片大小限制,单位kb
1434
- constructor(photoFileSizeLimit) {
1436
+ // 是否保持原始文件类型
1437
+ constructor(photoFileSizeLimit, keepFileType = false) {
1435
1438
  if (checkIsUndefinedOrNull(photoFileSizeLimit)) {
1436
1439
  this.photoFileSizeLimit = PHOTO_FILE_SIZE_LIMIT;
1437
1440
  } else {
1438
1441
  this.photoFileSizeLimit = photoFileSizeLimit;
1439
1442
  }
1443
+ this.keepFileType = keepFileType;
1440
1444
  }
1441
1445
  };
1442
1446
  var ImageProcessor = class {
@@ -1450,12 +1454,15 @@ var ImageProcessor = class {
1450
1454
  process() {
1451
1455
  const filename = this.file.name;
1452
1456
  const { lastModified } = this.file;
1453
- let fileType = this.file.type;
1454
- if (this.file.size > this.compressOptions.photoFileSizeLimit * 1024) {
1455
- fileType = "image/jpeg";
1456
- }
1457
- if (fileType === "image/gif") {
1458
- fileType = "image/png";
1457
+ const originalFileType = this.file.type;
1458
+ let fileType = originalFileType;
1459
+ if (!this.compressOptions.keepFileType) {
1460
+ if (this.file.size > this.compressOptions.photoFileSizeLimit * 1024) {
1461
+ fileType = "image/jpeg";
1462
+ }
1463
+ if (fileType === "image/gif") {
1464
+ fileType = "image/png";
1465
+ }
1459
1466
  }
1460
1467
  return file2Image(this.file).then((img) => {
1461
1468
  return resize(img, {
@@ -1467,18 +1474,43 @@ var ImageProcessor = class {
1467
1474
  const canvas = result;
1468
1475
  return yield renderWatermark(canvas, this.watermarkOptions);
1469
1476
  })).then((canvas) => {
1470
- const exportFilename = filename.replace(/\./g, "-") + ".jpg";
1477
+ let exportFilename;
1478
+ if (this.compressOptions.keepFileType) {
1479
+ const ext = this.getExtensionFromMimeType(fileType);
1480
+ exportFilename = filename.replace(/\.[^.]+$/, "") + "." + ext;
1481
+ } else {
1482
+ exportFilename = filename.replace(/\./g, "-") + ".jpg";
1483
+ }
1471
1484
  return this.compress(
1472
1485
  canvas,
1473
1486
  exportFilename,
1474
1487
  lastModified,
1475
1488
  fileType,
1476
- DEFAULT_JPEG_QUALITY
1489
+ DEFAULT_JPEG_QUALITY,
1490
+ -1,
1491
+ originalFileType
1492
+ // 传入原始文件类型,用于GIF等特殊格式
1477
1493
  );
1478
1494
  });
1479
1495
  }
1480
- compress(canvas, filename, lastModified, type, quality, lastCompressFileSize = -1) {
1481
- return canvas2File(canvas, filename, lastModified, type, quality).then(
1496
+ /**
1497
+ * 根据 MIME 类型获取文件扩展名
1498
+ */
1499
+ getExtensionFromMimeType(mimeType) {
1500
+ const mimeToExt = {
1501
+ "image/jpeg": "jpg",
1502
+ "image/jpg": "jpg",
1503
+ "image/png": "png",
1504
+ "image/gif": "gif",
1505
+ "image/webp": "webp",
1506
+ "image/bmp": "bmp",
1507
+ "image/svg+xml": "svg"
1508
+ };
1509
+ return mimeToExt[mimeType] || "jpg";
1510
+ }
1511
+ compress(canvas, filename, lastModified, type, quality, lastCompressFileSize = -1, originalFileType) {
1512
+ const forceFileType = originalFileType === "image/gif" ? originalFileType : void 0;
1513
+ return canvas2File(canvas, filename, lastModified, type, quality, forceFileType).then(
1482
1514
  (file) => {
1483
1515
  let qualityStep = JPEG_QUALITY_STEP;
1484
1516
  if (file.size > this.compressOptions.photoFileSizeLimit * 1024) {
@@ -1498,7 +1530,8 @@ var ImageProcessor = class {
1498
1530
  lastModified,
1499
1531
  type,
1500
1532
  this.roundToDecimalPlace(nextCompressQuality, 2),
1501
- file.size
1533
+ file.size,
1534
+ originalFileType
1502
1535
  );
1503
1536
  } else {
1504
1537
  return Promise.resolve(file);
package/package.json CHANGED
@@ -1,23 +1,10 @@
1
1
  {
2
2
  "name": "@egova-mobile/app-media-utils",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.mjs",
7
7
  "typings": "dist/index.d.ts",
8
- "scripts": {
9
- "clean": "rimraf ./dist",
10
- "dev": "node ./build.js -w",
11
- "build:types": "tsc -p ./tsconfig.json --emitDeclarationOnly",
12
- "build:bundle": "node ./build.js",
13
- "build": "pnpm clean && pnpm build:bundle && pnpm build:types",
14
- "release": "zartui-mobile-cli release",
15
- "prepare": "pnpm build"
16
- },
17
- "publishConfig": {
18
- "access": "public",
19
- "registry": "https://registry.npmjs.org/"
20
- },
21
8
  "exports": {
22
9
  ".": {
23
10
  "import": "./dist/index.esm.mjs",
@@ -41,5 +28,13 @@
41
28
  },
42
29
  "peerDependencies": {
43
30
  "dayjs": "^1.11.8"
31
+ },
32
+ "scripts": {
33
+ "clean": "rimraf ./dist",
34
+ "dev": "node ./build.js -w",
35
+ "build:types": "tsc -p ./tsconfig.json --emitDeclarationOnly",
36
+ "build:bundle": "node ./build.js",
37
+ "build": "pnpm clean && pnpm build:bundle && pnpm build:types",
38
+ "release": "zartui-mobile-cli release"
44
39
  }
45
- }
40
+ }