当前位置: 首页 > 科技观察

HarmonyOSSample的PixelMap图片功能开发

时间:2023-03-17 11:05:29 科技观察

更多内容请访问:Harmonyos技术社区https://harmonyos.51cto.com1.引入HarmonyOS图片模块,支持开发图片服务,图片解码等常用功能,图像编码,基本位图操作,图像编辑等。当然,它还通过接口组合支持更复杂的图像处理逻辑。那么什么是图像解码,什么是图像编码,什么是位图呢?PixelMap是图像解码后的一种未压缩的位图格式。图片解码就是将不同存档格式的图片(如JPEG、PNG等)解码成未压缩的位图格式。图片编码就是将未压缩的位图格式编码成不同格式的存档格式图片(JPEG、PNG等),无论是编码还是解码,目的都是为了方便在应用程序或系统中进行相应的处理。本文为参与优质创作者激励2.搭建环境,安装DevEcoStudio。具体请参考DevEcoStudio下载。搭建DevEcoStudio开发环境。DevEcoStudio开发环境依赖于网络环境。需要联网才能保证工具的正常使用。开发环境可根据以下两种情况进行配置:如果可以直接上网,只需要下载HarmonyOSSDK即可运行。如果网络不能直接访问Internet,则需要通过代理服务器访问。请参考配置开发环境。下载源码后,使用DevEcoStudio打开工程,运行模拟器。要在真机上运行,??需要将config.json中的buddleName修改为自己的。如果没有,请在AGC上进行配置,参见DebuggingwiththeSimulator。3.代码结构4.实例说明4.1.界面布局布局只有几个操作按钮,后面看效果图,不是本文重点。4.2.后台代码4.2.1图片解码功能图片解码是将支持格式的存档图片解码成统一的PixelMap图片,用于后续图片显示或其他处理,如旋转、缩放、裁剪等。目前支持的格式包括JPEG、PNG、GIF、HEIF、WebP、BMP。主要使用ImageSource等。ImageSource.SourceOptions指定数据源的格式信息,可选ImageSource.DecodingOptions用于支持解码过程中的图像处理操作,如缩放,裁剪,旋转,可选。接下来看一个最简单的图片解码例子:/***graphicdecoding*png-->ImageSource-->PixelMap**@paramcomponent*/privatevoidcommonDecode(Componentcomponent){cleanComponents();//1.获取应用程序文件在设备内部存储上的存储目录。StringpathName=newFile(getFilesDir(),"test.png").getPath();/*InputStreaminputStream=null;try{//2.读取媒体目录的图片();}catch(NotExistExceptione){e.printStackTrace();}*///------------------最简单的方法----------------------ImageSourceimageSource=ImageSource.create(pathName,null);//解码为位图格式PixelMappixelMap=imageSource.createPixelmap(null);//设置图片显示showFirstImage.setPixelMap(pixelMap);//--------------------使用SourceOptions,DecodingOptions选项------------//指定格式信息提高解码效率的数据源ImageSource.SourceOptionssourceOptions=newImageSource.SourceOptions();sourceOptions。formatHint="image/png";//图片来源imageSource=ImageSource.create(pathName,sourceOptions);//提供图片解码选项ImageSource.DecodingOptionsdecodingOptions=newImageSource.DecodingOptions();//裁剪,如果设置为全0,则不执行裁剪。358/227-448/279decodingOptions.desiredRegion=newRect(358,227,90,52);//缩放,如果选择的尺寸与原图尺寸不同,则将图片放大或缩小输出。全0则不缩放decodingOptions.desiredSize=newSize(90*3,52*3);//旋转角度,取值范围0~360。以原图像为旋转中心顺时针旋转图像。decodingOptions.rotateDegrees=180;//解码为位图格式pixelMap=imageSource.createPixelmap(decodingOptions);//设置图片先死showSecondImage.setPixelMap(pixelMap);//记得释放资源imageSource.release();pixelMap.释放();}效果:10-2619:02:01.59413148-13148/?D00000/=>MainAbilitySlice:pngCachePath:/data/user/0/com.buty.samples/files/test.png10-2619:02:01.59413148-13148/?D00000/=>MainAbilitySlice:jpgCachePath:/data/user/0/com.buty.samples/files/test.jpg还有一个progressivedecoding,官方文档的描述:当不是获取所有图片的时候,支持先更新一些数据尝试解码,调用updateData更新数据,并设置参数isFinal为false;当获取到所有数据后,最后一次更新数据时将isFinal设置为true,表示数据更新完成。去网上搜了下progressivedecoding的资料,就是这么说的。“渐进式解码提供了在整个图像下载完成之前逐步解码和渲染图像部分的能力。此功能极大地改善了用户从Internet上查看图像时的体验,因为用户不必等待整个图像下载在解码可以开始之前。用户可以在下载整个图像之前使用可用数据查看图像的预览。此功能对于用于查看来自Internet或带宽有限的数据源的图像的任何应用程序都是至关重要的。“增量解码是从不完整的图像文件中增量解码图像部分的能力。传统解码需要完整的图像文件才能开始解码。渐进解码在图像的渐进级别完成下载后开始。解码器执行解码通道在图像的当前渐进级别上。然后在下载每个渐进级别时对图像执行多个解码通道。每个解码通道显示更多图像,直到图像被完全下载和解码。解码完整图像所需的通道数取决于图像文件格式和创建图像所使用的编码过程。使用渐进式解码的要求:1.图像文件必须支持渐进式解码。大多数图像格式不支持渐进式解码,尽管常见的图像格式有JPEG、PNG、和GIF。2.图像文件必须编码为渐进式图像。图像文件不是使用渐进式图像创建的编码不能被渐进解码,即使文件格式支持渐进解码。3.必须有支持渐进式解码的编解码器。如果编解码器不支持渐进式解码,则编码为渐进式图像的图像将被解码为传统图像。"一起看一个渐进解码的例子,点击“渐进解码”按钮,执行imageSource.updateData/***渐进解码**@paramcomponent*/privatevoidregionDecode(Componentcomponent){if(buttonClickNum<10){//试试获取特定数据时解码,imageSource.updateData(fileByte,fileByte.length*buttonClickNum/10,fileByte.length/10,buttonClickNum==9?true:false);pixelMap=imageSource.createPixelmap(null);showResultText.setText((buttonClickNum+1)+"/10");showSecondImage.setPixelMap(pixelMap);buttonClickNum++;}else{pixelMap.release();imageSource.release();readFileForInitFileByte();buttonClickNum=0;cleanComponents();}}/***读取文件初始化fileByte变量*初始化imageSource*/privatevoidreadFileForInitFileByte(){Filefile=newFile(jpgCachePath);try{FileInputStreamfileInputStream=newFileInputStream(file);ByteArrayOutputStreambyteArrayOutputStream=newByteArrayOutputStream();byte[]data=new1024];intlen=-1;while((len=fileInputStream.read(data))!=-1){byteArrayOutputStream.write(data,0,len);}fileByte=byteArrayOutputStream.toByteArray();ImageSource.SourceOptionssrcOpts=newImageSource.SourceOptions();srcOpts.formatHint="image/jpeg";//增量源选项IncrementalSourceOptionsImageSource.IncrementalSourceOptionsincrementalSourceOptions=newImageSource.IncrementalOptionsSourceOptions/增量只输入增量数据更新源incrementalSourceOptions.mode=ImageSource.UpdateMode.INCREMENTAL_DATA;//创建增量数据源imageSource=ImageSource.createIncrementalSource(incrementalSourceOptions);}catch(IOExceptione){e.printStackTrace();}}作用:4.2.2图像编码函数图像编码主要使用ImagePackerImagePacker.PackingOptions设置编码选项,目前选项不多。/***UseImagePackertopackimages*表示将压缩后的图片打包成文件或其他对象的图片打包器。*调用create创建图片打包器,调用initializePacking设置打包选项,调用addImage添加待打包的图片数据,调用finalizePacking完成打包输出目标对象。**@paramcomponent*/privatevoidencode(Componentcomponent){cleanComponents();//创建ImagePacker对象ImagePackerimagePacker=ImagePacker.create();//设置编码选项ImagePacker.PackingOptionspackingOptions=newImagePacker.PackingOptions();//图像质量,范围从0-100,100是最好的质量。packingOptions.quality=90;//文件输出流,test_encode.jpgtry(FileOutputStreamoutputStream=newFileOutputStream(encodeOutPath)){//初始化输出结果到OutputStream对象的打包任务。imagePacker.initializePacking(outputStream,packingOptions);//图片数据源,test.pngImageSourceimageSource=ImageSource.create(pngCachePath,null);//转换为位图格式PixelMappixelMap=imageSource.createPixelmap(null);//将pixelMap加入Encoder,forencodingbooleanresult=imagePacker.addImage(pixelMap);showResultText.setText("Encoderesult:"+result+System.lineSeparator()+"OutputFilePath:"+encodeOutPath);//释放图片数据源imageSource.release();pixelMap.release();}catch(IOExceptione){HiLog.info(LABEL_LOG,"%{public}s","encodeIOException");}//释放imagePackerimagePacker.release();}4.2.3编辑位图函数a.通过imageSource创建缩略图,createThumbnailPixelmap//解码ImageSource实例中包含的缩略图数据生成缩略图,创建缩略图像素图。//allowFromImage-如果ImageSource不包含缩略图数据,则指定是否允许从原始图像创建。PixelMapthumbnailPixelMap=imageSource.createThumbnailPixelmap(decodingOpts,true);b.读写位图像素数据,绘制一个像素小人/***editbitmap*@paramcomponent*/privatevoidedit(Componentcomponent){cleanComponents();intcolorsWidth=552;intcolorsHeight=310;//PixelMapoptionsPixelMap.InitializationOptionsinitializationOptions=newPixelMap.InitializationOptions();//表示要创建的像素图的预期大小。initializationOptions.size=newSize(colorsWidth,colorsHeight);initializationOptions.pixelFormat=PixelFormat.ARGB_8888;//PixelMap是否允许修改initializationOptions.editable=true;//表示像素颜色的Int数组。数组中的每个元素都采用PixelFormat#ARGB_8888格式。int[]colors=newint[colorsWidth*colorsHeight];Arrays.fill(colors,Color.RED.getValue());//创建PixelMapPixelMappixelMap=PixelMap.create(colors,initializationOptions);//显示图片showFirstImage.setPixelMap(pixelMap);//使用另一个PixelMap作为数据源createaPixelMappixelMap2=PixelMap.create(pixelMap,initializationOptions);//读取指定位置的颜色值。intcolor=pixelMap2.readPixel(newPosition(1,1));HiLog.info(LABEL_LOG,"%{public}s","pixelMapEditreadPixelcolor:"+color);//背一剑for(inti=130;i<180;i++){//在指定位置写入像素pixelMap2.writePixel(newPosition(i,i),0xFF112233);}//在指定区域写入像素int[]pixelArray=newint[1024*1024];Arrays.fill(pixelArray,Color.BLACK.getValue());//HeaderRectregion=newRect(160,110,50,50);//Stride——表示数组每一行的像素个数。此值必须大于或等于此PixelMap中目标区域的宽度。pixelMap2.writePixels(pixelArray,0,100,region);Arrays.fill(pixelArray,Color.GREEN.getValue());//bodyRectregion2=newRect(150,160,70,60);//stride-代表每一行的数组像素数。此值必须大于或等于此PixelMap中目标区域的宽度。pixelMap2.writePixels(pixelArray,0,100,region2);Arrays.fill(pixelArray,Color.YELLOW.getValue());//armRectregion3=newRect(130,160,20,70);//stride-代表每一行的值数组的像素数。此值必须大于或等于此PixelMap中目标区域的宽度。pixelMap2.writePixels(pixelArray,0,100,region3);//armRectregion4=newRect(220,160,20,70);//stride——表示数组每一行的像素个数。此值必须大于或等于此PixelMap中目标区域的宽度。pixelMap2.writePixels(pixelArray,0,100,region4);Arrays.fill(pixelArray,Color.GRAY.getValue());//legRectregion5=newRect(160,200,20,70);//stride-代表每一行的值数组的像素数。此值必须大于或等于此PixelMap中目标区域的宽度。pixelMap2.writePixels(pixelArray,0,100,region5);//legRectregion6=newRect(190,200,20,70);//stride——表示数组每一行的像素个数。此值必须大于或等于此PixelMap中目标区域的宽度。pixelMap2.writePixels(pixelArray,0,100,region6);showSecondImage.setPixelMap(pixelMap2);//从位图对象中获取信息;byte[]ninePatchData=pixelMap.getNin??ePatchChunk();showResultText.setText("ThispixelMapdetailinfo:"+System.lineSeparator()+"capacity="+capacity+System.lineSeparator()+"bytesNumber="+bytesNumber+System.lineSeparator()+"rowBytes="+rowBytes+System.lineSeparator()+"ninePatchData="+Arrays.toString(ninePatchData)+System.lineSeparator());pixelMap.release();pixelMap2.release();}效果是这样的:4.2.4获取图片属性图片属性解码是获取图片所包含的属性信息,PropertyKey存放常用的属性KEY信息。看代码:/***获取图片的缩略图和位置信息**@paramcomponent*/privatevoidattribute(Componentcomponent){cleanComponents();ImageSource.SourceOptionssrcOpts=newImageSource.SourceOptions();srcOpts.formatHint="image/图片";HiLog.debug(LABEL_LOG,"jpgCachePath="+jpgCachePath);ImageSourceimageSource=ImageSource.create(jpgCachePath,srcOpts);ImageSource.DecodingOptionsdecodingOpts=newImageSource.DecodingOptions();//解码ImageSource实例中包含的缩略图数据生成缩略图并创建缩略图。//allowFromImage-如果ImageSource不包含缩略图数据,则指定是否允许从原始图像创建。PixelMapthumbnailPixelMap=imageSource.createThumbnailPixelmap(decodingOpts,true);//位置信息Stringlocation=imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION);HiLog.info(LABEL_LOG,"%{public}s","imageExiflocation:"+location);showResultText.setText("ImageSourceattribute:createThumbnailPixelMap");showSecondImage.setPixelMap(thumbnailPixelMap);//imageSource.release();thumbnailPixelMap.release();}效果:5.思考总结通过这次实践你能学到什么:概念位图,如何编码、解码和编辑图像。渐进式解码的概念,如何生成缩略图,获取其他图像属性等。文章相关附件,可点击下方原文链接下载https://harmonyos.51cto.com/resource/1419查看更多资讯请访问:Harmonyos.51cto,与华为官方共同打造的鸿蒙技术社区.com