• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Image
2
3图片组件,支持本地图片和网络图片的渲染展示。
4
5> **说明:**
6>
7> 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
8
9
10## 需要权限
11
12使用网络图片时,需要申请权限ohos.permission.INTERNET。具体申请方式请参考[权限申请声明](../../security/accesstoken-guidelines.md)。
13
14
15## 子组件
16
1718
19
20## 接口
21
22Image(src: string | PixelMap | Resource)
23
24通过图片数据源获取图片,用于后续渲染展示。
25
26从API version 9开始,该接口支持在ArkTS卡片中使用。
27
28**参数:**
29
30| 参数名  | 参数类型                                     | 必填   | 参数描述                                     |
31| ---- | ---------------------------------------- | ---- | ---------------------------------------- |
32| src  | string\|&nbsp;[PixelMap](../apis/js-apis-image.md#pixelmap7)&nbsp;\|&nbsp;[Resource](ts-types.md#resource类型) | 是    | 图片的数据源,支持本地图片和网络图片。<br/>当使用相对路径引用图片资源时,例如`Image("common/test.jpg")`,不支持跨包/跨模块调用该Image组件,建议使用`$r`方式来管理需全局使用的图片资源。<br/>\- 支持的图片格式包括png、jpg、bmp、svg和gif。<br/>\- 支持`Base64`字符串。格式`data:image/[png\|jpeg\|bmp\|webp];base64,[base64 data]`, 其中`[base64 data]`为`Base64`字符串数据。<br/>\- 支持`datashare://`路径前缀的字符串,用于访问通过data&nbsp;ability提供的图片路径。<br/>\- 支持file:///data/storage路径前缀的字符串,用于读取本应用安装目录下files文件夹下的图片资源。需要保证目录包路径下的文件有可读权限。<br/>**说明:**<br/>- ArkTS卡片上支持gif图片格式动效,但仅在显示时播放一次。<br/>- ArkTS卡片上不支持`http://`等网络相关路径前缀、`datashare://`路径前缀以及`file://data/storage`路径前缀的字符串<br/>- ArkTS卡片上不支持&nbsp;[PixelMap](../apis/js-apis-image.md#pixelmap7)类型 |
33
34## 属性
35
36除支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性:
37
38| 名称                       | 参数类型                                     | 描述                                       |
39| ------------------------ | ---------------------------------------- | ---------------------------------------- |
40| alt                      | string \| [Resource](ts-types.md#resource类型) | 加载时显示的占位图,支持本地图片。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
41| objectFit                | [ImageFit](ts-appendix-enums.md#imagefit) | 设置图片的缩放类型。<br/>默认值:ImageFit.Cover<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
42| objectRepeat             | [ImageRepeat](ts-appendix-enums.md#imagerepeat) | 设置图片的重复样式。<br/>默认值:ImageRepeat.NoRepeat<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:**<br/>svg类型图源不支持该属性。 |
43| interpolation            | [ImageInterpolation](#imageinterpolation) | 设置图片的插值效果,即减轻低清晰度图片在放大显示的时候出现的锯齿问题,仅针对图片放大插值。<br/>默认值:ImageInterpolation.None<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:**<br/>svg类型图源不支持该属性。<br/>PixelMap资源不支持该属性。 |
44| renderMode               | [ImageRenderMode](#imagerendermode)      | 设置图片渲染的模式。<br/>默认值:ImageRenderMode.Original<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:**<br/>svg类型图源不支持该属性。 |
45| sourceSize               | {<br/>width:&nbsp;number,<br/>height:&nbsp;number<br/>} | 设置图片裁剪尺寸,将原始图片解码成pixelMap,指定尺寸的图片,单位为px。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:**<br/>PixelMap资源和SVG图片不支持该属性。 |
46| matchTextDirection       | boolean                                  | 设置图片是否跟随系统语言方向,在RTL语言环境下显示镜像翻转显示效果。<br/>默认值:false<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
47| fitOriginalSize          | boolean                                  | 图片组件尺寸未设置时,其显示尺寸是否跟随图源尺寸。<br/>默认值:false<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
48| fillColor                | [ResourceColor](ts-types.md#resourcecolor) | 填充颜色。设置的填充颜色会覆盖在图片上。仅对svg图源生效,设置后会替换svg图片的fill颜色。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
49| autoResize               | boolean                                  | 是否需要在图片解码过程中对图源做resize操作,该操作会根据显示区域的尺寸决定用于绘制的图源尺寸,有利于减少内存占用。<br/>默认值:true<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
50| syncLoad<sup>8+</sup>    | boolean                                  | 设置是否同步加载图片,默认是异步加载。同步加载时阻塞UI线程,不会显示占位图。<br/>默认值:false<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
51| copyOption<sup>9+</sup>  | [CopyOptions](ts-appendix-enums.md#copyoptions9) | 设置图片是否可复制(SVG图片不支持复制)。<br/>当copyOption设置为非CopyOptions.None时,支持使用长按、鼠标右击、快捷组合键'CTRL+C'等方式进行复制。<br/>默认值:CopyOptions.None<br/>该接口支持在ArkTS卡片中使用。 |
52| colorFilter<sup>9+</sup> | [ColorFilter](ts-types.md#colorfilter9)  | 给图像设置颜色滤镜效果。<br/>该接口支持在ArkTS卡片中使用。       |
53| draggable<sup>9+</sup> | boolean | 设置默认拖拽效果。(不能和[onDragStart](ts-universal-events-drag-drop.md)事件同时使用。)<br/>默认值:false |
54
55>  **说明:**
56>
57>  使用快捷组合键对Image组件复制的前提是,该组件必须处于获焦状态。将Image组件的属性focusable设置为true,即可使用TAB键将焦点切换到Image组件上,再将Image组件的focusOnTouch属性设置为true,即可实现点击获焦。
58>  图片设置svg图源时,支持的标签范围有限,目前支持的svg标签包括svg、rect、circle、ellipse、path、line、polyline、polygon。
59
60### ImageInterpolation
61
62从API version 9开始,该接口支持在ArkTS卡片中使用。
63
64| 名称     | 描述                        |
65| ------ | ------------------------- |
66| None   | 不使用插值图片数据。                |
67| High   | 插值图片数据的使用率高,可能会影响图片渲染的速度。 |
68| Medium | 插值图片数据的使用率中。              |
69| Low    | 插值图片数据的使用率低。              |
70
71### ImageRenderMode
72
73从API version 9开始,该接口支持在ArkTS卡片中使用。
74
75| 名称       | 描述                    |
76| -------- | --------------------- |
77| Original | 按照原图进行渲染,包括颜色。        |
78| Template | 将图片渲染为模板图片,忽略图片的颜色信息。 |
79
80## 事件
81
82除支持[通用事件](ts-universal-events-click.md)外,还支持以下事件:
83
84| 名称                                       | 功能描述                                     |
85| ---------------------------------------- | ---------------------------------------- |
86| onComplete(callback:&nbsp;(event?:&nbsp;{&nbsp;width:&nbsp;number,&nbsp;height:&nbsp;number,&nbsp;componentWidth:&nbsp;number,<br>&nbsp;componentHeight:&nbsp;number,&nbsp;loadingStatus:&nbsp;number&nbsp;})&nbsp;=&gt;&nbsp;void) | 图片成功加载时触发该回调,返回成功加载的图片尺寸。<br>- width:图片的宽,单位为像素。<br/>- height:图片的高,单位为像素。<br/>- componentWidth:组件的宽,单位为像素。<br/>- componentHeight:组件的高,单位为像素。<br/>- loadingStatus:图片加载成功的状态。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:** <br/>loadingStatus返回的状态值为0时,代表图片加载失败;返回的状态值为1时,代表图片加载成功。 |
87| onError(callback:&nbsp;(event?:&nbsp;{&nbsp;componentWidth:&nbsp;number,&nbsp;componentHeight:&nbsp;number&nbsp;, message<sup>9+</sup>: string })&nbsp;=&gt;&nbsp;void) | 图片加载出现异常时触发该回调。<br>- componentWidth:组件的宽,单位为像素。<br/>- componentHeight:组件的高,单位为像素。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
88| onFinish(event:&nbsp;()&nbsp;=&gt;&nbsp;void) | 当加载的源文件为带动效的svg图片时,当svg动效播放完成时会触发这个回调,如果动效为无限循环动效,则不会触发这个回调。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 |
89
90## 示例
91
92### 图片加载
93
94加载显示不同类型的图片,并设置图片的缩放类型。
95
96```ts
97@Entry
98@Component
99struct ImageExample1 {
100  private on: string = 'www.example.com'
101  @State src: string = this.on
102
103  build() {
104    Column() {
105      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
106        Text('default').fontSize(16).fontColor(0xcccccc).height(30)
107        Row({ space: 5 }) {
108          Image($r('app.media.ic_png'))
109            .width(110).height(110).border({ width: 1 })
110            .overlay('png', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
111          Image($r('app.media.ic_gif'))
112            .width(110).height(110).border({ width: 1 })
113            .overlay('gif', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
114          Image($r('app.media.ic_svg'))
115            .width(110).height(110).border({ width: 1 })
116            .overlay('svg', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
117        }
118        Row({ space: 5 }) {
119          Image($r('app.media.img_example'))
120            .width(110).height(110).border({ width: 1 })
121            .overlay('jpg', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
122          Image(this.src)
123            .width(110).height(110).border({ width: 1 })
124            .overlay('network', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
125        }.margin({ top: 25, bottom: 10 })
126      }
127
128      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
129        Text('objectFit').fontSize(16).fontColor(0xcccccc).height(30)
130        Row({ space: 5 }) {
131          Image($r('app.media.img_example'))
132            .border({ width: 1 })
133            .objectFit(ImageFit.None).width(110).height(110)
134            .overlay('None', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
135          Image($r('app.media.img_example'))
136            .border({ width: 1 })
137            .objectFit(ImageFit.Fill).width(110).height(110)
138            .overlay('Fill', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
139          Image($r('app.media.img_example'))
140            .border({ width: 1 })
141            .objectFit(ImageFit.Cover).width(110).height(110)
142            .overlay('Cover', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
143        }
144        Row({ space: 5 }) {
145          Image($r('app.media.img_example_w250'))
146            .border({ width: 1 })
147            .objectFit(ImageFit.Contain).width(110).height(110)
148            .overlay('Contain', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
149          Image($r('app.media.img_example_w250'))
150            .border({ width: 1 })
151            .objectFit(ImageFit.ScaleDown).width(110).height(110)
152            .overlay('ScaleDown', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
153        }.margin({ top: 25 })
154      }
155    }.height(320).width(360).padding({ right: 10, top: 10 })
156  }
157}
158```
159
160![zh-cn_image_0000001250492613](figures/zh-cn_image_0000001250492613.gif)
161
162
163
164### 网络图片
165
166加载网络图片时,默认网络超时是5分钟,建议使用alt配置加载时的占位图。如果需要更灵活的网络配置,可以使用SDK中提供的[HTTP](../../connectivity/http-request.md)工具包发送网络请求,接着将返回的数据解码为Image组件中的`PixelMap`,图片开发可参考[图片处理](../../media/image-overview.md)。代码如下。
167
168```tsx
169// @ts-nocheck
170import http from '@ohos.net.http'
171import ResponseCode from '@ohos.net.http'
172import image from '@ohos.multimedia.image'
173
174
175@Entry
176@Component
177struct Index {
178
179  // 先创建一个PixelMap状态变量用于接收网络图片
180  @State image: PixelMap = undefined
181
182  build() {
183    Column({space: 10}) {
184      Button("获取网络图片")
185        .onClick(() => {
186          this.httpRequest()
187        })
188      Image(this.image).height(100).width(100)
189    }
190    .width('100%')
191    .height('100%')
192    .padding(10)
193  }
194
195  // 网络图片请求方法
196  private httpRequest() {
197    let httpRequest = http.createHttp()
198
199    httpRequest.request(
200      "https://www.example.com/xxx.png",   // 请填写一个具体的网络图片地址
201      (error, data) => {
202        if(error) {
203          console.log("error code: " + error.code + ", msg: " + error.message)
204        } else {
205          let code = data.responseCode
206          if(ResponseCode.ResponseCode.OK == code) {
207            let imageSource = image.createImageSource(data.result)
208            let options = {alphaType: 0,                     // 透明度
209                           editable: false,                  // 是否可编辑
210                           pixelFormat: 3,                   // 像素格式
211                           scaleMode: 1,                     // 缩略值
212                           size: {height: 100, width: 100}}  // 创建图片大小
213            imageSource.createPixelMap(options).then((pixelMap) => {
214              this.image = pixelMap
215            })
216          } else {
217            console.log("response code: " + code)
218          }
219        }
220      }
221    )
222  }
223}
224```
225
226**说明**:网络图片加载的请求方式、超时、额外请求参数等配置可以参考HTTP工具包中关于[`request()`](../../reference/apis/js-apis-http.md)请求方法的细节。
227
228### 设置属性
229
230```ts
231@Entry
232@Component
233struct ImageExample2 {
234
235  build() {
236    Column({ space: 10 }) {
237      Text('renderMode').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
238      Row({ space: 50 }) {
239        Image($r('app.media.img_example'))
240          .renderMode(ImageRenderMode.Original).width(100).height(100)
241          .border({ width: 1 })
242          .overlay('Original', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
243        Image($r('app.media.img_example'))
244          .renderMode(ImageRenderMode.Template).width(100).height(100)
245          .border({ width: 1 })
246          .overlay('Template', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
247      }
248
249      Text('alt').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
250      Image('')
251        .alt($r('app.media.Image_none'))
252        .width(100).height(100).border({ width: 1 })
253
254      Text('sourceSize').fontSize(12).fontColor(0xcccccc).width('96%')
255      Row({ space: 50 }) {
256        Image($r('app.media.img_example'))
257          .sourceSize({
258            width: 150,
259            height: 150
260          })
261          .objectFit(ImageFit.ScaleDown).width('25%').aspectRatio(1)
262          .border({ width: 1 })
263          .overlay('w:150 h:150', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
264        Image($r('app.media.img_example'))
265          .sourceSize({
266            width: 200,
267            height: 200
268          })
269          .objectFit(ImageFit.ScaleDown).width('25%').aspectRatio(1)
270          .border({ width: 1 })
271          .overlay('w:200 h:200', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
272      }
273
274      Text('objectRepeat').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
275      Row({ space: 5 }) {
276        Image($r('app.media.ic_health_heart'))
277          .width(120).height(125).border({ width: 1 })
278          .objectRepeat(ImageRepeat.XY).objectFit(ImageFit.ScaleDown)
279          .overlay('ImageRepeat.XY', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
280        Image($r('app.media.ic_health_heart'))
281          .width(110).height(125).border({ width: 1 })
282          .objectRepeat(ImageRepeat.Y).objectFit(ImageFit.ScaleDown)
283          .overlay('ImageRepeat.Y', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
284        Image($r('app.media.ic_health_heart'))
285          .width(110).height(125).border({ width: 1 })
286          .objectRepeat(ImageRepeat.X).objectFit(ImageFit.ScaleDown)
287          .overlay('ImageRepeat.X', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
288      }
289    }.height(150).width('100%').padding({ right: 10 })
290  }
291}
292```
293
294![zh-cn_image_0000001205812616](figures/zh-cn_image_0000001205812616.png)
295
296### 事件调用
297
298```ts
299@Entry
300@Component
301struct ImageExample3 {
302  @State widthValue: number = 0
303  @State heightValue: number = 0
304  private on: Resource = $r('app.media.image_on')
305  private off: Resource = $r('app.media.image_off')
306  private on2off: Resource = $r('app.media.image_on2off')
307  private off2on: Resource = $r('app.media.image_off2on')
308  @State src: Resource = this.on
309
310  build() {
311    Column() {
312      Row({ space: 20 }) {
313        Column() {
314          Image($r('app.media.img_example1'))
315            .alt($r('app.media.ic_public_picture'))
316            .sourceSize({
317              width: 900,
318              height: 900
319            })
320            .objectFit(ImageFit.Cover)
321            .height(180).width(180)
322            // 图片加载完成后,获取图片尺寸。
323            .onComplete((msg: { width: number,height: number }) => {
324              this.widthValue = msg.width
325              this.heightValue = msg.height
326            })
327            .onError(() => {
328              console.log('load image fail')
329            })
330            .overlay('\nwidth: ' + String(this.widthValue) + ' height: ' + String(this.heightValue), {
331              align: Alignment.Bottom,
332              offset: { x: 0, y: 20 }
333            })
334        }
335        // 为图片添加点击事件,点击完成后加载特定图片。
336        Image(this.src)
337          .width(120).height(120)
338          .onClick(() => {
339            if (this.src == this.on || this.src == this.off2on) {
340              this.src = this.on2off
341            } else {
342              this.src = this.off2on
343            }
344          })
345          .onFinish(() => {
346            if (this.src == this.off2on) {
347              this.src = this.on
348            } else {
349              this.src = this.off
350            }
351          })
352      }
353    }.width('100%')
354  }
355}
356```
357
358![zh-cn_image_0000001205972610](figures/zh-cn_image_0000001205972610.gif)
359
360###  渲染沙箱路径图片
361
362```ts
363import fileio from '@ohos.fileio';
364import fs from '@ohos.file.fs';
365import context from '@ohos.app.ability.common';
366
367@Entry
368@Component
369struct LoadImageExample {
370  @State resourcesPath: string = ''
371  @State sandboxPath: string = ''
372  context: context.UIAbilityContext = getContext(this) as context.UIAbilityContext
373
374  build() {
375    Column() {
376      Button('读取沙箱图片')
377        .margin({ bottom: 10, top: 10 })
378        .onClick(() => {
379          this.sandboxPath = this.context.getApplicationContext().filesDir + '/icon.png'
380          console.log(`读取沙箱图片=========>${this.sandboxPath}`)
381          let fd = fs.openSync(this.sandboxPath, 0o100)
382          console.log(`create file========>${fd}`)
383          let srcPath = this.context.bundleCodeDir + '/entry/resources/base/media/icon.png'
384          console.log('mySrcpath' + srcPath)
385          fileio.copyFileSync(srcPath, this.sandboxPath) // 复制图片到沙箱路径
386          this.sandboxPath = 'file://' + this.context.getApplicationContext().filesDir + '/icon.png'
387        })
388      Button('读取资源图片')
389        .margin({ bottom: 10 })
390        .onClick(() => {
391          this.resourcesPath = 'file://' + this.context.bundleCodeDir + '/entry/resources/base/media/icon.png'
392        })
393      Text(`资源图片路径:${this.resourcesPath}`)
394        .fontSize(20)
395        .margin({ bottom: 10 })
396      Image(this.resourcesPath)
397        .width(100)
398        .height(100)
399        .colorFilter([
400          0.30, 0.59, 0.11, 0, 0,
401          0.30, 0.59, 0.11, 0, 0,
402          0.30, 0.59, 0.11, 0, 0,
403          0, 0, 0, 1.0, 0
404        ])
405      Text(`沙箱图片路径:${this.sandboxPath}`)
406        .fontSize(20)
407        .margin({ bottom: 10 })
408      Image(this.sandboxPath)
409        .width(100)
410        .height(100)
411    }
412    .width('100%').height('100%')
413  }
414}
415```
416
417### 为图片增加滤镜
418
419```ts
420// xxx.ets
421@Entry
422@Component
423struct colorFilterExample {
424  @State colorFilterR: number = 0
425  @State colorFilterG: number = 0
426  @State colorFilterB: number = 0
427  @State colorFilterA: number = 0
428
429  build() {
430    Row() {
431      Column() {
432        Image($r('app.media.sky'))
433          .width(200)
434          .height(200)
435        Image($r('app.media.sky'))
436          .width(200)
437          .height(200)
438          .colorFilter([
439          this.colorFilterR, 0, this.colorFilterR, 0, 0,
440            0, this.colorFilterG, this.colorFilterG, 0, 0,
441          this.colorFilterB, 0, this.colorFilterB, 0, 0,
442            0, 0, this.colorFilterA, 0, 0
443          ])
444
445        Row() {
446          Text('R')
447          Slider({
448            min: 0,
449            max: 1,
450            step: 0.01
451          })
452            .onChange((valueR) => {
453              this.colorFilterR = valueR
454            })
455        }
456
457        Row() {
458          Text('G')
459          Slider({
460            min: 0,
461            max: 1,
462            step: 0.01
463          })
464            .onChange((valueG) => {
465              this.colorFilterG = valueG
466            })
467        }
468
469        Row() {
470          Text('B')
471          Slider({
472            min: 0,
473            max: 1,
474            step: 0.01
475          })
476            .onChange((valueB) => {
477              this.colorFilterB = valueB
478            })
479        }
480
481        Row() {
482          Text('A')
483          Slider({
484            min: 0,
485            max: 1,
486            step: 0.01
487          })
488            .onChange((valueA) => {
489              this.colorFilterA = valueA
490            })
491        }
492      }.width('90%').alignItems(HorizontalAlign.Center)
493    }.height('100%').width('100%').justifyContent(FlexAlign.Center)
494  }
495}
496```
497
498![colorFilter](figures/colorFilter.gif)