1# 显示图片 (Image) 2 3 4开发者经常需要在应用中显示一些图片,例如:按钮中的icon、网络图片、本地图片等。在应用中显示图片需要使用Image组件实现,Image支持多种图片格式,包括png、jpg、bmp、svg和gif,具体用法请参考[Image](../reference/apis-arkui/arkui-ts/ts-basic-components-image.md)组件。 5 6 7Image通过调用接口来创建,接口调用形式如下: 8 9```ts 10Image(src: PixelMap | ResourceStr | DrawableDescriptor) 11``` 12 13 14该接口通过图片数据源获取图片,支持本地图片和网络图片的渲染展示。其中,src是图片的数据源,加载方式请参考[加载图片资源](#加载图片资源)。 15 16 17## 加载图片资源 18 19Image支持加载存档图、多媒体像素图两种类型。 20 21 22### 存档图类型数据源 23 24存档图类型的数据源可以分为本地资源、网络资源、Resource资源、媒体库资源和base64。 25 26- 本地资源 27 28 创建文件夹,将本地图片放入ets文件夹下的任意位置。 29 30 Image组件引入本地图片路径,即可显示图片(根目录为ets文件夹)。 31 32 ```ts 33 Image('images/view.jpg') 34 .width(200) 35 ``` 36 37- 网络资源 38 39 引入网络图片需申请权限ohos.permission.INTERNET,具体申请方式请参考[声明权限](../security/AccessToken/declare-permissions.md)。此时,Image组件的src参数为网络图片的链接。 40 41 Image组件首次加载网络图片时,需要请求网络资源,非首次加载时,默认从缓存中直接读取图片,更多图片缓存设置请参考[setImageCacheCount、setImageRawDataCacheSize、setImageFileCacheSize](../reference/apis-arkui/js-apis-system-app.md#setimagecachecount7)。 42 43 ```ts 44 Image('https://www.example.com/example.JPG') // 实际使用时请替换为真实地址 45 ``` 46 47- Resource资源 48 49 使用资源格式可以跨包/跨模块引入图片,resources文件夹下的图片都可以通过$r资源接口读 取到并转换到Resource格式。 50 51 **图1** resources 52 53  54 55 调用方式: 56 57 ``` 58 Image($r('app.media.icon')) 59 ``` 60 61 还可以将图片放在rawfile文件夹下。 62 63 **图2** rawfile 64 65  66 67 调用方式: 68 69 ``` 70 Image($rawfile('example1.png')) 71 ``` 72 73- 媒体库file://data/storage 74 75 支持file://路径前缀的字符串,用于访问通过[媒体库](../reference/apis-core-file-kit/js-apis-file-picker.md)提供的图片路径。 76 77 1. 调用接口获取图库的照片url。 78 ```ts 79 import picker from '@ohos.file.picker'; 80 import { BusinessError } from '@ohos.base'; 81 82 @Entry 83 @Component 84 struct Index { 85 @State imgDatas: string[] = []; 86 // 获取照片url集 87 getAllImg() { 88 let result = new Array<string>(); 89 try { 90 let PhotoSelectOptions:picker.PhotoSelectOptions = new picker.PhotoSelectOptions(); 91 PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; 92 PhotoSelectOptions.maxSelectNumber = 5; 93 let photoPicker:picker.PhotoViewPicker = new picker.PhotoViewPicker(); 94 photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult:picker.PhotoSelectResult) => { 95 this.imgDatas = PhotoSelectResult.photoUris; 96 console.info('PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult)); 97 }).catch((err:Error) => { 98 let message = (err as BusinessError).message; 99 let code = (err as BusinessError).code; 100 console.error(`PhotoViewPicker.select failed with. Code: ${code}, message: ${message}`); 101 }); 102 } catch (err) { 103 let message = (err as BusinessError).message; 104 let code = (err as BusinessError).code; 105 console.error(`PhotoViewPicker failed with. Code: ${code}, message: ${message}`); } 106 } 107 108 // aboutToAppear中调用上述函数,获取图库的所有图片url,存在imgDatas中 109 async aboutToAppear() { 110 this.getAllImg(); 111 } 112 // 使用imgDatas的url加载图片。 113 build() { 114 Column() { 115 Grid() { 116 ForEach(this.imgDatas, (item:string) => { 117 GridItem() { 118 Image(item) 119 .width(200) 120 } 121 }, (item:string):string => JSON.stringify(item)) 122 } 123 }.width('100%').height('100%') 124 } 125 } 126 ``` 127 128 2. 从媒体库获取的url格式通常如下。 129 ```ts 130 Image('file://media/Photos/5') 131 .width(200) 132 ``` 133 134- base64 135 136 路径格式为data:image/[png|jpeg|bmp|webp];base64,[base64 data],其中[base64 data]为Base64字符串数据。 137 138 Base64格式字符串可用于存储图片的像素数据,在网页上使用较为广泛。 139 140 141### 多媒体像素图 142 143PixelMap是图片解码后的像素图,具体用法请参考[图片开发指导](../media/image/image-overview.md)。以下示例将加载的网络图片返回的数据解码成PixelMap格式,再显示在Image组件上, 144 1451. 创建PixelMap状态变量。 146 147 ```ts 148 @State image: PixelMap | undefined = undefined; 149 ``` 150 1512. 引用多媒体。 152 153 请求网络图片,解码编码PixelMap。 154 155 1. 引用网络权限与媒体库权限。 156 ```ts 157 import http from '@ohos.net.http'; 158 import ResponseCode from '@ohos.net.http'; 159 import image from '@ohos.multimedia.image'; 160 import { BusinessError } from '@ohos.base'; 161 ``` 162 2. 填写网络图片地址。 163 ```ts 164 let OutData: http.HttpResponse 165 http.createHttp().request("https://www.example.com/xxx.png", 166 (error: BusinessError, data: http.HttpResponse) => { 167 if (error) { 168 console.error(`http reqeust failed with. Code: ${error.code}, message: ${error.message}`); 169 } else { 170 OutData = data 171 } 172 } 173 ) 174 ``` 175 3. 将网络地址成功返回的数据,编码转码成pixelMap的图片格式。 176 ```ts 177 let code: http.ResponseCode | number = OutData.responseCode 178 if (ResponseCode.ResponseCode.OK === code) { 179 let imageData: ArrayBuffer = OutData.result as ArrayBuffer; 180 let imageSource: image.ImageSource = image.createImageSource(imageData); 181 182 class tmp { 183 height: number = 100 184 width: number = 100 185 } 186 187 let si: tmp = new tmp() 188 let options: Record<string, number | boolean | tmp> = { 189 'alphaType': 0, // 透明度 190 'editable': false, // 是否可编辑 191 'pixelFormat': 3, // 像素格式 192 'scaleMode': 1, // 缩略值 193 'size': { height: 100, width: 100 } 194 } // 创建图片大小 195 196 class imagetmp { 197 image: PixelMap | undefined = undefined 198 set(val: PixelMap) { 199 this.image = val 200 } 201 } 202 203 imageSource.createPixelMap(options).then((pixelMap: PixelMap) => { 204 let im = new imagetmp() 205 im.set(pixelMap) 206 }) 207 } 208 ``` 209 4. 显示图片。 210 ```ts 211 class htp{ 212 httpRequest: Function | undefined = undefined 213 set(){ 214 if(this.httpRequest){ 215 this.httpRequest() 216 } 217 } 218 } 219 Button("获取网络图片") 220 .onClick(() => { 221 let sethtp = new htp() 222 sethtp.set() 223 }) 224 Image(this.image).height(100).width(100) 225 ``` 226 227 228## 显示矢量图 229 230Image组件可显示矢量图(svg格式的图片),支持的svg标签为:svg、rect、circle、ellipse、path、line、polyline、polygon和animate。 231 232svg格式的图片可以使用fillColor属性改变图片的绘制颜色。 233 234 235```ts 236Image($r('app.media.cloud')) 237 .width(50) 238 .fillColor(Color.Blue) 239``` 240 241 **图3** 原始图片 242 243 244 245 **图4** 设置绘制颜色后的svg图片 246 247 248 249 250## 添加属性 251 252给Image组件设置属性可以使图片显示更灵活,达到一些自定义的效果。以下是几个常用属性的使用示例,完整属性信息详见[Image](../reference/apis-arkui/arkui-ts/ts-basic-components-image.md)。 253 254 255### 设置图片缩放类型 256 257通过objectFit属性使图片缩放到高度和宽度确定的框内。 258 259 260```ts 261@Entry 262@Component 263struct MyComponent { 264 scroller: Scroller = new Scroller() 265 266 build() { 267 Scroll(this.scroller) { 268 Column() { 269 Row() { 270 Image($r('app.media.img_2')) 271 .width(200) 272 .height(150) 273 .border({ width: 1 }) 274 // 保持宽高比进行缩小或者放大,使得图片完全显示在显示边界内。 275 .objectFit(ImageFit.Contain) 276 .margin(15) 277 .overlay('Contain', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 278 Image($r('app.media.ic_img_2')) 279 .width(200) 280 .height(150) 281 .border({ width: 1 }) 282 .objectFit(ImageFit.Cover) 283 .margin(15) 284 // 保持宽高比进行缩小或者放大,使得图片两边都大于或等于显示边界。 285 .overlay('Cover', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 286 Image($r('app.media.img_2')) 287 .width(200) 288 .height(150) 289 .border({ width: 1 }) 290 // 自适应显示。 291 .objectFit(ImageFit.Auto) 292 .margin(15) 293 .overlay('Auto', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 294 } 295 296 Row() { 297 Image($r('app.media.img_2')) 298 .width(200) 299 .height(150) 300 .border({ width: 1 }) 301 .objectFit(ImageFit.Fill) 302 .margin(15) 303 // 不保持宽高比进行放大缩小,使得图片充满显示边界。 304 .overlay('Fill', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 305 Image($r('app.media.img_2')) 306 .width(200) 307 .height(150) 308 .border({ width: 1 }) 309 // 保持宽高比显示,图片缩小或者保持不变。 310 .objectFit(ImageFit.ScaleDown) 311 .margin(15) 312 .overlay('ScaleDown', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 313 Image($r('app.media.img_2')) 314 .width(200) 315 .height(150) 316 .border({ width: 1 }) 317 // 保持原有尺寸显示。 318 .objectFit(ImageFit.None) 319 .margin(15) 320 .overlay('None', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 321 } 322 } 323 } 324 } 325} 326``` 327 328 329 330 331### 图片插值 332 333当原图分辨率较低并且放大显示时,图片会模糊出现锯齿。这时可以使用interpolation属性对图片进行插值,使图片显示得更清晰。 334 335 336```ts 337@Entry 338@Component 339struct Index { 340 build() { 341 Column() { 342 Row() { 343 Image($r('app.media.grass')) 344 .width('40%') 345 .interpolation(ImageInterpolation.None) 346 .borderWidth(1) 347 .overlay("Interpolation.None", { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 348 .margin(10) 349 Image($r('app.media.grass')) 350 .width('40%') 351 .interpolation(ImageInterpolation.Low) 352 .borderWidth(1) 353 .overlay("Interpolation.Low", { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 354 .margin(10) 355 }.width('100%') 356 .justifyContent(FlexAlign.Center) 357 358 Row() { 359 Image($r('app.media.grass')) 360 .width('40%') 361 .interpolation(ImageInterpolation.Medium) 362 .borderWidth(1) 363 .overlay("Interpolation.Medium", { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 364 .margin(10) 365 Image($r('app.media.grass')) 366 .width('40%') 367 .interpolation(ImageInterpolation.High) 368 .borderWidth(1) 369 .overlay("Interpolation.High", { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 370 .margin(10) 371 }.width('100%') 372 .justifyContent(FlexAlign.Center) 373 } 374 .height('100%') 375 } 376} 377``` 378 379 380 381 382### 设置图片重复样式 383 384通过objectRepeat属性设置图片的重复样式方式,重复样式请参考[ImageRepeat](../reference/apis-arkui/arkui-ts/ts-appendix-enums.md#imagerepeat)枚举说明。 385 386 387```ts 388@Entry 389@Component 390struct MyComponent { 391 build() { 392 Column({ space: 10 }) { 393 Row({ space: 5 }) { 394 Image($r('app.media.ic_public_favor_filled_1')) 395 .width(110) 396 .height(115) 397 .border({ width: 1 }) 398 .objectRepeat(ImageRepeat.XY) 399 .objectFit(ImageFit.ScaleDown) 400 // 在水平轴和竖直轴上同时重复绘制图片 401 .overlay('ImageRepeat.XY', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 402 Image($r('app.media.ic_public_favor_filled_1')) 403 .width(110) 404 .height(115) 405 .border({ width: 1 }) 406 .objectRepeat(ImageRepeat.Y) 407 .objectFit(ImageFit.ScaleDown) 408 // 只在竖直轴上重复绘制图片 409 .overlay('ImageRepeat.Y', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 410 Image($r('app.media.ic_public_favor_filled_1')) 411 .width(110) 412 .height(115) 413 .border({ width: 1 }) 414 .objectRepeat(ImageRepeat.X) 415 .objectFit(ImageFit.ScaleDown) 416 // 只在水平轴上重复绘制图片 417 .overlay('ImageRepeat.X', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 418 } 419 }.height(150).width('100%').padding(8) 420 } 421} 422``` 423 424 425 426 427### 设置图片渲染模式 428 429通过renderMode属性设置图片的渲染模式为原色或黑白。 430 431 432```ts 433@Entry 434@Component 435struct MyComponent { 436 build() { 437 Column({ space: 10 }) { 438 Row({ space: 50 }) { 439 Image($r('app.media.example')) 440 // 设置图片的渲染模式为原色 441 .renderMode(ImageRenderMode.Original) 442 .width(100) 443 .height(100) 444 .border({ width: 1 }) 445 // overlay是通用属性,用于在组件上显示说明文字 446 .overlay('Original', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 447 Image($r('app.media.example')) 448 // 设置图片的渲染模式为黑白 449 .renderMode(ImageRenderMode.Template) 450 .width(100) 451 .height(100) 452 .border({ width: 1 }) 453 .overlay('Template', { align: Alignment.Bottom, offset: { x: 0, y: 20 } }) 454 } 455 }.height(150).width('100%').padding({ top: 20,right: 10 }) 456 } 457} 458``` 459 460 461 462 463### 设置图片解码尺寸 464 465通过sourceSize属性设置图片解码尺寸,降低图片的分辨率。 466 467原图尺寸为1280\*960,该示例将图片解码为40\*40和90\*90。 468 469 470```ts 471@Entry 472@Component 473struct Index { 474 build() { 475 Column() { 476 Row({ space: 50 }) { 477 Image($r('app.media.example')) 478 .sourceSize({ 479 width: 40, 480 height: 40 481 }) 482 .objectFit(ImageFit.ScaleDown) 483 .aspectRatio(1) 484 .width('25%') 485 .border({ width: 1 }) 486 .overlay('width:40 height:40', { align: Alignment.Bottom, offset: { x: 0, y: 40 } }) 487 Image($r('app.media.example')) 488 .sourceSize({ 489 width: 90, 490 height: 90 491 }) 492 .objectFit(ImageFit.ScaleDown) 493 .width('25%') 494 .aspectRatio(1) 495 .border({ width: 1 }) 496 .overlay('width:90 height:90', { align: Alignment.Bottom, offset: { x: 0, y: 40 } }) 497 }.height(150).width('100%').padding(20) 498 } 499 } 500} 501``` 502 503 504 505 506### 为图片添加滤镜效果 507 508通过colorFilter修改图片的像素颜色,为图片添加滤镜。 509 510 511```ts 512@Entry 513@Component 514struct Index { 515 build() { 516 Column() { 517 Row() { 518 Image($r('app.media.example')) 519 .width('40%') 520 .margin(10) 521 Image($r('app.media.example')) 522 .width('40%') 523 .colorFilter( 524 [1, 1, 0, 0, 0, 525 0, 1, 0, 0, 0, 526 0, 0, 1, 0, 0, 527 0, 0, 0, 1, 0]) 528 .margin(10) 529 }.width('100%') 530 .justifyContent(FlexAlign.Center) 531 } 532 } 533} 534``` 535 536 537 538 539### 同步加载图片 540 541一般情况下,图片加载流程会异步进行,以避免阻塞主线程,影响UI交互。但是特定情况下,图片刷新时会出现闪烁,这时可以使用syncLoad属性,使图片同步加载,从而避免出现闪烁。不建议图片加载较长时间时使用,会导致页面无法响应。 542 543 544```ts 545Image($r('app.media.icon')) 546 .syncLoad(true) 547``` 548 549 550## 事件调用 551 552通过在Image组件上绑定onComplete事件,图片加载成功后可以获取图片的必要信息。如果图片加载失败,也可以通过绑定onError回调来获得结果。 553 554 555```ts 556@Entry 557@Component 558struct MyComponent { 559 @State widthValue: number = 0 560 @State heightValue: number = 0 561 @State componentWidth: number = 0 562 @State componentHeight: number = 0 563 564 build() { 565 Column() { 566 Row() { 567 Image($r('app.media.ic_img_2')) 568 .width(200) 569 .height(150) 570 .margin(15) 571 .onComplete(msg => { 572 if(msg){ 573 this.widthValue = msg.width 574 this.heightValue = msg.height 575 this.componentWidth = msg.componentWidth 576 this.componentHeight = msg.componentHeight 577 } 578 }) 579 // 图片获取失败,打印结果 580 .onError(() => { 581 console.info('load image fail') 582 }) 583 .overlay('\nwidth: ' + String(this.widthValue) + ', height: ' + String(this.heightValue) + '\ncomponentWidth: ' + String(this.componentWidth) + '\ncomponentHeight: ' + String(this.componentHeight), { 584 align: Alignment.Bottom, 585 offset: { x: 0, y: 60 } 586 }) 587 } 588 } 589 } 590} 591``` 592 593 594 595