1/* 2 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 */ 15import router from '@ohos.router'; 16import image from '@ohos.multimedia.image'; 17import effectKit from '@ohos.effectKit'; 18import { logger } from '../util/Logger'; 19import { copyPixelMap } from '../util/CopyObj'; 20import { adjustDatas, cropTaskDatas, markDatas } from '../model/AdjustModels'; 21import { CropTasks, TaskData, Tasks } from '../model/AdjustData'; 22import { ScalePhotoPage } from '../pages/ScalePhotoPage'; 23import MaterialEdit from './MaterialEdit'; 24import InputTextDialog from './InputTextDialog'; 25import LoadingDialog from './LoadingDialog'; 26import PixelMapQueue from '../feature/PixelMapQueue'; 27import { readImage } from '../util/MediaUtil'; 28import { FontColorData, MaterialData } from '../model/MaterialData'; 29import { fontColors, stickers } from '../model/MaterialModels'; 30import { getContainSize, Size } from '../util/ImageUtil'; 31import { savePixelMap } from '../util/FileUtil'; 32import { BusinessError } from '@ohos.base'; 33 34const TAG: string = '[Sample_EditImage]'; 35 36@Component 37export struct EditImage { 38 @State mediaUris: string = (router.getParams() as Record<string, Object>)['mediaUris'] as string; 39 @State pixelMap: PixelMap | undefined | null = undefined; 40 @State adjustMarkJudg: boolean = false; 41 @State currentTask: number = Tasks.ADJUST; 42 @State currentCropTask: number = CropTasks.NONE; 43 @State tempPixelMap: image.PixelMap | undefined | null = undefined; 44 @State cancelOkText: Resource | null = null; 45 @State brightnessValue: number = 0; 46 @State outSetValueOne: number = 0; 47 @State cropFlag: boolean = false; 48 @State originBM: PixelMap | null = null; 49 @State cropIndex: number = 0; 50 @State canClick: boolean = true; 51 @State loading: boolean = false; 52 @State isCancelQuit: boolean = false; 53 // 选择资源素材index 54 @State resourceIndex: number = 0; 55 @State isTextMaterial: boolean = true; 56 selectedResource: Resource | undefined = $r('app.color.material_font_color_one'); 57 scroller: Scroller = new Scroller(); 58 brightnessOriginBM: PixelMap | null | undefined = null; 59 @State resolution: string = ''; 60 @State inputValue: string = ''; 61 // 分辨率的坐标 62 @State dpiX: number = 0; 63 @State dpiY: number = 0; 64 // 分辨率 65 @State dpi: string = ''; 66 // 图片父容器大小 67 containerArea: Area | null = null; 68 private pixelMapQueue: PixelMapQueue = new PixelMapQueue(); 69 70 onOpen(): void { 71 if (this.loading) { 72 return; 73 } 74 this.loading = true; 75 this.loadingController.open(); 76 } 77 78 onClose(): void { 79 this.loading = false; 80 this.loadingController.close(); 81 } 82 83 84 /** 85 * 输入文字素材弹窗 86 */ 87 dialogController: CustomDialogController | undefined = new CustomDialogController({ 88 builder: InputTextDialog({ 89 cancel: (): void => this.onCancel(), 90 confirm: (): void => this.onAccept(), 91 inputValue: $inputValue 92 }), 93 cancel: (): void => this.existApp(), 94 autoCancel: true, 95 alignment: DialogAlignment.Bottom, 96 offset: { dx: 0, dy: -20 }, 97 gridCount: 4, 98 customStyle: false 99 }); 100 101 /** 102 * 加载弹窗 103 */ 104 loadingController: CustomDialogController = new CustomDialogController({ builder: LoadingDialog() }); 105 106 onCancel(): void { 107 console.info('Callback when the first button is clicked'); 108 } 109 110 onAccept(): void { 111 if (this.inputValue !== null && this.inputValue.length > 0) { 112 this.currentTask = Tasks.TEXT; 113 } 114 this.onSelectItem(markDatas[0], true); 115 } 116 117 async onEditCancel(): Promise<void> { 118 if (this.currentTask === Tasks.CROP || this.currentTask === Tasks.SCALE || 119 this.currentTask === Tasks.ROTATE || this.currentTask === Tasks.TONING) { 120 this.currentTask = Tasks.ADJUST; 121 this.cropIndex = 0; 122 } 123 if (this.currentTask === Tasks.TEXT || this.currentTask === Tasks.STICKER) { 124 this.currentTask = Tasks.MARK; 125 this.cropIndex = 0; 126 } 127 if (this.currentTask === Tasks.CROP) { 128 this.cropIndex = 0; 129 } 130 this.isCancelQuit = true; 131 this.outSetValueOne = 0; 132 if (this.originBM !== null && this.originBM !== undefined) { 133 this.pixelMap = await copyPixelMap(this.originBM); // 拷贝 134 } 135 // 移出一个缓存 136 const pm: image.PixelMap|undefined = this.pixelMapQueue.pop(); 137 this.releasePm(pm); 138 } 139 140 existApp(): void { 141 console.info('Click the callback in the blank area') 142 } 143 144 async aboutToAppear(): Promise<void> { 145 this.pixelMap = await readImage(this.mediaUris); 146 if (this.pixelMap !== null) { 147 this.originBM = await copyPixelMap(this.pixelMap); 148 } 149 } 150 151 aboutToDisappear(): void { 152 this.dialogController = undefined 153 } 154 155 /** 156 * 选择子菜单 157 * @param item 158 * @param hasInputText 159 */ 160 async onSelectItem(item: TaskData, hasInputText: boolean = false): Promise<void> { 161 if (hasInputText || item.task !== Tasks.TEXT) { 162 // 只有hasInputText,才是图片素材模式,其他都是贴纸 163 this.isTextMaterial = hasInputText; 164 this.resourceIndex = 0; 165 this.isCancelQuit = false; 166 if (item.task !== undefined) { 167 this.currentTask = item.task; 168 } 169 170 if (item.text !== undefined) { 171 this.cancelOkText = item.text; 172 } 173 174 if (this.pixelMap) { 175 this.originBM = await copyPixelMap(this.pixelMap); 176 } 177 // 保存到队列 178 if (this.originBM !== null && this.originBM !== undefined) { 179 this.pixelMapQueue.push(this.originBM); 180 } 181 } else if (item.task === Tasks.TEXT) { 182 this.dialogController?.open(); 183 } 184 } 185 186 /** 187 * 撤销功能 188 */ 189 async repeal(): Promise<void> { 190 const pm: image.PixelMap | undefined = this.pixelMapQueue.pop(); 191 if (pm !== null && pm !== undefined) { 192 this.pixelMap = await copyPixelMap(pm); 193 } 194 } 195 196 /** 197 * 刷新图层显示 198 */ 199 flushPage(): void { 200 this.tempPixelMap = this.pixelMap; 201 this.pixelMap = null; 202 this.pixelMap = this.tempPixelMap; 203 } 204 205 /** 206 * 亮度调节 207 */ 208 async brightChange(): Promise<void> { 209 let headFilter: effectKit.Filter = effectKit.createEffect(this.brightnessOriginBM); 210 if (headFilter !== null) { 211 headFilter.brightness(this.brightnessValue); 212 this.pixelMap = headFilter.getPixelMap(); 213 this.flushPage(); 214 } 215 } 216 217 /** 218 * 图片裁剪 219 * @param proportion 220 */ 221 async cropImage(proportion: number): Promise<void> { 222 if (!this.pixelMap) { 223 return; 224 } 225 let imageInfo: image.ImageInfo = await this.pixelMap.getImageInfo(); 226 if (!imageInfo) { 227 return; 228 } 229 let imageHeight: number = imageInfo.size.height; 230 let imageWith: number = imageInfo.size.width; 231 logger.info(TAG, `imageInfo = ${JSON.stringify(imageInfo)}`); 232 if (proportion === 1) { 233 if (imageHeight > imageWith) { 234 imageHeight = imageWith; 235 } else { 236 imageWith = imageHeight; 237 } 238 logger.info(TAG, `imageHeight = ${JSON.stringify(imageHeight)},imageWith = ${JSON.stringify(imageWith)}`); 239 } 240 try { 241 await this.pixelMap.crop({ 242 size: { height: imageHeight / proportion, width: imageWith }, 243 x: 0, 244 y: 0 245 }); 246 } catch (error) { 247 logger.info(TAG, `crop error = ${JSON.stringify(error)}`); 248 } 249 this.flushPage(); 250 } 251 252 /** 253 * 底部一级菜单 254 */ 255 @Builder 256 getFirstLvMenu() { 257 Row() { 258 Column() { 259 Image($r('app.media.ic_adjust')) 260 .width($r('app.float.size_30')) 261 .height($r('app.float.size_30')) 262 Text($r('app.string.edit_image_adjust')) 263 .fontColor(Color.White) 264 .fontSize($r('app.float.size_16')) 265 } 266 .justifyContent(FlexAlign.Center) 267 .height('100%') 268 .width('40%') 269 .margin({ left: '10%' }) 270 .backgroundColor(this.adjustMarkJudg ? Color.Black : $r('app.color.edit_image_adjust_selected')) 271 .onClick(async () => { 272 this.adjustMarkJudg = false; 273 this.currentTask = Tasks.ADJUST; 274 }) 275 276 Column() { 277 Image($r('app.media.ic_mark')) 278 .width($r('app.float.size_30')) 279 .height($r('app.float.size_30')) 280 Text($r('app.string.edit_image_mark')) 281 .fontColor(Color.White) 282 .fontSize($r('app.float.size_16')) 283 } 284 .justifyContent(FlexAlign.Center) 285 .onClick(() => { 286 this.adjustMarkJudg = true; 287 this.currentTask = Tasks.MARK; 288 }) 289 .backgroundColor(this.adjustMarkJudg ? $r('app.color.edit_image_adjust_selected') : Color.Black) 290 .height('100%') 291 .width('40%') 292 .margin({ right: '10%' }) 293 } 294 .height('9%') 295 .width('100%') 296 } 297 298 releasePm(pm: PixelMap | undefined): void { 299 if(!pm){ 300 return 301 } 302 303 pm.release().catch((err:BusinessError) => { 304 logger.error('pm release异常:' + JSON.stringify(err)); 305 }); 306 } 307 308 @Builder 309 CancelOrOk(text: string | Resource) { 310 Row() { 311 Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) { 312 Image($r('app.media.ic_cancel')) 313 .width($r('app.float.size_30')) 314 .height($r('app.float.size_30')) 315 .onClick(async () => { 316 await this.onEditCancel(); 317 }) 318 .margin({ left: '10%' }) 319 .id('Cancel') 320 321 Text(text) 322 .fontColor(Color.White) 323 .fontSize($r('app.float.size_18')) 324 .width($r('app.float.size_40')) 325 .height($r('app.float.size_30')) 326 327 Image($r('app.media.ic_ok')) 328 .width($r('app.float.size_30')) 329 .height($r('app.float.size_30')) 330 .margin({ right: '10%' }) 331 .onClick(() => { 332 if (this.currentTask === Tasks.CROP || this.currentTask === Tasks.SCALE || 333 this.currentTask === Tasks.ROTATE || this.currentTask === Tasks.TONING) { 334 this.currentTask = Tasks.ADJUST; 335 this.cropIndex = 0; 336 } 337 if (this.currentTask === Tasks.TEXT || this.currentTask === Tasks.STICKER) { 338 this.currentTask = Tasks.MARK; 339 this.cropIndex = 0; 340 } 341 this.outSetValueOne = 0; 342 }) 343 .id('Ok') 344 } 345 } 346 .backgroundColor($r('app.color.edit_image_public_background')) 347 .height('9%') 348 .width('100%') 349 } 350 351 @Builder 352 getMarkTool() { 353 Row() { 354 List() { 355 ForEach(markDatas, (item: TaskData, index) => { 356 ListItem() { 357 Column() { 358 Image(item.image) 359 .width($r('app.float.size_30')) 360 .height($r('app.float.size_30')) 361 Text(item.text) 362 .fontColor(Color.White) 363 .fontSize($r('app.float.size_15')) 364 .margin({ top: $r('app.float.size_5') }) 365 } 366 .justifyContent(FlexAlign.Center) 367 .height('100%') 368 .width('40%') 369 .margin(index === 0 ? { left: '10%' } : { right: '10%' }) 370 .onClick(async () => { 371 this.onSelectItem(item); 372 }) 373 } 374 }) 375 } 376 .listDirection(Axis.Horizontal) // 排列方向 377 .width('100%') 378 .height('14%') 379 } 380 .backgroundColor($r('app.color.edit_image_public_background')) 381 .width('100%') 382 .justifyContent(FlexAlign.SpaceAround) 383 .alignItems(VerticalAlign.Center) 384 } 385 386 @Builder 387 getCropTool() { 388 Row() { 389 List() { 390 ForEach(cropTaskDatas, (item: TaskData, index: number) => { 391 ListItem() { 392 Column() { 393 Image(item.image) 394 .width($r('app.float.size_30')) 395 .height($r('app.float.size_30')) 396 Text(item.text) 397 .fontColor(Color.White) 398 .fontSize($r('app.float.size_14')) 399 .margin({ top: $r('app.float.size_5') }) 400 } 401 .backgroundColor(this.cropIndex === index ? $r('app.color.edit_image_public_background') : $r('app.color.edit_image_crop_select')) 402 .justifyContent(FlexAlign.Center) 403 .height('100%') 404 .width('25%') 405 .onClick(async () => { 406 if (item.task !== undefined) { 407 this.currentCropTask = item.task; 408 } 409 this.pixelMap = await copyPixelMap(this.originBM); // 拷贝 410 this.flushPage(); 411 this.cropIndex = index; 412 if (this.currentCropTask === CropTasks.ORIGIN) { // 原图 413 this.pixelMap = await readImage(this.mediaUris); 414 } else if (this.currentCropTask === CropTasks.ONE_ONE) { 415 await this.cropImage(1); 416 console.log(TAG + 'CropTasks this.cropImage(1)' + this.currentCropTask) 417 } else if (this.currentCropTask === CropTasks.THREE_FOUR) { 418 await this.cropImage(4 / 3); 419 console.log(TAG + 'CropTasks cropImage(4 / 3)==' + this.currentTask) 420 } else if (this.currentCropTask === CropTasks.NINE_SIXTH) { 421 await this.cropImage(16 / 9); 422 console.log(TAG + 'CropTasks (16 / 9)==' + this.currentTask); 423 } 424 }) 425 } 426 }) 427 } 428 .listDirection(Axis.Horizontal) // 排列方向 429 .height('14%') 430 } 431 .width('100%') 432 } 433 434 @Builder 435 getAdjustTool() { 436 Row() { 437 List() { 438 ForEach(adjustDatas, (item: TaskData, index) => { 439 ListItem() { 440 Column() { 441 Image(item.image) 442 .width($r('app.float.size_30')) 443 .height($r('app.float.size_30')) 444 Text(item.text) 445 .fontColor(Color.White) 446 .fontSize($r('app.float.size_15')) 447 .margin({ top: $r('app.float.size_5') }) 448 } 449 .justifyContent(FlexAlign.Center) 450 .height('100%') 451 .width('25%') 452 .onClick(async () => { 453 if (item.task !== undefined) { 454 this.currentTask = item.task; 455 } 456 if (this.currentTask === Tasks.SCALE) { 457 this.computeDpiPosition(); 458 } 459 if (item.task === Tasks.TONING) { 460 this.brightnessOriginBM = this.pixelMap; 461 } 462 if (item.text !== undefined) { 463 this.cancelOkText = item.text 464 } 465 this.originBM = await copyPixelMap(this.pixelMap) // 拷贝 466 if (item.task === Tasks.ROTATE) { 467 this.pixelMap = await copyPixelMap(this.originBM); 468 } 469 // 保存到队列 470 this.pixelMapQueue.push(this.originBM); 471 }) 472 } 473 }) 474 } 475 .listDirection(Axis.Horizontal) // 排列方向 476 .height('14%') 477 } 478 .backgroundColor($r('app.color.edit_image_public_background')) 479 .width('100%') 480 .justifyContent(FlexAlign.SpaceAround) 481 .alignItems(VerticalAlign.Center) 482 } 483 484 @Builder 485 getScaleTool() { 486 ScalePhotoPage({ pixelMap: $pixelMap, dpi: $dpi }) 487 .backgroundColor($r('app.color.edit_image_public_background')) 488 .height('14%') 489 .width('100%') 490 .padding({ top: $r('app.float.size_10') }) 491 } 492 493 @Builder 494 getRotateTool() { 495 Row() { 496 Column() { 497 Image($r('app.media.ic_rotateto90')) 498 .width($r('app.float.size_30')) 499 .height($r('app.float.size_30')) 500 Text($r('app.string.edit_image_rotate_90')) 501 .margin({ top: $r('app.float.size_5') }) 502 .fontSize($r('app.float.size_14')) 503 .fontColor(Color.White) 504 } 505 .id('90') 506 .onClick(async () => { 507 if (this.canClick) { 508 this.canClick = false; 509 await this.pixelMap?.rotate(90); 510 setTimeout(() => { 511 this.canClick = true; 512 this.flushPage(); 513 }, 300) 514 } 515 }) 516 517 Column() { 518 Image($r('app.media.ic_rotate')) 519 .width($r('app.float.size_30')) 520 .height($r('app.float.size_30')) 521 Text($r('app.string.edit_image_rotate_down_90')) 522 .margin({ top: $r('app.float.size_5') }) 523 .fontColor(Color.White) 524 .fontSize($r('app.float.size_14')) 525 } 526 .id('-90') 527 .onClick(async () => { 528 if (this.canClick) { 529 this.canClick = false; 530 await this.pixelMap?.rotate(-90); 531 setTimeout(() => { 532 this.canClick = true; 533 this.flushPage(); 534 }, 300); 535 } 536 }) 537 } 538 .justifyContent(FlexAlign.SpaceAround) 539 .backgroundColor($r('app.color.edit_image_public_background')) 540 .height('14%') 541 .width('100%') 542 } 543 544 @Builder 545 getToningTool() { 546 Row() { 547 Row() { 548 Slider({ 549 value: this.outSetValueOne, 550 min: 0, 551 max: 30, 552 style: SliderStyle.OutSet, 553 }) 554 .id('Slider') 555 .trackThickness($r('app.float.size_5')) 556 .trackColor($r('app.color.edit_image_slider_trackColor')) 557 .selectedColor($r('app.color.edit_image_slider_selected')) 558 .onChange(async (value: number, mode: SliderChangeMode) => { 559 this.outSetValueOne = value; 560 this.brightnessValue = Number((value / 100).toFixed(2)); 561 await this.brightChange(); 562 }) 563 } 564 .height('14%') 565 .width('96%') 566 } 567 .justifyContent(FlexAlign.Center) 568 .width('100%') 569 .backgroundColor($r('app.color.edit_image_public_background')) 570 } 571 572 @Builder 573 getMaterialTool(materials: MaterialData[]) { 574 this.TextOrStickerScroll(materials) 575 } 576 577 async onSave(): Promise<void> { 578 if (this.loading) { 579 return; 580 } 581 this.loading = true; 582 this.loadingController.open(); 583 584 if (this.pixelMap !== undefined && this.pixelMap !== null) { 585 const uri: string = await savePixelMap(getContext(this), this.pixelMap); 586 logger.debug('保存图片地址为:' + uri); 587 router.pushUrl({ 588 url: 'pages/Index', 589 params: { isShowCamera: true } 590 }); 591 } 592 593 } 594 595 @Builder 596 TextOrStickerScroll(materials: MaterialData[]) { 597 Row() { 598 Scroll() { 599 List({ scroller: this.scroller }) { 600 ForEach(materials, (item: MaterialData, index:number) => { 601 ListItem() { 602 Column() { 603 if (item instanceof FontColorData) { 604 Text(item.getResource()) 605 .visibility(Visibility.Hidden) 606 .width($r('app.float.size_40')) 607 .height($r('app.float.size_40')) 608 } else { 609 Image(item.getResource()) 610 .width($r('app.float.size_40')) 611 .height($r('app.float.size_40')) 612 } 613 } 614 .justifyContent(FlexAlign.Center) 615 .borderRadius($r('app.float.size_10')) 616 .border(this.resourceIndex === index ? 617 { 618 width: $r('app.float.size_3'), 619 color: $r('app.color.edit_image_mark_scroll_selected'), 620 radius: $r('app.float.size_10') 621 } : { width: $r('app.float.size_0'), color: $r('app.color.edit_image_mark_scroll') }) 622 .backgroundColor(this.currentTask === Tasks.STICKER ? $r('app.color.edit_image_mark_scroll') : item.getResource()) 623 .width($r('app.float.size_45')) 624 .height($r('app.float.size_45')) 625 .onClick(() => { 626 this.resourceIndex = index; 627 this.selectedResource = item.getResource(); 628 }) 629 } 630 .height('100%') 631 .width('17%') 632 }) 633 } 634 .listDirection(Axis.Horizontal) // 排列方向 635 .height('14%') 636 } 637 .padding({ left: $r('app.float.size_30'), right: $r('app.float.size_30') }) 638 .scrollBar(BarState.Off) 639 .scrollable(ScrollDirection.Horizontal) 640 } 641 .alignItems(VerticalAlign.Center) 642 .backgroundColor($r('app.color.edit_image_public_background')) 643 .width('100%') 644 } 645 646 @Builder 647 getTopBar() { 648 Row() { 649 Image($r("app.media.ic_public_back")) 650 .fillColor(Color.White) 651 .width($r('app.float.size_32')) 652 .height($r('app.float.size_32')) 653 .onClick(() => { 654 router.back(); 655 }) 656 Blank() 657 // 非编辑模式,展示撤回和保存功能 658 if (this.currentTask === Tasks.ADJUST || this.currentTask === Tasks.MARK) { 659 Row({ space: 24 }) { 660 Image($r('app.media.ic_public_tosmall')) 661 .height($r('app.float.size_32')) 662 .width($r('app.float.size_32')) 663 .id('Repeal') 664 .onClick(async () => { 665 this.repeal(); 666 }) 667 Image($r('app.media.ic_public_save')) 668 .height($r('app.float.size_32')) 669 .width($r('app.float.size_32')) 670 .id('Save') 671 .onClick(() => { 672 this.onSave(); 673 }) 674 }.margin({ right: $r('app.float.size_10') }) 675 } 676 } 677 .width('100%') 678 .padding({ left: $r('app.float.size_14') }) 679 .margin({ top: $r('app.float.size_20') }); 680 } 681 682 async computeDpiPosition(): Promise<void> { 683 if (this.containerArea === null || this.pixelMap === null || this.pixelMap === undefined) { 684 return; 685 } 686 let imageInfo: image.ImageInfo = await this.pixelMap.getImageInfo() 687 if (!imageInfo) { 688 return; 689 } 690 const imageHeight: number = imageInfo.size.height; 691 const imageWith: number = imageInfo.size.width; 692 this.dpi = imageWith + "*" + imageHeight; 693 // 计算容器宽高 694 const containerHeight: number = Number(this.containerArea.height); 695 const containerWidth: number = Number(this.containerArea.width); 696 const size: Size = getContainSize(containerWidth * 0.9, containerHeight * 0.9, imageWith, imageHeight); 697 // 计算左上角的坐标 698 const x: number = containerWidth / 2 + size.width / 2; 699 const y: number = containerHeight / 2 - size.height / 2; 700 // 最终坐标还要除去控件宽高 701 this.dpiX = x - 100; 702 this.dpiY = y; 703 } 704 705 getResolutionText(): string { 706 const tip: string = getContext(this).resourceManager.getStringSync($r('app.string.edit_image_resolution')); 707 return tip + this.dpi; 708 } 709 710 build() { 711 Column() { 712 // 顶部功能区 713 this.getTopBar() 714 // 中间操作区 715 if (this.currentTask === Tasks.TEXT || this.currentTask === Tasks.STICKER) { 716 Stack() { 717 MaterialEdit({ 718 pixelMap: $pixelMap, 719 text: this.inputValue, 720 isCancelQuit: this.isCancelQuit, 721 selectedMaterialIndex: this.resourceIndex, 722 isTextMaterial: this.isTextMaterial, 723 onCancel: (): Promise<void> => this.onEditCancel(), 724 onOpen: (): void => this.onOpen(), 725 onClose: (): void => this.onClose() 726 }).width('90%') 727 .height('90%') 728 }.layoutWeight(1) 729 } else { 730 Stack({ alignContent: Alignment.Center }) { 731 Image(this.pixelMap) 732 .objectFit(ImageFit.Contain) 733 .width('90%') 734 .height('90%') 735 .backgroundColor($r('app.color.edit_image_stack_image')) 736 .alignRules( 737 { 738 middle: { anchor: '__container__', align: HorizontalAlign.Center }, 739 center: { anchor: '__container__', align: VerticalAlign.Center } 740 } 741 ) 742 .id('image') 743 744 if (this.currentTask === Tasks.SCALE) { 745 Stack() { 746 Text(this.getResolutionText()) 747 .fontSize($r('app.float.size_14')) 748 .fontColor(Color.White) 749 } 750 .position({ x: this.dpiX, y: this.dpiY }) 751 .backgroundColor($r('app.color.edit_image_stack_resolution')) 752 .id('dpi') 753 .padding($r('app.float.size_10')) 754 .width($r('app.float.size_100')) 755 .height($r('app.float.size_80')) 756 .border({ radius: $r('app.float.size_20') }) 757 } 758 }.layoutWeight(1) 759 .onAreaChange((oldValue: Area, newValue: Area) => { 760 this.containerArea = newValue; 761 }) 762 } 763 // 底部菜单栏 764 Column() { 765 if (this.currentTask === Tasks.MARK) { 766 this.getMarkTool(); 767 } else if (this.currentTask === Tasks.ADJUST) { 768 this.getAdjustTool(); 769 } else if (this.currentTask === Tasks.CROP) { 770 this.getCropTool(); 771 } else if (this.currentTask === Tasks.SCALE) { 772 this.getScaleTool(); 773 } else if (this.currentTask === Tasks.ROTATE) { 774 this.getRotateTool(); 775 } else if (this.currentTask === Tasks.TONING) { 776 this.getToningTool(); 777 } else if (this.currentTask === Tasks.TEXT) { 778 this.getMaterialTool(fontColors); 779 } else if (this.currentTask === Tasks.STICKER) { 780 this.getMaterialTool(stickers); 781 } 782 if (this.currentTask === Tasks.MARK || this.currentTask === Tasks.ADJUST) { 783 this.getFirstLvMenu(); 784 } else { 785 this.CancelOrOk(this.cancelOkText); 786 } 787 } 788 .width('100%') 789 } 790 .backgroundColor(Color.Black) 791 .width('100%') 792 .height('100%') 793 } 794}