Revert "降采样"
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
This commit is contained in:
parent
233b24032e
commit
0dd26b9e75
|
@ -3,7 +3,6 @@
|
||||||
- 修复加载错误图后未去请求排队队列中的请求
|
- 修复加载错误图后未去请求排队队列中的请求
|
||||||
- 子线程本地Resource参数类型转换成number
|
- 子线程本地Resource参数类型转换成number
|
||||||
- 修改使用hilog记录日志,默认打开debug级别的日志
|
- 修改使用hilog记录日志,默认打开debug级别的日志
|
||||||
- 增加降采样
|
|
||||||
- file格式图片,fd同步close
|
- file格式图片,fd同步close
|
||||||
- 解码pixelMap默认不可编辑,图形变化可编辑
|
- 解码pixelMap默认不可编辑,图形变化可编辑
|
||||||
- 修改网络请求超时设置
|
- 修改网络请求超时设置
|
||||||
|
|
24
README.md
24
README.md
|
@ -264,20 +264,8 @@ ImageKnifeAnimatorComponent({
|
||||||
}),animatorOption:this.animatorOption
|
}),animatorOption:this.animatorOption
|
||||||
}).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})
|
}).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})
|
||||||
```
|
```
|
||||||
#### 11.图片降采样 示例
|
|
||||||
```
|
|
||||||
ImageKnifeComponent({
|
|
||||||
imageKnifeOption:new ImageKnifeOption({
|
|
||||||
loadSrc:$r("app.media.pngSample"),
|
|
||||||
placeholderSrc:$r('app.media.loading'),
|
|
||||||
errorholderSrc:$r('app.media.failed'),
|
|
||||||
downsampleOf: DownsampleStrategy.NONE
|
|
||||||
}),animatorOption:this.animatorOption
|
|
||||||
}).width(300).height(300)
|
|
||||||
```
|
|
||||||
#### 复用场景
|
#### 复用场景
|
||||||
在aboutToRecycle生命周期清空组件内容;通过watch监听触发图片的加载。
|
在aboutToRecycle生命周期清空组件内容;通过watch监听触发图片的加载。
|
||||||
|
|
||||||
## 接口说明
|
## 接口说明
|
||||||
### ImageKnife组件
|
### ImageKnife组件
|
||||||
| 组件名称 | 入参内容 | 功能简介 |
|
| 组件名称 | 入参内容 | 功能简介 |
|
||||||
|
@ -320,17 +308,7 @@ ImageKnifeComponent({
|
||||||
| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) |
|
| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) |
|
||||||
| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) |
|
| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) |
|
||||||
| onLoadListener | onLoadStart: () => void、onLoadSuccess: (data: string | PixelMap | undefined) => void、onLoadFailed: (err: string) => void| 监听图片加载成功与失败 |
|
| onLoadListener | onLoadStart: () => void、onLoadSuccess: (data: string | PixelMap | undefined) => void、onLoadFailed: (err: string) => void| 监听图片加载成功与失败 |
|
||||||
| downsampleOf | DownsampleStrategy | 降采样(可选) |
|
|
||||||
### 降采样类型
|
|
||||||
| 类型 | 相关描述 |
|
|
||||||
|---------------------|-------------------|
|
|
||||||
| NONE | 不进行降采样 |
|
|
||||||
| AT_MOST | 请求尺寸大于实际尺寸不进行放大 |
|
|
||||||
| FIT_CENTER_MEMORY | 两边自适应内存优先 |
|
|
||||||
| FIT_CENTER_QUALITY | 两边自适应质量优先 |
|
|
||||||
| CENTER_INSIDE_MEMORY | 宽高缩放比最大的比例,进行缩放适配内存优先 |
|
|
||||||
| CENTER_INSIDE_QUALITY | 宽高缩放比最大的比例,进行缩放适配质量优先 |
|
|
||||||
| CENTER_OUTSIDE | 根据宽高的最小的比例,进行适配 |
|
|
||||||
### ImageKnife接口
|
### ImageKnife接口
|
||||||
|
|
||||||
| 参数名称 | 入参内容 | 功能简介 |
|
| 参数名称 | 入参内容 | 功能简介 |
|
||||||
|
|
|
@ -1,208 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 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 { DownsampleStrategy, ImageKnifeOption, } from '@ohos/imageknife';
|
|
||||||
import { ImageKnifeComponent, BlurTransformation, } from '@ohos/libraryimageknife';
|
|
||||||
import { image } from '@kit.ImageKit';
|
|
||||||
import { BusinessError } from '@kit.BasicServicesKit';
|
|
||||||
import { Downsampler } from '@ohos/imageknife/src/main/ets/downsampling/Downsampler';
|
|
||||||
import { FileTypeUtil } from '@ohos/imageknife/src/main/ets/utils/FileTypeUtil';
|
|
||||||
|
|
||||||
@Entry
|
|
||||||
@ComponentV2
|
|
||||||
struct DownSamplePage {
|
|
||||||
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption( {
|
|
||||||
loadSrc: $r('app.media.startIcon'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain
|
|
||||||
})
|
|
||||||
isBrightness: boolean = false
|
|
||||||
@Local beforeSampling: number = 0
|
|
||||||
@Local afterSampling: number = 0
|
|
||||||
@Local SamplingList: SamplingType[] = [
|
|
||||||
new SamplingType(0, "NONE"),
|
|
||||||
new SamplingType(1, "AT_MOST"),
|
|
||||||
new SamplingType(2, "FIT_CENTER_MEMORY"),
|
|
||||||
new SamplingType(4, "FIT_CENTER_QUALITY"),
|
|
||||||
new SamplingType(5, "CENTER_INSIDE_MEMORY"),
|
|
||||||
new SamplingType(6, "CENTER_INSIDE_QUALITY"),
|
|
||||||
new SamplingType(7, "CENTER_OUTSIDE"),
|
|
||||||
]
|
|
||||||
@Local checked: boolean = false
|
|
||||||
|
|
||||||
updateImageKnifeOption(value: string) {
|
|
||||||
if (value === 'NONE') {
|
|
||||||
this.imageKnifeOption =new ImageKnifeOption( {
|
|
||||||
loadSrc: $r('app.media.jpgSample'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.NONE
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.jpgSample'))
|
|
||||||
this.afterSamplingFunc($r('app.media.jpgSample'))
|
|
||||||
} else if (value === 'AT_MOST') {
|
|
||||||
this.imageKnifeOption =new ImageKnifeOption( {
|
|
||||||
loadSrc: $r('app.media.svgSample'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.AT_MOST
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.svgSample'))
|
|
||||||
this.afterSamplingFunc($r('app.media.svgSample'))
|
|
||||||
} else if (value === 'FIT_CENTER_MEMORY') {
|
|
||||||
this.imageKnifeOption =new ImageKnifeOption( {
|
|
||||||
loadSrc: $r('app.media.pngSample'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.FIT_CENTER_MEMORY
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.pngSample'))
|
|
||||||
this.afterSamplingFunc($r('app.media.pngSample'))
|
|
||||||
}
|
|
||||||
else if (value ==='FIT_CENTER_QUALITY') {
|
|
||||||
this.imageKnifeOption =new ImageKnifeOption( {
|
|
||||||
loadSrc: $r('app.media.pngSample'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.FIT_CENTER_QUALITY
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.pngSample'))
|
|
||||||
this.afterSamplingFunc($r('app.media.pngSample'))
|
|
||||||
}
|
|
||||||
else if (value === 'CENTER_INSIDE_MEMORY') {
|
|
||||||
this.imageKnifeOption = new ImageKnifeOption({
|
|
||||||
loadSrc: $r('app.media.jpgSample1'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.CENTER_INSIDE_MEMORY
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.jpgSample1'))
|
|
||||||
this.afterSamplingFunc($r('app.media.jpgSample1'))
|
|
||||||
} else if (value === 'CENTER_INSIDE_QUALITY') {
|
|
||||||
this.imageKnifeOption = new ImageKnifeOption({
|
|
||||||
loadSrc: $r('app.media.jpgSample1'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.CENTER_INSIDE_QUALITY
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.jpgSample1'))
|
|
||||||
this.afterSamplingFunc($r('app.media.jpgSample1'))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.imageKnifeOption = new ImageKnifeOption({
|
|
||||||
loadSrc: $r('app.media.jpgSample2'),
|
|
||||||
placeholderSrc: $r("app.media.loading"),
|
|
||||||
errorholderSrc: $r("app.media.app_icon"),
|
|
||||||
objectFit: ImageFit.Contain,
|
|
||||||
downsampleOf: DownsampleStrategy.CENTER_OUTSIDE
|
|
||||||
})
|
|
||||||
this.originalPixMap($r('app.media.jpgSample2'))
|
|
||||||
this.afterSamplingFunc($r('app.media.jpgSample2'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async afterSamplingFunc(imgs: Resource) {
|
|
||||||
let img: Uint8Array = await getContext(this).resourceManager.getMediaContent(imgs);
|
|
||||||
let imageSource: image.ImageSource = image.createImageSource(img.buffer.slice(0));
|
|
||||||
let fileTypeUtil = new FileTypeUtil();
|
|
||||||
let typeValue = fileTypeUtil.getFileType(img.buffer.slice(0));
|
|
||||||
let decodingOptions: image.DecodingOptions = {
|
|
||||||
editable: true,
|
|
||||||
desiredPixelFormat: 3,
|
|
||||||
}
|
|
||||||
let imageInfo = await imageSource.getImageInfo()
|
|
||||||
let reqSize =
|
|
||||||
new Downsampler().calculateScaling(typeValue, imageInfo.size.width, imageInfo.size.height, 300,
|
|
||||||
300, this.imageKnifeOption.downsampleOf)
|
|
||||||
decodingOptions = {
|
|
||||||
editable: true,
|
|
||||||
desiredSize: {
|
|
||||||
width: reqSize.targetWidth,
|
|
||||||
height: reqSize.targetHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 创建pixelMap
|
|
||||||
imageSource.createPixelMap(decodingOptions).then((pixelMap: image.PixelMap) => {
|
|
||||||
this.afterSampling = pixelMap.getPixelBytesNumber()
|
|
||||||
}).catch((err: BusinessError) => {
|
|
||||||
console.error("Failed to create PixelMap")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async originalPixMap(imgs: Resource,) {
|
|
||||||
let img: Uint8Array = await getContext(this).resourceManager.getMediaContent(imgs);
|
|
||||||
let imageSource: image.ImageSource = image.createImageSource(img.buffer.slice(0));
|
|
||||||
let decodingOptions: image.DecodingOptions = {
|
|
||||||
editable: true,
|
|
||||||
desiredPixelFormat: 3,
|
|
||||||
}
|
|
||||||
// 创建pixelMap
|
|
||||||
imageSource.createPixelMap(decodingOptions).then((pixelMap: image.PixelMap) => {
|
|
||||||
this.beforeSampling = pixelMap.getPixelBytesNumber()
|
|
||||||
}).catch((err: BusinessError) => {
|
|
||||||
console.error("Failed to create PixelMap")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
Scroll() {
|
|
||||||
Column() {
|
|
||||||
ForEach(this.SamplingList, (item: SamplingType, index) => {
|
|
||||||
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
|
|
||||||
Radio({ value: item.value + 'radio', group: 'radioGroup' })
|
|
||||||
.height(50)
|
|
||||||
.width(50)
|
|
||||||
.checked(this.checked)
|
|
||||||
.onClick(() => {
|
|
||||||
this.updateImageKnifeOption(item.value)
|
|
||||||
})
|
|
||||||
Text("降采样规格:" + item.value).fontSize(20)
|
|
||||||
}
|
|
||||||
}, (item: SamplingType) => JSON.stringify(item))
|
|
||||||
Column() {
|
|
||||||
Text(`未降采样大小:${this.beforeSampling}`).fontSize(20)
|
|
||||||
Text(`降采样后大小:${this.afterSampling}`).fontSize(20)
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageKnifeComponent({
|
|
||||||
imageKnifeOption: this.imageKnifeOption
|
|
||||||
})
|
|
||||||
.height(300)
|
|
||||||
.width(300)
|
|
||||||
.borderWidth(1)
|
|
||||||
.borderColor(Color.Pink)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.height('100%')
|
|
||||||
.width('100%')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SamplingType {
|
|
||||||
key: number
|
|
||||||
value: string
|
|
||||||
|
|
||||||
constructor(key: number, value: string) {
|
|
||||||
this.key = key
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -47,11 +47,6 @@ struct Index {
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("降采样").margin({top:10}).onClick(() => {
|
|
||||||
router.push({
|
|
||||||
uri: 'pages/DownSamplePage',
|
|
||||||
});
|
|
||||||
})
|
|
||||||
Button("单个图片使用").margin({top:10}).onClick(()=>{
|
Button("单个图片使用").margin({top:10}).onClick(()=>{
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/SingleImage',
|
uri: 'pages/SingleImage',
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 340 KiB |
Binary file not shown.
Before Width: | Height: | Size: 474 KiB |
Binary file not shown.
Before Width: | Height: | Size: 395 KiB |
|
@ -23,7 +23,6 @@
|
||||||
"pages/ImageAnimatorPage",
|
"pages/ImageAnimatorPage",
|
||||||
"pages/TestSetCustomImagePage",
|
"pages/TestSetCustomImagePage",
|
||||||
"pages/TestErrorHolderPage",
|
"pages/TestErrorHolderPage",
|
||||||
"pages/TestTaskResourcePage",
|
"pages/TestTaskResourcePage"
|
||||||
"pages/DownSamplePage"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -18,7 +18,6 @@ import ImageKnifeOptionTest from './ImageKnifeOption.test';
|
||||||
import MemoryLruCacheTest from './MemoryLruCache.test';
|
import MemoryLruCacheTest from './MemoryLruCache.test';
|
||||||
import ImageKnifeTest from './ImageKnife.test';
|
import ImageKnifeTest from './ImageKnife.test';
|
||||||
import Transform from './transform.test';
|
import Transform from './transform.test';
|
||||||
import SamplingTest from './SamplingTest.test';
|
|
||||||
|
|
||||||
export default function testsuite() {
|
export default function testsuite() {
|
||||||
MemoryLruCacheTest();
|
MemoryLruCacheTest();
|
||||||
|
@ -27,5 +26,4 @@ export default function testsuite() {
|
||||||
ImageKnifeOptionTest();
|
ImageKnifeOptionTest();
|
||||||
ImageKnifeTest();
|
ImageKnifeTest();
|
||||||
Transform();
|
Transform();
|
||||||
SamplingTest()
|
|
||||||
}
|
}
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
|
|
||||||
import { image } from '@kit.ImageKit'
|
|
||||||
import { BusinessError } from '@kit.BasicServicesKit'
|
|
||||||
import { calculateScaleType, Downsampler } from '@ohos/imageknife/src/main/ets/downsampling/Downsampler'
|
|
||||||
import { DownsampleStrategy } from '@ohos/imageknife'
|
|
||||||
|
|
||||||
export default function SamplingTest() {
|
|
||||||
describe('SamplingTest', () => {
|
|
||||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
|
||||||
beforeAll(() => {
|
|
||||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
|
||||||
// This API supports only one parameter: preset action function.
|
|
||||||
})
|
|
||||||
beforeEach(() => {
|
|
||||||
// Presets an action, which is performed before each unit test case starts.
|
|
||||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
|
||||||
// This API supports only one parameter: preset action function.
|
|
||||||
})
|
|
||||||
afterEach(() => {
|
|
||||||
// Presets a clear action, which is performed after each unit test case ends.
|
|
||||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
|
||||||
// This API supports only one parameter: clear action function.
|
|
||||||
})
|
|
||||||
afterAll(() => {
|
|
||||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
|
||||||
// This API supports only one parameter: clear action function.
|
|
||||||
})
|
|
||||||
it('NONE', 0, () => {
|
|
||||||
let reqSize: calculateScaleType =
|
|
||||||
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
|
|
||||||
200, DownsampleStrategy.NONE, false)
|
|
||||||
let req = (reqSize.targetWidth == 1024 && reqSize.targetHeight == 1024)
|
|
||||||
expect(req).assertEqual(true);
|
|
||||||
})
|
|
||||||
it('AT_MOST', 1, () => {
|
|
||||||
let reqSize: calculateScaleType =
|
|
||||||
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
|
|
||||||
200, DownsampleStrategy.AT_MOST, false)
|
|
||||||
let req = (reqSize.targetWidth < 1024 && reqSize.targetHeight < 1024)
|
|
||||||
expect(req).assertEqual(true);
|
|
||||||
})
|
|
||||||
it('FIT_CENTER', 2, () => {
|
|
||||||
let reqSize: calculateScaleType =
|
|
||||||
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
|
|
||||||
200, DownsampleStrategy.FIT_CENTER, false)
|
|
||||||
let req = (reqSize.targetWidth < 1024 && reqSize.targetHeight < 1024)
|
|
||||||
expect(req).assertEqual(true);
|
|
||||||
})
|
|
||||||
it('CENTER_INSIDE', 3, () => {
|
|
||||||
let reqSize: calculateScaleType =
|
|
||||||
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
|
|
||||||
200, DownsampleStrategy.CENTER_INSIDE, false)
|
|
||||||
let req = (reqSize.targetWidth < 1024 && reqSize.targetHeight < 1024)
|
|
||||||
expect(req).assertEqual(true);
|
|
||||||
})
|
|
||||||
it('CENTER_OUTSIDE', 4, () => {
|
|
||||||
let reqSize: calculateScaleType =
|
|
||||||
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
|
|
||||||
200, DownsampleStrategy.CENTER_OUTSIDE, false)
|
|
||||||
let req = (reqSize.targetWidth < 1024 && reqSize.targetHeight < 1024)
|
|
||||||
expect(req).assertEqual(true);
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -66,6 +66,4 @@ export { CropTransformation } from './src/main/ets/transform/CropTransformation'
|
||||||
|
|
||||||
export { MaskTransformation } from './src/main/ets/transform/MaskTransformation'
|
export { MaskTransformation } from './src/main/ets/transform/MaskTransformation'
|
||||||
|
|
||||||
export { SepiaTransformation } from './src/main/ets/transform/SepiaTransformation'
|
export { SepiaTransformation } from './src/main/ets/transform/SepiaTransformation'
|
||||||
|
|
||||||
export { DownsampleStrategy } from './src/main/ets/downsampling/DownsampleStartegy'
|
|
|
@ -40,8 +40,6 @@ import {
|
||||||
} from './model/ImageKnifeData'
|
} from './model/ImageKnifeData'
|
||||||
import { combineArrayBuffers } from './model/utils';
|
import { combineArrayBuffers } from './model/utils';
|
||||||
import { BusinessError } from '@kit.BasicServicesKit';
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
import { Downsampler } from './downsampling/Downsampler';
|
|
||||||
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
|
||||||
|
|
||||||
export class ImageKnifeDispatcher {
|
export class ImageKnifeDispatcher {
|
||||||
// 最大并发
|
// 最大并发
|
||||||
|
@ -191,10 +189,7 @@ export class ImageKnifeDispatcher {
|
||||||
fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(),
|
fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(),
|
||||||
isAnimator:isAnimator,
|
isAnimator:isAnimator,
|
||||||
moduleName: moduleName == "" ? undefined : moduleName,
|
moduleName: moduleName == "" ? undefined : moduleName,
|
||||||
resName: resName == "" ? undefined : resName,
|
resName: resName == "" ? undefined : resName
|
||||||
targetWidth: currentRequest.componentWidth,
|
|
||||||
targetHeight: currentRequest.componentHeight,
|
|
||||||
downsampType: currentRequest.imageKnifeOption.downsampleOf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(request.customGetImage == undefined) {
|
if(request.customGetImage == undefined) {
|
||||||
|
@ -209,7 +204,7 @@ export class ImageKnifeDispatcher {
|
||||||
emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => {
|
emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => {
|
||||||
this.progressCallBack(requestList! , data?.data?.value as number)
|
this.progressCallBack(requestList! , data?.data?.value as number)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start:" + currentRequest.imageKnifeOption.loadSrc)
|
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start:" + currentRequest.imageKnifeOption.loadSrc)
|
||||||
taskpool.execute(task).then((res: Object) => {
|
taskpool.execute(task).then((res: Object) => {
|
||||||
|
@ -345,8 +340,8 @@ export class ImageKnifeDispatcher {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
|
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
|
||||||
// 回调请求成功
|
// 回调请求成功
|
||||||
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed")
|
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -489,7 +484,7 @@ async function requestJob(request: RequestJobRequest, requestList?: List<ImageKn
|
||||||
if (data == 200 || data == 206 || data == 204) {
|
if (data == 200 || data == 206 || data == 204) {
|
||||||
resBuf = combineArrayBuffers(arrayBuffers)
|
resBuf = combineArrayBuffers(arrayBuffers)
|
||||||
} else {
|
} else {
|
||||||
loadError = "HttpDownloadClient has error, http code =" + JSON.stringify(data)
|
loadError = "HttpDownloadClient has error, http code =" + JSON.stringify(data)
|
||||||
}
|
}
|
||||||
}).catch((err: Error) => {
|
}).catch((err: Error) => {
|
||||||
loadError = err.message;
|
loadError = err.message;
|
||||||
|
@ -510,21 +505,21 @@ async function requestJob(request: RequestJobRequest, requestList?: List<ImageKn
|
||||||
loadError = "success get image from filecache for key = " + fileKey;
|
loadError = "success get image from filecache for key = " + fileKey;
|
||||||
}
|
}
|
||||||
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
|
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
|
||||||
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
|
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
|
||||||
await fs.stat(file.fd).then(async (stat) =>{
|
await fs.stat(file.fd).then(async (stat) =>{
|
||||||
let buf = new ArrayBuffer(stat.size);
|
let buf = new ArrayBuffer(stat.size);
|
||||||
await fs.read(file.fd, buf).then((readLen) => {
|
await fs.read(file.fd, buf).then((readLen) => {
|
||||||
resBuf = buf;
|
resBuf = buf;
|
||||||
fs.closeSync(file.fd);
|
fs.close(file.fd);
|
||||||
|
}).catch((err:BusinessError) => {
|
||||||
|
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
|
||||||
|
})
|
||||||
}).catch((err:BusinessError) => {
|
}).catch((err:BusinessError) => {
|
||||||
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
|
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
|
||||||
})
|
})
|
||||||
}).catch((err:BusinessError) => {
|
}).catch((err:BusinessError) => {
|
||||||
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
|
loadError ='LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
|
||||||
})
|
})
|
||||||
}).catch((err:BusinessError) => {
|
|
||||||
loadError ='LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
|
|
||||||
})
|
|
||||||
} else { //从本地文件获取
|
} else { //从本地文件获取
|
||||||
try {
|
try {
|
||||||
let stat = fs.statSync(request.src);
|
let stat = fs.statSync(request.src);
|
||||||
|
@ -656,20 +651,6 @@ async function requestJob(request: RequestJobRequest, requestList?: List<ImageKn
|
||||||
editable: true,
|
editable: true,
|
||||||
desiredSize: defaultSize
|
desiredSize: defaultSize
|
||||||
};
|
};
|
||||||
let imageInfo = await imageSource.getImageInfo()
|
|
||||||
if ((request.downsampType !== DownsampleStrategy.NONE && request.downsampType !== undefined) &&
|
|
||||||
request.requestSource == ImageKnifeRequestSource.SRC) {
|
|
||||||
let reqSize =
|
|
||||||
new Downsampler().calculateScaling(typeValue, imageInfo.size.width, imageInfo.size.height, request.targetWidth,
|
|
||||||
request.targetHeight, request.downsampType)
|
|
||||||
opts = {
|
|
||||||
editable: true,
|
|
||||||
desiredSize: {
|
|
||||||
height: vp2px(reqSize.targetHeight),
|
|
||||||
width: vp2px(reqSize.targetWidth)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await imageSource.createPixelMap(opts)
|
await imageSource.createPixelMap(opts)
|
||||||
.then((pixelmap: PixelMap) => {
|
.then((pixelmap: PixelMap) => {
|
||||||
resPixelmap = pixelmap
|
resPixelmap = pixelmap
|
||||||
|
@ -682,22 +663,6 @@ async function requestJob(request: RequestJobRequest, requestList?: List<ImageKn
|
||||||
type:typeValue
|
type:typeValue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let imageInfo = await imageSource.getImageInfo()
|
|
||||||
if ((request.downsampType !== undefined && request.downsampType !== DownsampleStrategy.NONE) &&
|
|
||||||
request.requestSource == ImageKnifeRequestSource.SRC) {
|
|
||||||
let reqSize =
|
|
||||||
new Downsampler().calculateScaling(typeValue, imageInfo.size.width, imageInfo.size.height, request.targetWidth,
|
|
||||||
request.targetHeight, request.downsampType)
|
|
||||||
|
|
||||||
decodingOptions = {
|
|
||||||
editable: true,
|
|
||||||
desiredSize: {
|
|
||||||
width: reqSize.targetWidth,
|
|
||||||
height: reqSize.targetHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let size = (await imageSource.getImageInfo()).size
|
let size = (await imageSource.getImageInfo()).size
|
||||||
await imageSource.createPixelMap(decodingOptions)
|
await imageSource.createPixelMap(decodingOptions)
|
||||||
.then((pixelmap: PixelMap) => {
|
.then((pixelmap: PixelMap) => {
|
||||||
|
|
|
@ -16,7 +16,6 @@ import taskpool from '@ohos.taskpool';
|
||||||
import common from '@ohos.app.ability.common'
|
import common from '@ohos.app.ability.common'
|
||||||
import { CacheStrategy, ImageKnifeData,EventImage } from './model/ImageKnifeData';
|
import { CacheStrategy, ImageKnifeData,EventImage } from './model/ImageKnifeData';
|
||||||
import { PixelMapTransformation } from './transform/PixelMapTransformation';
|
import { PixelMapTransformation } from './transform/PixelMapTransformation';
|
||||||
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
|
||||||
import { drawing } from '@kit.ArkGraphics2D';
|
import { drawing } from '@kit.ArkGraphics2D';
|
||||||
|
|
||||||
export interface HeaderOptions {
|
export interface HeaderOptions {
|
||||||
|
@ -91,8 +90,6 @@ interface ImageOption {
|
||||||
onLoadListener?: OnLoadCallBack | undefined;
|
onLoadListener?: OnLoadCallBack | undefined;
|
||||||
onComplete?:(event:EventImage | undefined) => void
|
onComplete?:(event:EventImage | undefined) => void
|
||||||
drawingColorFilter?: ColorFilter | drawing.ColorFilter
|
drawingColorFilter?: ColorFilter | drawing.ColorFilter
|
||||||
downsampleOf?: DownsampleStrategy
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ObservedV2
|
@ObservedV2
|
||||||
export class ImageKnifeOption {
|
export class ImageKnifeOption {
|
||||||
|
@ -124,9 +121,6 @@ export class ImageKnifeOption {
|
||||||
onLoadListener?: OnLoadCallBack | undefined;
|
onLoadListener?: OnLoadCallBack | undefined;
|
||||||
onComplete?:(event:EventImage | undefined) => void
|
onComplete?:(event:EventImage | undefined) => void
|
||||||
drawingColorFilter?: ColorFilter | drawing.ColorFilter
|
drawingColorFilter?: ColorFilter | drawing.ColorFilter
|
||||||
// 下采样
|
|
||||||
downsampleOf?: DownsampleStrategy = DownsampleStrategy.NONE
|
|
||||||
|
|
||||||
constructor(option?:ImageOption) {
|
constructor(option?:ImageOption) {
|
||||||
this.loadSrc = option?.loadSrc == undefined ? "" : option?.loadSrc
|
this.loadSrc = option?.loadSrc == undefined ? "" : option?.loadSrc
|
||||||
this.placeholderSrc = option?.placeholderSrc
|
this.placeholderSrc = option?.placeholderSrc
|
||||||
|
@ -147,7 +141,6 @@ export class ImageKnifeOption {
|
||||||
this.onLoadListener = option?.onLoadListener
|
this.onLoadListener = option?.onLoadListener
|
||||||
this.onComplete = option?.onComplete
|
this.onComplete = option?.onComplete
|
||||||
this.drawingColorFilter = option?.drawingColorFilter
|
this.drawingColorFilter = option?.drawingColorFilter
|
||||||
this.downsampleOf = option?.downsampleOf
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
import { ImageKnifeOption } from './ImageKnifeOption';
|
import { ImageKnifeOption } from './ImageKnifeOption';
|
||||||
import common from '@ohos.app.ability.common';
|
import common from '@ohos.app.ability.common';
|
||||||
import { ImageKnifeRequestSource } from './model/ImageKnifeData';
|
import { ImageKnifeRequestSource } from './model/ImageKnifeData';
|
||||||
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
|
||||||
|
|
||||||
export class ImageKnifeRequest {
|
export class ImageKnifeRequest {
|
||||||
requestState: ImageKnifeRequestState = ImageKnifeRequestState.PROGRESS
|
requestState: ImageKnifeRequestState = ImageKnifeRequestState.PROGRESS
|
||||||
|
@ -27,22 +27,18 @@ export class ImageKnifeRequest {
|
||||||
ImageKnifeRequestCallback: ImageKnifeRequestCallback
|
ImageKnifeRequestCallback: ImageKnifeRequestCallback
|
||||||
componentVersion: number = 0
|
componentVersion: number = 0
|
||||||
headers: Map<string,Object> = new Map<string,Object>()
|
headers: Map<string,Object> = new Map<string,Object>()
|
||||||
downsampType?: DownsampleStrategy
|
|
||||||
constructor(option: ImageKnifeOption,
|
constructor(option: ImageKnifeOption,
|
||||||
uIAbilityContext: common.UIAbilityContext,
|
uIAbilityContext: common.UIAbilityContext,
|
||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
version: number,
|
version: number,
|
||||||
ImageKnifeRequestCallback: ImageKnifeRequestCallback,
|
ImageKnifeRequestCallback: ImageKnifeRequestCallback) {
|
||||||
downsampType?: DownsampleStrategy,
|
|
||||||
) {
|
|
||||||
this.imageKnifeOption = option
|
this.imageKnifeOption = option
|
||||||
this.context = uIAbilityContext
|
this.context = uIAbilityContext
|
||||||
this.componentWidth = width
|
this.componentWidth = width
|
||||||
this.componentHeight = height
|
this.componentHeight = height
|
||||||
this.componentVersion = version
|
this.componentVersion = version
|
||||||
this.ImageKnifeRequestCallback = ImageKnifeRequestCallback
|
this.ImageKnifeRequestCallback = ImageKnifeRequestCallback
|
||||||
this.downsampType = downsampType
|
|
||||||
}
|
}
|
||||||
// RequestOption调用header对于的方法
|
// RequestOption调用header对于的方法
|
||||||
addHeader(key: string, value: Object) {
|
addHeader(key: string, value: Object) {
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 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 { DownsampleStrategy } from './DownsampleStartegy';
|
|
||||||
|
|
||||||
import { SampleSizeRounding } from './DownsampleUtils';
|
|
||||||
|
|
||||||
export interface BaseDownsampling {
|
|
||||||
getName(): string
|
|
||||||
|
|
||||||
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number,downsampType?:DownsampleStrategy): number
|
|
||||||
|
|
||||||
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number,
|
|
||||||
requestHeight: number,downsampType?:DownsampleStrategy): SampleSizeRounding
|
|
||||||
}
|
|
|
@ -1,184 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 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 { BaseDownsampling } from './BaseDownsampling';
|
|
||||||
import { highestOneBit, SampleSizeRounding } from './DownsampleUtils';
|
|
||||||
|
|
||||||
export class FitCenter implements BaseDownsampling {
|
|
||||||
getName() {
|
|
||||||
return "FitCenter"
|
|
||||||
}
|
|
||||||
|
|
||||||
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,downsampType:DownsampleStrategy
|
|
||||||
): number {
|
|
||||||
if (downsampType===DownsampleStrategy.FIT_CENTER_QUALITY) {
|
|
||||||
const widthPercentage = requestedWidth / sourceWidth
|
|
||||||
const heightPercentage = requestedHeight / sourceHeight
|
|
||||||
return Math.min(widthPercentage, heightPercentage)
|
|
||||||
} else {
|
|
||||||
const maxIntegerFactor = Math.max(sourceHeight / requestedHeight, sourceWidth / requestedWidth);
|
|
||||||
const a = maxIntegerFactor === 0 ? 1 : 1 / highestOneBit(maxIntegerFactor)
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//实现 getSampleSizeRounding 方法
|
|
||||||
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,downsampType:DownsampleStrategy
|
|
||||||
): number {
|
|
||||||
if (downsampType===DownsampleStrategy.FIT_CENTER_QUALITY) {
|
|
||||||
return SampleSizeRounding.QUALITY;
|
|
||||||
} else {
|
|
||||||
return SampleSizeRounding.MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class None implements BaseDownsampling {
|
|
||||||
getName(): string {
|
|
||||||
return "DownsampleNone"
|
|
||||||
}
|
|
||||||
|
|
||||||
public getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number,
|
|
||||||
requestedHeight: number): number {
|
|
||||||
//不进行任何下采样,缩放因子为 1
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//实现 getSampleSizeRounding 方法
|
|
||||||
public getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number,
|
|
||||||
requestedHeight: number): SampleSizeRounding {
|
|
||||||
return SampleSizeRounding.QUALITY
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*宽高进行等比缩放宽高里面最小的比例先放进去
|
|
||||||
然后再更据原图的缩放比去适配另一边*/
|
|
||||||
|
|
||||||
export class CenterOutside implements BaseDownsampling {
|
|
||||||
getName() {
|
|
||||||
return "CenterOutside"
|
|
||||||
}
|
|
||||||
|
|
||||||
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): number {
|
|
||||||
const widthPercentage = requestedWidth / sourceWidth;
|
|
||||||
const heightPercentage = requestedHeight / sourceHeight;
|
|
||||||
//返回宽度和高度比例中最大的值
|
|
||||||
return Math.max(widthPercentage, heightPercentage);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number,
|
|
||||||
requestedHeight: number): SampleSizeRounding {
|
|
||||||
//根据 CenterOutside 的逻辑,总是返回 QUALITY
|
|
||||||
return SampleSizeRounding.QUALITY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*请求尺寸大于实际尺寸不进行放大,按照原图展示*/
|
|
||||||
|
|
||||||
export class AtMost implements BaseDownsampling {
|
|
||||||
getName() {
|
|
||||||
return "AtMost"
|
|
||||||
}
|
|
||||||
|
|
||||||
//实现 getScaleFactor 方法
|
|
||||||
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): number {
|
|
||||||
const maxIntegerFactor = Math.ceil(Math.max(sourceHeight / requestedHeight, sourceWidth / requestedWidth));
|
|
||||||
let lesserOrEqualSampleSize = Math.max(1, highestOneBit(maxIntegerFactor));
|
|
||||||
let greaterOrEqualSampleSize = lesserOrEqualSampleSize
|
|
||||||
if (lesserOrEqualSampleSize < maxIntegerFactor) {
|
|
||||||
greaterOrEqualSampleSize = lesserOrEqualSampleSize <<= 1;
|
|
||||||
}
|
|
||||||
greaterOrEqualSampleSize = lesserOrEqualSampleSize << (lesserOrEqualSampleSize < maxIntegerFactor ? 1 : 0)
|
|
||||||
//返回缩放因子
|
|
||||||
return 1 / greaterOrEqualSampleSize
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number,
|
|
||||||
requestHeight: number): SampleSizeRounding {
|
|
||||||
//根据 AtMost 的逻辑,总是返回 MEMORY
|
|
||||||
return SampleSizeRounding.MEMORY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*宽高进行等比缩放宽高里面最大的比例先放进去
|
|
||||||
然后再更据原图的缩放比去适配另一边*/
|
|
||||||
export class CenterInside implements BaseDownsampling {
|
|
||||||
getName() {
|
|
||||||
return "CenterInside"
|
|
||||||
}
|
|
||||||
|
|
||||||
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,downsampType:DownsampleStrategy
|
|
||||||
): number {
|
|
||||||
//获取 FIT_CENTER 的缩放因子
|
|
||||||
const fitCenterScaleFactor: ESObject =
|
|
||||||
this.getScale(sourceWidth, sourceHeight, requestedWidth, requestedHeight, downsampType);
|
|
||||||
//返回不超过 1 的缩放因子,即尽量缩小图像以适应目标尺寸,但不会放大
|
|
||||||
return Math.min(1, fitCenterScaleFactor);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
getScale(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,downsampType:DownsampleStrategy
|
|
||||||
): number {
|
|
||||||
if (downsampType===DownsampleStrategy.FIT_CENTER_QUALITY) {
|
|
||||||
const widthPercentage = requestedWidth / sourceWidth
|
|
||||||
const heightPercentage = requestedHeight / sourceHeight
|
|
||||||
return Math.min(widthPercentage, heightPercentage)
|
|
||||||
} else {
|
|
||||||
//类似 AT_LEAST,但只要求一个维度或另一个维度大于等于请求的尺寸
|
|
||||||
const maxIntegerFactor = Math.max(sourceHeight / requestedHeight, sourceWidth / requestedWidth);
|
|
||||||
return maxIntegerFactor === 0 ? 1 : 1 / highestOneBit(maxIntegerFactor);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,downsampType:DownsampleStrategy
|
|
||||||
): SampleSizeRounding {
|
|
||||||
//如果缩放因子为 1,表示没有缩放,优先选择质量
|
|
||||||
if (this.getScaleFactor(sourceWidth, sourceHeight, requestedWidth, requestedHeight, downsampType) === 1) {
|
|
||||||
return SampleSizeRounding.QUALITY
|
|
||||||
}
|
|
||||||
//否则,使用 FIL_CENTER 的 SampleSizeRounding 值
|
|
||||||
return this.getSampleSize(sourceWidth, sourceHeight, requestedWidth, requestedHeight,downsampType);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSampleSize(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,downsampType:DownsampleStrategy
|
|
||||||
): SampleSizeRounding {
|
|
||||||
if (downsampType===DownsampleStrategy.CENTER_INSIDE_QUALITY) {
|
|
||||||
return SampleSizeRounding.QUALITY;
|
|
||||||
} else {
|
|
||||||
return SampleSizeRounding.MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum DownsampleStrategy {
|
|
||||||
//请求尺寸大于实际尺寸不进行放大
|
|
||||||
AT_MOST,
|
|
||||||
//两边自适应内存优先
|
|
||||||
FIT_CENTER_MEMORY ,
|
|
||||||
//两边自适应质量优先
|
|
||||||
FIT_CENTER_QUALITY,
|
|
||||||
//按照宽高比的最大比进行适配内存优先
|
|
||||||
CENTER_INSIDE_MEMORY ,
|
|
||||||
//按照宽高比的最大比进行适配质量优先
|
|
||||||
CENTER_INSIDE_QUALITY,
|
|
||||||
//宽高进行等比缩放宽高里面最小的比例先放进去,然后再根据原图的缩放比去适配
|
|
||||||
CENTER_OUTSIDE,
|
|
||||||
//不进行降采样
|
|
||||||
NONE,
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 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.
|
|
||||||
*/
|
|
||||||
export enum SampleSizeRounding {
|
|
||||||
/**
|
|
||||||
* Prefer to round the sample size up so that the image is downsampled to smaller than the
|
|
||||||
* requested size to use less memory.
|
|
||||||
*/
|
|
||||||
//(内存优先)
|
|
||||||
MEMORY,
|
|
||||||
/**
|
|
||||||
* Prefer to round the sample size down so that the image is downsampled to larger than the
|
|
||||||
* requested size to maintain quality at the expense of extra memory usage.
|
|
||||||
*/
|
|
||||||
//(质量优先)
|
|
||||||
QUALITY
|
|
||||||
}
|
|
||||||
export function highestOneBit(i: number): number {
|
|
||||||
i |= (i >> 1);
|
|
||||||
i |= (i >> 2);
|
|
||||||
i |= (i >> 4);
|
|
||||||
i |= (i >> 8);
|
|
||||||
i |= (i >> 16);
|
|
||||||
return i - (i >>> 1);
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 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 {
|
|
||||||
AtMost,
|
|
||||||
CenterInside,
|
|
||||||
CenterOutside,
|
|
||||||
DownsampleStrategy,
|
|
||||||
FitCenter,
|
|
||||||
None,
|
|
||||||
} from './DownsampleStartegy';
|
|
||||||
import { highestOneBit, SampleSizeRounding } from './DownsampleUtils';
|
|
||||||
|
|
||||||
export interface calculateScaleType {
|
|
||||||
targetWidth: number,
|
|
||||||
targetHeight: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Downsampler {
|
|
||||||
calculateScaling(
|
|
||||||
typeValue: string | null,
|
|
||||||
sourceHeight: number, //原始宽高
|
|
||||||
sourceWidth: number | undefined, //原始宽高
|
|
||||||
requestHeight: number, //请求宽高
|
|
||||||
requestWidth: number, //请求宽高
|
|
||||||
downsampType: DownsampleStrategy | undefined,
|
|
||||||
|
|
||||||
): calculateScaleType {
|
|
||||||
let degreesToRotate: ESObject = 90;
|
|
||||||
const fileType = typeValue //获取图片类型
|
|
||||||
let powerOfTwoWidth: number | null = null;
|
|
||||||
let powerOfTwoHeight: number | null = null;
|
|
||||||
let targetWidth: number = 0
|
|
||||||
let targetHeight: number = 0
|
|
||||||
|
|
||||||
if (sourceHeight <= 0 || sourceWidth == undefined || sourceWidth == null || sourceWidth <= 0) {
|
|
||||||
throw new Error("Cannot found width or height");
|
|
||||||
}
|
|
||||||
let orientedSourceWidth = sourceWidth;
|
|
||||||
let orientedSourceHeight = sourceHeight;
|
|
||||||
if (this.isRotationRequired(degreesToRotate)) {
|
|
||||||
orientedSourceWidth = sourceHeight;
|
|
||||||
orientedSourceHeight = sourceWidth;
|
|
||||||
}
|
|
||||||
if (requestWidth && !requestHeight) {
|
|
||||||
targetWidth = this.round((requestHeight) * orientedSourceWidth / orientedSourceHeight)
|
|
||||||
} else if (requestHeight && !requestWidth) {
|
|
||||||
targetHeight = this.round((requestWidth) * orientedSourceHeight / orientedSourceWidth)
|
|
||||||
} else if (requestHeight && requestWidth) {
|
|
||||||
targetWidth =
|
|
||||||
requestHeight == sourceWidth ? (this.isRotationRequired(degreesToRotate) ? sourceHeight : sourceWidth) :
|
|
||||||
requestWidth;
|
|
||||||
targetHeight =
|
|
||||||
requestHeight == sourceHeight ? (this.isRotationRequired(degreesToRotate) ? sourceWidth : sourceHeight) :
|
|
||||||
requestWidth;
|
|
||||||
} else {
|
|
||||||
throw new Error("Cannot found width or height");
|
|
||||||
}
|
|
||||||
let exactScaleFactor: number | undefined
|
|
||||||
let rounding: SampleSizeRounding | undefined
|
|
||||||
switch (downsampType) {
|
|
||||||
case DownsampleStrategy.FIT_CENTER_MEMORY || DownsampleStrategy.FIT_CENTER_QUALITY:
|
|
||||||
exactScaleFactor = new FitCenter()
|
|
||||||
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,downsampType)
|
|
||||||
rounding = new FitCenter()
|
|
||||||
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,downsampType)
|
|
||||||
break;
|
|
||||||
case DownsampleStrategy.NONE:
|
|
||||||
exactScaleFactor = new None()
|
|
||||||
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
|
||||||
rounding = new None()
|
|
||||||
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
|
||||||
break
|
|
||||||
case DownsampleStrategy.AT_MOST:
|
|
||||||
exactScaleFactor = new AtMost()
|
|
||||||
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
|
||||||
rounding = new AtMost()
|
|
||||||
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
|
||||||
break
|
|
||||||
case DownsampleStrategy.CENTER_INSIDE_MEMORY || DownsampleStrategy.CENTER_INSIDE_QUALITY:
|
|
||||||
exactScaleFactor = new CenterInside()
|
|
||||||
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,downsampType)
|
|
||||||
rounding = new CenterInside()
|
|
||||||
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,downsampType)
|
|
||||||
break
|
|
||||||
|
|
||||||
case DownsampleStrategy.CENTER_OUTSIDE:
|
|
||||||
exactScaleFactor = new CenterOutside()
|
|
||||||
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
|
||||||
rounding = new CenterOutside()
|
|
||||||
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if (exactScaleFactor==undefined|| exactScaleFactor <= 0 ) {
|
|
||||||
throw new Error("Cannot round with exactScaleFactor");
|
|
||||||
}
|
|
||||||
if (rounding == undefined) {
|
|
||||||
throw new Error("Cannot round with null rounding");
|
|
||||||
}
|
|
||||||
let outWidth: number = this.round(exactScaleFactor * orientedSourceWidth);
|
|
||||||
let outHeight: number = this.round(exactScaleFactor * orientedSourceHeight);
|
|
||||||
let widthScaleFactor = orientedSourceWidth / outWidth;
|
|
||||||
let heightScaleFactor = orientedSourceHeight / outHeight;
|
|
||||||
let scaleFactor = rounding ==SampleSizeRounding.QUALITY ? Math.max(widthScaleFactor, heightScaleFactor) :
|
|
||||||
Math.min(widthScaleFactor, heightScaleFactor) //将整型的缩放因子转换为2的次幂采样大小
|
|
||||||
let powerOfTwoSampleSize: number = scaleFactor;
|
|
||||||
powerOfTwoSampleSize = Math.max(1, highestOneBit(scaleFactor))
|
|
||||||
if (rounding == 1 && (powerOfTwoSampleSize < (1 / exactScaleFactor))) {
|
|
||||||
powerOfTwoSampleSize = powerOfTwoSampleSize << 1;
|
|
||||||
}
|
|
||||||
//基于上一步得出的采样大小,根据不同的图片类型,计算采样后的图片尺寸
|
|
||||||
if (fileType === "png") {
|
|
||||||
powerOfTwoWidth = Math.floor(orientedSourceWidth / powerOfTwoSampleSize);
|
|
||||||
powerOfTwoHeight = Math.floor(orientedSourceHeight / powerOfTwoSampleSize);
|
|
||||||
} else if (fileType === "webp") {
|
|
||||||
powerOfTwoWidth = Math.round(orientedSourceWidth / powerOfTwoSampleSize);
|
|
||||||
powerOfTwoHeight = Math.round(orientedSourceHeight / powerOfTwoSampleSize);
|
|
||||||
} else {
|
|
||||||
powerOfTwoWidth = orientedSourceWidth / powerOfTwoSampleSize;
|
|
||||||
powerOfTwoHeight = orientedSourceHeight / powerOfTwoSampleSize;
|
|
||||||
}
|
|
||||||
let a: calculateScaleType = {
|
|
||||||
"targetWidth": powerOfTwoWidth,
|
|
||||||
"targetHeight": powerOfTwoHeight
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
round(value: number): number {
|
|
||||||
return Math.floor(value + 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
isRotationRequired(degreesToRotate: number): boolean {
|
|
||||||
return degreesToRotate == 90 || degreesToRotate == 270;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,7 +17,6 @@ import { ImageKnifeOption } from '../ImageKnifeOption';
|
||||||
import { IEngineKey } from './IEngineKey';
|
import { IEngineKey } from './IEngineKey';
|
||||||
import { PixelMapTransformation } from '../transform/PixelMapTransformation';
|
import { PixelMapTransformation } from '../transform/PixelMapTransformation';
|
||||||
import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
||||||
import { DownsampleStrategy } from '../downsampling/DownsampleStartegy';
|
|
||||||
|
|
||||||
@Sendable
|
@Sendable
|
||||||
export class DefaultEngineKey implements IEngineKey {
|
export class DefaultEngineKey implements IEngineKey {
|
||||||
|
@ -32,9 +31,6 @@ export class DefaultEngineKey implements IEngineKey {
|
||||||
if (imageKnifeOption.transformation) {
|
if (imageKnifeOption.transformation) {
|
||||||
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
|
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
|
||||||
}
|
}
|
||||||
if ((imageKnifeOption.downsampleOf !== DownsampleStrategy.NONE && imageKnifeOption.downsampleOf !== undefined)) {
|
|
||||||
key += "downsampleOf" + imageKnifeOption.downsampleOf +"width="+width+"height="+ height
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { IEngineKey } from '../key/IEngineKey'
|
||||||
import { PixelMapTransformation } from '../transform/PixelMapTransformation'
|
import { PixelMapTransformation } from '../transform/PixelMapTransformation'
|
||||||
import common from '@ohos.app.ability.common';
|
import common from '@ohos.app.ability.common';
|
||||||
import { Size } from '@kit.ArkUI'
|
import { Size } from '@kit.ArkUI'
|
||||||
import { DownsampleStrategy } from '../downsampling/DownsampleStartegy'
|
|
||||||
export interface ImageKnifeData {
|
export interface ImageKnifeData {
|
||||||
source: PixelMap | string,
|
source: PixelMap | string,
|
||||||
imageWidth: number,
|
imageWidth: number,
|
||||||
|
@ -103,9 +103,6 @@ export interface RequestJobRequest {
|
||||||
fileCacheFolder: string,
|
fileCacheFolder: string,
|
||||||
isAnimator?: boolean,
|
isAnimator?: boolean,
|
||||||
moduleName?:string,
|
moduleName?:string,
|
||||||
resName?: string,
|
resName?: string
|
||||||
targetWidth: number
|
|
||||||
targetHeight: number
|
|
||||||
downsampType?: DownsampleStrategy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue