鸿蒙应用开发之媒体(图像)

一、基本概念

  • 图像解码

    图像解码就是不同的存档格式图片(如JPEGPNG等)解码为无压缩的位图格式,以方便在应用或者系统中进行相应的处理。

  • PixelMap

    PixelMap是图像解码后无压缩的位图格式,用于图像显示或者进一步的处理。

  • 渐进式解码

    渐进式解码是在无法一次性提供完整图像文件数据的场景下,随着图像文件数据的逐步增加,通过多次增量解码逐步完成图像解码的模式。

  • 预乘

    预乘时,RGB各通道的值被替换为原始值乘以Alpha通道不透明的比例(0~1)后的值,方便后期直接合成叠加;不预乘指RGB各通道的数值是图像的原始值,与Alpha通道的值无关。

  • 图像编码

    图像编码就是将无压缩的位图格式,编码成不同格式的存档格式图片(JPEGPNG等),以方便在应用或者系统中进行相应的处理。

约束与限制

  • 为及时释放本地资源,建议在图像解码的ImageSource对象、位图图像PixelMap对象或图像编码的ImagePacker对象使用完成后,主动调用release()方法

二、图像解码

图像解码就是将所支持格式的存档图片解码成统一的PixelMap图像,用于后续图像显示或其他处理,比如旋转、缩放、裁剪等。当前支持格式包括JPEGPNGGIFHEIFWebPBMP

图像解码主要用到ImageSource,其常用接口如下

接口名 描述
create(String pathName, SourceOptions opts) 从图像文件路径创建图像数据源。
create(InputStream is, SourceOptions opts) 从输入流创建图像数据源。
create(byte[] data, SourceOptions opts) 从字节数组创建图像源。
create(byte[] data, int offset, int length, SourceOptions opts) 从字节数组指定范围创建图像源。
create(File file, SourceOptions opts) 从文件对象创建图像数据源。
create(FileDescriptor fd, SourceOptions opts) 从文件描述符创建图像数据源。
createIncrementalSource(SourceOptions opts) 创建渐进式图像数据源。
createIncrementalSource(IncrementalSourceOptions opts) 创建渐进式图像数据源,支持设置渐进式数据更新模式。
createPixelmap(DecodingOptions opts) 从图像数据源解码并创建PixelMap图像。
createPixelmap(int index, DecodingOptions opts) 从图像数据源解码并创建PixelMap图像,如果图像数据源支持多张图片的话,支持指定图像索引。
updateData(byte[] data, boolean isFinal) 更新渐进式图像源数据。
updateData(byte[] data, int offset, int length, boolean isFinal) 更新渐进式图像源数据,支持设置输入数据的有效数据范围。
getImageInfo() 获取图像基本信息。
getImageInfo(int index) 根据特定的索引获取图像基本信息。
getSourceInfo() 获取图像源信息。
release() 释放对象关联的本地资源。

普通开发

开发流程如下

/**
 * @description 普通模式解码
 * @author PengHuAnZhi
 * @date 2021/1/17 13:23
 */
private void testNormalImgDecode() {
    
    
    /**
     *1、
     *   创建图像数据源ImageSource对象,可以通过SourceOptions指定数据源的格式信息,此格式信息仅为给解码器的提示,正确提供能帮助提高
     *   解码效率,如果不设置或设置不正确,会自动检测正确的图像格式。不使用该选项时,可以将create接口传入的SourceOptions设置为null。
     */
    ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
    srcOpts.formatHint = "image/png";
    String pathName = "/path/to/image.png";
    ImageSource imageSource = ImageSource.create(pathName, srcOpts);
    //也可以设置为空
    ImageSource imageSourceNoOptions = ImageSource.create(pathName, null);
    /**
     * 2、
     * 设置解码参数,解码获取PixelMap图像对象,解码过程中同时支持图像处理操作。设置desiredRegion支持按矩形区域裁剪,如果设置为全0,则不
     * 进行裁剪。设置desiredSize支持按尺寸缩放,如果设置为全0,则不进行缩放。设置rotateDegrees支持旋转角度,以图像中心点顺时针旋转。如果只
     * 需要解码原始图像,不使用该选项时,可将给createPixelMap传入的DecodingOptions 设置为null。
     */
    // 普通解码叠加旋转、缩放、裁剪
    ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
    decodingOpts.desiredSize = new Size(100, 2000);
    decodingOpts.desiredRegion = new Rect(0, 0, 100, 100);
    decodingOpts.rotateDegrees = 90;
    PixelMap pixelMap = imageSource.createPixelmap(decodingOpts);
    //3、普通解码
    PixelMap pixelMapNoOptions = imageSource.createPixelmap(null);
    //4、解码完成获取到PixelMap对象后,可以进行后续处理,比如渲染显示等。
    //这里直接让一个image控件显示
    mTestImg.setPixelMap(pixelMapNoOptions);
}

