Pre Merge pull request !275 from 田双明/master

This commit is contained in:
田双明 2024-05-23 06:57:02 +00:00 committed by Gitee
commit 378093b053
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
9 changed files with 239 additions and 211 deletions

View File

@ -135,4 +135,12 @@ export { LogUtil } from './src/main/ets/components/imageknife/utils/LogUtil'
/*下采样*/
export {Downsampler} from './src/main/ets/components/imageknife/downsampling/Downsampler'
export {DownsampleNone as sampleNone, FitCenter as fitter} from './src/main/ets/components/imageknife/downsampling/DownsampleStartegy'
export {
DownsampleNone as sampleNone,
FitCenter as fitter,
CenterOutside,
Atleast,
AtMost,
CenterInside as Center_Inside
} from './src/main/ets/components/imageknife/downsampling/DownsampleStartegy'

View File

@ -1,18 +1,3 @@
/*
* 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';
type ISendable = lang.ISendable;

View File

@ -12,138 +12,152 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BaseDownsampling } from './BaseDownsampling'
@Sendable
export class CenterInside {
getName() {
return "CenterInside"
}
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
return Math.min(1, this.getScale(sourceWidth, sourceHeight, requestWidth, requestHeight))
}
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
//下采样因子
return 1
}
getScale(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
let widthPercentage = requestWidth / sourceWidth
let heightPercentage = requestHeight / sourceHeight
return Math.min(widthPercentage, heightPercentage)
}
}
/*不进行下采样*/
@Sendable
export class DownsampleNone implements BaseDownsampling {
getName() {
return "DownsampleNone"
}
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
//下采样因子
return 1
}
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
//下采样因子
return 1
}
}
/* 下采样使得图像的组大尺寸在给定的尺寸的1/2之间*/
@Sendable
export class AtMost implements BaseDownsampling {
getName() {
return "AtMost"
}
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
let maxIntegerFactor = Math.ceil(Math.max(sourceHeight / requestHeight, sourceWidth / requestWidth));
let lesserOrEqualSampleSize = Math.max(1, this.highestOneBit(maxIntegerFactor))
let greaterOrEqualSampleSize = lesserOrEqualSampleSize << (lesserOrEqualSampleSize < maxIntegerFactor ? 1 : 0)
return 1 / greaterOrEqualSampleSize
}
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
return 0
}
highestOneBit(i: number): number {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
}
@Sendable
export class Atleast implements BaseDownsampling {
getName() {
return "Atleast"
}
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
let minIntegerFactor = Math.floor(Math.min(sourceHeight / requestHeight, sourceWidth / requestWidth))
return minIntegerFactor == 0 ? 1 : 1 / this.highestOneBit(minIntegerFactor)
}
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
//下采样因子
return 1
}
highestOneBit(i: number): number {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
}
@Sendable
export class CenterOutside implements BaseDownsampling {
getName() {
return "CenterOutside"
}
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
let widthPercentage = requestWidth / sourceWidth
let heightPercentage = requestHeight / sourceHeight
return Math.max(widthPercentage, heightPercentage)
}
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
//下采样因子
return 1
}
}
import { BaseDownsampling } from './BaseDownsampling';
import { highestOneBit, SampleSizeRounding } from './downsampleUtils';
//FitCenter类实现DownsampleStartegy
@Sendable
export class FitCenter implements BaseDownsampling {
getName() {
return "FitCenter"
}
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
let widthPercentage = requestWidth / sourceWidth
let heightPercentage = requestHeight / sourceHeight
return Math.min(widthPercentage, heightPercentage)
//实现 getScaleFactor 方法
getScaleFactor(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): number {
const maxIntegerFactor = Math.max(sourceHeight / requestedHeight, sourceWidth / requestedWidth);
const a = maxIntegerFactor === 0 ? 1 : 1 / highestOneBit(maxIntegerFactor)
return a;
}
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number {
//下采样因子
return 1
getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): number {
return SampleSizeRounding.MEMORY;
}
}
export enum SampleSizeRounding {
MEMORY,
QUALITY
//None 类实现 DownsampleStrategy 接口
@Sendable
export class DownsampleNone 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 {
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
greaterOrEqualSampleSize = lesserOrEqualSampleSize << (lesserOrEqualSampleSize < maxIntegerFactor ? 1 : 0)
//返回缩放因子
return 1 / greaterOrEqualSampleSize
}
//实现 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): number {
//获取 FIT_CENTER 的缩放因子
const fitCenterScaleFactor: ESObject = this.getScale(sourceWidth, sourceHeight, requestedWidth, requestedHeight);
//返回不超过 1 的缩放因子,即尽量缩小图像以适应目标尺寸,但不会放大
return Math.min(1, fitCenterScaleFactor);
}
getScale(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): number {
//类似 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): SampleSizeRounding {
//如果缩放因子为 1表示没有缩放优先选择质量
if (this.getScaleFactor(sourceWidth, sourceHeight, requestedWidth, requestedHeight) === 1) {
return SampleSizeRounding.QUALITY
}
//否则,使用 FIL_CENTER 的 SampleSizeRounding 值
return this.getSampleSize(sourceWidth, sourceHeight, requestedWidth, requestedHeight);
}
getSampleSize(sourceWidth: number, sourceHeight: number, requestedWidth: number, requestedHeight: number): SampleSizeRounding {
return SampleSizeRounding.MEMORY;
}
}

