Pre Merge pull request !273 from 田双明/3.x
This commit is contained in:
commit
6d85eab2bf
|
@ -171,7 +171,7 @@ ImageKnifeComponent({ ImageKnifeOption:
|
||||||
| headerOption | Array<HeaderOptions> | 设置请求头(可选) |
|
| headerOption | Array<HeaderOptions> | 设置请求头(可选) |
|
||||||
| transformation | PixelMapTransformation | 图片变换(可选) |
|
| transformation | PixelMapTransformation | 图片变换(可选) |
|
||||||
| 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 | 降采样(可选) |
|
||||||
### ImageKnife接口
|
### ImageKnife接口
|
||||||
|
|
||||||
| 参数名称 | 入参内容 | 功能简介 |
|
| 参数名称 | 入参内容 | 功能简介 |
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* 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, ImageKnifeComponent } from '@ohos/imageknife';
|
||||||
|
@Entry
|
||||||
|
@Component
|
||||||
|
struct DownSamplePage {
|
||||||
|
@State message: string = 'Hello World';
|
||||||
|
build() {
|
||||||
|
Scroll() {
|
||||||
|
Column(){
|
||||||
|
Text('jpg')
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.jpgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampleOf: DownsampleStrategy.FIT_CENTER,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
Text('png')
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.pngSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampleOf: DownsampleStrategy.AT_MOST,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
Text('svg')
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.svgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampleOf: DownsampleStrategy.AT_LEAST,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
Text('svg网络图片')
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc:"https://gitee.com/tianshuangming/ImageKnife/raw/master/entry/src/main/resources/base/media/svgSample.svg",
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampleOf: DownsampleStrategy.CENTER_INSIDE,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
Text('jpg网络图片')
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampleOf: DownsampleStrategy.CENTER_OUTSIDE,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
Text('png网络图片')
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png",
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampleOf: DownsampleStrategy.NONE,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.height('100%')
|
||||||
|
.width('100%')
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,6 @@ import router from '@system.router';
|
||||||
@Entry
|
@Entry
|
||||||
@Component
|
@Component
|
||||||
struct Index {
|
struct Index {
|
||||||
|
|
||||||
|
|
||||||
aboutToAppear(): void {
|
aboutToAppear(): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,73 +24,78 @@ struct Index {
|
||||||
build() {
|
build() {
|
||||||
|
|
||||||
Column() {
|
Column() {
|
||||||
Button("单个图片使用").onClick(()=>{
|
Button("单个图片使用").onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/SingleImage',
|
uri: 'pages/SingleImage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("多图 + LazyForEach").margin({top:10}).onClick(()=>{
|
Button("下采样").margin({ top: 10 }).onClick(() => {
|
||||||
|
router.push({
|
||||||
|
uri: "pages/DownSamplePage",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
Button("多图 + LazyForEach").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/ManyPhotoShowPage',
|
uri: 'pages/ManyPhotoShowPage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("多图 + reuse + LazyForeach").margin({top:10}).onClick(()=>{
|
Button("多图 + reuse + LazyForeach").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/UserPage',
|
uri: 'pages/UserPage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("长图显示").margin({top:10}).onClick(()=>{
|
Button("长图显示").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/LongImagePage',
|
uri: 'pages/LongImagePage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("缩放图片").margin({top:10}).onClick(()=>{
|
Button("缩放图片").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/TransformPage',
|
uri: 'pages/TransformPage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("消息+List").margin({top:10}).onClick(()=>{
|
Button("消息+List").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/TestImageFlash',
|
uri: 'pages/TestImageFlash',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("自定义缓存key").margin({top:10}).onClick(()=>{
|
Button("自定义缓存key").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/SignatureTestPage',
|
uri: 'pages/SignatureTestPage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("预加载图片到文件缓存").margin({top:10}).onClick(()=>{
|
Button("预加载图片到文件缓存").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/TestPrefetchToFileCache',
|
uri: 'pages/TestPrefetchToFileCache',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("从缓存获取图片显示").margin({top:10}).onClick(()=>{
|
Button("从缓存获取图片显示").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/TestIsUrlExist',
|
uri: 'pages/TestIsUrlExist',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("测试单个请求头").margin({top:10}).onClick(()=>{
|
Button("测试单个请求头").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/TestHeader',
|
uri: 'pages/TestHeader',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("测试写入缓存策略").margin({top:10}).onClick(()=>{
|
Button("测试写入缓存策略").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/TestWriteCacheStage',
|
uri: 'pages/TestWriteCacheStage',
|
||||||
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
Button("图片变换").margin({top:10}).onClick(()=>{
|
Button("图片变换").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/ImageTransformation',
|
uri: 'pages/ImageTransformation',
|
||||||
|
|
||||||
|
@ -100,7 +103,7 @@ struct Index {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Button("不同的ObjectFit").margin({top:10}).onClick(()=>{
|
Button("不同的ObjectFit").margin({ top: 10 }).onClick(() => {
|
||||||
router.push({
|
router.push({
|
||||||
uri: 'pages/ObjectFitPage',
|
uri: 'pages/ObjectFitPage',
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 678 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<?xml-stylesheet type="text/css" href="ic_launcher_round.css" ?>
|
||||||
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 800 800" xml:space="preserve" width="200" height="200">
|
||||||
|
<rect class="brick4" width="800" height="800.5" fill="#6A6ACC"/>
|
||||||
|
<g fill="#55346A">
|
||||||
|
<path d="M242.4,800.6c-0.2-0.9-0.3-1.9-0.5-2.8c-0.2-0.8-0.3-1.7-0.5-2.5c-0.5-2.5-1.1-5-1.7-7.5l0,0
|
||||||
|
c-0.5-1.6-0.8-3.3-1.2-4.8l0,0c-8.1-29.2-22.3-54.7-40.6-73.9c-1.1-1.1-2-2.2-3.1-3.1c-2-2-4.2-4.1-6.4-5.9
|
||||||
|
c50.1-46.1,129.1-75.7,218.2-75.7c88.1,0,166.3,29,216.4,74.2c-27.6,23.1-48.1,59.5-55.9,102.1"/>
|
||||||
|
<path d="M242.7,802.8"/>
|
||||||
|
<path d="M679.6,800.6c-4.4-38.3-24.8-73.4-56.7-102.1c-27.6,23.1-48.1,59.5-55.9,102.1"/>
|
||||||
|
<path d="M242.7,802.8"/>
|
||||||
|
<path d="M133,800.6h109.2"/>
|
||||||
|
<path d="M242.7,802.8c-0.2-0.8-0.3-1.4-0.5-2.2H133c4.4-37.6,24.2-72.3,55.1-100.7c2.2,1.9,4.4,3.9,6.4,5.9
|
||||||
|
c1.1,1.1,2,2,3.1,3.1c18.3,19.2,32.5,44.7,40.6,73.9l0,0c0.5,1.6,0.9,3.3,1.2,4.8l0,0c0.6,2.5,1.2,5,1.7,7.5
|
||||||
|
c0.2,0.8,0.3,1.7,0.5,2.5c0.2,0.9,0.3,1.9,0.6,2.8C242.5,801.4,242.7,802,242.7,802.8z"/>
|
||||||
|
</g>
|
||||||
|
<path id="hjk" fill="#F0E9ED" d="M398.2,588.6h19.7c17.8,0,32.3,14.4,32.3,32.3l0,0V704c0,23.3-18.9,42.2-42.2,42.2l0,0
|
||||||
|
c-23.3,0-42.2-18.9-42.2-42.2v-83.1C365.9,603.1,380.2,588.6,398.2,588.6L398.2,588.6z"/>
|
||||||
|
<path fill="#F3BEBB" d="M398.2,555.5h19.7c17.8,0,32.3,14.4,32.3,32.3l0,0v83.1c0,23.3-18.9,42.2-42.2,42.2l0,0
|
||||||
|
c-23.3,0-42.2-18.9-42.2-42.2v-83.1C365.9,570,380.2,555.5,398.2,555.5L398.2,555.5z"/>
|
||||||
|
<path fill="#D9A7A6" d="M381.7,477.2h52.9c8.6,0,15.6,7,15.6,15.6v118.7c0,12.8-10.3,23.1-23.1,23.1l0,0h-37.9
|
||||||
|
c-12.8,0-23.1-10.3-23.1-23.1l0,0V492.8C366,484.2,373.1,477.2,381.7,477.2L381.7,477.2z"/>
|
||||||
|
<path class="st6" d="M232.8,318.1h344.6l0,0v121.8c0,95.1-77.1,172.2-172.2,172.4l0,0l0,0c-95.1,0-172.2-77.1-172.4-172.2l0,0V318.1
|
||||||
|
L232.8,318.1z"/>
|
||||||
|
<path fill="#F3BEBB" d="M567.9,378.3h46.4c12.5,0,22.6,10.2,22.6,22.6l0,0v14.5c0,32.5-26.4,58.9-58.9,58.9l0,0h-10.3
|
||||||
|
c-1.9,0-3.3-1.4-3.3-3.3v-89.5C564.7,379.7,566.2,378.3,567.9,378.3L567.9,378.3z"/>
|
||||||
|
<path fill="#F3BEBB" d="M238.8,474.3h-10.3c-32.5,0-58.9-26.4-58.9-58.9l0,0v-14.5c0-12.5,10.2-22.6,22.6-22.6l0,0h46.4
|
||||||
|
c1.9,0,3.3,1.4,3.3,3.3V471C242.2,472.9,240.6,474.3,238.8,474.3L238.8,474.3z"/>
|
||||||
|
<path fill="#F8D7D7" d="M232.8,282.6h344.6l0,0v162.6c0,72.6-58.9,131.5-131.5,131.5l0,0h-81.5c-72.6,0-131.5-58.9-131.5-131.5l0,0
|
||||||
|
V282.6H232.8z"/>
|
||||||
|
<path fill="#F3BEBB" d="M411.3,578.3h-12c-91.8,0-166.3-74.5-166.3-166.3v35.4c0,91.8,74.5,166.3,166.3,166.3h12
|
||||||
|
c91.8,0,166.3-74.5,166.3-166.3v-35.4C577.5,503.8,503.1,578.3,411.3,578.3z"/>
|
||||||
|
<path class="brick2" fill="#2B0E27" d="M666.3,190c-1.6-42.2-37-75.3-79.3-73.7c-27.3,0.9-52,16.6-64.8,40.8c-5.2,10-17.3,13.9-27.3,8.9
|
||||||
|
c-25-12.6-52.6-19.4-80.6-19.2h-20.8c-27.2,0-54,6.2-78.4,18.3c-9.8,4.8-21.7,0.9-26.9-8.7c-20.5-37-67-50.6-104-30.3
|
||||||
|
s-50.6,66.8-30.3,103.8c13.4,24.5,39.2,39.8,67.1,39.8l0,0c1.4,0,2.3,1.1,2.5,2.3c0,0.3,0,0.5-0.2,0.8c-5.2,16.9-7.8,34.4-7.8,52
|
||||||
|
v46.8c0,22.2,18.1,40.3,40.3,40.3l0,0h57.9c10.8,0,19.4-8.7,19.4-19.4l0,0V342c-0.2-7.5,5.6-13.9,13.1-14.5c7.8-0.6,14.5,5.3,15,13
|
||||||
|
c0,0.3,0,0.6,0,1.1v51.1c0,10.8,8.7,19.4,19.4,19.4l0,0h171c22.2,0,40.3-18.1,40.3-40.3v-46.8c0-17.6-2.7-35.3-7.8-52.2
|
||||||
|
c-0.5-1.2,0.3-2.7,1.6-3c0.3-0.2,0.6-0.2,0.8-0.2c0.9,0,2,0,3,0c42.3,0,76.5-34.2,76.5-76.5C666.5,192.1,666.3,191,666.3,190z"/>
|
||||||
|
<path fill="#FFFFFF" d="M367.8,489.1H444c10.3,0,18.7,8.4,18.7,18.7l0,0c0,24.2-19.5,43.7-43.7,43.7h-26.2c-24.2,0-43.7-19.5-43.7-43.7
|
||||||
|
l0,0C349,497.5,357.4,489.1,367.8,489.1L367.8,489.1z"/>
|
||||||
|
<path class="brick3" fill="#222D3C" stroke="#222D3C" stroke-width="14" stroke-linecap="round" stroke-linejoin="round" d="M292.8,456.4c0-12.5,15.1-22.6,34-22.6c18.9,0,34,10.2,34,22.6"/>
|
||||||
|
<path class="brick3" fill="#222D3C" stroke="#222D3C" stroke-width="14" stroke-linecap="round" stroke-linejoin="round" d="M444.9,456.4c0-12.5,15.1-22.6,34-22.6s34,10.2,34,22.6"/>
|
||||||
|
<ellipse rx="22.2" ry="22.2" fill="none" stroke="#FFD56E" stroke-width="8" transform="translate(594.7 492.3)" />
|
||||||
|
<ellipse rx="22.2" ry="22.2" fill="none" stroke="#FFD56E" stroke-width="8" transform="translate(215.2 492.3)" />
|
||||||
|
<path fill="#F3BEBB" d="M395.4,459.9h15.1c4.8,0,8.9,3.9,8.9,8.9l0,0c0,4.8-3.9,8.9-8.9,8.9h-15.1c-4.8,0-8.9-3.9-8.9-8.9l0,0
|
||||||
|
C386.5,463.8,390.4,459.9,395.4,459.9z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.2 KiB |
|
@ -14,8 +14,9 @@
|
||||||
"pages/TestHeader",
|
"pages/TestHeader",
|
||||||
"pages/ImageTransformation",
|
"pages/ImageTransformation",
|
||||||
"pages/ObjectFitPage",
|
"pages/ObjectFitPage",
|
||||||
"pages/TestWriteCacheStage",
|
|
||||||
"pages/LoadStatePage",
|
"pages/LoadStatePage",
|
||||||
"pages/TestRemoveCache"
|
"pages/TestRemoveCache",
|
||||||
|
"pages/TestWriteCacheStage",
|
||||||
|
"pages/DownSamplePage"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -22,4 +22,6 @@ export { BrightnessTransformation } from './src/main/ets/transform/BrightnessTra
|
||||||
|
|
||||||
export { BlurTransformation } from './src/main/ets/transform/BlurTransformation'
|
export { BlurTransformation } from './src/main/ets/transform/BlurTransformation'
|
||||||
|
|
||||||
|
export { DownsampleStrategy } from './src/main/ets/downsampling/DownsampleStartegy'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@ import {
|
||||||
RequestJobRequest
|
RequestJobRequest
|
||||||
} from './model/ImageKnifeData'
|
} from './model/ImageKnifeData'
|
||||||
import { combineArrayBuffers } from './model/utils';
|
import { combineArrayBuffers } from './model/utils';
|
||||||
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
|
import { Downsampler } from './downsampling/Downsampler'
|
||||||
|
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
||||||
|
|
||||||
export class ImageKnifeDispatcher {
|
export class ImageKnifeDispatcher {
|
||||||
// 最大并发
|
// 最大并发
|
||||||
|
@ -144,7 +147,12 @@ export class ImageKnifeDispatcher {
|
||||||
.isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存
|
.isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存
|
||||||
engineKey: this.engineKey,
|
engineKey: this.engineKey,
|
||||||
signature: currentRequest.imageKnifeOption.signature,
|
signature: currentRequest.imageKnifeOption.signature,
|
||||||
requestSource
|
requestSource,
|
||||||
|
targetWidth: currentRequest.componentWidth,
|
||||||
|
targetHeight: currentRequest.componentHeight,
|
||||||
|
downsampType: currentRequest.imageKnifeOption.downsampleOf,
|
||||||
|
autoResize:currentRequest.imageKnifeOption.autoResize
|
||||||
|
|
||||||
}
|
}
|
||||||
// 启动线程下载和解码主图
|
// 启动线程下载和解码主图
|
||||||
let task = new taskpool.Task(requestJob, request)
|
let task = new taskpool.Task(requestJob, request)
|
||||||
|
@ -404,7 +412,6 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (resBuf == undefined) {
|
if (resBuf == undefined) {
|
||||||
return {
|
return {
|
||||||
pixelMap: undefined,
|
pixelMap: undefined,
|
||||||
|
@ -418,7 +425,6 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
||||||
let typeValue = fileTypeUtil.getFileType(resBuf);
|
let typeValue = fileTypeUtil.getFileType(resBuf);
|
||||||
if (typeValue === 'gif' || typeValue === 'webp') {
|
if (typeValue === 'gif' || typeValue === 'webp') {
|
||||||
let base64Help = new util.Base64Helper()
|
let base64Help = new util.Base64Helper()
|
||||||
|
|
||||||
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(resBuf))
|
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(resBuf))
|
||||||
return {
|
return {
|
||||||
pixelMap: base64str,
|
pixelMap: base64str,
|
||||||
|
@ -426,10 +432,19 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
||||||
fileKey: fileKey
|
fileKey: fileKey
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
let autoResizes = request.autoResize
|
||||||
let imageSource: image.ImageSource = image.createImageSource(resBuf);
|
let imageSource: image.ImageSource = image.createImageSource(resBuf);
|
||||||
let decodingOptions: image.DecodingOptions = {
|
let imageInfo = await imageSource.getImageInfo()
|
||||||
|
let a = new Downsampler().calculateScaling(typeValue, imageInfo.size.width, imageInfo.size.height, request.targetWidth,
|
||||||
|
request.targetHeight, request.downsampType,autoResizes)
|
||||||
|
let decodingOptions: image.DecodingOptions = request.downsampType === DownsampleStrategy.NONE ? {
|
||||||
editable: true,
|
editable: true,
|
||||||
|
} : {
|
||||||
|
editable: true,
|
||||||
|
desiredSize: {
|
||||||
|
width: a.targetWidth,
|
||||||
|
height: a.targetHeight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let resPixelmap: PixelMap | undefined = undefined
|
let resPixelmap: PixelMap | undefined = undefined
|
||||||
|
|
|
@ -13,14 +13,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import taskpool from '@ohos.taskpool';
|
import taskpool from '@ohos.taskpool';
|
||||||
import common from '@ohos.app.ability.common'
|
import common from '@ohos.app.ability.common';
|
||||||
import { CacheStrategy } from './model/ImageKnifeData';
|
import { CacheStrategy } from './model/ImageKnifeData';
|
||||||
import { PixelMapTransformation } from './transform/PixelMapTransformation';
|
import { PixelMapTransformation } from './transform/PixelMapTransformation';
|
||||||
|
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
||||||
|
|
||||||
export interface HeaderOptions {
|
export interface HeaderOptions {
|
||||||
key: string;
|
key: string;
|
||||||
value: Object;
|
value: Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Observed
|
@Observed
|
||||||
export class ImageKnifeOption {
|
export class ImageKnifeOption {
|
||||||
// 主图资源
|
// 主图资源
|
||||||
|
@ -29,38 +31,31 @@ export class ImageKnifeOption {
|
||||||
placeholderSrc?: string | PixelMap | Resource;
|
placeholderSrc?: string | PixelMap | Resource;
|
||||||
// 失败占位图
|
// 失败占位图
|
||||||
errorholderSrc?: string | PixelMap | Resource;
|
errorholderSrc?: string | PixelMap | Resource;
|
||||||
|
|
||||||
headerOption?: Array<HeaderOptions>;
|
headerOption?: Array<HeaderOptions>;
|
||||||
|
|
||||||
// 自定义缓存关键字
|
// 自定义缓存关键字
|
||||||
signature?: string;
|
signature?: string;
|
||||||
|
|
||||||
// 主图填充效果
|
// 主图填充效果
|
||||||
objectFit?: ImageFit
|
objectFit?: ImageFit
|
||||||
|
|
||||||
// 占位图填充效果
|
// 占位图填充效果
|
||||||
placeholderObjectFit?: ImageFit
|
placeholderObjectFit?: ImageFit
|
||||||
|
|
||||||
// 错误图填充效果
|
// 错误图填充效果
|
||||||
errorholderObjectFit?: ImageFit
|
errorholderObjectFit?: ImageFit
|
||||||
|
|
||||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>
|
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>
|
||||||
|
|
||||||
border?: BorderOptions
|
border?: BorderOptions
|
||||||
// 缓存策略
|
// 缓存策略
|
||||||
writeCacheStrategy?: CacheStrategy
|
writeCacheStrategy?: CacheStrategy
|
||||||
// 仅使用缓存加载数据
|
// 仅使用缓存加载数据
|
||||||
onlyRetrieveFromCache?: boolean = false;
|
onlyRetrieveFromCache?: boolean = false;
|
||||||
|
priority?: taskpool.Priority = taskpool.Priority.LOW
|
||||||
priority? : taskpool.Priority = taskpool.Priority.LOW
|
|
||||||
|
|
||||||
context?: common.UIAbilityContext;
|
context?: common.UIAbilityContext;
|
||||||
|
|
||||||
progressListener?: (progress: number)=>void;
|
progressListener?: (progress: number)=>void;
|
||||||
|
|
||||||
transformation?: PixelMapTransformation
|
transformation?: PixelMapTransformation
|
||||||
onLoadListener?: OnLoadCallBack | undefined;
|
onLoadListener?: OnLoadCallBack | undefined;
|
||||||
|
// 下采样
|
||||||
|
downsampleOf?: DownsampleStrategy = DownsampleStrategy.NONE
|
||||||
|
autoResize?:boolean
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -25,20 +25,29 @@ export class ImageKnifeRequest {
|
||||||
context: common.UIAbilityContext
|
context: common.UIAbilityContext
|
||||||
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
|
||||||
|
autoResizes?:boolean
|
||||||
|
|
||||||
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,
|
||||||
|
autoResizes?:boolean
|
||||||
|
) {
|
||||||
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
|
||||||
|
this.autoResizes = autoResizes
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestOption调用header对于的方法
|
// RequestOption调用header对于的方法
|
||||||
addHeader(key: string, value: Object) {
|
addHeader(key: string, value: Object) {
|
||||||
this.headers.set(key, value);
|
this.headers.set(key, value);
|
||||||
|
@ -63,5 +72,5 @@ export enum ImageKnifeRequestState {
|
||||||
|
|
||||||
|
|
||||||
export interface ImageKnifeRequestCallback {
|
export interface ImageKnifeRequestCallback {
|
||||||
showPixelMap: (version: number, pixelMap: PixelMap | string , requestSource: ImageKnifeRequestSource) => void;
|
showPixelMap: (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource) => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import common from '@ohos.app.ability.common';
|
||||||
import { ImageKnife } from '../ImageKnife';
|
import { ImageKnife } from '../ImageKnife';
|
||||||
import { LogUtil } from '../utils/LogUtil';
|
import { LogUtil } from '../utils/LogUtil';
|
||||||
import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
|
||||||
|
import { Downsampler } from '../downsampling/Downsampler';
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export struct ImageKnifeComponent {
|
export struct ImageKnifeComponent {
|
||||||
|
@ -33,6 +34,8 @@ export struct ImageKnifeComponent {
|
||||||
private currentHeight: number = 0
|
private currentHeight: number = 0
|
||||||
private componentVersion: number = 0
|
private componentVersion: number = 0
|
||||||
private currentContext: common.UIAbilityContext | undefined = undefined
|
private currentContext: common.UIAbilityContext | undefined = undefined
|
||||||
|
private targetHeight: number =0
|
||||||
|
private targetWidth: number =0
|
||||||
|
|
||||||
aboutToAppear(): void {
|
aboutToAppear(): void {
|
||||||
//闪动问题失效,注释相应代码后续修复
|
//闪动问题失效,注释相应代码后续修复
|
||||||
|
@ -117,8 +120,7 @@ export struct ImageKnifeComponent {
|
||||||
this.pixelMap = pixelMap
|
this.pixelMap = pixelMap
|
||||||
if (typeof this.pixelMap !== 'string') {
|
if (typeof this.pixelMap !== 'string') {
|
||||||
if (this.imageKnifeOption.objectFit === ImageFit.Auto) {
|
if (this.imageKnifeOption.objectFit === ImageFit.Auto) {
|
||||||
let info = await this.pixelMap.getImageInfo()
|
let info =await this.pixelMap.getImageInfo()
|
||||||
|
|
||||||
this.adaptiveWidth = this.currentWidth
|
this.adaptiveWidth = this.currentWidth
|
||||||
this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width
|
this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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 { lang } from '@kit.ArkTS';
|
||||||
|
import { SampleSizeRounding } from './downsampleUtils';
|
||||||
|
type ISendable = lang.ISendable;
|
||||||
|
|
||||||
|
export interface BaseDownsampling extends ISendable {
|
||||||
|
getName(): string
|
||||||
|
|
||||||
|
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number
|
||||||
|
|
||||||
|
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): SampleSizeRounding
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
@Sendable
|
||||||
|
export class FitCenter implements BaseDownsampling {
|
||||||
|
getName() {
|
||||||
|
return "FitCenter"
|
||||||
|
}
|
||||||
|
//实现 getScaleFactor 方法
|
||||||
|
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,autoResize?:boolean): number {
|
||||||
|
const IS_BITMAP_FACTORY_SCALING_SUPPORTED = autoResize; //这里需要根据实际情况设置这个值
|
||||||
|
if (IS_BITMAP_FACTORY_SCALING_SUPPORTED) {
|
||||||
|
const widthPercentage = requestedWidth / sourceWidth
|
||||||
|
const heightPercentage = requestedHeight / sourceHeight
|
||||||
|
return Math.min(widthPercentage, heightPercentage)
|
||||||
|
}else{
|
||||||
|
//类似 AT_LEAST,但只要求一个维度或另一个维度大于等于请求的尺寸
|
||||||
|
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,autoResize?:boolean): number {
|
||||||
|
const IS_BITMAP_FACTORY_SCALING_SUPPORTED = autoResize; //这里需要根据实际情况设置这个值
|
||||||
|
|
||||||
|
if (!IS_BITMAP_FACTORY_SCALING_SUPPORTED) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SampleSizeRounding.MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Sendable
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*宽高进行等比缩放宽高里面最小的比例先放进去
|
||||||
|
然后再更据原图的缩放比去适配另一边*/
|
||||||
|
@Sendable
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*请求尺寸大于实际尺寸不进行放大,按照原图展示*/
|
||||||
|
@Sendable
|
||||||
|
export class Atleast implements BaseDownsampling {
|
||||||
|
getName() {
|
||||||
|
return "AtLeast"
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现 getScaleFactor 方法
|
||||||
|
public getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): SampleSizeRounding {
|
||||||
|
//计算最小整数因子
|
||||||
|
const minIntegerFactor = Math.min(sourceHeight / requestedHeight, sourceWidth / requestedWidth)
|
||||||
|
//根据最小整数因子计算缩放因子
|
||||||
|
return minIntegerFactor === 0 ? 1 : 1 / highestOneBit(minIntegerFactor);
|
||||||
|
}
|
||||||
|
public getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): SampleSizeRounding {
|
||||||
|
//总是返回 QUALITY
|
||||||
|
return SampleSizeRounding.QUALITY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*请求尺寸大于实际尺寸不进行放大,按照原图展示*/
|
||||||
|
@Sendable
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*宽高进行等比缩放宽高里面最大的比例先放进去
|
||||||
|
然后再更据原图的缩放比去适配另一边*/
|
||||||
|
@Sendable
|
||||||
|
export class CenterInside implements BaseDownsampling {
|
||||||
|
getName() {
|
||||||
|
return "CenterInside"
|
||||||
|
}
|
||||||
|
|
||||||
|
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,autoResize?:boolean): number {
|
||||||
|
//获取 FIT_CENTER 的缩放因子
|
||||||
|
const fitCenterScaleFactor : ESObject = this.getScale(sourceWidth,sourceHeight,requestedWidth,requestedHeight,autoResize);
|
||||||
|
//返回不超过 1 的缩放因子,即尽量缩小图像以适应目标尺寸,但不会放大
|
||||||
|
return Math.min(1,fitCenterScaleFactor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getScale(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,autoResize?:boolean): number {
|
||||||
|
const IS_BITMAP_FACTORY_SCALING_SUPPORTED = autoResize;
|
||||||
|
if (IS_BITMAP_FACTORY_SCALING_SUPPORTED) {
|
||||||
|
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,autoResize?:boolean): SampleSizeRounding {
|
||||||
|
//如果缩放因子为 1,表示没有缩放,优先选择质量
|
||||||
|
if (this.getScaleFactor(sourceWidth,sourceHeight,requestedWidth,requestedHeight,autoResize) === 1) {
|
||||||
|
return SampleSizeRounding.QUALITY
|
||||||
|
}
|
||||||
|
//否则,使用 FIL_CENTER 的 SampleSizeRounding 值
|
||||||
|
return this.getSampleSize(sourceWidth,sourceHeight,requestedWidth,requestedHeight);
|
||||||
|
}
|
||||||
|
getSampleSize(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,autoResize?:boolean): SampleSizeRounding {
|
||||||
|
const IS_BITMAP_FACTORY_SCALING_SUPPORTED = autoResize;
|
||||||
|
|
||||||
|
if (IS_BITMAP_FACTORY_SCALING_SUPPORTED) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SampleSizeRounding.MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DownsampleStrategy{
|
||||||
|
AT_LEAST,
|
||||||
|
AT_MOST,
|
||||||
|
FIT_CENTER,
|
||||||
|
CENTER_INSIDE,
|
||||||
|
CENTER_OUTSIDE,
|
||||||
|
NONE,
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
Atleast,
|
||||||
|
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,
|
||||||
|
//原始宽高 7106
|
||||||
|
requestHeight: number, //请求宽高
|
||||||
|
requestWidth: number, //请求宽高
|
||||||
|
downsampType: DownsampleStrategy | undefined,
|
||||||
|
autoResize:boolean |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 = new FitCenter()
|
||||||
|
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,autoResize)
|
||||||
|
/*安卓的模式*/
|
||||||
|
let rounding: SampleSizeRounding = new FitCenter()
|
||||||
|
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,autoResize)
|
||||||
|
switch (downsampType) {
|
||||||
|
case DownsampleStrategy.FIT_CENTER:
|
||||||
|
exactScaleFactor = new FitCenter()
|
||||||
|
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
||||||
|
rounding = new FitCenter()
|
||||||
|
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
||||||
|
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:
|
||||||
|
exactScaleFactor = new CenterInside()
|
||||||
|
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,autoResize)
|
||||||
|
rounding = new CenterInside()
|
||||||
|
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight,autoResize)
|
||||||
|
break
|
||||||
|
case DownsampleStrategy.AT_LEAST:
|
||||||
|
exactScaleFactor = new Atleast()
|
||||||
|
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
||||||
|
rounding = new Atleast()
|
||||||
|
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
||||||
|
break
|
||||||
|
case DownsampleStrategy.CENTER_OUTSIDE:
|
||||||
|
exactScaleFactor = new CenterOutside()
|
||||||
|
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
||||||
|
rounding = new CenterOutside()
|
||||||
|
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (exactScaleFactor <= 0) {
|
||||||
|
throw new Error("Cannot round with exactScaleFactor");
|
||||||
|
}
|
||||||
|
if (rounding == null) {
|
||||||
|
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 == 1 ? 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 === "jpeg") {
|
||||||
|
let nativeScaling = Math.min(powerOfTwoSampleSize, 8);
|
||||||
|
powerOfTwoWidth = Math.ceil(orientedSourceWidth / nativeScaling);
|
||||||
|
powerOfTwoHeight = Math.ceil(orientedSourceHeight / nativeScaling);
|
||||||
|
let secondaryScaling = Math.floor(powerOfTwoSampleSize / 8);
|
||||||
|
if (secondaryScaling > 0) {
|
||||||
|
powerOfTwoWidth = powerOfTwoWidth / secondaryScaling;
|
||||||
|
powerOfTwoHeight = powerOfTwoHeight / secondaryScaling;
|
||||||
|
}
|
||||||
|
} else 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;
|
||||||
|
}
|
||||||
|
console.log(`输出长宽 === 高:${powerOfTwoHeight}宽:${powerOfTwoWidth}`,);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDensityMultiplier(adjustedScaleFactor: number): number {
|
||||||
|
return Math.round(Number.MAX_VALUE * (adjustedScaleFactor <= 1 ? adjustedScaleFactor : 1 / adjustedScaleFactor));
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustTargetDensityForError(adjustedScaleFactor: number): number {
|
||||||
|
let densityMultiplier = this.getDensityMultiplier(adjustedScaleFactor);
|
||||||
|
let targetDensity = this.round(densityMultiplier * adjustedScaleFactor);
|
||||||
|
let scaleFactorWithError = targetDensity / densityMultiplier;
|
||||||
|
let difference = adjustedScaleFactor / scaleFactorWithError;
|
||||||
|
return this.round(difference * targetDensity)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
QUALITY,
|
||||||
|
MEMORY
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import { ImageKnifeRequest } from '../ImageKnifeRequest'
|
||||||
import { IEngineKey } from '../key/IEngineKey'
|
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 { DownsampleStrategy} from '../downsampling/DownsampleStartegy'
|
||||||
|
|
||||||
export interface ImageKnifeData {
|
export interface ImageKnifeData {
|
||||||
source: PixelMap | string,
|
source: PixelMap | string,
|
||||||
|
@ -60,7 +61,6 @@ export interface RequestJobResult {
|
||||||
fileKey: string
|
fileKey: string
|
||||||
loadFail?: string,
|
loadFail?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* request子线程处理时的请求参数
|
* request子线程处理时的请求参数
|
||||||
*/
|
*/
|
||||||
|
@ -76,5 +76,9 @@ export interface RequestJobRequest {
|
||||||
writeCacheStrategy?: CacheStrategy
|
writeCacheStrategy?: CacheStrategy
|
||||||
signature?: string
|
signature?: string
|
||||||
engineKey: IEngineKey
|
engineKey: IEngineKey
|
||||||
|
targetWidth:number
|
||||||
|
targetHeight: number
|
||||||
|
downsampType?:DownsampleStrategy
|
||||||
|
autoResize?:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue