《鸿蒙开发-答案之书》压缩图片到指定大小以下

75 阅读3分钟
《鸿蒙开发-答案之书》压缩图片到指定大小以下

往往上传图片到服务器时需要压缩图片,太大的会很慢还可能断开连接。 现在说下如何压缩到指定大小以下

直接上代码:

export async function compressedImagePath(fd: number,
  maxCompressedImageSize: number,name:string): Promise<fs.File> {

  // 创建ImageSource实例
  const imageSource: image.ImageSource = image.createImageSource(fd);
  // 设置解码参数DecodingOptions,解码获取PixelMap图片对象。
  const decodingOptions: image.DecodingOptions = {
    editable: true, // 是否可编辑。当取值为false时,图片不可二次编辑,如crop等操作将失败。
    desiredPixelFormat: 3, // 解码的像素格式。3表示RGBA_8888。
  }
  let originalPixelMap = await imageSource.createPixelMap(decodingOptions)
  // 压缩图片
  return compressedImage(originalPixelMap, maxCompressedImageSize,name)

}
/**
 * 图片压缩,保存
 * @param sourcePixelMap:原始待压缩图片的PixelMap对象
 * @param maxCompressedImageSize:指定图片的压缩目标大小,单位kb
 * @returns compressedImageInfo:返回最终压缩后的图片信息
 */
export async function compressedImage(sourcePixelMap: image.PixelMap,
  maxCompressedImageSize: number,name:string): Promise<fs.File> {


  // 创建图像编码ImagePacker对象
  const imagePackerApi = image.createImagePacker();
  // 定义图片质量参数
  const IMAGE_QUALITY = 0;
  // 设置编码输出流和编码参数。图片质量参数quality范围0-100。
  const packOpts: image.PackingOption = { format: "image/jpeg", quality: IMAGE_QUALITY };
  // 通过PixelMap进行编码。compressedImageData为打包获取到的图片文件流。
  let compressedImageData: ArrayBuffer = await imagePackerApi.packing(sourcePixelMap, packOpts);
  // 压缩目标图像字节长度
  const maxCompressedImageByte = maxCompressedImageSize * 1024;
  // TODO 知识点:图片压缩。先判断设置图片质量参数quality为0时,packing能压缩到的图片最小字节大小是否满足指定的图片压缩大小。如果满足,则使用packing方式二分查找最接近指定图片压缩目标大小的quality来压缩图片。如果不满足,则使用scale对图片先进行缩放,采用while循环每次递减0.4倍缩放图片,再用packing(图片质量参数quality设置0)获取压缩图片大小,最终查找到最接近指定图片压缩目标大小的缩放倍数的图片压缩数据。
  if (maxCompressedImageByte > compressedImageData.byteLength) {
    // 使用packing二分压缩获取图片文件流
    compressedImageData =
      await packingImage(compressedImageData, sourcePixelMap, IMAGE_QUALITY, maxCompressedImageByte);
  } else {
    // 使用scale对图片先进行缩放,采用while循环每次递减0.4倍缩放图片,再用packing(图片质量参数quality设置0)获取压缩图片大小,最终查找到最接近指定图片压缩目标大小的缩放倍数的图片压缩数据
    let imageScale = 1; // 定义图片宽高的缩放倍数,1表示原比例。
    const REDUCE_SCALE = 0.4; // 图片缩小倍数
    // 判断压缩后的图片大小是否大于指定图片的压缩目标大小,如果大于,继续降低缩放倍数压缩。
    while (compressedImageData.byteLength > maxCompressedImageByte) {
      if (imageScale > 0) {
        // 性能知识点: 由于scale会直接修改图片PixelMap数据,所以不适用二分查找scale缩放倍数。这里采用循环递减0.4倍缩放图片,来查找确定最适
        // 合的缩放倍数。如果对图片压缩质量要求不高,建议调高每次递减的缩放倍数reduceScale,减少循环,提升scale压缩性能。
        imageScale = imageScale - REDUCE_SCALE; // 每次缩放倍数减0.4
        // 使用scale对图片进行缩放
        await sourcePixelMap.scale(imageScale, imageScale);
        // packing压缩
        compressedImageData = await packing(sourcePixelMap, IMAGE_QUALITY);
      } else {
        // imageScale缩放小于等于0时,没有意义,结束压缩。这里不考虑图片缩放倍数小于reduceScale的情况。
        break;
      }
    }
  }
  // 保存图片,返回压缩后的图片信息。
  let file: fileIo.File = await saveImage(compressedImageData,name);
  return file;
}

有鸿蒙开发bug或者功能需求的都可以私信我,我每天都看私信的