parent
a7c8d54324
commit
41f370f23c
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* 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(){
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.jpgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampling: DownsampleStrategy.FIT_CENTER,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampling: DownsampleStrategy.AT_MOST,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.jpgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampling: DownsampleStrategy.AT_LEAST,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.jpgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampling: DownsampleStrategy.CENTER_INSIDE,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.jpgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampling: DownsampleStrategy.CENTER_OUTSIDE,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
ImageKnifeComponent({
|
||||||
|
imageKnifeOption: {
|
||||||
|
loadSrc: $r("app.media.jpgSample"),
|
||||||
|
placeholderSrc: $r("app.media.loading"),
|
||||||
|
errorholderSrc: $r("app.media.app_icon"),
|
||||||
|
downsampling: DownsampleStrategy.NONE,
|
||||||
|
objectFit: ImageFit.Contain,
|
||||||
|
autoResize:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.height(300)
|
||||||
|
.width(300)
|
||||||
|
.borderWidth(1)
|
||||||
|
.borderColor(Color.Pink)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.height('100%')
|
||||||
|
.width('100%')
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 678 KiB |
|
@ -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,237 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
//FitCenter类实现DownsampleStartegy
|
||||||
|
@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 {
|
||||||
|
// TODO: 这个逻辑可能不正确,但是如果不这样做,我们可能会跳过一个采样尺寸,因为 QUALITY 更喜欢宽度和高度缩放因子中比较小的那个
|
||||||
|
// MEMORY 折中方案,他让我们更喜欢两者中较大的那个
|
||||||
|
return SampleSizeRounding.MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//None 类实现 DownsampleStrategy 接口
|
||||||
|
@Sendable
|
||||||
|
export class None implements BaseDownsampling{
|
||||||
|
getName(): string{
|
||||||
|
return "DownsampleNone"
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现 getScaleFactor 方法
|
||||||
|
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 {
|
||||||
|
//总是返回 QUALITY
|
||||||
|
return SampleSizeRounding.QUALITY
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*宽高进行等比缩放宽高里面最小的比例先放进去
|
||||||
|
然后再更据原图的缩放比去适配另一边*/
|
||||||
|
@Sendable
|
||||||
|
export class CenterOutside implements BaseDownsampling {
|
||||||
|
getName() {
|
||||||
|
return "CenterOutside"
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现 getScaleFactor 方法
|
||||||
|
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): number {
|
||||||
|
const widthPercentage = requestedWidth / sourceWidth;
|
||||||
|
const heightPercentage = requestedHeight / sourceHeight;
|
||||||
|
//返回宽度和高度比例中最大的值
|
||||||
|
return Math.max(widthPercentage, heightPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现 getSampleSizeRounding 方法
|
||||||
|
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): SampleSizeRounding {
|
||||||
|
//根据 CenterOutside 的逻辑,总是返回 QUALITY
|
||||||
|
return SampleSizeRounding.QUALITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*请求尺寸大于实际尺寸不进行放大,按照原图展示*/
|
||||||
|
@Sendable
|
||||||
|
export class Atleast implements BaseDownsampling {
|
||||||
|
//构造函数
|
||||||
|
constructor(){
|
||||||
|
//TypeScript 默认构造函数不需要特殊标记
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
//实现 getSampleSizeRounding 方法
|
||||||
|
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) {
|
||||||
|
// let greaterOrEqualSampleSize = lesserOrEqualSampleSize <<= 1; // lest shift by 1
|
||||||
|
// }
|
||||||
|
greaterOrEqualSampleSize = lesserOrEqualSampleSize << (lesserOrEqualSampleSize < maxIntegerFactor ? 1 : 0)
|
||||||
|
//返回缩放因子
|
||||||
|
return 1 / greaterOrEqualSampleSize
|
||||||
|
}
|
||||||
|
|
||||||
|
highestOneBit(i: number): number {
|
||||||
|
i |= (i >> 1);
|
||||||
|
i |= (i >> 2);
|
||||||
|
i |= (i >> 4);
|
||||||
|
i |= (i >> 8);
|
||||||
|
i |= (i >> 16);
|
||||||
|
return i - (i >>> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现 getSampleSizeRounding 方法
|
||||||
|
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 方法
|
||||||
|
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number,autoResize?:boolean): number {
|
||||||
|
//获取 FIT_CENTER 的缩放因子
|
||||||
|
const fitCenterScaleFactor : ESObject = this.getScale(sourceWidth,sourceHeight,requestedWidth,requestedHeight,autoResize);
|
||||||
|
//实现 getScaleFactor 方法
|
||||||
|
//返回不超过 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 方法
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
highestOneBit(i: number): number {
|
||||||
|
i |= (i >> 1);
|
||||||
|
i |= (i >> 2);
|
||||||
|
i |= (i >> 4);
|
||||||
|
i |= (i >> 8);
|
||||||
|
i |= (i >> 16);
|
||||||
|
return i - (i >>> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现 getSampleSizeRounding 方法
|
||||||
|
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 {
|
||||||
|
// TODO: 这个逻辑可能不正确,但是如果不这样做,我们可能会跳过一个采样尺寸,因为 QUALITY 更喜欢宽度和高度缩放因子中比较小的那个
|
||||||
|
// MEMORY 折中方案,他让我们更喜欢两者中较大的那个
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
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 = 0; //获取旋转角度
|
||||||
|
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);
|
||||||
|
}
|
Loading…
Reference in New Issue