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