• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import FileModel from '../../Model/FileModel';
17import { Log, MediaSize } from '@ohos/common';
18import { Constants, PageDirection, ColorCode } from '@ohos/common';
19import { GlobalThisHelper, GlobalThisStorageKey } from '@ohos/common';
20import CheckEmptyUtils from '@ohos/common';
21import image from '@ohos.multimedia.image';
22
23const canvasScale = 2
24const to300DPI = 300/72
25const TAG = 'PreviewComponent'
26
27@Component
28export struct PreviewComponent {
29
30  @Consume('ImageCount') imageCount: number
31  @Consume('CurrentIndex') currentIndex: number
32  @Consume('IsGlobalDisable') isGlobalDisable: boolean
33  @Consume('PreviewCompHeight')@Watch('onHeightLoad') previewCompHeight: number//预览区组件高度
34
35  @Consume('IsBorderless')isBorderless: boolean
36  @Consume('PrintRange')@Watch('onPrintRangeChange')  printRange: Array<number>
37  @Link @Watch('onPageDirectionChange') pageDirection:number
38  @Link @Watch('onMediaSizeChange') mediaSize:MediaSize
39  @Link @Watch('handleImage')  imageSources: Array<FileModel>
40
41  @State currentImage: FileModel = undefined;
42  @State isPreviewFailed: boolean = false;
43  @State @Watch('loadCurrentPix')currentPixelMap: PixelMap = undefined;
44  @State imageOrientation: number = PageDirection.VERTICAL;
45  @State canvasWidth: number = 313 / canvasScale;
46  @State canvasHeight: number = 444 / canvasScale;
47  @State canvasRatio: number = 313 / 444;//width/height
48  @State offCanvasWidth: number = this.canvasWidth * to300DPI * canvasScale;
49  @State offCanvasHeight: number = this.canvasHeight * to300DPI * canvasScale;
50  @State imageWidth: number = Constants.NUMBER_0;
51  @State imageHeight: number = Constants.NUMBER_0;
52  @State xPosition: number = Constants.NUMBER_0;
53  @State yPosition: number = Constants.NUMBER_0;
54  @State firstPageBackgroundColor: Resource = $r('app.color.effect_color_none');
55  @State previousBackgroundColor: Resource = $r('app.color.effect_color_none');
56  @State nextBackgroundColor: Resource = $r('app.color.effect_color_none');
57  @State lastPageBackgroundColor: Resource = $r('app.color.effect_color_none');
58  @State originalIndex: number = 1;
59  private readonly maxWidth = 304
60  private readonly maxHeight = 261
61  @Link colorMode:number
62
63  private rate: number = 1.5
64
65  build() {
66    Column() {
67      Row() {
68        Image($r('app.media.ic_firstPage')).width(36).height(36).key('PreviewComponent_Image_firstPage')
69          .enabled(this.currentIndex !== 1 && !this.isGlobalDisable)
70          .opacity((this.currentIndex !== 1 && !this.isGlobalDisable) ? Constants.NUMBER_1 : $r('app.float.disable_opacity'))
71          .onClick(() => {
72            this.currentIndex = 1;
73            this.parseImageSize(false);
74          })
75          .borderRadius($r('app.float.radius_m'))
76          .backgroundColor(this.firstPageBackgroundColor)
77          .onHover((isHover: boolean) => {
78            if (isHover) {
79              this.firstPageBackgroundColor =  $r('app.color.effect_color_hover')
80            } else {
81              this.firstPageBackgroundColor =  $r('app.color.effect_color_none')
82            }
83          })
84          .onTouch((event: TouchEvent) => {
85            if (event.type === TouchType.Down) {
86              this.firstPageBackgroundColor =  $r('app.color.effect_color_press')
87            }
88            if (event.type === TouchType.Up) {
89              this.firstPageBackgroundColor =  $r('app.color.effect_color_none')
90            }
91
92          })
93        Image($r('app.media.ic_previous')).width(36).height(36).key('PreviewComponent_Image_previous')
94          .enabled(this.currentIndex !== 1 && !this.isGlobalDisable)
95          .opacity((this.currentIndex !== 1 && !this.isGlobalDisable) ? Constants.NUMBER_1 : $r('app.float.disable_opacity'))
96          .onClick(() => {
97            Log.info(TAG,'this.currentIndex --:'+this.currentIndex)
98            if(this.currentIndex === 1) {
99              return
100            }
101            this.currentIndex -= 1;
102            this.parseImageSize(false);
103          })
104          .borderRadius($r('app.float.radius_m'))
105          .backgroundColor(this.previousBackgroundColor)
106          .onHover((isHover: boolean) => {
107            if (isHover) {
108              this.previousBackgroundColor =  $r('app.color.effect_color_hover')
109            } else {
110              this.previousBackgroundColor =  $r('app.color.effect_color_none')
111            }
112          })
113          .onTouch((event: TouchEvent) => {
114            if (event.type === TouchType.Down) {
115              this.previousBackgroundColor =  $r('app.color.effect_color_press')
116            }
117            if (event.type === TouchType.Up) {
118              this.previousBackgroundColor =  $r('app.color.effect_color_none')
119            }
120
121          })
122        Text(this.currentIndex+'/'+this.imageCount).key('PreviewComponent_Text_imageCount')
123          .fontSize($r('app.float.font_size_body1'))
124          .width($r('app.float.preview_pages_comp_width'))
125          .height($r('app.float.params_comp_height')).textAlign(TextAlign.Center)
126          .margin({left:$r('app.float.preview_pages_comp_margin_left'),right:$r('app.float.preview_pages_comp_margin_right')})
127        Image($r('app.media.ic_next')).key('PreviewComponent_Image_next')
128          .width(36)
129          .height(36)
130          .enabled(this.currentIndex !== this.imageCount && !this.isGlobalDisable)
131          .opacity((this.currentIndex !== this.imageCount && !this.isGlobalDisable) ? Constants.NUMBER_1 : $r('app.float.disable_opacity'))
132          .onClick(() => {
133            Log.info(TAG,'this.currentIndex --:'+this.currentIndex)
134            if(this.currentIndex === this.imageCount) {
135              return;
136            }
137            this.currentIndex += 1;
138            this.parseImageSize(false);
139          })
140          .borderRadius($r('app.float.radius_m'))
141          .backgroundColor(this.nextBackgroundColor)
142          .onHover((isHover: boolean) => {
143            if (isHover) {
144              this.nextBackgroundColor =  $r('app.color.effect_color_hover')
145            } else {
146              this.nextBackgroundColor =  $r('app.color.effect_color_none')
147            }
148          })
149          .onTouch((event: TouchEvent) => {
150            if (event.type === TouchType.Down) {
151              this.nextBackgroundColor =  $r('app.color.effect_color_press')
152            }
153            if (event.type === TouchType.Up) {
154              this.nextBackgroundColor =  $r('app.color.effect_color_none')
155            }
156
157          })
158        Image($r('app.media.ic_lastPage')).key('PreviewComponent_Image_lastPage')
159          .width(36)
160          .height(36)
161          .enabled(this.currentIndex !== this.imageCount && !this.isGlobalDisable)
162          .opacity((this.currentIndex !== this.imageCount && !this.isGlobalDisable) ? Constants.NUMBER_1 : $r('app.float.disable_opacity'))
163          .onClick(() => {
164            this.currentIndex = this.imageCount;
165            this.parseImageSize(false)
166          })
167          .borderRadius($r('app.float.radius_m'))
168          .backgroundColor(this.lastPageBackgroundColor)
169          .onHover((isHover: boolean) => {
170            if (isHover) {
171              this.lastPageBackgroundColor =  $r('app.color.effect_color_hover')
172            } else {
173              this.lastPageBackgroundColor =  $r('app.color.effect_color_none')
174            }
175          })
176          .onTouch((event: TouchEvent) => {
177            if (event.type === TouchType.Down) {
178              this.lastPageBackgroundColor =  $r('app.color.effect_color_press')
179            }
180            if (event.type === TouchType.Up) {
181              this.lastPageBackgroundColor =  $r('app.color.effect_color_none')
182            }
183
184          })
185      }.height(48)
186      .margin({top:8, bottom : 8})
187      Row() {
188        if (this.currentPixelMap) {
189          Image(this.currentPixelMap).key('PreviewComponent_Image_currentPixelMap')
190            .width(this.canvasWidth).height(this.canvasHeight)
191            .backgroundColor($r('app.color.white'))
192            .objectFit(this.isBorderless?ImageFit.Cover:ImageFit.Contain)
193            .renderMode(this.colorMode === ColorCode.COLOR ? ImageRenderMode.Original : ImageRenderMode.Template)
194            .shadow(ShadowStyle.OUTER_DEFAULT_MD)
195        }else{
196          Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
197            Column(){
198              if (CheckEmptyUtils.isEmptyArr(this.imageSources)) {
199                Image($r('app.media.ic_gallery_list_damage')).fillColor('#66000000').width(36).height(36).margin({bottom:8})
200                Text($r('app.string.preview_failed')).fontColor('#66000000').fontSize($r('app.float.font_size_body2'))
201              }else{
202                LoadingProgress().width(36).height(36).margin({bottom:8})
203                Text( $r('app.string.preview_loading')).fontColor('#66000000').fontSize($r('app.float.font_size_body2'))
204              }
205            }
206          }.width(this.canvasWidth).height(this.canvasHeight).backgroundColor($r('app.color.white'))
207          .shadow({ radius: $r('app.float.radius_m'), color: Color.Gray, offsetX: Constants.NUMBER_0, offsetY: Constants.NUMBER_0 })
208        }
209      }
210      .width(480)
211      .height(this.previewCompHeight-80)
212      .justifyContent(FlexAlign.Center)
213      .alignItems(VerticalAlign.Center)
214      .margin({bottom : $r('app.float.preview_comp_margin')})
215    }
216    .width($r('app.float.preview_comp_width'))
217    .height(this.previewCompHeight)
218    .alignItems(HorizontalAlign.Center)
219    .backgroundColor($r('app.color.preview_background_color'))
220  }
221
222  aboutToAppear() {
223    if(this.imageSources !== undefined){
224      this.handleImage()
225    }else{
226      this.checkCanvasWidth()
227    }
228  }
229
230  aboutToDisappear() {
231  }
232
233  parseImageSize(isRendered: boolean) {
234    this.originalIndex = this.printRange[this.currentIndex - 1]
235    this.currentImage = this.imageSources[this.originalIndex - 1];
236    if (CheckEmptyUtils.isEmpty(this.currentImage)){
237      return;
238    }
239    if (!isRendered) {
240      this.fdToPixelMap(this.currentImage.fd);
241    }
242    let width = this.currentImage.width
243    let height = this.currentImage.height
244    if(width > height) {
245      this.imageOrientation = PageDirection.LANDSCAPE  //图片横向
246    } else {
247      this.imageOrientation = PageDirection.VERTICAL //图片竖向
248    }
249    this.updateCanvasSize()
250  }
251
252  updateCanvasSize() {
253    if (this.pageDirection === PageDirection.AUTO) {
254      if (this.imageOrientation === PageDirection.LANDSCAPE) {//图片横向
255        this.setWidthMax()
256      } else if (this.imageOrientation === PageDirection.VERTICAL) {//图片竖向
257        this.setHeightMax()
258      }
259    } else if (this.pageDirection === PageDirection.LANDSCAPE) {
260      //横向
261      this.setWidthMax()
262    } else if (this.pageDirection === PageDirection.VERTICAL) {
263      //竖向
264      this.setHeightMax()
265    }
266  }
267
268  setWidthMax(){
269    this.canvasWidth = this.maxWidth
270    this.canvasHeight = this.canvasWidth * this.canvasRatio
271  }
272
273  setHeightMax(){
274    this.canvasHeight = this.previewCompHeight-80
275    this.canvasWidth = this.canvasHeight * this.canvasRatio
276  }
277
278
279  /**
280   * 纸张尺寸修改事件
281   */
282  onMediaSizeChange() {
283    let pixelSize = this.mediaSize.getPixelMediaSize()
284    this.canvasWidth = pixelSize.width / this.rate
285    this.canvasHeight = pixelSize.height / this.rate;
286    this.canvasRatio  = pixelSize.width / pixelSize.height
287    this.checkCanvasWidth()
288    this.parseImageSize(true)
289  }
290
291  /**
292   * 纸张方向修改
293   */
294  onPageDirectionChange() {
295    Log.info(TAG, 'onPageDirectionChange enter');
296    this.parseImageSize(true)
297  }
298  /**
299   * 打印范围修改
300   */
301  onPrintRangeChange() {
302    Log.info(TAG, 'onPrintRangeChange enter',JSON.stringify(this.printRange));
303    if (this.printRange.length === 0 || this.imageSources === undefined) {
304      return;
305    }
306    if (this.currentIndex>this.printRange.length) {
307      Log.info(TAG, 'parseImageSize this.printRange.length: ', JSON.stringify(this.printRange.length))
308      this.currentIndex = this.printRange.length
309    }
310    let newIndex = this.printRange[this.currentIndex - 1]
311    Log.info(TAG,'newIndex: '+newIndex+' originalIndex: '+this.originalIndex)
312    if (newIndex === this.originalIndex) {
313      this.parseImageSize(true)
314    } else {
315      this.parseImageSize(false)
316    }
317  }
318
319  /**
320   *界面高度调整
321   */
322  onHeightLoad(){
323    Log.info(TAG,'onHeightLoad:'+this.previewCompHeight)
324    if (this.imageSources === undefined ){
325      return;
326    }
327    if(this.previewCompHeight){
328      this.handleImage();
329    }
330  }
331
332
333  /**
334   * 调整画布的方向
335   */
336  swapCanvasWidthAndHeight() {
337    let temp = this.canvasWidth;
338    this.canvasWidth = this.canvasHeight
339    this.canvasHeight = temp
340    this.checkCanvasWidth()
341  }
342  /**
343   * 画布宽度是否超过最大值
344   */
345  checkCanvasWidth(){
346    let ratio = null
347    if(this.canvasWidth > Constants.CANVAS_MAX_WIDTH){
348      ratio = this.canvasHeight/this.canvasWidth
349      this.canvasWidth = Constants.CANVAS_MAX_WIDTH
350      this.canvasHeight = this.canvasWidth * ratio
351    }
352    if(this.canvasHeight > Constants.CANVAS_MAX_HEIGHT){
353      ratio = this.canvasWidth/this.canvasHeight
354      this.canvasHeight = Constants.CANVAS_MAX_HEIGHT
355      this.canvasWidth = this.canvasHeight * ratio
356    }
357  }
358  /**
359   * fd生成pixelMap
360   * @param fd
361   */
362  fdToPixelMap(fd:number){
363    if (image === undefined) {
364      Log.error(TAG, 'image is undefined');
365      return;
366    }
367    Log.info(TAG, 'fd is: ' + fd);
368    Log.debug(TAG, 'this.currentImage: ' + JSON.stringify(this.currentImage));
369    if (this.currentImage === undefined) {
370      Log.error(TAG, 'currentImage is undefined');
371      return;
372    }
373    if (CheckEmptyUtils.isEmpty(this.currentImage.imageSource)) {
374      this.currentImage.imageSource = image.createImageSource(fd);
375      if (this.currentImage.imageSource === undefined) {
376        Log.error(TAG, 'createImageSource error');
377        return;
378      }
379    }
380    let info = this.currentImage.imageSource.getImageInfo();
381    if (CheckEmptyUtils.isEmpty(info)) {
382      Log.error(TAG, 'createImageSource error: invalid imageSource');
383      return;
384    }
385    let decodingOptions
386    let width = this.currentImage.width
387    let height = this.currentImage.height
388    let ratio = width/height
389    if(width*height>=Constants.MAX_PIXELMAP){//超过像素上限pixelmap无法显示在image组件里,需要resize
390      height = Math.floor(Math.sqrt(Constants.MAX_PIXELMAP/ratio))
391      Log.info(TAG,'decodingOptions width: '+height*ratio+' height: '+height)
392      decodingOptions = {
393        desiredSize:{width:height*ratio,height:height}
394      }
395    }
396    this.currentImage.imageSource.createPixelMap(decodingOptions).then(pixelmap => {
397      Log.info(TAG,'Succeeded in creating pixelmap object through image decoding parameters.');
398      if(this.currentPixelMap!==undefined){
399        this.currentPixelMap.release().then(()=>{
400          Log.info(TAG,'currentPixelMap release success');
401          this.currentPixelMap = pixelmap
402          GlobalThisHelper.createValue<PixelMap>(this.currentPixelMap, GlobalThisStorageKey.KEY_CURRENT_PIXELMAP);
403        })
404      }else{
405        this.currentPixelMap = pixelmap
406        GlobalThisHelper.createValue<PixelMap>(this.currentPixelMap, GlobalThisStorageKey.KEY_CURRENT_PIXELMAP);
407      }
408
409    }).catch(error => {
410      Log.info(TAG,'Failed to create pixelmap object through image decoding parameters.'+error);
411    })
412  }
413
414  handleImage(){
415    Log.info(TAG,'handleImage'+this.imageSources.length)
416    this.checkCanvasWidth()
417    this.parseImageSize(false);
418  }
419
420  loadCurrentPix(){
421    if (this.currentPixelMap === undefined) {
422      Log.info(TAG,'loadCurrentPix load failed')
423    }else{
424      Log.info(TAG,'loadCurrentPix load success')
425    }
426  }
427}
428