图片压缩指定宽高和限制大小

应用开发中,用户头像时需要特定的宽高和大小限制,这个时候我们需要对用户上传的头像进行严格精准的压缩,维持在一个标准内,下面demo为例,实现将一个1.9M大小的图片,压缩成宽500,高500,且大小保持在100kb以内。

HarmonyOS
2024-05-21 20:48:19
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
wngsheng

使用的核心API

图像变换(ArkTS)

图片编码(ArkTS)

初始化图片资源到沙箱

async aboutToAppear(): Promise<void> { 
  const resourceManager = getContext(this).resourceManager 
  const imageArray = await resourceManager.getMediaContent($r('app.media.100')); 
​ 
  console.log("yuv_path is:" + path); 
  let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 
​ 
  fs.write(file.fd, imageArray.buffer).then((writeLen) => { 
    console.info("write data to file succeed and size is:" + writeLen); 
    fs.closeSync(file); 
  }).catch((err: BusinessError) => { 
    console.info("write data to file failed with error message: " + err.message + ", error code: " + err.code); 
  }); 
}

创建pixelMap,并调用压缩方法

/ // path为已获得的沙箱路径 
        const imageSource: image.ImageSource = image.createImageSource(path); 
​ 
        //创建pixelMap 
        this.pixelMap = await imageSource.createPixelMap(decodingOptions); 
​ 
        console.log("6666661" + this.pixelMap.getPixelBytesNumber()); 
        //指定压缩宽、高、大小 
        this.packingDetail(500, 500, 100)

根据压缩后目标图片宽高计算缩放比 并进行缩放,调用packing方法实现第一次压缩

  if (this.pixelMap) { 
    Logger.info("zhaohao before scaling pixelmap." + this.pixelMap.getPixelBytesNumber()); 
​ 
    let imageInfo = await this.pixelMap.getImageInfo(); 
​ 
    let a = this.pixelMap 
    //计算压缩比 
    let scaleX: number = targetWidth / imageInfo.size.width; 
    let scaleY: number = targetHeight / imageInfo.size.height; 
    this.pixelMap.scale(scaleX, scaleY, (err: BusinessError) => { 
      if (err) { 
        console.error("zhaohao Failed to scale pixelmap."); 
        return; 
      } else { 
        console.log("zhaohao in scaling pixelmap." + a.getPixelBytesNumber()); 
      } 
    }); 
  } 
  let imagePackerApi = image.createImagePacker(); 
  let packOpts: image.PackingOption = { format: "image/jpeg", quality: 100 }; 
  imagePackerApi.packing(this.pixelMap, packOpts).then((data: ArrayBuffer) => { 
    Logger.info("zhaohao in 100 quality data" + data.byteLength) 
    this.compressPictures(data, targetPixelSize, 99); 
  });

调用递归算法,当压缩后的data ,小于等于压缩目标图片大小时将data写入本地沙箱并结束递归

compressPictures(data?: ArrayBuffer, size?: number, quality?: number): void { 
  if (data && size && quality) { 
    const currentSize = data.byteLength / 1024 
    if (currentSize <= size || quality === 0) { 
      console.log("finally quallity is:" + ++quality) 
      let file = fs.openSync(path9, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 
      fs.write(file.fd, data).then(async (writeLen) => { 
        console.info("write data to file succeed2 and size is:" + writeLen); 
        fs.closeSync(file); 
      }).catch((err: BusinessError) => { 
        console.info("write data to file failed1 with error message: " + err.message + ", error code: " + err.code); 
      }); 
      return; 
    } 
  } 
  if (quality) { 
    let packOpts: image.PackingOption = { format: "image/jpeg", quality: quality } 
    let imagePackerApi = image.createImagePacker(); 
    imagePackerApi.packing(this.pixelMap, packOpts) 
      .then((ret: ArrayBuffer) => { 
        //递归算法,直到压缩到指定大小的data 
        if (quality) { 
          Logger.info("PACKING66666"+quality) 
          return this.compressPictures(ret, size, quality - 1) 
        } 
​ 
      }).catch((err: BusinessError) => { 
      console.log(`lbh`) 
      return false 
    }) 
  } 
}

实现效果

原图

压缩后目标图片

注明适配的版本信息

API版本:

11

软件版本:

ALN-AL00 4.1.0.66(SP58DEVC00E66R4P1log)

分享
微博
QQ
微信
回复
2024-05-22 16:54:59
相关问题
HarmonyOS图片压缩不到指定大小
636浏览 • 1回复 待解决
如何将图片PixelMap压缩指定大小
1808浏览 • 1回复 待解决
图片压缩尺寸大小问题
411浏览 • 1回复 待解决
如何将PixelMap压缩指定大小
986浏览 • 1回复 待解决
HarmonyOS photoAsset获取图片失败
357浏览 • 1回复 待解决
HarmonyOS如何获取指定子组件的
1259浏览 • 1回复 待解决
JS UI框架中canvas如何动态指定
6902浏览 • 1回复 待解决
鸿蒙如何获取Element图片
7924浏览 • 1回复 待解决
如何获取图片,你知道吗?
2448浏览 • 1回复 待解决
页面加载前获取网络图片
709浏览 • 1回复 待解决