图片压缩并保存方法,有人知道吗?

图片压缩并保存方法

HarmonyOS
2024-05-21 21:57:38
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
jshyb

场景:图片压缩功能,能将原始图片压缩成不同质量不同格式的新图片并保存。关键开发流程:先获取图片数据并展示,创建ImageSource实例,设置quality参数,设置编码输出流和编码参数 ,format为图像的编码格式,当前仅支持jpeg、webp 和 png;quality为图像质量,范围从0-100,100为最佳质量。再进行压缩图片,将数据写入文件并保存。

使用的核心API

接口:imagepacker: 图片打包器类,用于图片压缩和打包。在调用ImagePacker的方法前,需要先通过createImagePacker构建一个ImagePacker实例,当前支持格式有:jpeg webp png。

picking: 图片压缩或重新打包,使用Promise形式返回结果。

核心代码解释

import image from '@ohos.multimedia.image'; 
import fs from '@ohos.file.fs'; 
import axios from '@ohos/axios'; 
import fileuri from "@ohos.file.fileuri"; 
//压缩图片接口 
interface CompressImageOption { 
  imagePath: string, //应用沙箱路径 
  limitLength: number, 
  lossy?: boolean, 
  success: Function 
  fail?: Function 
  complete?: Function 
  
} 
//访问图片链接返回的数据类型 
interface ResponseType { 
  data: ArrayBuffer 
} 
@Entry 
@Component 
export default struct demo { 
  @State imageUrl: image.PixelMap = null 
  @State uri:string='' 
  build() { 
    Column() { 
      //图片展示 
      Image(this.imageUrl) 
        .width('100%') 
        .height(200) 
      Image($r('app.media.icon')) 
        .width('100') 
        .height(200) 
      Image(this.uri) 
        .width('100') 
        .height(200) 
      Button('压缩图片') 
        .onClick(async () => { 
          this.compressImage({ 
            imagePath: 'https://j5.dfcfw.com/imagesystem/material_imgs/1698131145895686.png', 
            limitLength: 0, 
            success: async (path: string) => { 
              console.log('shishuang compresspath', path) 
              const file: fs.File = fs.openSync(path, fs.OpenMode.READ_WRITE); 
              const fd: number = file?.fd; 
              // fd为已获得的文件描述符 
              const imageSource: image.ImageSource = image.createImageSource(fd); 
              this.uri = fileuri.getUriFromPath(path) 
              console.info('shishuang  uri '+this.uri) 
              console.info('shishuang fd'+fd) 
              let decodingOptions: image.DecodingOptions = { 
                editable: true, 
                desiredPixelFormat: 3, 
              } 
              // const color = new ArrayBuffer(96);  //96为需要创建的像素buffer大小,取值为:height * width *4 
              // let bufferArr = new Uint8Array(color); 
              // let opts = { editable: true, pixelFormat: 3, size: { height: 4, width: 6 } } 
              // // 创建pixelMap并进行简单的旋转和缩放 
              // let options = { 
              //   alphaType: 0, // 透明度 
              //   editable: false, // 是否可编辑 
              //   pixelFormat: 3, // 像素格式 
              //   scaleMode: 1, // 缩略值 
              //   size: { height: 100, width: 100 } 
              // } // 创建图片大小 
              imageSource.createPixelMap(decodingOptions) 
                .then((pixelMap) => { 
                  //展示图片 
                  this.imageUrl = pixelMap 
                }) 
                .catch((err: object) => { 
                  console.log('shishuang  err', JSON.stringify(err)) 
                }) 
  
            }, 
            fail: ((err: object) => { 
              console.log('压缩失败', JSON.stringify(err)) 
            }), 
            complete: (() => { 
              console.log('压缩结束') 
            }), 
          }) 
        }) 
        .margin({ top: 20 }) 
    } 
  } 
  /** 
   * 压缩图片 
   * @param CompressImageOption 
   * @returns Promise<void> 
   */ 
  async compressImage(params: CompressImageOption): Promise<void> { 
    params.lossy = params.lossy || true //默认开启有损压缩 
    console.info('shishuang1') 
  
    try { 
      console.info('shishuang2') 
      const imagePackerApi: image.ImagePacker = image.createImagePacker(); 
      //获取图片数据 
      const imageData: ResponseType = await axios({ 
        url: params.imagePath, 
        method: 'get', 
      }) //获取网络图片数据 
      console.log('byteLength', imageData.data.byteLength) 
      //创建ImageSource实例 
      const imageSource: image.ImageSource = image.createImageSource(imageData.data); 
      //设置quality参数 无损 quality = 100,有损 quality = 80 
      let quality: number = 0 
      if (params.lossy) { 
        quality = 80 
      } else { 
        quality = 100 
      } 
      //设置编码输出流和编码参数 format为图像的编码格式,当前仅支持jpeg、webp 和 png,选用WebP,因为压缩率更高;quality为图像质量,范围从0-100,100为最佳质量 
      let packOpts: image.PackingOption = { 
        format: "image/png", 
        quality: quality, 
        bufferSize: params.limitLength 
      } 
      //压缩图片 
      imagePackerApi.packing(imageSource, packOpts) 
        .then((data: ArrayBuffer) => { 
          console.info('shishuang packLength', data.byteLength) 
          const path: string = this.writeFile(data, 'png') 
          if (params?.success) params.success(path) 
        }) 
        .catch((err: object) => { 
          console.info('shishuang4') 
  
          if (params?.fail) params.fail(err) 
        }) 
        .finally(() => { 
          console.info('shishuang5') 
  
          if (params?.complete) params.complete() 
        }) 
    } catch (err) { 
      console.info('shishuang3') 
  
      if (params?.fail) params.fail(err) 
      if (params?.complete) params.complete() 
    } 
  } 
  /** 
   * 将数据写入文件 
   * 
   * @param content 压缩数据 
   * @param type 压缩图片的类型 
   * @return path 压缩图片的存储路径 
   */ 
  writeFile(content: ArrayBuffer | string, type: string): string { 
    let context: Context | undefined = getContext('context'); //获取context 
    const path: string = context.filesDir + '/' + 'tt_compress_image' //设定存储路径 
  
    if (!this.existFolder(path)) { 
      this.createFolder(path, true) 
    } 
  
    let tempPath = path + '/' + `${new Date().getTime()}` + '.' + type 
    console.log('tempPath', tempPath) 
    this.writeDataToFile(tempPath, content) //将压缩后的数据进行保存 
    return tempPath 
  } 
  /** 
   * 判断文件夹是否存在 
   * 
   * @param path 文件夹绝对路径 
   */ 
  existFolder(path: string): boolean { 
    try { 
      let stat = fs.statSync(path) 
      return stat.isDirectory() 
    } catch (e) { 
      // console.error("FileUtils folder exist e " + e) 
      return false 
    } 
  } 
  /** 
   * 创建文件夹 
   * 
   * @param path 文件夹绝对路径,只有是权限范围内的路径,可以生成 
   * @param recursive 
   */ 
  createFolder(path: string, recursive?: boolean) { 
    if (recursive) { 
      if (!this.existFolder(path)) { 
        let lastInterval = path.lastIndexOf('/') 
        if (lastInterval == 0) { 
          return 
        } 
        let newPath = path.substring(0, lastInterval) 
        this.createFolder(newPath, true) 
        if (!this.existFolder(path)) { 
          fs.mkdirSync(path) 
        } 
      } 
    } else { 
      if (!this.existFolder(path)) { 
        fs.mkdirSync(path) 
      } 
    } 
  } 
  //将数据写入文件 
  writeDataToFile(path: string, content: ArrayBuffer | string) { 
    let fd = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).fd 
    fs.truncateSync(fd) 
    fs.writeSync(fd, content) 
    fs.fsyncSync(fd) 
    fs.closeSync(fd) 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.

实现效果

适配的版本信息

本示例仅支持标准系统上运行,支持设备:华为手机或运行在DevEco Studio上的华为手机设备模拟器。

本示例为Stage模型,支持API version 9。

本示例需要使用DevEco Studio 3.1 Release版本进行编译运行。

分享
微博
QQ
微信
回复
2024-05-22 17:45:19
相关问题
如何保存faultLogger ,有人知道吗
622浏览 • 1回复 待解决
如何压缩字符串,有人知道吗
793浏览 • 1回复 待解决
怎么压缩一个目录?有人知道吗
749浏览 • 1回复 待解决
如何实现图片预览,有人知道吗
625浏览 • 1回复 待解决
如何对网络图片处理,有人知道吗
357浏览 • 1回复 待解决
taskpool 使用问题,有人知道吗
891浏览 • 1回复 待解决
如何发送短信,有人知道吗?
1920浏览 • 1回复 待解决
如何跳出ForEach,有人知道吗
2063浏览 • 1回复 待解决
有人知道吗
230浏览 • 1回复 待解决
有人知道吗
657浏览 • 1回复 待解决
webview组件demo ,有人知道吗
803浏览 • 1回复 待解决
如何获取windowStage,有人知道吗
461浏览 • 1回复 待解决
clientid相关问题,有人知道吗
1839浏览 • 1回复 待解决
如何实现振动,有人知道吗
1166浏览 • 2回复 待解决
List组件性能问题,有人知道吗
2069浏览 • 1回复 待解决
如何定义dialog动画,有人知道吗?
1945浏览 • 1回复 待解决
导航栏如何适配,有人知道吗?
1825浏览 • 0回复 待解决
如何使用快速修复,有人知道吗
685浏览 • 1回复 待解决
如何引用HSP库,有人知道吗?
1675浏览 • 1回复 待解决
如何实现翻页功能,有人知道吗
1947浏览 • 1回复 待解决
如何获取wifi列表,有人知道吗
547浏览 • 1回复 待解决
IDE如何开启ASAN,有人知道吗
338浏览 • 1回复 待解决
有人知道吗
340浏览 • 0回复 待解决
IP地址如何转化,有人知道吗
639浏览 • 1回复 待解决
怎么主动关闭键盘,有人知道吗
432浏览 • 1回复 待解决