100aff185Sopenharmony_ci/*
200aff185Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
300aff185Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
400aff185Sopenharmony_ci * you may not use this file except in compliance with the License.
500aff185Sopenharmony_ci * You may obtain a copy of the License at
600aff185Sopenharmony_ci *
700aff185Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
800aff185Sopenharmony_ci *
900aff185Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1000aff185Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1100aff185Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1200aff185Sopenharmony_ci * See the License for the specific language governing permissions and
1300aff185Sopenharmony_ci * limitations under the License.
1400aff185Sopenharmony_ci */
1500aff185Sopenharmony_ci
1600aff185Sopenharmony_ciimport { Log } from './Log';
1700aff185Sopenharmony_ciimport { Constants } from '../model/common/Constants';
1800aff185Sopenharmony_ciimport display from '@ohos.display';
1900aff185Sopenharmony_ciimport image from '@ohos.multimedia.image';
2000aff185Sopenharmony_ci
2100aff185Sopenharmony_ciconst TAG: string = 'common_ImageUtil';
2200aff185Sopenharmony_ci
2300aff185Sopenharmony_citype ImageSize = {
2400aff185Sopenharmony_ci  width: number;
2500aff185Sopenharmony_ci  height: number;
2600aff185Sopenharmony_ci};
2700aff185Sopenharmony_ci
2800aff185Sopenharmony_ciexport class ImageUtil {
2900aff185Sopenharmony_ci  // 默认缩略图大小,用于大图跳转
3000aff185Sopenharmony_ci  static readonly DEFAULT_THUMBNAIL_SIZE: number = 640;
3100aff185Sopenharmony_ci
3200aff185Sopenharmony_ci  static computeSampleSize(width: number, height: number, minSideLength: number, maxNumOfPixels: number): number {
3300aff185Sopenharmony_ci    if (width == 0 || height == 0 || minSideLength == 0 || maxNumOfPixels == 0) {
3400aff185Sopenharmony_ci      return 2;
3500aff185Sopenharmony_ci    }
3600aff185Sopenharmony_ci    let initialSize = ImageUtil.computeInitialSampleSize(width, height, minSideLength, maxNumOfPixels);
3700aff185Sopenharmony_ci    Log.debug(TAG, `initialSize:  ${initialSize}`);
3800aff185Sopenharmony_ci    return initialSize <= 8 ? ImageUtil.nextPowerOf2(initialSize) : Math.floor((initialSize + 8 - 1) / 8) * 8;
3900aff185Sopenharmony_ci  }
4000aff185Sopenharmony_ci
4100aff185Sopenharmony_ci  static getScreenNailSize(size: image.Size): void {
4200aff185Sopenharmony_ci    let displayClass: display.Display = display.getDefaultDisplaySync();
4300aff185Sopenharmony_ci    // 屏幕最长边px值
4400aff185Sopenharmony_ci    let screenWidth: number = displayClass.width;
4500aff185Sopenharmony_ci    let screenHeight: number = displayClass.height;
4600aff185Sopenharmony_ci    let maxScreenSideLength = Math.max(screenWidth, screenHeight);
4700aff185Sopenharmony_ci    Log.info(TAG, `getScreenNailSize maxSideLength: ${maxScreenSideLength}`);
4800aff185Sopenharmony_ci    let targetSize = maxScreenSideLength * Constants.NUMBER_1 / Constants.NUMBER_4;
4900aff185Sopenharmony_ci    let sizeWidth: number = size.width;
5000aff185Sopenharmony_ci    let sizeHeight: number = size.height;
5100aff185Sopenharmony_ci    let maxImageSideLength: number = Math.max(sizeWidth, sizeHeight);
5200aff185Sopenharmony_ci    if (maxImageSideLength === 0) {
5300aff185Sopenharmony_ci      Log.error(TAG, 'screen max length is zero');
5400aff185Sopenharmony_ci      return;
5500aff185Sopenharmony_ci    }
5600aff185Sopenharmony_ci    let scale = targetSize / maxImageSideLength;
5700aff185Sopenharmony_ci    size.width = Math.ceil(size.width * scale);
5800aff185Sopenharmony_ci    size.height = Math.ceil(size.height * scale);
5900aff185Sopenharmony_ci    Log.info(TAG, `getScreenNailSize scale: ${scale}, target height ${size.height}`);
6000aff185Sopenharmony_ci  }
6100aff185Sopenharmony_ci
6200aff185Sopenharmony_ci  static nextPowerOf2(value: number): number {
6300aff185Sopenharmony_ci    let useValue = value;
6400aff185Sopenharmony_ci    if (useValue <= 0 || useValue > (1 << 30)) {
6500aff185Sopenharmony_ci      Log.warn(TAG, `invalid sample value ${useValue}!`);
6600aff185Sopenharmony_ci      return 1;
6700aff185Sopenharmony_ci    }
6800aff185Sopenharmony_ci    useValue -= 1;
6900aff185Sopenharmony_ci    useValue |= useValue >> 16;
7000aff185Sopenharmony_ci    useValue |= useValue >> 8;
7100aff185Sopenharmony_ci    useValue |= useValue >> 4;
7200aff185Sopenharmony_ci    useValue |= useValue >> 2;
7300aff185Sopenharmony_ci    useValue |= useValue >> 1;
7400aff185Sopenharmony_ci    Log.debug(TAG, `nextPowerOf2:${useValue}`);
7500aff185Sopenharmony_ci    return useValue + 1;
7600aff185Sopenharmony_ci  }
7700aff185Sopenharmony_ci
7800aff185Sopenharmony_ci  /**
7900aff185Sopenharmony_ci   * Calculate the aspect ratio, considering the direction of rotation
8000aff185Sopenharmony_ci   *
8100aff185Sopenharmony_ci   * @param info include orientation width height
8200aff185Sopenharmony_ci   * @return the aspect ratio
8300aff185Sopenharmony_ci   */
8400aff185Sopenharmony_ci  static calcRatio(info: ImageSize): number {
8500aff185Sopenharmony_ci    if (info == null || info == undefined) {
8600aff185Sopenharmony_ci      return 1;
8700aff185Sopenharmony_ci    }
8800aff185Sopenharmony_ci    if (info.width == 0 || info.height == 0) {
8900aff185Sopenharmony_ci      return 1;
9000aff185Sopenharmony_ci    }
9100aff185Sopenharmony_ci    return info.width / info.height;
9200aff185Sopenharmony_ci  }
9300aff185Sopenharmony_ci
9400aff185Sopenharmony_ci  /**
9500aff185Sopenharmony_ci   * 计算缩略图大小生成对应路径
9600aff185Sopenharmony_ci   * 计算缩略图大小规格:短边等于不小于给定大小;如果原图短边小于给定大小则返回原图大小
9700aff185Sopenharmony_ci   *
9800aff185Sopenharmony_ci   * @param uri 图片媒体路径
9900aff185Sopenharmony_ci   * @param imageHeight 图片原高
10000aff185Sopenharmony_ci   * @param imageWidth 图片原宽
10100aff185Sopenharmony_ci   */
10200aff185Sopenharmony_ci  static calcThumbnail(uri: string, imageHeight: number, imageWidth: number, orientation?: number): string {
10300aff185Sopenharmony_ci    if (uri == null) {
10400aff185Sopenharmony_ci      return '';
10500aff185Sopenharmony_ci    }
10600aff185Sopenharmony_ci    if (!imageWidth || !imageHeight) {
10700aff185Sopenharmony_ci      // 长宽无效返回缩略图默认值256 * 256
10800aff185Sopenharmony_ci      return `${uri}/thumbnail/256/256`
10900aff185Sopenharmony_ci    }
11000aff185Sopenharmony_ci    if (imageHeight < this.DEFAULT_THUMBNAIL_SIZE || imageWidth < this.DEFAULT_THUMBNAIL_SIZE) {
11100aff185Sopenharmony_ci      return `${uri}/thumbnail/${imageWidth}/${imageHeight}`
11200aff185Sopenharmony_ci    }
11300aff185Sopenharmony_ci
11400aff185Sopenharmony_ci    let width = 0;
11500aff185Sopenharmony_ci    let height = 0;
11600aff185Sopenharmony_ci    if (orientation != null && (orientation == Constants.ANGLE_90 || orientation == Constants.ANGLE_270)) {
11700aff185Sopenharmony_ci      let temp = imageWidth;
11800aff185Sopenharmony_ci      imageWidth = imageHeight;
11900aff185Sopenharmony_ci      imageHeight = temp;
12000aff185Sopenharmony_ci    }
12100aff185Sopenharmony_ci    if (imageHeight < imageWidth) {
12200aff185Sopenharmony_ci      height = this.DEFAULT_THUMBNAIL_SIZE;
12300aff185Sopenharmony_ci      width = Math.round(height * imageWidth / imageHeight)
12400aff185Sopenharmony_ci    } else {
12500aff185Sopenharmony_ci      width = this.DEFAULT_THUMBNAIL_SIZE;
12600aff185Sopenharmony_ci      height = Math.round(width * imageHeight / imageWidth);
12700aff185Sopenharmony_ci    }
12800aff185Sopenharmony_ci    return `${uri}/thumbnail/${width}/${height}`
12900aff185Sopenharmony_ci  }
13000aff185Sopenharmony_ci
13100aff185Sopenharmony_ci  private static computeInitialSampleSize(width: number, height: number,
13200aff185Sopenharmony_ci                                          minSideLength: number, maxNumOfPixels: number): number {
13300aff185Sopenharmony_ci    if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
13400aff185Sopenharmony_ci      return 1;
13500aff185Sopenharmony_ci    }
13600aff185Sopenharmony_ci
13700aff185Sopenharmony_ci    let lowerBound: number = (maxNumOfPixels == -1) ? 1 : Math.ceil(Math.sqrt((width * height) / maxNumOfPixels));
13800aff185Sopenharmony_ci    Log.debug(TAG, `lowerBound: ${lowerBound}`);
13900aff185Sopenharmony_ci    if (minSideLength == -1) {
14000aff185Sopenharmony_ci      return lowerBound;
14100aff185Sopenharmony_ci    } else {
14200aff185Sopenharmony_ci      let sampleSize = Math.min(width / minSideLength, height / minSideLength);
14300aff185Sopenharmony_ci      return Math.max(sampleSize, lowerBound);
14400aff185Sopenharmony_ci    }
14500aff185Sopenharmony_ci  }
14600aff185Sopenharmony_ci}