渐进式解码

/**
 * @description 渐进模式解码
 * @author PengHuAnZhi
 * @date 2021/1/17 13:34
 */
private void testGradualImgDecode() {
    
    
    /**
     * 1、
     * 创建渐进式图像数据源ImageSource对象,可以通过SourceOptions指定数据源的格式信息,此格式信息仅为提示,如
     * 果填写不正确,会自动检测正确的图像格式,使用IncrementalSourceOptions指定图像数据的更新方式为渐进式更新。
     */
    ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
    srcOpts.formatHint = "image/jpeg";
    ImageSource.IncrementalSourceOptions incOpts = new ImageSource.IncrementalSourceOptions();
    incOpts.opts = srcOpts;
    incOpts.mode = ImageSource.UpdateMode.INCREMENTAL_DATA;
    ImageSource imageSource = ImageSource.createIncrementalSource(incOpts);
    //2、渐进式更新数据,在未获取到全部图像时,支持先更新部分数据来尝试解码,更新数据时设置isFinal为false,当获取到全部数据后,最后一次更新数据时设置isFinal为true,表示数据更新完毕。设置解码参数同普通解码。
    // 获取到一定的数据时尝试解码,这里的第一个参数数据字节数组只是为了显示而模拟的,真实情况不是这样
    imageSource.updateData(new byte[2048], 0, 20, false);
    ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
    PixelMap pixelMap = imageSource.createPixelmap(decodingOpts);
    mTestImg.setPixelMap(pixelMap);
    // 更新数据再次解码,重复调用直到数据全部更新完成
    imageSource.updateData(new byte[2048], 0, 20, false);
    PixelMap pixelMapNext = imageSource.createPixelmap(decodingOpts);
    mTestImg.setPixelMap(pixelMapNext);
    // 3、数据全部更新完成时需要传入isFinal为true
    imageSource.updateData(new byte[2048], 0, 20, true);
    PixelMap pixelMapFinal = imageSource.createPixelmap(decodingOpts);
    //4、解码完成获取到PixelMap对象后,可以进行后续处理,比如渲染显示等。   
    mTestImg.setPixelMap(pixelMapFinal);
}

三、图像编码

图像编码就是将PixelMap图像编码成不同存档格式图片,用于后续其他处理,比如保存、传输等。当前仅支持JPEG格式。

图像编码主要使用ImagePacker,其主要接口如下

接口名 描述
create() 创建图像打包器实例。
initializePacking(byte[] data, PackingOptions opts) 初始化打包任务,将字节数组设置为打包后输出目的。
initializePacking(byte[] data, int offset, PackingOptions opts) 初始化打包任务,将带偏移量的字节数组设置为打包后输出目的。
initializePacking(OutputStream outputStream, PackingOptions opts) 初始化打包任务,将输出流设置为打包后输出目的。
addImage(PixelMap pixelmap) 将PixelMap对象添加到图像打包器中。
addImage(ImageSource source) 将图像数据源ImageSource中图像添加到图像打包器中。
addImage(ImageSource source, int index) 将图像数据源ImageSource中指定图像添加到图像打包器中。
finalizePacking() 完成图像打包任务。
release() 释放对象关联的本地资源。

开发流程如下

/**
 * @description 图像编码
 * @author PengHuAnZhi
 * @date 2021/1/17 13:45
 */
private void testImgEncode() {
    
    
    //1、创建图像编码ImagePacker对象。
    ImagePacker imagePacker = ImagePacker.create();
    //2、设置编码输出流和编码参数。设置format为编码的图像格式,当前支持jpeg格式。设置quality为图像质量,范围从0-100,100为最佳质量。
    FileOutputStream outputStream = null;
    try {
    
    
        outputStream = new FileOutputStream("/path/to/packed.file");
    } catch (FileNotFoundException e) {
    
    
        e.printStackTrace();
    }
    ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions();
    packingOptions.format = "image/jpeg";
    packingOptions.quality = 90;
    boolean result = imagePacker.initializePacking(outputStream, packingOptions);
    //这里开始是纯为了构造一个pixel而写的,无实际意义
    ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
    srcOpts.formatHint = "image/png";
    String pathName = "/path/to/image.png";
    ImageSource imageSource = ImageSource.create(pathName, srcOpts);
    ImageSource imageSourceNoOptions = ImageSource.create(pathName, null);
   
    ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
    decodingOpts.desiredSize = new Size(100, 2000);
    decodingOpts.desiredRegion = new Rect(0, 0, 100, 100);
    decodingOpts.rotateDegrees = 90;
    //结束,创建了一个pixelMap
    PixelMap pixelMap = imageSource.createPixelmap(decodingOpts);
    result = imagePacker.addImage(pixelMap);
    long dataSize = imagePacker.finalizePacking();
    //5、编码输出完成后,可以进行后续处理,比如保存、传输等。
}

四、位图

位图操作就是指对PixelMap图像进行相关的操作,比如创建、查询信息、读写像素数据等。

位图操作类PixelMap主要接口如下

接口名 描述
create(InitializationOptions opts) 根据图像大小、像素格式、alpha类型等初始化选项创建PixelMap。
create(int[] colors, InitializationOptions opts) 根据图像大小、像素格式、alpha类型等初始化选项,以像素颜色数组为数据源创建PixelMap。
create(int[] colors, int offset, int stride, InitializationOptions opts) 根据图像大小、像素格式、alpha类型等初始化选项,以像素颜色数组、起始偏移量、行像素大小描述的数据源创建PixelMap。
create(PixelMap source, InitializationOptions opts) 根据图像大小、像素格式、alpha类型等初始化选项,以源PixelMap为数据源创建PixelMap。
create(PixelMap source, Rect srcRegion, InitializationOptions opts) 根据图像大小、像素格式、alpha类型等初始化选项,以源PixelMap、源裁剪区域描述的数据源创建PixelMap。
getBytesNumberPerRow() 获取每行像素数据占用的字节数。
getPixelBytesCapacity() 获取存储Pixelmap像素数据的内存容量。
isEditable() 判断PixelMap是否允许修改。
isSameImage(PixelMap other) 判断两个图像是否相同,包括ImageInfo属性信息和像素数据。
readPixel(Position pos) 读取指定位置像素的颜色值,返回的颜色格式为PixelFormat.ARGB_8888。
readPixels(int[] pixels, int offset, int stride, Rect region) 读取指定区域像素的颜色值,输出到以起始偏移量、行像素大小描述的像素数组,返回的颜色格式为PixelFormat.ARGB_8888。
readPixels(Buffer dst) 读取像素的颜色值到缓冲区,返回的数据是PixelMap中像素数据的原样拷贝,即返回的颜色数据格式与PixelMap中像素格式一致。
resetConfig(Size size, PixelFormat pixelFormat) 重置PixelMap的大小和像素格式配置,但不会改变原有的像素数据也不会重新分配像素数据的内存,重置后图像数据的字节数不能超过PixelMap的内存容量。
setAlphaType(AlphaType alphaType) 设置PixelMap的Alpha类型。
writePixel(Position pos, int color) 向指定位置像素写入颜色值,写入颜色格式为PixelFormat.ARGB_8888。
writePixels(int[] pixels, int offset, int stride, Rect region) 将像素颜色数组、起始偏移量、行像素的个数描述的源像素数据写入PixelMap的指定区域,写入颜色格式为PixelFormat.ARGB_8888。
writePixels(Buffer src) 将缓冲区描述的源像素数据写入PixelMap,写入的数据将原样覆盖PixelMap中的像素数据,即写入数据的颜色格式应与PixelMap的配置兼容。
writePixels(int color) 将所有像素都填充为指定的颜色值,写入颜色格式为 PixelFormat.ARGB_8888。
getPixelBytesNumber() 获取全部像素数据包含的字节数。
setBaseDensity(int baseDensity) 设置PixelMap的基础像素密度值。
getBaseDensity() 获取PixelMap的基础像素密度值。
setUseMipmap(boolean useMipmap) 设置PixelMap渲染是否使用mipmap。
useMipmap() 获取PixelMap渲染是否使用mipmap。
getNinePatchChunk() 获取图像的NinePatchChunk数据。
getFitDensitySize(int targetDensity) 获取适应目标像素密度的图像缩放的尺寸。
getImageInfo() 获取图像基本信息。
release() 释放对象关联的本地资源。