View File

@ -1,26 +1,7 @@
/*
* 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 { RequestOption } from '../RequestOption';
import { FileTypeUtil } from '../utils/FileTypeUtil';
import { CenterOutside, FitCenter, SampleSizeRounding } from './DownsampleStartegy';
let TAG = 'downsampling'
export interface calculateScaleType {
targetWidth: number,
targetHeight: number
}
import { Atleast, AtMost, CenterInside, CenterOutside, DownsampleNone, FitCenter } from './DownsampleStartegy';
import { calculateScaleType, highestOneBit, SampleSizeRounding } from './downsampleUtils';
export class Downsampler {
@ -29,40 +10,79 @@ export class Downsampler {
sourceHeight: number,
sourceWidth: number,
request?: RequestOption
): calculateScaleType {
const fileType: string | null = new FileTypeUtil().getFileType(imageType)
let powerOfTwoWidth: number | null = null;
let powerOfTwoHeight: number | null = null;
): ESObject {
let degreesToRotate:number = 0 //获取旋转角度
const fileType: string | null = new FileTypeUtil().getFileType(imageType)//获取图片类型
let powerOfTwoWidth: number = 0;
let powerOfTwoHeight: number = 0;
let targetWidth: number = 0
let targetHeight: number = 0
if (request?.size.width && !request?.size.height) {
targetWidth = this.round((request?.size.height) * sourceWidth / sourceHeight)
} else if (request?.size.height && !request?.size.width) {
targetHeight = this.round((request?.size.width) * sourceHeight / sourceWidth)
} else if (request?.size.height && request?.size.width) {
targetHeight = request.size.height;
targetWidth = request?.size.width;
} else {
throw new Error("Cannot found width or height ");
}
if (sourceWidth <= 0 || sourceHeight <= 0) {
throw new Error("Cannot found width or height ");
};
let orientedSourceWidth = sourceWidth;
let orientedSourceHeight = sourceHeight;
if (this.isRotationRequired(90)) {
if (this.isRotationRequired(degreesToRotate)) {
orientedSourceWidth = sourceHeight;
orientedSourceHeight = sourceWidth;
}
if (request?.size.width && !request?.size.height) {
targetWidth = this.round((request?.size.height) * sourceWidth / sourceHeight)
} else if (request?.size.height && !request?.size.width) {
targetHeight = this.round((request?.size.width) * sourceHeight / sourceWidth)
} else if (request?.size.height && request?.size.width) {
targetWidth = request?.size.width===sourceWidth?(this.isRotationRequired(degreesToRotate)?sourceHeight:sourceWidth):request?.size.width
targetHeight = request?.size.height===sourceHeight?(this.isRotationRequired(degreesToRotate)?sourceWidth:sourceHeight):request?.size.height;
} else {
throw new Error("Cannot found width or height ");
}
/*安卓的模式*/
let exactScaleFactor: number = new FitCenter()
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
if (exactScaleFactor <= 0) {
throw new Error("Cannot round with exactScaleFactor");
}
/*安卓的模式*/
let rounding: SampleSizeRounding = new FitCenter()
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
switch (request?.downsampType.getName()) {
case "FitCenter":
exactScaleFactor = new FitCenter()
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
rounding = new FitCenter()
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
break;
case "DownsampleNone":
exactScaleFactor = new DownsampleNone()
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
rounding = new DownsampleNone()
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
break
case "AtMost":
exactScaleFactor = new AtMost()
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
rounding = new AtMost()
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
break
case "CenterInside":
exactScaleFactor = new CenterInside()
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
rounding = new CenterInside()
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
break
case "AtLeast":
exactScaleFactor = new Atleast()
.getScaleFactor(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
rounding = new Atleast()
.getSampleSizeRounding(orientedSourceWidth, orientedSourceHeight, targetWidth, targetHeight)
break
case "CenterOutside":
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");
}
@ -75,7 +95,7 @@ export class Downsampler {
Math.min(widthScaleFactor, heightScaleFactor)
// 将整型的缩放因子转换为2的次幂采样大小
let powerOfTwoSampleSize: number = 0;
powerOfTwoSampleSize = Math.max(1, this.highestOneBit(scaleFactor))
powerOfTwoSampleSize = Math.max(1, highestOneBit(scaleFactor))
if (rounding == SampleSizeRounding.MEMORY && powerOfTwoSampleSize < (1 / exactScaleFactor)) {
powerOfTwoSampleSize = powerOfTwoSampleSize << 1;
}
@ -103,15 +123,6 @@ export class Downsampler {
return a
}
highestOneBit(i: number): number {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
round(value: number): number {
return Math.floor(value + 0.5);
}
@ -119,16 +130,4 @@ export class Downsampler {
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);
}
}

View File

@ -0,0 +1,19 @@
//假设的枚举类型与Java中的枚举相似
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);
}
export interface calculateScaleType {
targetWidth: number,
targetHeight: number
}

