From ae56f5b46a7a4cf822e3a319415eb97c5cf60f51 Mon Sep 17 00:00:00 2001 From: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> Date: Tue, 9 Sep 2025 07:02:53 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=8D=95=E8=8E=B7?= =?UTF-8?q?=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> --- entry/src/main/ets/utils/DecodeUtil.ets | 23 +++++++++++----- entry/src/main/ets/utils/EncodeUtil.ets | 35 ++++++++++++++++--------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/entry/src/main/ets/utils/DecodeUtil.ets b/entry/src/main/ets/utils/DecodeUtil.ets index d9ad2cd..f71a69b 100644 --- a/entry/src/main/ets/utils/DecodeUtil.ets +++ b/entry/src/main/ets/utils/DecodeUtil.ets @@ -17,6 +17,8 @@ import { fileIo } from '@kit.CoreFileKit'; import { image } from '@kit.ImageKit'; import Logger from './LoggerUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BusinessError } from '@kit.BasicServicesKit'; const TAG: string = 'imageEdit_Decode'; @@ -26,13 +28,20 @@ const TAG: string = 'imageEdit_Decode'; * @return file fd. */ async function getResourceFd(component: UIContext) { - const context = component.getHostContext()!; - const resourceMgr = context.resourceManager; - let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low")) - let filePath = context.cacheDir + '/' + CommonConstants.RAW_FILE_NAME; - let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); - fileIo.writeSync(file.fd, imageBuffer.buffer); - return file.fd; + let fd: number = 0; + try { + const context = component.getHostContext()!; + const resourceMgr = context.resourceManager; + let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low")) + let filePath = context.cacheDir + '/' + CommonConstants.RAW_FILE_NAME; + let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + fileIo.writeSync(file.fd, imageBuffer.buffer); + fd = file.fd; + } catch (error) { + let err = error as BusinessError; + hilog.error(0x0000, 'GetResourceString', `getResourceString failed. code=${err.code}, message=${err.message}`); + } + return fd; } /** diff --git a/entry/src/main/ets/utils/EncodeUtil.ets b/entry/src/main/ets/utils/EncodeUtil.ets index d9fd69f..ea74ae3 100644 --- a/entry/src/main/ets/utils/EncodeUtil.ets +++ b/entry/src/main/ets/utils/EncodeUtil.ets @@ -18,6 +18,8 @@ import { fileIo } from '@kit.CoreFileKit'; import { image } from '@kit.ImageKit'; import Logger from './LoggerUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; const TAG: string = 'imageEdit_Encode'; /** @@ -33,17 +35,24 @@ export async function encode(component: UIContext, pixelMap: PixelMap) { format: CommonConstants.ENCODE_FORMAT, quality: CommonConstants.ENCODE_QUALITY } - const imageData = await imagePackerApi.packToData(newPixelMap, packOptions); - Logger.info(TAG, `imageData's length is ${imageData.byteLength}`); - // Create image asset. - let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE; - let extension: string = 'jpg'; - const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(component.getHostContext()); - phAccessHelper.createAsset(photoType, extension, (err, uri) => { - if (uri != undefined) { - let file = fileIo.openSync(uri, fileIo.OpenMode.READ_WRITE); - fileIo.writeSync(file.fd, imageData); - fileIo.close(file.fd); - } - }); + try { + const imageData = await imagePackerApi.packToData(newPixelMap, packOptions); + Logger.info(TAG, `imageData's length is ${imageData.byteLength}`); + // Create image asset. + let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE; + let extension: string = 'jpg'; + const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(component.getHostContext()); + phAccessHelper.createAsset(photoType, extension, (err, uri) => { + if (uri != undefined) { + let file = fileIo.openSync(uri, fileIo.OpenMode.READ_WRITE); + fileIo.writeSync(file.fd, imageData); + fileIo.close(file.fd).catch(() => { + hilog.error(0x0000, TAG, `fileIo close failed. code=${err.code}, message=${err.message}`); + }); + } + }); + } catch (error) { + let err = error as BusinessError; + hilog.error(0x0000, TAG, `createAsset failed. code=${err.code}, message=${err.message}`); + } } \ No newline at end of file -- Gitee From 27cb8b61f7ee87148f53a91ab14a3a62344070a5 Mon Sep 17 00:00:00 2001 From: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> Date: Tue, 23 Sep 2025 03:20:46 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=8D=95=E8=8E=B7?= =?UTF-8?q?=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> --- build-profile.json5 | 1 + entry/src/main/ets/utils/DecodeUtil.ets | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build-profile.json5 b/build-profile.json5 index b3b0115..403004a 100644 --- a/build-profile.json5 +++ b/build-profile.json5 @@ -5,6 +5,7 @@ "name": "default", "signingConfig": "default", "compatibleSdkVersion": "5.0.5(17)", + "targetSdkVersion": "5.0.5(17)", "runtimeOS": "HarmonyOS" } ], diff --git a/entry/src/main/ets/utils/DecodeUtil.ets b/entry/src/main/ets/utils/DecodeUtil.ets index f71a69b..6a8d0ee 100644 --- a/entry/src/main/ets/utils/DecodeUtil.ets +++ b/entry/src/main/ets/utils/DecodeUtil.ets @@ -32,7 +32,7 @@ async function getResourceFd(component: UIContext) { try { const context = component.getHostContext()!; const resourceMgr = context.resourceManager; - let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low")) + let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low").id) let filePath = context.cacheDir + '/' + CommonConstants.RAW_FILE_NAME; let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); fileIo.writeSync(file.fd, imageBuffer.buffer); -- Gitee From c3a8a75e53e4481155a0323a58684f7add531a65 Mon Sep 17 00:00:00 2001 From: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> Date: Wed, 12 Nov 2025 09:33:38 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B0=83=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> --- .../ets/common/constant/CommonConstants.ts | 15 +++ entry/src/main/ets/pages/HomePage.ets | 119 ++++++++++++++++-- entry/src/main/ets/view/SliderComponent | 102 +++++++++++++++ 3 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 entry/src/main/ets/view/SliderComponent diff --git a/entry/src/main/ets/common/constant/CommonConstants.ts b/entry/src/main/ets/common/constant/CommonConstants.ts index eef0dee..18ae2e9 100644 --- a/entry/src/main/ets/common/constant/CommonConstants.ts +++ b/entry/src/main/ets/common/constant/CommonConstants.ts @@ -187,4 +187,19 @@ export class CommonConstants { * Rawfile name. */ static readonly RAW_FILE_NAME = 'low.jpg'; + + /** + * Mode light + */ + static readonly SELECT_MODE_LIGHT: number = 1 + + /** + * Mode contrast ratio + */ + static readonly SELECT_MODE_CONTRAST_RATIO: number = 2 + + /** + * Mode exposure + */ + static readonly SELECT_MODE_EXPOSURE: number = 3 } \ No newline at end of file diff --git a/entry/src/main/ets/pages/HomePage.ets b/entry/src/main/ets/pages/HomePage.ets index 9dec4b3..a73c1ee 100644 --- a/entry/src/main/ets/pages/HomePage.ets +++ b/entry/src/main/ets/pages/HomePage.ets @@ -15,7 +15,6 @@ import { image } from '@kit.ImageKit'; import { IconStatus } from '../viewModel/IconListViewModel'; -import AdjustContentView from '../view/AdjustContentView'; import { cropIconChangeList, menuIconList } from '../viewModel/IconListViewModel'; import Logger from '../utils/LoggerUtil'; import { RotateType, CropType, MainTabId } from '../viewModel/OptionViewModel'; @@ -23,6 +22,9 @@ import { square, banner, rectangle } from '../utils/CropUtil'; import { encode } from '../utils/EncodeUtil'; import getPixelMap from '../utils/DecodeUtil'; import { CommonConstants } from '../common/constant/CommonConstants'; +import { SliderComponent } from '../view/SliderComponent'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; const TAG: string = 'imageEdit'; @@ -51,6 +53,21 @@ struct HomePage { text: SaveDescription.SAVE_IMAGE, buttonType: ButtonType.Capsule } + @State @Watch('onValueChange') adjustValue: number = 0; + @State selectMode: number = 1; + @State lightValue: number = 0; + @State contrastRatioValue: number = 0; + @State saturateValue: number = 0; + + onValueChange() { + if (this.selectMode === CommonConstants.SELECT_MODE_LIGHT) { + this.lightValue = this.adjustValue + } else if (this.selectMode === CommonConstants.SELECT_MODE_CONTRAST_RATIO) { + this.contrastRatioValue = this.adjustValue + } else { + this.saturateValue = this.adjustValue + } + } @Builder NavigationTitle() { @@ -188,6 +205,10 @@ struct HomePage { .backgroundColor(Color.Transparent) .onClick(() => { this.pixelInit(); + this.adjustValue = 0; + this.lightValue = 0; + this.contrastRatioValue = 0; + this.saturateValue = 0; }) SaveButton(this.saveButtonOptions) @@ -199,9 +220,18 @@ struct HomePage { primaryButton: { value: $r('app.string.save'), action: () => { - if (this.pixelMap) { - encode(this.getUIContext(), this.pixelMap); - } + this.getUIContext() + .getComponentSnapshot() + .get('low', { scale: 1, waitUntilRenderFinished: true }) + .then((pixelMap: image.PixelMap) => { + if (pixelMap) { + encode(this.getUIContext(), pixelMap); + } + }) + .catch((error: BusinessError) => { + hilog.error(0x0000, 'HomePage', + `get snap shot failed, code=${error.code}, message=${error.message}`); + }) } }, secondaryButton: { @@ -223,14 +253,32 @@ struct HomePage { if (this.isPixelMapChange) { Image(this.pixelMap) .objectFit(ImageFit.None) - } - else { + .brightness(this.selectMode === CommonConstants.SELECT_MODE_LIGHT ? this.adjustValue / 200 + 1 : + this.lightValue / 200 + 1) + .contrast(this.selectMode === CommonConstants.SELECT_MODE_CONTRAST_RATIO ? this.adjustValue / 200 + 1 : + this.contrastRatioValue / 200 + 1) + .saturate(this.selectMode === CommonConstants.SELECT_MODE_EXPOSURE ? this.adjustValue / 200 + 1 : + this.saturateValue / 200 + 1) + .width(this.getUIContext().px2vp(862)) + .height(this.getUIContext().px2vp(1267)) + .id('low') + } else { Image(this.pixelMap) .objectFit(ImageFit.None) + .brightness(this.selectMode === CommonConstants.SELECT_MODE_LIGHT ? this.adjustValue / 200 + 1 : + this.lightValue / 200 + 1) + .contrast(this.selectMode === CommonConstants.SELECT_MODE_CONTRAST_RATIO ? this.adjustValue / 200 + 1 : + this.contrastRatioValue / 200 + 1) + .saturate(this.selectMode === CommonConstants.SELECT_MODE_EXPOSURE ? this.adjustValue / 200 + 1 : + this.saturateValue / 200 + 1) + .width(this.getUIContext().px2vp(862)) + .height(this.getUIContext().px2vp(1267)) + .id('low') } } .width(CommonConstants.LAYOUT_FULL_SCREEN) .height(CommonConstants.IMAGE_SHOW_HEIGHT) + .justifyContent(FlexAlign.Center) Column() { Tabs({ barPosition: BarPosition.End }) { @@ -277,7 +325,64 @@ struct HomePage { .tabBar(this.TabBuilderMenu(MainTabId.ROTATE, $r('app.string.rotate'))) TabContent() { - AdjustContentView() + Column() { + Text(this.adjustValue.toString()) + .fontColor(Color.White) + .margin({ top: $r('app.float.slider_margin_top') }) + .fontSize($r('app.float.slider_font_size')) + SliderComponent({ + blockSize: 16, + trackWidth: 280, + returnValue: this.adjustValue + }) + .margin({ top: 20 }) + Row() { + Column({ space: 5 }) { + Image(this.selectMode === CommonConstants.SELECT_MODE_LIGHT ? + $r('app.media.ic_brightness_filled') : $r('app.media.ic_brightness')) + .width(24) + Text($r('app.string.brightness')) + .fontColor(this.selectMode === CommonConstants.SELECT_MODE_LIGHT ? '#5291FF' : Color.White) + .fontSize(12) + } + .onClick(() => { + this.selectMode = CommonConstants.SELECT_MODE_LIGHT + this.adjustValue = this.lightValue + }) + + Column({ space: 5 }) { + Image(this.selectMode === CommonConstants.SELECT_MODE_CONTRAST_RATIO ? + $r('app.media.ic_transparency_filled') : $r('app.media.ic_transparency')) + .width(24) + Text($r('app.string.transparency')) + .fontColor(this.selectMode === CommonConstants.SELECT_MODE_CONTRAST_RATIO ? '#5291FF' : + Color.White) + .fontSize(12) + } + .onClick(() => { + this.selectMode = CommonConstants.SELECT_MODE_CONTRAST_RATIO + this.adjustValue = this.contrastRatioValue + }) + + Column({ space: 5 }) { + Image(this.selectMode === CommonConstants.SELECT_MODE_EXPOSURE ? + $r('app.media.ic_saturation_filled') : $r('app.media.ic_saturation')) + .width(24) + + Text($r('app.string.saturation')) + .fontColor(this.selectMode === CommonConstants.SELECT_MODE_EXPOSURE ? '#5291FF' : Color.White) + .fontSize(12) + } + .onClick(() => { + this.selectMode = CommonConstants.SELECT_MODE_EXPOSURE + this.adjustValue = this.saturateValue + }) + } + .width('100%') + .justifyContent(FlexAlign.SpaceAround) + .margin({ top: 20 }) + } + .width('100%') } .tabBar(this.TabBuilderMenu(MainTabId.ADJUST, $r('app.string.adjust'))) } diff --git a/entry/src/main/ets/view/SliderComponent b/entry/src/main/ets/view/SliderComponent new file mode 100644 index 0000000..9315939 --- /dev/null +++ b/entry/src/main/ets/view/SliderComponent @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Component +export struct SliderComponent { + @State x: number = 0; + @State positionX: number = 0; + @State offsetX: number = 0; + @State trackWidth: number = 350 + @State blockSize: number = 20 + @Link @Watch('onReturnChange') returnValue: number + @State @Watch('onChange') value: number = this.trackWidth / 2 + + aboutToAppear(): void { + this.value = this.returnValue * this.trackWidth / 200 + this.trackWidth / 2 + } + + onChange() { + let value = (this.value - this.trackWidth / 2) / (this.trackWidth / 200) + if (value > 100) { + this.returnValue = 100 + } else if (value < -100) { + this.returnValue = -100 + } else { + this.returnValue = Math.floor(value) + } + } + + onReturnChange() { + this.value = this.trackWidth / 2 + this.returnValue * (this.trackWidth / 200) + } + + build() { + Column() { + Stack({ alignContent: Alignment.Start }) { + Row() + .height(6) + .width('100%') + .backgroundColor('#1C1C1D') + .borderRadius(3) + + Row() + .height(6) + .width((this.value < 0 || this.value > this.trackWidth) ? this.trackWidth / 2 : + Math.abs(this.value - this.trackWidth / 2)) + .margin({ + left: this.value < 0 ? 0 : this.value > this.trackWidth ? this.trackWidth / 2 : + (this.value - this.trackWidth / 2) > 0 ? this.trackWidth / 2 : this.value + }) + .borderRadius(3) + .backgroundColor($r('sys.color.brand_font')) + + Row() + .height(this.blockSize) + .width(this.blockSize) + .borderRadius(this.blockSize / 2) + .backgroundColor(Color.White) + .margin({ + left: this.value < 0 ? 0 - this.blockSize / 2 : + this.value > this.trackWidth ? this.trackWidth - this.blockSize / 2 : this.value - this.blockSize / 2 + }) + .gesture( + PanGesture() + .onActionStart(() => { + this.x = this.value + }) + .onActionUpdate((event: GestureEvent | undefined) => { + if (event) { + this.offsetX = this.positionX + event.offsetX; + this.value = this.x + event.offsetX + } + }) + .onActionEnd(() => { + this.x = this.value + this.positionX = this.offsetX; + }) + ) + } + .gesture( + TapGesture({ count: 1 }) + .onAction((event: GestureEvent | undefined) => { + if (event) { + this.value = event.fingerList[0].localX; + } + })) + .height(this.blockSize) + .width(this.trackWidth) + } + } +} -- Gitee From 661e657f943a796a02af931532e1939ee9b5eaba Mon Sep 17 00:00:00 2001 From: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> Date: Wed, 12 Nov 2025 09:39:23 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B0=83=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ZhangQ <12903047+zq-kexin@user.noreply.gitee.com> --- entry/src/main/ets/view/SliderComponent.ets | 102 ++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 entry/src/main/ets/view/SliderComponent.ets diff --git a/entry/src/main/ets/view/SliderComponent.ets b/entry/src/main/ets/view/SliderComponent.ets new file mode 100644 index 0000000..9315939 --- /dev/null +++ b/entry/src/main/ets/view/SliderComponent.ets @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Component +export struct SliderComponent { + @State x: number = 0; + @State positionX: number = 0; + @State offsetX: number = 0; + @State trackWidth: number = 350 + @State blockSize: number = 20 + @Link @Watch('onReturnChange') returnValue: number + @State @Watch('onChange') value: number = this.trackWidth / 2 + + aboutToAppear(): void { + this.value = this.returnValue * this.trackWidth / 200 + this.trackWidth / 2 + } + + onChange() { + let value = (this.value - this.trackWidth / 2) / (this.trackWidth / 200) + if (value > 100) { + this.returnValue = 100 + } else if (value < -100) { + this.returnValue = -100 + } else { + this.returnValue = Math.floor(value) + } + } + + onReturnChange() { + this.value = this.trackWidth / 2 + this.returnValue * (this.trackWidth / 200) + } + + build() { + Column() { + Stack({ alignContent: Alignment.Start }) { + Row() + .height(6) + .width('100%') + .backgroundColor('#1C1C1D') + .borderRadius(3) + + Row() + .height(6) + .width((this.value < 0 || this.value > this.trackWidth) ? this.trackWidth / 2 : + Math.abs(this.value - this.trackWidth / 2)) + .margin({ + left: this.value < 0 ? 0 : this.value > this.trackWidth ? this.trackWidth / 2 : + (this.value - this.trackWidth / 2) > 0 ? this.trackWidth / 2 : this.value + }) + .borderRadius(3) + .backgroundColor($r('sys.color.brand_font')) + + Row() + .height(this.blockSize) + .width(this.blockSize) + .borderRadius(this.blockSize / 2) + .backgroundColor(Color.White) + .margin({ + left: this.value < 0 ? 0 - this.blockSize / 2 : + this.value > this.trackWidth ? this.trackWidth - this.blockSize / 2 : this.value - this.blockSize / 2 + }) + .gesture( + PanGesture() + .onActionStart(() => { + this.x = this.value + }) + .onActionUpdate((event: GestureEvent | undefined) => { + if (event) { + this.offsetX = this.positionX + event.offsetX; + this.value = this.x + event.offsetX + } + }) + .onActionEnd(() => { + this.x = this.value + this.positionX = this.offsetX; + }) + ) + } + .gesture( + TapGesture({ count: 1 }) + .onAction((event: GestureEvent | undefined) => { + if (event) { + this.value = event.fingerList[0].localX; + } + })) + .height(this.blockSize) + .width(this.trackWidth) + } + } +} -- Gitee