开发流程如下

/**
 * @description 位图
 * @author PengHuAnZhi
 * @date 2021/1/17 13:52
 */
private void testPixelMap() {
    
    
    //创建位图对象PixelMap。
    // 指定初始化选项创建
    // 从像素颜色数组创建
    int[] defaultColors = new int[]{
    
    5, 5, 5, 5, 6, 6, 3, 3, 3, 0};
    /**
     *  可以指定的初始化选项有下面几个
     *  public AlphaType alphaType;//AlphaType是一个枚举类,其中定义了若干常量
     *  public boolean editable = false;//是否可编辑
     *  public PixelFormat pixelFormat;//描述图像像素格式,也是一个枚举类
     *  public boolean releaseSource = false;//字面意思是释放资源,我也不知道是什么
     *  public ScaleMode scaleMode;//又是一个枚举类,图像缩放效果
     *  public Size size;//大小吧
     *  public boolean useSourceIfMatch = false;//如果匹配使用资源?
     */
    PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
    initializationOptions.size = new Size(3, 2);
    initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
    PixelMap pixelMap1 = PixelMap.create(defaultColors, initializationOptions);
    // 以另外一个PixelMap作为数据源创建
    PixelMap pixelMap2 = PixelMap.create(pixelMap1, initializationOptions);
    //从位图对象中获取信息。
    long capacity = pixelMap1.getPixelBytesCapacity();
    long bytesNumber = pixelMap1.getPixelBytesNumber();
    int rowBytes = pixelMap1.getBytesNumberPerRow();
    byte[] ninePatchData = pixelMap1.getNinePatchChunk();
    //读写位图像素数据。
    // 读取指定位置像素
    int color = pixelMap1.readPixel(new Position(1, 1));
    // 读取指定区域像素
    int[] pixelArray = new int[50];
    Rect region = new Rect(0, 0, 10, 5);
    pixelMap1.readPixels(pixelArray, 0, 10, region);
    // 读取像素到Buffer
    IntBuffer pixelBuf = IntBuffer.allocate(50);
    pixelMap1.readPixels(pixelBuf);
    // 在指定位置写入像素
    pixelMap1.writePixel(new Position(1, 1), 0xFF112233);
    // 在指定区域写入像素
    pixelMap1.writePixels(pixelArray, 0, 10, region);
    // 写入Buffer中的像素
    pixelMap1.writePixels(defaultColors[0]);
}

五、图像属性解码

图像属性解码就是获取图像中包含的属性信息,比如EXIF属性

功能主要由ImageSourceExifUtils提供。

  • ImageSource
接口名 描述
getThumbnailInfo() 获取嵌入图像文件的缩略图的基本信息。
getImageThumbnailBytes() 获取嵌入图像文件缩略图的原始数据。
getThumbnailFormat() 获取嵌入图像文件缩略图的格式。
  • ExifUtils
接口名 描述
getLatLong(ImageSource imageSource) 获取嵌入图像文件的经纬度信息。
getAltitude(ImageSource imageSource, double defaultValue) 获取嵌入图像文件的海拔信息。

开发流程如下

/**
 * @description 图像属性解码
 * @author PengHuAnZhi
 * @date 2021/1/17 14:02
 */
private void testImgValueDecode() {
    
    
    //1、创建图像数据源ImageSource对象,可以通过SourceOptions指定数据源的格式信息,此格式信息仅为给
    // 解码器的提示,正确提供能帮助提高解码效率,如果不设置或设置不正确,会自动检测正确的图像格式。
    ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
    srcOpts.formatHint = "image/jpeg";
    String pathName = "/path/to/image.jpg";
    ImageSource imageSource = ImageSource.create(pathName, srcOpts);
    //2、获取缩略图信息。
    int format = imageSource.getThumbnailFormat();
    byte[] thumbnailBytes = imageSource.getImageThumbnailBytes();
    //3、将缩略图解码为PixelMap对象
    ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
    PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, false);
}

猜你喜欢

转载自blog.csdn.net/qq_43509535/article/details/112778407
今日推荐