View File

@ -17,7 +17,8 @@ import { IParseImage } from '../interface/IParseImage'
import image from '@ohos.multimedia.image';
import { BusinessError } from '@ohos.base'
import { RequestOption } from '../RequestOption';
import {Downsampler,calculateScaleType } from '../downsampling/Downsampler';
import { Downsampler } from '../downsampling/Downsampler';
import { calculateScaleType } from '../Downsampling/downsampleUtils';
export class ParseImageUtil implements IParseImage<PixelMap> {
parseImage(

View File

@ -20,7 +20,8 @@ import worker, { ErrorEvent, MessageEvents } from '@ohos.worker';
import taskpool from '@ohos.taskpool'
import { LogUtil } from '../LogUtil'
import { RequestOption } from '../../RequestOption'
import { Downsampler,calculateScaleType } from '../../downsampling/Downsampler'
import { Downsampler } from '../../downsampling/Downsampler'
import { calculateScaleType } from '../../Downsampling/downsampleUtils'
export interface senderData {
type: string,

View File

@ -17,7 +17,8 @@ import { RequestOption } from '../../RequestOption'
import { BusinessError } from '@ohos.base'
import { ImageKnifeData, ImageKnifeType } from '../../ImageKnifeData'
import image from '@ohos.multimedia.image'
import { Downsampler, calculateScaleType } from '../../downsampling/Downsampler'
import { Downsampler } from '../../downsampling/Downsampler'
import { calculateScaleType } from '../../Downsampling/downsampleUtils'
export class SVGParseImpl implements IParseSvg {
parseSvg(option: RequestOption, imageInfo: ArrayBuffer,