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

图片压缩并保存方法

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) 
  } 
}

实现效果

适配的版本信息

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

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

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

分享
微博
QQ
微信
回复
2024-05-22 17:45:19
相关问题
如何保存faultLogger ,有人知道吗
172浏览 • 1回复 待解决
如何压缩字符串,有人知道吗
444浏览 • 1回复 待解决
怎么压缩一个目录?有人知道吗
352浏览 • 1回复 待解决
如何发送短信,有人知道吗?
665浏览 • 1回复 待解决
webview组件demo ,有人知道吗
444浏览 • 1回复 待解决
如何跳出ForEach,有人知道吗
699浏览 • 1回复 待解决
taskpool 使用问题,有人知道吗
424浏览 • 1回复 待解决
有人知道吗
54浏览 • 1回复 待解决
clientid相关问题,有人知道吗
586浏览 • 1回复 待解决
如何实现振动,有人知道吗
712浏览 • 2回复 待解决
List组件性能问题,有人知道吗
699浏览 • 1回复 待解决
如何使用快速修复,有人知道吗
255浏览 • 1回复 待解决
如何实现翻页功能,有人知道吗
655浏览 • 1回复 待解决
如何定义dialog动画,有人知道吗?
793浏览 • 1回复 待解决
如何引用HSP库,有人知道吗?
676浏览 • 1回复 待解决
导航栏如何适配,有人知道吗?
664浏览 • 0回复 待解决
如何开启AOT编译模式,有人知道吗
781浏览 • 1回复 待解决
是否有无网判断接口,有人知道吗
595浏览 • 1回复 待解决
如何实现http长连接,有人知道吗
619浏览 • 1回复 待解决
charles抓包流程,有人知道吗
284浏览 • 1回复 待解决
状态管理相关问题,有人知道吗?
380浏览 • 1回复 待解决
如何获取系统电量,有人知道吗
692浏览 • 1回复 待解决
如何获取组件高度,有人知道吗
662浏览 • 1回复 待解决
IP地址如何转化,有人知道吗
251浏览 • 1回复 待解决
如何设置约束优先级,有人知道吗
401浏览 • 2回复 待解决