diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7f8c3..523e46e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.2.2-rc.1 +- Support EXIF metadata carried by images as display orientation + ## 3.2.2-rc.0 - Add ImageKnifeComponent to destroy network request interruption - Code refactoring during the download of image resources stage diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 9707118..6ee83eb 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -224,6 +224,11 @@ struct Index { }); }) + Button($r('app.string.test_exif')).margin({ top: 10 }).onClick(() => { + router.push({ + uri: 'pages/TestImageExif', + }); + }) } } .width('100%') .height('100%') diff --git a/entry/src/main/ets/pages/TestImageExif.ets b/entry/src/main/ets/pages/TestImageExif.ets new file mode 100644 index 0000000..4a29b1d --- /dev/null +++ b/entry/src/main/ets/pages/TestImageExif.ets @@ -0,0 +1,92 @@ +/* + * 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. + */ +import { ImageKnifeComponent } from '@ohos/libraryimageknife'; +import fs from '@ohos.file.fs'; + +@Entry +@Component +struct LocalImage { + scroller: Scroller = new Scroller; + + build() { + Scroll(this.scroller) { + Column() { + Column() { + Text($r('app.string.base_image')) + .fontSize(20) + .fontWeight(FontWeight.Bold) + Row() { + Image($rawfile('rotate/rotate.jpg')).width(100).height(100).margin({ right: 10 }) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $rawfile('rotate/rotate.jpg'), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + } + } + .margin({ bottom: 20 }) + + Column() { + Text($r('app.string.rotate_mirror')) + .fontSize(20) + .fontWeight(FontWeight.Bold) + Row() { + Image($rawfile('rotate/rotate_mirror.jpg')).width(100).height(100).margin({ right: 10 }) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $rawfile('rotate/rotate_mirror.jpg'), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + } + }.margin({ bottom: 20 }) + + Column() { + Text($r('app.string.rotate_rotate90')) + .fontSize(20) + .fontWeight(FontWeight.Bold) + Row() { + Image($rawfile('rotate/rotate_rotate90.jpg')).width(100).height(100).margin({ right: 10 }) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $rawfile('rotate/rotate_rotate90.jpg'), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + } + }.margin({ bottom: 20 }) + + Column() { + Text($r('app.string.rotate_mirror_rotate270')) + .fontSize(20) + .fontWeight(FontWeight.Bold) + Row() { + Image($rawfile('rotate/rotate_mirror_rotate270.jpg')).width(100).height(100).margin({ right: 10 }) + ImageKnifeComponent({ + imageKnifeOption: { + loadSrc: $rawfile('rotate/rotate_mirror_rotate270.jpg'), + objectFit: ImageFit.Contain + } + }).width(100).height(100) + } + } + } + .width('100%') + } + .height('100%') + } +} + diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json index f2cea47..e0ff91e 100644 --- a/entry/src/main/resources/base/element/string.json +++ b/entry/src/main/resources/base/element/string.json @@ -687,6 +687,26 @@ { "name": "Error_Message", "value": "error message" + }, + { + "name": "test_exif", + "value": "Test display orientation base on the EXIF metadata " + }, + { + "name": "base_image", + "value": "The image don't carry rotation information" + }, + { + "name": "rotate_mirror", + "value": "Mirror horizontal" + }, + { + "name": "rotate_rotate90", + "value": "Rotate 90°" + }, + { + "name": "rotate_mirror_rotate270", + "value": "Mirror horizontal and rotate 270°" } ] } \ No newline at end of file diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index d0370e7..67444d8 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -42,6 +42,7 @@ "pages/SingleImageCallBack", "pages/MultipleImageCallBack", "pages/LocalImage", - "pages/ErrorMessageDownload" + "pages/ErrorMessageDownload", + "pages/TestImageExif" ] } \ No newline at end of file diff --git a/entry/src/main/resources/rawfile/rotate/rotate.jpg b/entry/src/main/resources/rawfile/rotate/rotate.jpg new file mode 100644 index 0000000..982708a Binary files /dev/null and b/entry/src/main/resources/rawfile/rotate/rotate.jpg differ diff --git a/entry/src/main/resources/rawfile/rotate/rotate_mirror.jpg b/entry/src/main/resources/rawfile/rotate/rotate_mirror.jpg new file mode 100644 index 0000000..b309125 Binary files /dev/null and b/entry/src/main/resources/rawfile/rotate/rotate_mirror.jpg differ diff --git a/entry/src/main/resources/rawfile/rotate/rotate_mirror_rotate270.jpg b/entry/src/main/resources/rawfile/rotate/rotate_mirror_rotate270.jpg new file mode 100644 index 0000000..3e764fd Binary files /dev/null and b/entry/src/main/resources/rawfile/rotate/rotate_mirror_rotate270.jpg differ diff --git a/entry/src/main/resources/rawfile/rotate/rotate_rotate90.jpg b/entry/src/main/resources/rawfile/rotate/rotate_rotate90.jpg new file mode 100644 index 0000000..1d31a7c Binary files /dev/null and b/entry/src/main/resources/rawfile/rotate/rotate_rotate90.jpg differ diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json index 265b743..28a083d 100644 --- a/entry/src/main/resources/zh_CN/element/string.json +++ b/entry/src/main/resources/zh_CN/element/string.json @@ -679,6 +679,26 @@ { "name": "Error_Message", "value": "错误信息" + }, + { + "name": "base_image", + "value": "图片不携带旋转信息" + }, + { + "name": "test_exif", + "value": "测试图片携带的EXIF元数据作为显示方向" + }, + { + "name": "rotate_mirror", + "value": "水平翻转" + }, + { + "name": "rotate_rotate90", + "value": "顺时针90°" + }, + { + "name": "rotate_mirror_rotate270", + "value": "水平翻转后再顺时针270°" } ] } \ No newline at end of file diff --git a/library/oh-package.json5 b/library/oh-package.json5 index 6bc82bf..abae842 100644 --- a/library/oh-package.json5 +++ b/library/oh-package.json5 @@ -14,7 +14,7 @@ "main": "index.ets", "repository": "https://gitee.com/openharmony-tpc/ImageKnife", "type": "module", - "version": "3.2.2-rc.0", + "version": "3.2.2-rc.1", "dependencies": { "@ohos/gpu_transform": "^1.0.2" }, diff --git a/library/src/main/ets/ImageKnifeLoader.ets b/library/src/main/ets/ImageKnifeLoader.ets index 77ec8dd..380aac5 100644 --- a/library/src/main/ets/ImageKnifeLoader.ets +++ b/library/src/main/ets/ImageKnifeLoader.ets @@ -16,6 +16,7 @@ import { CacheStrategy, DecodeImageInfo, ErrorInfo, + FlipRotate, ImageKnifeData, ImageKnifeRequestSource, ImageKnifeRequestWithSource, RequestJobRequest, @@ -164,6 +165,14 @@ export class ImageKnifeLoader { } timeInfo.decodeStartTime = Date.now(); + // 获取旋转信息 + let exif: string | undefined = undefined; + await imageSource.getImageProperty(image.PropertyKey.ORIENTATION).then((res)=>{ + exif = res; + }).catch((error: BusinessError)=>{ + LogUtil.info("The normal image don't have rotation information, " + error.message); + }) + await imageSource.createPixelMap(decodingOptions) .then((pixelmap: PixelMap) => { timeInfo.decodeEndTime = Date.now(); @@ -186,6 +195,17 @@ export class ImageKnifeLoader { } catch (e) { LogUtil.error('PixelMap setTransferDetached failed:' + JSON.stringify(e)) } + // 设置翻转和旋转角度 + if(exif && exif !== 'Top-left'){ + let result = ImageKnifeLoader.getOrientation(exif); + if(result.horizontal || result.vertical) { + resPixelmap?.flipSync(result.horizontal, result.vertical); + } + if(result.rotate > 0) { + resPixelmap?.rotateSync(result.rotate); + } + LogUtil.log('The normal image set flip , horizontal=' + result.horizontal + ', vertical=' +result.vertical + ', rotate=' + result.rotate); + } //获取各个pixelMap的大小 if (resPixelmap !== undefined) { @@ -253,6 +273,15 @@ export class ImageKnifeLoader { return } timeInfo.decodeStartTime = Date.now(); + + // 获取旋转信息 + let exif: string | undefined = undefined; + await imageSource.getImageProperty(image.PropertyKey.ORIENTATION).then((res)=>{ + exif = res; + }).catch((error: BusinessError)=>{ + LogUtil.info("Svg image don't have rotation information, " + error.message); + }) + await imageSource.createPixelMap(opts) .then((pixelmap: PixelMap) => { timeInfo.decodeEndTime = Date.now(); @@ -260,6 +289,17 @@ export class ImageKnifeLoader { imageSource.release() try { resPixelmap.setTransferDetached(true) + // 设置翻转和旋转角度 + if(exif && exif !== 'Top-left'){ + let result = ImageKnifeLoader.getOrientation(exif); + if(result.horizontal || result.vertical) { + resPixelmap?.flipSync(result.horizontal, result.vertical); + } + if(result.rotate > 0) { + resPixelmap?.rotateSync(result.rotate); + } + LogUtil.log('Svg image set flip , horizontal=' + result.horizontal + ', vertical=' +result.vertical + ', rotate=' + result.rotate); + } } catch (e) { LogUtil.error('PixelMap setTransferDetached failed:' + JSON.stringify(e)) } @@ -489,4 +529,39 @@ export class ImageKnifeLoader { } } } + + static getOrientation(orientation: string | undefined){ + let horizontal: boolean = false; + let vertical: boolean = false; + let rotate: number= 0; + switch (orientation){ + case 'Top-left': break + case 'Top-right': + horizontal = true; + break; + case 'Bottom-left': + vertical = true; + break + case 'Bottom-right': + rotate = 180; + break; + case 'Left-top': + horizontal = true; + rotate = 270; + break + case 'Right-top': + rotate = 90; + break; + case 'Left-bottom': + rotate = 270; + break + case 'Right-bottom': + horizontal = true; + rotate = 90; + break; + } + + let data: FlipRotate = { horizontal: horizontal, vertical: vertical, rotate:rotate }; + return data + } } \ No newline at end of file diff --git a/library/src/main/ets/model/ImageKnifeData.ets b/library/src/main/ets/model/ImageKnifeData.ets index 91268e6..fbf8b8c 100644 --- a/library/src/main/ets/model/ImageKnifeData.ets +++ b/library/src/main/ets/model/ImageKnifeData.ets @@ -158,3 +158,9 @@ export interface RequestJobRequest { readTimeout?: number } +export interface FlipRotate{ + horizontal: boolean, + vertical: boolean, + rotate: number, +} +