diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39187eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/local.properties +/.idea +**/build \ No newline at end of file diff --git a/READEME.OpenSource.md b/READEME.OpenSource.md new file mode 100644 index 0000000..4eeb1d0 --- /dev/null +++ b/READEME.OpenSource.md @@ -0,0 +1,62 @@ +[ + { + "Name": "glide", + "License": "under one or more license", + "License File": "https://github.com/bumptech/imageknife/blob/master/LICENSE", + "Version Number": "4.13.1", + "Owner" : "bumptech" + "Upstream URL": "https://github.com/bumptech/imageknife", + "Description": "An image loading and caching library focused on smooth scrolling" + }, + + { + "Name": "glide-transformations", + "License": "Apache License 2.0", + "License File": "https://github.com/wasabeef/imageknife-transformations/blob/main/LICENSE", + "Version Number": "4.3.0", + "Owner" : "wasabeef" + "Upstream URL": "https://github.com/wasabeef/imageknife-transformations", + "Description": " An transformation library providing a variety of image transformations for Glide. " + }, + + { + "Name": "fresco", + "License": "MIT License", + "License File": "https://github.com/facebook/fresco/blob/main/LICENSE", + "Version Number": "2.6.0", + "Owner" : "facebook" + "Upstream URL": "https://github.com/facebook/fresco", + "Description": " An library for managing images and the memory they use. " + }, + + { + "Name": "UPNG.js", + "License": "MIT License", + "License File": "https://github.com/photopea/UPNG.js/blob/master/LICENSE", + "Version Number": "1.0.0", + "Owner" : "photopea" + "Upstream URL": "https://github.com/photopea/UPNG.js", + "Description": " Fast and advanced PNG (APNG) decoder and encoder (lossy / lossless) " + }, + + { + "Name": "Luban", + "License": "Apache License 2.0", + "License File": "https://github.com/Curzibn/Luban/blob/master/LICENSE", + "Version Number": "1.1.8", + "Owner" : " Curzibn" + "Upstream URL": "https://github.com/Curzibn/Luban", + "Description": " Luban(鲁班)—Image compression with efficiency very close to WeChat Moments/可能是最接近微信朋友圈的图片压缩算法 " + }, + + { + "Name": "uCrop", + "License": "Apache License 2.0", + "License File": "https://github.com/Yalantis/uCrop/blob/develop/README.md", + "Version Number": "2.2.8", + "Owner" : " Yalantis" + "Upstream URL": "https://github.com/Yalantis/uCrop", + "Description": " Image Cropping Library " + } + +] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3e55f0a --- /dev/null +++ b/README.md @@ -0,0 +1,339 @@ +# ImageKnife + +**专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单** + +## 简介 + +本项目基于开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本 + +- 支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存 +- 支持磁盘缓存,对于下载图片会保存一份至磁盘当中 +- 支持进行图片变换 +- 支持用户配置参数使用:(例如:配置是否开启第一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等) +- 推荐使用ImageKnifeComponent组件配合ImageKnifeOption参数来实现功能 +- 支持用户自定义配置实现能力参考ImageKnifeComponent组件中对于入参ImageKnifeOption的处理 + +## 下载安装 + +1.参考安装教程 [如何安装OpenHarmony npm包](https://gitee.com/openharmony-tpc/docs/blob/master/OpenHarmony_npm_usage.md) + +2.安装命令如下: + +``` +npm install @ohos/imageknife --save +``` + + + +## 使用说明 + +[跳转至代码示例](##'代码示例') + +## 目录 + +``` +/imageknife/src/ +- main/ets/components + - cache # 缓存相关内容 + - diskstrategy # 缓存策略 + - key # 缓存key生成策略 + - Base64.ets # Base64算法 + - CustomMap.ets # 自定义Map封装 + - DiskCacheEntry.ets# 磁盘缓存entry + - DiskLruCache.ets # 磁盘LRU缓存策略 + - FileReader.ets # 文件读取相关 + - FileUtils.ets # 文件工具类 + - LruCache.ets # 内存LRU缓存策略 + - Md5.ets # MD5算法 + + - imageknife # imageknife主要内容 + - compress # 压缩相关 + - constants # 常量相关 + - entry # 部分数据结构 + - holder # 占位图相关解析 + - interface # 接口相关 + - networkmanage # 网络相关 + - pngj # pngj相关 + - requestmanage # imageknife请求相关 + - resourcemanage # 本地资源解析相关 + - transform # 图片变换相关 + - utils # 工具类相关 + - ImageKnife.ets # imageknife门面,app持久化类 + - ImageKnifeData.ets # 数据封装 + - ImageKnifeComponent.ets # 自定义控件封装 + - ImageKnifeOption.ets # 用户传参数封装 + - PixelMapPack.ets # PixelMap封装 + - RequestOption.ets # 用户设置参数封装 + +/entry/src/ +- main/ets/MainAbility + - pages # 测试page页面列表 + - basicTestFeatureAbilityPage.ets # 测试元能力 + - basicTestFileIOPage.ets # 测试fileio + - basicTestMediaImage.ets # 测试媒体image + - basicTestResourceManagerPage.ets # 测试本地资源解析 + - compressPage.ets # 压缩页面 + - frescoImageTestCasePage.ets # 测试属性动画组件切换 + - frescoLayerTestCasePage.ets # 测试ImageKnifeComponent组件切换配合属性动画 + - frescoRetryTestCasePage.ets # 测试ImageKnifeComponent加载失败重试 + - index.ets # 测试页面入口 + - indexFresco.ets # 二级测试页面入口 + - loadNetworkTestCasePage.ets # 网络加载测试 + - loadResourceTestCasePage.ets # 本地加载测试 + - showErrorholderTestCasePage.ets # 加载失败占位图测试 + - storageTestDiskLruCache.ets # 磁盘缓存测试 + - storageTestLruCache.ets # 内存缓存测试 + - testAllCacheInfoPage.ets # 所有缓存信息获取测试 + - testAllTypeImageKnifeComponentPage.ets # 所有类型图片加载测试 + - testAllTypeNativeImagePage.ets # 所有类型本地图片加载测试 + - testGifDontAnimatePage.ets # gif加载静态图片测试 + - testImageKnifeOptionChangedPage.ets # ImageKnifeOption数据切换测试 + - testImageKnifeOptionChangedPage2.ets # ImageKnifeOption数据切换测试 + - testMultiThreadWorkerPage2.ets # 多线程测试 + - testPlaceholderPage.ets # 加载占位图测试 + - testPreloadPage.ets # 预加载测试 + - testResourceManagerPage.ets # 解析本地资源测试 + - transformPixelMapPage.ets # 所有类型变换测试 + - transformTestCasePage.ets # 所有类型变换配合ImageKnifeComponent测试 + + - workers # 测试worker多线程 + - worker1.js # worker多线程测试 +``` + +## 接口说明 + +### RequestOpton 用户配置参数 + +| 方法名 | 入参 | 接口描述 | +| ------------------------------------------------------------ | ---------------------------------------------------------- | -------------------------------------------------------- | +| load(src: string \| PixelMap \| Resource) | string \| PixelMap \| Resource | 待加载图片的资源 | +| setImageViewSize(imageSize: { width: number, height: number }) | { width: number, height: number } | 传入显示图片组件的大小,变换的时候需要作为参考 | +| diskCacheStrategy(strategy: DiskStrategy) | DiskStrategy | 配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC | +| placeholder(src: PixelMap \| Resource, func?: AsyncSuccess) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置占位图,其中func为数据回调函数 | +| errorholder(src: PixelMap \| Resource, func?: AsyncSuccess) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置加载失败占位图,其中func为数据回调函数 | +| addListener(func: AsyncCallback) | func: AsyncCallback | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 | +| thumbnail(sizeMultiplier:number, func?: AsyncSuccess) | sizeMultiplier:number, func?: AsyncSuccess | 设置缩略图比例,缩略图返回后,加载并展示缩略图 | +| addProgressListener(func?: AsyncSuccess){ this.progressFunc = func; return this; } | func?: AsyncSuccess | 设置网络下载百分比监听,返回数据加载百分比数值 | +| addRetryListener(func?: AsyncSuccess){ this.retryFunc = func; return this; } | func?: AsyncSuccess | 设置重试监听 | +| addAllCacheInfoCallback(func: IAllCacheInfoCallback) | func: IAllCacheInfoCallback | 设置获取所有缓存信息监听 | +| skipMemoryCache(skip: boolean) | skip: boolean | 配置是否跳过内存缓存 | +| retrieveDataFromCache(flag: boolean) | flag: boolean | 配置仅从缓存中加载数据 | + +同时支持[图片变换相关](##'图片变换相关')接口 + +### ImageKnife 启动器/门面类 + +| 方法名 | 入参 | 接口描述 | +| ------------------------------- | ---------------------- | ---------------------------------- | +| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 | +| preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 | + +### 缓存策略相关 + +| 使用方法 | 类型 | 策略描述 | +| ------------------------------------------ | --------- | ---------------------------------------- | +| request.diskCacheStrategy(new ALL()) | ALL | 表示既缓存原始图片,也缓存转换过后的图片 | +| request.diskCacheStrategy(new AUTOMATIC()) | AUTOMATIC | 表示尝试对本地和远程图片使用最佳的策略 | +| request.diskCacheStrategy(new DATA()) | DATA | 表示只缓存原始图片 | +| request.diskCacheStrategy(new NONE()) | NONE | 表示不缓存任何内容 | +| request.diskCacheStrategy(new RESOURCE()) | RESOURCE | 表示只缓存转换过后的图片 | + +### 图片变换相关 + +| 使用方法 | 类型 | 相关描述 | +| ------------------------------ | ---------------------------------- | ---------------------------------------------------- | +| request.centerCrop() | CenterCrop | 可以根据图片文件,目标显示大小,进行对应centerCrop | +| request.centerInside() | CenterInside | 可以根据图片文件,目标显示大小,进行对应centerInside | +| request.fitCenter() | FitCenter | 可以根据图片文件,目标显示大小,进行对应fitCenter | +| request.blur() | BlurTransformation | 模糊处理 | +| request.brightnessFilter() | BrightnessFilterTransformation | 亮度滤波器 | +| request.contrastFilter() | ContrastFilterTransformation | 对比度滤波器 | +| request.cropCircle() | CropCircleTransformation | 圆形剪裁显示 | +| request.cropCircleWithBorder() | CropCircleWithBorderTransformation | 圆环展示 | +| request.cropSquare() | CropSquareTransformation | 正方形剪裁 | +| request.crop() | CropTransformation | 自定义矩形剪裁 | +| request.grayscale() | GrayscaleTransformation | 灰度级转换 | +| request.invertFilter() | InvertFilterTransformation | 反转滤波器 | +| request.pixelationFilter() | PixelationFilterTransformation | 像素化滤波器 | +| request.rotateImage() | RotateImageTransformation | 图片旋转 | +| request.roundedCorners() | RoundedCornersTransformation | 圆角剪裁 | +| request.sepiaFilter() | SepiaFilterTransformation | 乌墨色滤波器 | +| request.sketchFilter() | SketchFilterTransformation | 素描滤波器 | + + + + + +## 代码示例 + +1.首先初始化全局ImageKnife实例,在app.ets中调用ImageKnife.with()进行初始化 + +``` +import {ImageKnife} from '@ohos/imageknife' +export default { + data: { + imageKnife: {} // ImageKnife全局占位符 + }, + onCreate() { + this.data.imageKnife = ImageKnife.with();// ImageKnife占位符全局初始化赋值 + } +} +``` + +2.在页面index.ets中使用ImageKnife + +``` +@Entry +@Component +struct Index { + build() { + + } + + // 页面初始化完成,生命周期回调函数中 进行调用ImageKnife + aboutToAppear() { + let requestOption = new RequestOption(); + requestOptin.load($r('app.media.IceCream')) + .addListener((err,data) => { + //加载成功/失败回调监听 + }) + ... + ImageKnife.call(requestOption) + } +} + +var ImageKnife; +var defaultTemp = globalThis.exports.default +if (defaultTemp != undefined) { + ImageKnife = defaultTemp.data.imageKnife; +} +``` + + + +#### 推荐使用: + +使用ImageKnifeOption作为入参,配合自定义组件ImageKnifeComponent使用。 + +```typescript +@Entry +@Component +struct Index { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + } + } + .width('100%') + .height('100%') + } +} +``` + +#### 自定义实现: + +使用原生Image组件,配合用户配置参数实现。 + +##### 步骤1: + +定义自定义类 + +``` +export default class PixelMapPack{ + pixelMap:PixelMap; +} +``` + +使用@State关联PixelMapPack +```typescript +@State imageKnifePixelMapPack:PixelMapPack = new PixelMapPack(); +width:number = 200; +height:number = 200; +``` + +##### 步骤2: + +在你的component组件中,写下一个Image组件,将基础参数(入参PixelMap,组件的宽、高)配置好 + +``` +Image(this.imageKnifePixelMapPack.pixelMap) + .backgroundColor(Color.Grey) + .objectFit(ImageFit.Contain) + .width(this.width) + .height(this.height) +``` + +##### 步骤3: + +在aboutToAppear() 函数中调用加载流程 + +```typescript +//配置参数 +let requestOptin = new RequestOption(); + //加载本地图片 + requestOptin.load($r('app.media.jpgSample')) + .addListener((err,data) => { + //加载成功/失败回调监听 + }) + .placeholder( $r('app.media.icon_loading'), (data)=>{ + // 占位图回调监听 + }) + .errorholder( $r('app.media.icon_failed'), (data)=>{ + // 失败占位图回调监听 + }) + .thumbnail(0.3, (data) => { + // 缩略图加载成功回调 + }) + // 一定要把控件大小传给RequestOption,图片变换必须 + .setImageViewSize({width:200, height:200}) + // 设置缓存策略 + .diskCacheStrategy(new AUTOMATIC()) + .addProgressListener((percentValue: string) => { + // 图片网络加载进度条百分比回调 + }) + .addRetryListener((error: any) => { + // 加载失败重试监听 图片加载失败时优先展示重试图层,点击重试图层,会重新进行一次加载流程 + }) + // 左上圆角10pixel像素点 + .roundedCorners({top:10}) + // 启动加载流程,执行结果将会返回到上面的回调接口中 + ImageKnife.call(requestOptin); +``` + +##### 步骤4: + +更多细节设置请参考自定义Component的ImageKnifeComponent实现 + +## 演示 + + + + + +## 兼容性 + +支持OpenHarmony API version 8 及以上版本 + +## 开源协议 + +[协议详见](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) + +## 贡献代码 + +使用过程中发现任何问题都可以提[issue](https://gitee.com/openharmony-tpc/ImageKnife/issues)给我们,当然,我们也非常欢迎你给我们发[PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) + +## 遗留问题 + +1.图片变换缓慢(待优化) + +2.目前只支持一种图片变换效果 \ No newline at end of file diff --git a/build-profile.json5 b/build-profile.json5 new file mode 100644 index 0000000..d787b0e --- /dev/null +++ b/build-profile.json5 @@ -0,0 +1,44 @@ +{ + "app": { + "signingConfigs": [ + { + "name": "default", + "material": { + "certpath": "C:\\Users\\zwx1045834\\.ohos\\config\\openharmony\\auto_ohos.cer", + "storePassword": "000000184CD86AF7B78D3E3B6C36B9221705137AC28BD8A341A757477E5DC27D95E6A0DFD5EB51AE", + "keyAlias": "debugKey", + "keyPassword": "00000018DAB1AB9C9DF6E7C4D35BE8EAF4323EFA49131AB39C65BA5C44DE6D3879C6B31AA70D1E14", + "profile": "C:\\Users\\zwx1045834\\.ohos\\config\\openharmony\\auto_ohos_default_com.example.imageknifegiteepro.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\zwx1045834\\.ohos\\config\\openharmony\\auto_ohos.p12" + } + } + ], + "compileSdkVersion": 8, + "compatibleSdkVersion": 8, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + }, + { + "name": "imageknife", + "srcPath": "./imageknife" + } + ] +} \ No newline at end of file diff --git a/entry/.gitignore b/entry/.gitignore new file mode 100644 index 0000000..4f9a973 --- /dev/null +++ b/entry/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/.preview +/build \ No newline at end of file diff --git a/entry/build-profile.json5 b/entry/build-profile.json5 new file mode 100644 index 0000000..ae58d1d --- /dev/null +++ b/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'faMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/entry/hvigorfile.js b/entry/hvigorfile.js new file mode 100644 index 0000000..bcec4c9 --- /dev/null +++ b/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').legacyHapTasks diff --git a/entry/package-lock.json b/entry/package-lock.json new file mode 100644 index 0000000..91c2411 --- /dev/null +++ b/entry/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "entry", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ohos/imageknife": { + "version": "file:../imageknife", + "requires": { + "pako": "^1.0.5" + }, + "dependencies": { + "pako": { + "version": "1.0.11", + "resolved": "http://mirrors.tools.huawei.com/npm/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + } + } + } + } +} diff --git a/entry/package.json b/entry/package.json new file mode 100644 index 0000000..bce3fa8 --- /dev/null +++ b/entry/package.json @@ -0,0 +1,14 @@ +{ + "license": "Apache License 2.0", + "devDependencies": {}, + "name": "entry", + "ohos": { + "org": "huawei", + "directoryLevel": "module", + "buildTool": "hvigor" + }, + "version": "1.0.0", + "dependencies": { + "@ohos/imageknife": "file:../imageknife" + } +} diff --git a/entry/src/main/config.json b/entry/src/main/config.json new file mode 100644 index 0000000..77afc4e --- /dev/null +++ b/entry/src/main/config.json @@ -0,0 +1,140 @@ +{ + "app": { + "vendor": "example", + "bundleName": "com.example.imageknifegiteepro", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": { + "default": { + "network": { + "cleartextTraffic": true + } + } + }, + "module": { + "mainAbility": ".MainAbility", + "deviceType": [ + "phone", + "tablet" + ], + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "visible": true, + "srcPath": "MainAbility", + "name": ".MainAbility", + "srcLanguage": "ets", + "icon": "$media:icon", + "description": "$string:ImageKnife_OHOS", + "formsEnabled": false, + "label": "$string:ImageKnife_OHOS", + "type": "page", + "launchType": "standard" + } + ], + "distro": { + "moduleType": "entry", + "installationFree": false, + "deliveryWithInstall": true, + "moduleName": "entry" + }, + "package": "com.example.entry", + "srcPath": "", + "name": ".entry", + "reqPermissions": [ + { + "name": "ohos.permission.READ_USER_STORAGE" + }, + { + "name": "ohos.permission.INTERNET", + "reason": "Api call", + "usedScene": { + "ability": [ + "com.example.imageknifegiteepro.MainAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "location background", + "usedScene": { + "when": "always", + "ability": [ + "com.example.imageknifegiteepro.MainAbility" + ] + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "location background", + "usedScene": { + "when": "always", + "ability": [ + "com.example.imageknifegiteepro.MainAbility" + ] + } + } + ], + "js": [ + { + "mode": { + "syntax": "ets", + "type": "pageAbility" + }, + "pages": [ + "pages/index", + "pages/indexFresco", + "pages/frescoLayerTestCasePage", + "pages/frescoImageTestCasePage", + "pages/frescoRetryTestCasePage", + "pages/basicTestFeatureAbilityPage", + "pages/basicTestFileIOPage", + "pages/basicTestMediaImage", + "pages/basicTestResourceManagerPage", + "pages/storageTestLruCache", + "pages/storageTestDiskLruCache", + "pages/transformTestCasePage", + "pages/pngjTestCasePage", + "pages/testAllTypeImageKnifeComponentPage", + "pages/testAllTypeNativeImagePage", + "pages/loadResourceTestCasePage", + "pages/loadNetworkTestCasePage", + "pages/showErrorholderTestCasePage", + "pages/transformPixelMapPage", + "pages/testGifDontAnimatePage", + "pages/testPreloadPage", + "pages/testImageKnifeOptionChangedPage", + "pages/testImageKnifeOptionChangedPage2", + "pages/compressPage", + "pages/testAllCacheInfoPage", + "pages/testResourceManagerPage", + "pages/testMultiThreadWorkerPage2", + "pages/testImageKnifeOptionChangedPage", + "pages/cropImagePage" + ], + "name": ".MainAbility", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/app.ets b/entry/src/main/ets/MainAbility/app.ets new file mode 100644 index 0000000..b2d066b --- /dev/null +++ b/entry/src/main/ets/MainAbility/app.ets @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 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 app from '@system.app'; + +import {ImageKnife} from '@ohos/imageknife' + +export default { + data: { + imageKnife: {} // ImageKnife + }, + onCreate() { + this.data.imageKnife = ImageKnife.with(); + }, + onDestroy() { + + }, +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestFeatureAbilityPage.ets b/entry/src/main/ets/MainAbility/pages/basicTestFeatureAbilityPage.ets new file mode 100644 index 0000000..3caf286 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestFeatureAbilityPage.ets @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 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 featureAbility from '@ohos.ability.featureAbility'; + +@Entry +@Component +struct BasicTestFeatureAbilityPage { + @Watch("watchPathChange") @State filePath:string= "查看featureAbility路径"; + + watchPathChange() { + console.log("watchPathChange"); + } + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.filePath).fontSize(20) + Button("featureAbility.getContext().getFilesDir()") + .margin({top:20}) + .onClick(()=>{ + featureAbility.getContext() + .getFilesDir() + .then((data) => { + console.log("ImageKnife filesPath = " + data) + this.filePath = data + }) + .catch((error) => { + console.error('ImageKnife Failed to obtain the filesPath directory. Cause:' + error.message); + }) + }) + Button("featureAbility.getContext().getCacheDir()") + .margin({top:20}) + .onClick(()=>{ + featureAbility.getContext().getCacheDir() + .then((data) => { + console.log("ImageKnife cachesPath = " + data) + this.filePath = data + }) + .catch((error) => { + console.error('ImageKnife Failed to obtain the cachesPath directory. Cause:' + error.message); + }) + }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestFileIOPage.ets b/entry/src/main/ets/MainAbility/pages/basicTestFileIOPage.ets new file mode 100644 index 0000000..3e9c7e4 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestFileIOPage.ets @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 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 featureAbility from '@ohos.ability.featureAbility'; +import { FileUtils } from '@ohos/imageknife' +import resourceManager from '@ohos.resourceManager'; + +@Entry +@Component +struct BasicTestFileIOPage { + @Watch('watchPathChange') @State filePath: string= '查看featureAbility路径'; + appFilePath = ''; + appCachePath = ''; + @State imageFile: string = '' + @State imageRes: Resource = $r('app.media.pngSample') + @State imagePixelMap: PixelMap = undefined + @State normalPixelMap: boolean = false; + @State normalResource: boolean = false; + + watchPathChange() { + console.log('watchPathChange'); + } + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.filePath).fontSize(20) + Button('featureAbility.getContext().getFilesDir()') + .margin({ top: 10 }) + .onClick(() => { + featureAbility.getContext() + .getFilesDir() + .then((data) => { + console.log('ImageKnife filesPath = ' + data) + this.filePath = data + this.appFilePath = data; + }) + .catch((error) => { + console.error('ImageKnife Failed to obtain the filesPath directory. Cause:' + error.message); + }) + }) + Button('featureAbility.getContext().getCacheDir()') + .margin({ top: 10 }) + .onClick(() => { + featureAbility.getContext() + .getCacheDir() + .then((data) => { + console.log('ImageKnife cachesPath = ' + data) + this.filePath = data + this.appCachePath = data + }) + .catch((error) => { + console.error('ImageKnife Failed to obtain the cachesPath directory. Cause:' + error.message); + }) + }) + Button('files目录创建Folder1和Folder2 验证statSync mkdirSync') + .margin({ top: 10 }) + .onClick(() => { + FileUtils.getInstance() + .createFolder(this.appFilePath + '/Folder1'); + FileUtils.getInstance() + .createFolder(this.appFilePath + '/Folder2'); + }) + Button('将media资源存入Folder1 验证writeSync mkdirSync createStreamSync') + .margin({ top: 10 }) + .onClick(() => { + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.gifSample').id,) + .then(data => { + console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data) + let arrayBuffer = this.typedArrayToBuffer(data); + FileUtils.getInstance().writeFile(this.appFilePath + '/Folder1/jpgSample.gif', arrayBuffer) + this.imageFile = 'file://' + this.appFilePath + '/Folder1/jpgSample.gif' + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + }) + Button('copy:Folder1至Folder2, 验证copyFileSync') + .margin({ top: 10 }) + .onClick(() => { + let filePath1 = this.appFilePath + '/Folder1/jpgSample.gif'; + let filePath2 = this.appFilePath + '/Folder2/jpgSample.gif'; + FileUtils.getInstance().createFolder(this.appFilePath + '/Folder2') + FileUtils.getInstance().copyFile(filePath1, filePath2); + this.imageFile = 'file://' + this.appFilePath + '/Folder2/jpgSample.gif' + }) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('显示空PixelMap') + .margin({ left: 10 }) + .onClick(() => { + this.normalPixelMap=true; + this.normalResource = false; + }) + Button('显示RES') + .margin({ left: 10 }) + .onClick(() => { + this.normalPixelMap=false; + this.normalResource = true; + }) + Button('显示String') + .margin({ left: 10 }) + .onClick(() => { + this.normalPixelMap=false; + this.normalResource = false; + }) + } + + + Image(this.normalPixelMap?this.imagePixelMap:(this.normalResource? this.imageRes:this.imageFile)) + .width(200) + .height(200) + .backgroundColor(Color.Pink) + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestMediaImage.ets b/entry/src/main/ets/MainAbility/pages/basicTestMediaImage.ets new file mode 100644 index 0000000..105926a --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestMediaImage.ets @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 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 featureAbility from '@ohos.ability.featureAbility'; +import {FileUtils} from '@ohos/imageknife' +import {FileTypeUtil} from '@ohos/imageknife' +import resourceManager from '@ohos.resourceManager'; +import {Base64} from '@ohos/imageknife' +import {PixelMapPack} from '@ohos/imageknife' +import {ParseImageUtil} from '@ohos/imageknife' + +@Entry +@Component +struct BasicTestMediaImage { + @State pixelMapPack:PixelMapPack= new PixelMapPack(); + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button('本地资源jpg') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let jpgPack = new PixelMapPack(); + jpgPack.pixelMap = pxielmap; + this.pixelMapPack = jpgPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源png') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.pngSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let pngPack = new PixelMapPack(); + pngPack.pixelMap = pxielmap; + this.pixelMapPack = pngPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源bmp') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.bmpSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let bmpPack = new PixelMapPack(); + bmpPack.pixelMap = pxielmap; + this.pixelMapPack = bmpPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源webp') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.webpSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let webpPack = new PixelMapPack(); + webpPack.pixelMap = pxielmap; + this.pixelMapPack = webpPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源gif') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.gifSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let gifPack = new PixelMapPack(); + gifPack.pixelMap = pxielmap; + this.pixelMapPack = gifPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + } + .margin({top:15}) + Image(this.pixelMapPack.pixelMap) + .width(300) + .height(300) + .backgroundColor(Color.Pink) + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestResourceManagerPage.ets b/entry/src/main/ets/MainAbility/pages/basicTestResourceManagerPage.ets new file mode 100644 index 0000000..3670561 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestResourceManagerPage.ets @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 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 featureAbility from '@ohos.ability.featureAbility'; +import {FileUtils} from '@ohos/imageknife' +import {FileTypeUtil} from '@ohos/imageknife' +import resourceManager from '@ohos.resourceManager'; +import {Base64} from '@ohos/imageknife' + +@Entry +@Component +struct BasicTestResourceManagerPage { + @State fileTypeStr: string = '解析后图片类型'; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.fileTypeStr).fontSize(20) + .width(300).height(200).backgroundColor(Color.Pink) + Button('getMedia解析一张jpg图片') + .margin({ top: 10 }) + .onClick(() => { + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample') + .id,) + .then(data => { + console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data) + let arrayBuffer = this.typedArrayToBuffer(data); + let filetypeUtil = new FileTypeUtil(); + let fileType = filetypeUtil.getFileType(arrayBuffer); + this.fileTypeStr = fileType; + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + }) + Button('getMediaBase64解析一张png图片') + .margin({ top: 10 }) + .onClick(() => { + resourceManager.getResourceManager() + .then(result => { + result.getMediaBase64($r('app.media.pngSample') + .id) + .then(data => { + console.log('ParseResClientBase64 - 本地加载资源 解析后数据data = ' + data) + let matchReg = ';base64,'; + var firstIndex = data.indexOf(matchReg); + data = data.substring(firstIndex + matchReg.length, data.length) + console.log('ParseResClientBase64 - 本地加载资源 解析后数据剔除非必要数据后data= ' + data) + let arrayBuffer = Base64.getInstance() + .decode(data); + let filetypeUtil = new FileTypeUtil(); + let fileType = filetypeUtil.getFileType(arrayBuffer); + this.fileTypeStr = fileType; + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + }) + + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/compressPage.ets b/entry/src/main/ets/MainAbility/pages/compressPage.ets new file mode 100644 index 0000000..9f32a0c --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/compressPage.ets @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2021 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 {ImageKnife} from '@ohos/imageknife' +import {PixelMapPack} from '@ohos/imageknife' +import {OnRenameListener} from '@ohos/imageknife' +import {OnCompressListener} from '@ohos/imageknife' + +@Entry +@Component +struct CompressPage { + @State mRPixelMap: PixelMapPack = new PixelMapPack(); + @State mFPixelMap: PixelMapPack = new PixelMapPack(); + @State mResultText: string= "压缩回调结果" + @State mResultPath: string= "压缩路径:" + @State mAsyncPath: string= "" + @State mAsyncPathHint: string= "" + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { + + Column() { + Column() { + Text("Resource image compress").fontColor(Color.Gray).fontSize(16); + Button() { + Text("同步压缩").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.compressAsyncRecource(); + }); + Scroll(){ + Text(this.mAsyncPathHint).fontSize(13) + } + .height(55) + .width(350) + + + Image(this.mAsyncPath) + .width(200) + .height(200) + .margin({ top: 10 }) + .backgroundColor(Color.Pink) + + Button() { + Text($r("app.string.resource_image_compress")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.cropressRecource(); + }); + Image(this.mRPixelMap.pixelMap) + .objectFit(ImageFit.None) + .width(200) + .height(200) + .margin({ top: 10 }) + Text(this.mResultText).fontColor(Color.Gray).fontSize(16); + Text(this.mResultPath).fontColor(Color.Gray).fontSize(16); + }.margin({ top: 10 }); + + Column() { + Text("file image compress").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.file_image_compress")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + }); + Image(this.mFPixelMap.pixelMap) + .objectFit(ImageFit.None) + .width(200) + .height(200) + .margin({ top: 10 }); + }.margin({ top: 10 }).visibility(Visibility.Hidden); + }.margin({ bottom: 30 }); + }.width('100%').height('100%'); + } + private compressAsyncRecource() { + var data = new Array(); + data.push($r('app.media.jpgSample')) + + console.info("asasd start compress") + ImageKnife.with() + .compressBuilder() + .load(data) + .ignoreBy(100) + .get() + .then((path)=>{ + this.mAsyncPathHint = path; + this.mAsyncPath='file://' + path; + }) + ; + console.info("asasd start compress end") + } + private cropressRecource() { + var data = new Array(); + data.push($r('app.media.photo5')) + var rename: OnRenameListener = { + reName() { + return "test_1.jpg"; + } + } + var that = this; + var listener: OnCompressListener = { + start() { + that.mResultText = "start" + console.info("asasd start") + }, + onScuccess(p: PixelMap, path: string) { + let pack = new PixelMapPack(); + pack.pixelMap = p; + that.mRPixelMap = pack; + console.info("asasd success path:" + this.mRPixelMap) + that.mResultText = "success"; + that.mResultPath = path; + }, + onError(s: string) { + console.info("asasd onError:" + s) + that.mResultText = "fail"; + } + } + console.info("asasd start compress") + ImageKnife.with() + .compressBuilder() + .load(data) + .ignoreBy(100) + .setRenameListener(rename) + .setCompressListener(listener) + .launch(); + console.info("asasd start compress end") + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/cropImagePage.ets b/entry/src/main/ets/MainAbility/pages/cropImagePage.ets new file mode 100644 index 0000000..bb0a02f --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/cropImagePage.ets @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 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 {CropImage} from '@ohos/imageknife' +import {CropOptions} from '@ohos/imageknife' +import {Crop} from '@ohos/imageknife' +import {RecourseProvider} from '@ohos/imageknife' +import {PixelMapPack} from '@ohos/imageknife' + + +@Component +@Entry +export struct CropImagePage { + private _resource: Resource= $r('app.media.demo_org'); + @State x: number = 0; + @State y: number = 0; + @State crop_size: number = 100; + @State colorRotate: number = 100; + @State _mCropPixelMap: PixelMapPack= new PixelMapPack(); + @State _mCropOptions: CropOptions= { + src: this._mCropPixelMap.pixelMap, + size: { + width: 200, + height: 200 + } + } + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text('原图').fontSize(20) + Image(this._resource).width(300).height(300).margin(10).objectFit(ImageFit.Contain); + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + TextInput({ text: '', placeholder: '裁X坐标' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.x = parseInt(value); + }) + .height(60) + .width(130) + .margin(2) + TextInput({ text: '', placeholder: '裁Y坐标' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.y = parseInt(value); + }) + .height(60) + .width(130) + .margin(2) + + TextInput({ text: '', placeholder: '裁剪长度' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.crop_size = parseInt(value); + }) + .height(60) + .width(130) + .margin(2) + + TextInput({ text: '', placeholder: '颜色比<1' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.colorRotate = parseFloat(value); + }) + .height(60) + .width(130) + .margin(2) + + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Button() { + Text('Crop').fontSize(15).fontColor(Color.White) + } + .height(35) + .width(150) + .onClick(() => { + var provider = new RecourseProvider(this._resource); + provider.openInternal((buffer) => { + Crop.crop(buffer, this.x, this.y, this.crop_size, this.crop_size, (error, data) => { + let result = new CropOptions(); + result.src=null; + this._mCropOptions=result; + setTimeout(() => { + this._mCropOptions = { + src: data, + size: { + width: 200, + height: 200 + } + } + },100) + + }, this.colorRotate); + }) + }).margin(10); + CropImage({ _mOptions: $_mCropOptions }) + }.width('100%').height('100%'); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/frescoImageTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/frescoImageTestCasePage.ets new file mode 100644 index 0000000..ed85957 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/frescoImageTestCasePage.ets @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct FrescoImageTestCasePage { + + @State progresshint:string = "输出加载百分比回调信息" + + + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + displayProgressListener:(value)=>{ + console.log("百分比value:"+value) + this.progresshint+="\n"+value; + + } + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + Scroll() { + Text(this.progresshint).fontSize(15) + }.width(300).height(200) + + + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/frescoLayerTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/frescoLayerTestCasePage.ets new file mode 100644 index 0000000..9569cfe --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/frescoLayerTestCasePage.ets @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2021 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 router from '@system.router'; + +@Entry +@Component +struct FrescoLayerTestCasePage { + + @Watch("watchV1") @State v1:Visibility = Visibility.Visible + @Watch("watchV2") @State v2:Visibility = Visibility.Visible + @Watch("watchV3") @State v3:Visibility = Visibility.Visible + + @State v1Width:string = "100%"; + @State v1Height:string = "100%"; + @State v2Width:string = "100%"; + @State v2Height:string = "100%"; + @State v3Width:string = "100%"; + @State v3Height:string = "100%"; + + + + + watchV1(){ + console.log("watchV1") + } + watchV2(){ + console.log("watchV2") + } + watchV3(){ + console.log("watchV3") + } + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Stack() { + Text('1%') + .fontSize(100) + .fontWeight(FontWeight.Bold) + .visibility(this.v1) + .width(this.v1Width) + .height(this.v1Height) + Image($r('app.media.icon_failed')) + .visibility(this.v2) + .width(this.v2Width) + .height(this.v2Height) + Image($r('app.media.jpgSample')) + .visibility(this.v3) + .width(this.v3Width) + .height(this.v3Height) + } + .width(200) + .height(200) + + Button("显示第一个组件") + .onClick(()=>{ + this.v1 = Visibility.Visible; + this.v2 = Visibility.Hidden; + this.v3 = Visibility.Hidden; + + animateTo({duration:500,curve:Curve.Linear},()=>{ + this.v1Width = "100%"; + this.v1Height = "100%"; + + this.v2Width = "0%"; + this.v2Height = "0%"; + + this.v3Width = "0%"; + this.v3Height = "0%"; + }) + + + }) + Button("显示第二个组件") + .onClick(()=>{ + this.v2 = Visibility.Visible; + this.v1 = Visibility.Hidden; + this.v3 = Visibility.Hidden; + + animateTo({duration:500,curve:Curve.Linear},()=>{ + this.v2Width = "100%"; + this.v2Height = "100%"; + + this.v1Width = "0%"; + this.v1Height = "0%"; + + this.v3Width = "0%"; + this.v3Height = "0%"; + }) + }) + Button("显示第三个组件") + .onClick(()=>{ + this.v3 = Visibility.Visible; + this.v2 = Visibility.Hidden; + this.v1 = Visibility.Hidden; + + animateTo({duration:500,curve:Curve.Linear},()=>{ + this.v3Width = "100%"; + this.v3Height = "100%"; + + this.v2Width = "0%"; + this.v2Height = "0%"; + + this.v1Width = "0%"; + this.v1Height = "0%"; + }) + }) + + } + } + .width('100%') + .height('100%') + } + + + + +} + diff --git a/entry/src/main/ets/MainAbility/pages/frescoRetryTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/frescoRetryTestCasePage.ets new file mode 100644 index 0000000..a251039 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/frescoRetryTestCasePage.ets @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct FrescoImageTestCasePage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/testRetryxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/index.ets b/entry/src/main/ets/MainAbility/pages/index.ets new file mode 100644 index 0000000..e966fb1 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/index.ets @@ -0,0 +1,175 @@ +/* + * Copyright (C) 1521 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 router from '@system.router'; +import {Pngj} from '@ohos/imageknife' + + +@Entry +@Component +struct Index { + @State hint1:string = '启用网络模拟加载替换网络加载' + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("OHOS基础接口测试列表").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试元能力") + .onClick(() => { + console.log("测试元能力子系统") + router.push({ uri: "pages/basicTestFeatureAbilityPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试文件") + .onClick(() => { + console.log("测试文件子系统") + router.push({ uri: "pages/basicTestFileIOPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试全球化") + .onClick(() => { + console.log("测试全球化子系统") + router.push({ uri: "pages/basicTestResourceManagerPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试媒体") + .onClick(() => { + console.log("测试媒体子系统") + router.push({ uri: "pages/basicTestMediaImage" }); + }).margin({ top: 5, left: 3 }) + + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试图片切换功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试本地加载") + .onClick(() => { + console.log("测试bmp,webp,jpg,png本地加载 页面跳转") + router.push({ uri: "pages/loadResourceTestCasePage" }); + }).margin({ top: 5, left: 3 }) + Button("测试图片切换") + .onClick(() => { + console.log("测试ImageKnifeComponent所有图片切换") + router.push({ uri: "pages/testImageKnifeOptionChangedPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试thumbnail") + .onClick(() => { + console.log("测试ImageKnifeComponent thumbnail") + router.push({ uri: "pages/testImageKnifeOptionChangedPage2" }); + }).margin({ top: 5, left: 3 }) + + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试存储(1级 2级缓存)功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试一级内存缓存") + .onClick(() => { + console.log("测试一级内存缓存") + router.push({ uri: "pages/storageTestLruCache" }); + }).margin({ top: 5, left: 3 }) + Button("测试二级内存缓存") + .onClick(() => { + console.log("测试二级内存缓存") + router.push({ uri: "pages/storageTestDiskLruCache" }); + }).margin({ top: 5, left: 3 }) + + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试占位图 失败占位图 功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试占位图") + .onClick(() => { + console.log("测试占位图") + router.push({ uri: "pages/loadNetworkTestCasePage" }); + }).margin({ top: 5, left: 3 }) + Button("测试失败占位图") + .onClick(() => { + console.log("测试失败占位图") + router.push({ uri: "pages/showErrorholderTestCasePage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试预加载 gif静态动态切换功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试预加载") + .onClick(() => { + console.log("测试预加载") + router.push({ uri: "pages/testPreloadPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试gif静态动态切换") + .onClick(() => { + console.log("测试gif静态动态切换") + router.push({ uri: "pages/testGifDontAnimatePage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试图片变换 图片压缩 功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试图片变换") + .onClick(() => { + console.log("测试图片变换") + router.push({ uri: "pages/transformPixelMapPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试图片压缩") + .onClick(() => { + console.log("测试图片压缩") + router.push({ uri: "pages/compressPage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + + Button("测试所有缓存信息输出") + .onClick(() => { + console.log("pages/testAllCacheInfoPage 页面跳转") + router.push({ uri: "pages/testAllCacheInfoPage" }); + }).margin({ top: 15 }) + + Button("测试fresco部分AR") + .onClick(() => { + console.log("pages/indexFresco 页面跳转") + router.push({ uri: "pages/indexFresco" }); + }).margin({ top: 15 }) + Button("测试pngj") + .onClick(() => { + console.log("pages/pngjTestCasePage 页面跳转") + router.push({ uri: "pages/pngjTestCasePage" }); + }).margin({ top: 15 }) + Button("测试图片的裁剪") + .onClick(() => { + console.log("pages/cropImagePage 页面跳转") + router.push({ uri: "pages/cropImagePage" }); + }).margin({ top: 15 }) + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + } + + onBackPress() { + let cache = ImageKnife.getMemoryCache(); + cache.print() + } +} +var ImageKnife; +var defaultTemp = globalThis.exports.default +if (defaultTemp != undefined) { + ImageKnife = defaultTemp.data.imageKnife; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/indexFresco.ets b/entry/src/main/ets/MainAbility/pages/indexFresco.ets new file mode 100644 index 0000000..b130c16 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/indexFresco.ets @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 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 router from '@system.router'; + +@Entry +@Component +struct IndexFresco { + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试控件隐藏与展示和动画") + .onClick(() => { + router.push({ uri: "pages/frescoLayerTestCasePage" }); + }).margin({ top: 15 }) + Button("测试自定义控件FrescoImage的加载百分比") + .onClick(() => { + router.push({ uri: "pages/frescoImageTestCasePage" }); + }).margin({ top: 15 }) + Button("测试自定义控件FrescoImage重试Retry") + .onClick(() => { + router.push({ uri: "pages/frescoRetryTestCasePage" }); + }).margin({ top: 15 }) + + + + } + } + .width('100%') + .height('100%') + } + + + + +} + diff --git a/entry/src/main/ets/MainAbility/pages/loadNetworkTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/loadNetworkTestCasePage.ets new file mode 100644 index 0000000..db7c604 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/loadNetworkTestCasePage.ets @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct LoadNetworkTestCasePage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/loadResourceTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/loadResourceTestCasePage.ets new file mode 100644 index 0000000..709b71c --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/loadResourceTestCasePage.ets @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct LoadResourceTestCasePage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, +// placeholderSrc: $r('app.media.icon_loading'), +// errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, +// placeholderSrc: $r('app.media.icon_loading'), +// errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, +// placeholderSrc: $r('app.media.icon_loading'), +// errorholderSrc: $r('app.media.icon_failed'), + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) +// ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + } + } + .width('100%') + .height('100%') + } +} + diff --git a/entry/src/main/ets/MainAbility/pages/pngjTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/pngjTestCasePage.ets new file mode 100644 index 0000000..4fa289e --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/pngjTestCasePage.ets @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2021 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 router from '@system.router'; +import {Pngj} from '@ohos/imageknife' +import resourceManager from '@ohos.resourceManager'; +import {FileUtils} from '@ohos/imageknife' +import featureability from '@ohos.ability.featureAbility' +import ArkWorker from '@ohos.worker' +@Entry +@Component +struct PngjTestCasePage { + pngSource: ArrayBuffer = new ArrayBuffer(0); + rootFolder: string = ''; + @State hint1: string = 'readPngImageInfo内容展示' + @State hint2: string = 'readPngImage内容展示' + @State hint3: string = 'writePngWithString内容展示' + @State hint4: string = 'writePngWithString内容展示' + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text('pngj接口测试列表').fontSize(20) + + Button('点击获取Png图片buffer').fontSize(20) + .onClick(() => { + + featureability.getContext() + .getFilesDir() + .then((data) => { + this.rootFolder = data; + }) + .catch((err) => { + console.log('点击获取Png图片buffer 路径获取失败 err:' + err) + }) + + + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.Tomato').id) + .then(data => { + this.pngSource = FileUtils.getInstance().uint8ArrayToBuffer(data); + }) + .catch(err => { + console.log('点击获取Png图片buffer err=' + err) + }) + }) + }) + + + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('测试readPngImageInfo') + .onClick(() => { + let pngj = new Pngj(); + pngj.readPngImageInfo(this.pngSource, (sender, value) => { + this.hint1 = JSON.stringify(value); + }) + }).margin({ top: 5, left: 10 }) + Button('测试readPngImage') + .onClick(() => { + let pngj = new Pngj(); + pngj.readPngImage(this.pngSource, (sender, value) => { + this.hint2 = 'img with=' + value.width + ' img height=' + value.height + + ' img depth=' + value.depth + ' img ctype=' + value.ctype + console.log('png data =' + value.data); + }) + }).margin({ top: 5, left: 10 }) + Button('测试writePngWithString') + .onClick(() => { + let pngj = new Pngj(); + pngj.writePngWithString('hello world', this.pngSource, (sender, value) => { + + FileUtils.getInstance().createFileProcess( + this.rootFolder + '/pngj', + this.rootFolder + '/pngj/newPng.png', + value) + let png1 = new Uint8Array(value) + this.hint3 = 'png写入后长度' + png1.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng.png' + '保存后使用2进制查看数据是否新增' + }) + }).margin({ top: 5, left: 10 }) + Button('测试writePng') + .onClick(() => { + let pngj = new Pngj(); + pngj.writePng(this.pngSource, (sender, value) => { + FileUtils.getInstance().createFileProcess( + this.rootFolder + '/pngj', + this.rootFolder + '/pngj/newPng2.png', + value) + let png2 = new Uint8Array(value) + this.hint4 = 'png2未写入长度' + png2.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng2.png' + '保存后使用2进制查看数据是否新增' + }) + }).margin({ top: 5, left: 10 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('测试readPngImageInfo') + .onClick(() => { + let pngj = new Pngj(); + pngj.readPngImageInfo(this.pngSource, (sender, value) => { + this.hint1 = JSON.stringify(value); + }) + }).margin({ top: 5, left: 10 }) + Button('测试readPngImageAsync') + .onClick(() => { + let pngj = new Pngj(); + let worker = new ArkWorker.Worker('workers/worker1.js', { type: 'classic', name: 'readPngImageAsync'}) + pngj.readPngImageAsync(worker, this.pngSource, (sender, value) => { + this.pngSource = sender + this.hint2 = 'img with=' + value.width + ' img height=' + value.height + + ' img depth=' + value.depth + ' img ctype=' + value.ctype + }) + }).margin({ top: 5, left: 10 }) + Button('测试writePngWithStringAsync') + .onClick(() => { + let pngj = new Pngj(); + let worker = new ArkWorker.Worker('workers/worker1.js', { type: 'classic', name: 'writePngWithStringAsync'}) + pngj.writePngWithStringAsync(worker, 'hello world', this.pngSource, (sender, value) => { + this.pngSource = sender + FileUtils.getInstance().createFileProcess( + this.rootFolder + '/pngj', + this.rootFolder + '/pngj/newPng.png', + value) + let png1 = new Uint8Array(value) + this.hint3 = 'png写入后长度' + png1.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng.png' + '保存后使用2进制查看数据是否新增' + }) + }).margin({ top: 5, left: 10 }) + Button('测试writePngAsync') + .onClick(() => { + let pngj = new Pngj(); + let worker = new ArkWorker.Worker('workers/worker1.js', { type: 'classic', name: 'writePngAsync'}) + pngj.writePngAsync(worker, this.pngSource, (sender, value) => { + this.pngSource = sender + FileUtils.getInstance().createFileProcess( + this.rootFolder + '/pngj', + this.rootFolder + '/pngj/newPng2.png', + value) + let png2 = new Uint8Array(value) + this.hint4 = 'png2未写入长度' + png2.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng2.png' + '保存后使用2进制查看数据是否新增' + }) + }).margin({ top: 5, left: 10 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text(this.hint1) + .width('100%') + .height(120) + Text(this.hint2) + .width('100%') + .height(120) + Text(this.hint3) + .width('100%') + .height(120) + Text(this.hint4) + .width('100%') + .height(120) + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/showErrorholderTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/showErrorholderTestCasePage.ets new file mode 100644 index 0000000..5f86bfe --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/showErrorholderTestCasePage.ets @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct ShowErrorholderTestCasePage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: "https://hbimg.huabanimg.com/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/storageTestDiskLruCache.ets b/entry/src/main/ets/MainAbility/pages/storageTestDiskLruCache.ets new file mode 100644 index 0000000..24fa508 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/storageTestDiskLruCache.ets @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeOption} from '@ohos/imageknife' +import {RequestOption} from '@ohos/imageknife' +import {ImageKnifeData} from '@ohos/imageknife' +import {PixelMapPack} from '@ohos/imageknife' + + + + +@Entry +@Component +struct StorageTestDiskLruCache { + @Watch('watchImageKnifeOption') @State imageKnifeOption: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State imageKnifePixelMapPack: PixelMapPack = new PixelMapPack(); + @State imageKnifeResource: Resource = $r('app.media.icon_loading') + @State imageKnifeString: string = "" + @State normalPixelMap: boolean = false; + @State normalResource: boolean = true; + previousData: ImageKnifeData = null; + nowData: ImageKnifeData = null; + @State logText: string = "打印日志结果"; + + + watchImageKnifeOption() { + this.imageKnifeExecute(); + } + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("ImageKnife测试DiskLruCache能力") + .backgroundColor(Color.Blue) + Button("替换ImageKnife默认DiskLruCache并设置大小1M") + .onClick(() => { + DiskImageKnife.replaceDiskLruCache(1 * 1024 * 1024) + }).margin({top:15, bottom:15}) + + Button("替换ImageKnife默认DiskLruCache并设置大小30M") + .onClick(() => { + DiskImageKnife.replaceDiskLruCache(30 * 1024 * 1024) + }).margin({top:15, bottom:15}) + + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("加载jpg网络图") + .onClick(() => { + this.imageKnifeOption = { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({ top: 5, left: 10 }) + Button("加载png网络图") + .onClick(() => { + this.imageKnifeOption = { + loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({ top: 5, left: 10 }) + Button("加载webp网络图") + .onClick(() => { + this.imageKnifeOption = { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({ top: 5, left: 10 }) + Button("加载bmp网络图") + .onClick(() => { + this.imageKnifeOption = { + loadSrc: "https://img-blog.csdn.net/20140514114029140", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({ top: 5, left: 10 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + + Image(this.normalPixelMap ? this.imageKnifePixelMapPack.pixelMap : (this.normalResource ? this.imageKnifeResource : this.imageKnifeString)) + .width(this.imageKnifeOption.size ? this.imageKnifeOption.size.width : '100%') + .height(this.imageKnifeOption.size ? this.imageKnifeOption.size.height : '100%') + .objectFit(this.imageKnifeOption.imageFit ? this.imageKnifeOption.imageFit : ImageFit.Fill) + .backgroundColor(this.imageKnifeOption.backgroundColor ? this.imageKnifeOption.backgroundColor : Color.White) + .margin(this.imageKnifeOption.margin ? this.imageKnifeOption.margin : { left: 0, top: 0, right: 0, bottom: 0 }) + + + + Scroll() { + Text(this.logText).fontSize(15) + }.width(300).height(300).margin({top:20}).backgroundColor(Color.Pink) + + + } + } + .width('100%') + .height('100%') + } + + +// imageKnife 第一次启动和数据刷新后重新发送请求 + imageKnifeExecute() { + let request = new RequestOption(); + request.load(this.imageKnifeOption.loadSrc) + .addListener((err, data) => { + this.imageKnifeChangeSource(data) + return false; + }) + if (this.imageKnifeOption.placeholderSrc) { + request.placeholder(this.imageKnifeOption.placeholderSrc, (data) => { + this.imageKnifeChangeSource(data) + }) + } + if (this.imageKnifeOption.errorholderSrc) { + request.errorholder(this.imageKnifeOption.errorholderSrc, (data) => { + this.imageKnifeChangeSource(data) + }) + } + if (this.imageKnifeOption.transformations) { + request.transforms(this.imageKnifeOption.transformations) + } + + if (this.imageKnifeOption.size) { + request.setImageViewSize(this.imageKnifeOption.size) + } + + if (this.imageKnifeOption.onlyRetrieveFromCache) { + request.retrieveDataFromCache(this.imageKnifeOption.onlyRetrieveFromCache) + } + + if (this.imageKnifeOption.isCacheable) { + request.skipMemoryCache(!this.imageKnifeOption.isCacheable) + } + + if (this.imageKnifeOption.strategy) { + request.diskCacheStrategy(this.imageKnifeOption.strategy) + } + + if (this.imageKnifeOption.dontAnimateFlag) { + request.dontAnimate() + } + if (this.imageKnifeOption.allCacheInfoCallback) { + request.addAllCacheInfoCallback(this.imageKnifeOption.allCacheInfoCallback) + } + + DiskImageKnife.call(request); + } + + imageKnifeChangeSource(data:ImageKnifeData) { + this.imageKnifeSpecialFixed(data); + + //查看mImageKnife中的DiskLruCache + let disk = DiskImageKnife.getDiskMemoryCache(); + let showDisk = '' + disk.foreachDiskLruCache((value, key, map) => { + showDisk += "key=" + key + "&value=" + value; + }) + this.logText = "日志结果:" + showDisk; + } + + imageKnifeSpecialFixed(data:ImageKnifeData) { + if (this.nowData) { + this.previousData = this.nowData; + this.nowData = data; + if (data.isPixelMap()) { + // PixelMap + console.log("ImageKnife占位图输出=PixelMap") + if (this.previousData.isSvg()) { + console.log("ImageKnife占位图输出=PixelMap 上一个是SVG") + this.normalPixelMap = true; + this.normalResource = true; + + let pixelMapPack1 = new PixelMapPack(); + + this.imageKnifePixelMapPack = pixelMapPack1; + + setTimeout(() => { + let pixelMapPack2 = new PixelMapPack(); + pixelMapPack2.pixelMap = data.imageKnifeValue as PixelMap; + this.imageKnifePixelMapPack = pixelMapPack2; + }, 100) + } else { + this.normalPixelMap = true; + this.normalResource = true; + + let pixelMapPack3 = new PixelMapPack(); + pixelMapPack3.pixelMap = data.imageKnifeValue as PixelMap; + + this.imageKnifePixelMapPack = pixelMapPack3; + } + } + else if (data.isString()) { + // String + console.log("imageKnifevalue=" + JSON.stringify(data)); + console.log("ImageKnife占位图输出=String") + if (this.previousData.isSvg()) { + + console.log("data.imageKnifeValue=" + JSON.stringify(data.imageKnifeValue)) + console.log("ImageKnife占位图输出=String 拥有上一个图片类型 上一个是SVG") + this.normalPixelMap = false; + this.normalResource = false; + let firstIndex = (data.imageKnifeValue as string).indexOf(DiskImageKnife.getSvgAndGifFolder()); + console.log("firstIndex=" + firstIndex); + let suffix = (data.imageKnifeValue as string).substring(firstIndex, (data.imageKnifeValue as string).length) + console.log("suffix =" + suffix); + let imageKnifeNeedStr = 'internal://app/' + suffix; + this.imageKnifeString = imageKnifeNeedStr; + } else { + console.log("data.imageKnifeValue=" + JSON.stringify(data.imageKnifeValue)) + console.log("ImageKnife占位图输出=String 拥有上一个图片类型 上一个不是SVG") + + this.normalPixelMap = false; + this.normalResource = false; + let firstIndex = (data.imageKnifeValue as string).indexOf(DiskImageKnife.getSvgAndGifFolder()); + console.log("firstIndex=" + firstIndex); + let suffix = (data.imageKnifeValue as string).substring(firstIndex, (data.imageKnifeValue as string).length) + console.log("suffix =" + suffix); + let imageKnifeNeedStr = 'internal://app/' + suffix; + this.imageKnifeString = imageKnifeNeedStr; + } + } else if (data.isResource()) { + console.log("ImageKnife占位图输出=Resource") + if (this.previousData.isSvg()) { + console.log("ImageKnife占位图输出=Resource 上一个是SVG") + this.normalPixelMap = false; + this.normalResource = true; + this.imageKnifeResource = data.imageKnifeValue as Resource; + } else { + this.normalPixelMap = false; + this.normalResource = true; + this.imageKnifeResource = data.imageKnifeValue as Resource; + } + } else { + console.log("ImageKnife占位图输出=数据错误") + } + + } else { + this.nowData = data; + if (data.isPixelMap()) { + // PixelMap + console.log("ImageKnife占位图输出=PixelMap") + this.normalPixelMap = true; + this.normalResource = true; + + let pixelMapPack4 = new PixelMapPack(); + pixelMapPack4.pixelMap = data.imageKnifeValue as PixelMap; + + this.imageKnifePixelMapPack = pixelMapPack4; + } + else if (data.isString()) { + // String + console.log("data.imageKnifeValue=" + JSON.stringify(data.imageKnifeValue)) + console.log("ImageKnife占位图输出=String 没有上一个图片类型") + this.normalPixelMap = false; + this.normalResource = false; + let firstIndex = (data.imageKnifeValue as string).indexOf(DiskImageKnife.getSvgAndGifFolder()); + console.log("firstIndex=" + firstIndex); + let suffix = (data.imageKnifeValue as string).substring(firstIndex, (data.imageKnifeValue as string).length) + console.log("suffix =" + suffix); + let imageKnifeNeedStr = 'internal://app/' + suffix; + this.imageKnifeString = imageKnifeNeedStr; + } else if (data.isResource()) { + console.log("ImageKnife占位图输出=Resource") + this.normalPixelMap = false; + this.normalResource = true; + this.imageKnifeResource = data.imageKnifeValue as Resource; + } else { + console.log("ImageKnife占位图输出=数据错误") + } + + } + } + +//函数在自定义组件析构消耗之前执行。 +//不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。 + aboutToDisappear() { + + } +//当此页面显示时触发一次。包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 + onPageShow() { + } +//当此页面消失时触发一次。包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 + onPageHide() { + } + +// 当用户点击返回按钮时触发,,仅@Entry修饰的自定义组件生效。 +//返回true表示页面自己处理返回逻辑, 不进行页面路由。 +//返回false表示使用默认的返回逻辑。 +//不返回值会作为false处理。 + onBackPress() { + + } +} +var DiskImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/storageTestLruCache.ets b/entry/src/main/ets/MainAbility/pages/storageTestLruCache.ets new file mode 100644 index 0000000..8837ad5 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/storageTestLruCache.ets @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 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 featureAbility from '@ohos.ability.featureAbility'; +import {LruCache} from '@ohos/imageknife' + +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值 +} + +@Entry +@Component +struct StorageTestLruCache { + @State logText:string = "打印日志结果"; + @State nowNumText:string = "显示输入的数据"; + mLruCache:LruCache = new LruCache(5); + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("默认创建一个容量为5的LruCache") + .backgroundColor(Color.Blue) + Button("随机存入一个数字0-9") + .onClick(()=>{ + let randomNum = getRandomInt(0,10); + this.nowNumText = ''+randomNum; + this.mLruCache.put(randomNum+"",randomNum+"") + this.logText = "日志结果:"+this.mLruCache.print(); + }) .margin({top:20}) + + Button(this.nowNumText) + .margin({top:20}) + + Scroll() { + Text(this.logText).fontSize(15) + }.width(300).height(200).margin({top:20}).backgroundColor(Color.Pink) + + } + .width('100%') + .height('100%') + } + } +} diff --git a/entry/src/main/ets/MainAbility/pages/testAllCacheInfoPage.ets b/entry/src/main/ets/MainAbility/pages/testAllCacheInfoPage.ets new file mode 100644 index 0000000..b474d96 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testAllCacheInfoPage.ets @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2021 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 '@ohos/imageknife' +import {AllCacheInfo,IAllCacheInfoCallback} from '@ohos/imageknife' +import {ImageKnifeComponent} from '@ohos/imageknife' +import {TransformType} from '@ohos/imageknife' +import {PixelMapPack} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestAllCacheInfoPage { + @State nativePixelMap: PixelMapPack = new PixelMapPack(); + @State networkPixelMap: PixelMapPack = new PixelMapPack(); + allCacheInfoCallback1 =(allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback imageknifecomponent1 memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback imageknifecomponent1 resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback imageknifecomponent1 data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo3 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + } + allCacheInfoCallback2 =(allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback imageknifecomponent2 memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback imageknifecomponent2 resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback imageknifecomponent2 data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo4 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + } + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{top:15}, + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + }, + allCacheInfoCallback:this.allCacheInfoCallback1 + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{top:15}, + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + }, + allCacheInfoCallback:this.allCacheInfoCallback2 + }; + imageKnifeComponentAngle:number = 90; + + @State cacheinfo1:string = "观察本地资源获取缓存信息输出" + @State cacheinfo2:string = "观察网络资源获取缓存信息输出" + @State cacheinfo3:string = "观察ImageKnifeComponent本地缓存输出" + @State cacheinfo4:string = "观察ImageKnifeComponent网络缓存输出" + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("加载本地资源获取缓存信息") + .width(300).height(25) + .onClick(() => { + this.testAllCacheInfoNative(); + }).margin({ top: 15 }) + Scroll() { + Text(this.cacheinfo1).fontSize(15) + }.width(300).height(200) + Image(this.nativePixelMap.pixelMap) + .width(300) + .height(300) + .objectFit(ImageFit.Contain) + .backgroundColor(Color.Green) + .margin({ top: 15 }) + Button("加载网络资源获取缓存信息").width(300).height(25) + .onClick(() => { + this.testAllCacheInfoNetwork(); + }).margin({ top: 15 }) + Scroll() { + Text(this.cacheinfo2).fontSize(15) + }.width(300).height(200) + Image(this.networkPixelMap.pixelMap) + .width(300) + .height(300) + .objectFit(ImageFit.Contain) + .backgroundColor(Color.Green) + .margin({ top: 15 }) + + Button("ImageKnifeComponent加载本地资源获取缓存信息").width(300).height(25) + .onClick(() => { + this.imageKnifeComponentAngle = this.imageKnifeComponentAngle + 45; + this.imageKnifeOption1 = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { top: 15 }, + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:this.imageKnifeComponentAngle + }, + allCacheInfoCallback:this.allCacheInfoCallback1 + }; + }).margin({ top: 15 }) + Scroll() { + Text(this.cacheinfo3).fontSize(15) + }.width(300).height(200) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + + Button("ImageKnifeComponent加载网络资源获取缓存信息").width(300).height(25) + .onClick(() => { + this.imageKnifeComponentAngle = this.imageKnifeComponentAngle + 45; + this.imageKnifeOption2 = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { top: 15 }, + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:this.imageKnifeComponentAngle + }, + allCacheInfoCallback:this.allCacheInfoCallback2 + }; + }) + Scroll() { + Text(this.cacheinfo4).fontSize(15) + }.width(300).height(200) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + + } + + private testAllCacheInfoNative() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load($r('app.media.pngSample')) + .setImageViewSize({width:300,height:300}) + .addListener((err, data) => { + let pack = new PixelMapPack(); + pack.pixelMap = data.imageKnifeValue as PixelMap;; + this.nativePixelMap = pack; + return false; + }).addAllCacheInfoCallback((allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo1 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + }) + ImageKnife.call(imageKnifeOption); + } + + private testAllCacheInfoNetwork() { + let imageKnifeOption2 = new RequestOption(); + imageKnifeOption2.load("https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp") + .addListener((err, data) => { + let pack = new PixelMapPack(); + pack.pixelMap = data.imageKnifeValue as PixelMap; + this.networkPixelMap = pack; + console.log("imageknife2 图片2 赋值!") + return false; + }).addAllCacheInfoCallback((allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo2 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + }) + .setImageViewSize({width:300,height:300}) + .rotateImage(180) + ImageKnife.call(imageKnifeOption2); + } +} + + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testAllTypeImageKnifeComponentPage.ets b/entry/src/main/ets/MainAbility/pages/testAllTypeImageKnifeComponentPage.ets new file mode 100644 index 0000000..bc11d40 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testAllTypeImageKnifeComponentPage.ets @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestAllTypeImageKnifeComponentPage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: $r('app.media.svgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + @State imageKnifeOption5: ImageKnifeOption = + { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption5 }) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testAllTypeNativeImagePage.ets b/entry/src/main/ets/MainAbility/pages/testAllTypeNativeImagePage.ets new file mode 100644 index 0000000..a946d49 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testAllTypeNativeImagePage.ets @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestAllTypeNativeImagePage { + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Image($r('app.media.jpgSample')) + .width(300) + .height(300) + Image($r('app.media.pngSample')) + .width(300) + .height(300) + Image($r('app.media.webpSample')) + .width(300) + .height(300) + Image($r('app.media.svgSample')) + .width(300) + .height(300) + Image($r('app.media.bmpSample')) + .width(300) + .height(300) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testGifDontAnimatePage.ets b/entry/src/main/ets/MainAbility/pages/testGifDontAnimatePage.ets new file mode 100644 index 0000000..a6a1c2f --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testGifDontAnimatePage.ets @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestGifDontAnimatePage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15} + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button('本地资源gif') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15} + } + + }).margin({left:15}).backgroundColor(Color.Grey) + Button('本地资源gif静态') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15}, + dontAnimateFlag:true + } + + }).margin({left:15}).backgroundColor(Color.Grey) + } + .margin({top:15}) + Flex({direction:FlexDirection.Row}){ + Button('网络资源gif') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15} + }; + }).margin({left:15}).backgroundColor(Color.Grey) + Button('网络资源gif静态') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15}, + dontAnimateFlag:true + }; + }).margin({left:15}).backgroundColor(Color.Grey) + } + .margin({top:15}) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log('aboutToAppear()') + } +} + + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testImageKnifeOptionChangedPage.ets b/entry/src/main/ets/MainAbility/pages/testImageKnifeOptionChangedPage.ets new file mode 100644 index 0000000..7ed0f20 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testImageKnifeOptionChangedPage.ets @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestImageKnifeOptionChangedPage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button('本地资源jpg') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源png') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源bmp') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源webp') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源svg') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.svgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源gif') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + };; + + }).margin({left:5}).backgroundColor(Color.Blue) + } + .margin({top:15}) + Flex({direction:FlexDirection.Row}){ + Button('网络资源jpg') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源png') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://img-blog.csdnimg.cn/20191215043500229.png', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源bmp') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://img-blog.csdn.net/20140514114029140', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源webp') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源svg') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/30df266a-485e-411e-b178-b9fb1d8e0748.svg', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源gif') + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + } + .margin({top:15}) + + Text('下面为展示图片区域').margin({top:5}) + Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + }.width(400).height(400).margin({top:10}).backgroundColor(Color.Pink) + + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log('aboutToAppear()') + } +} + + diff --git a/entry/src/main/ets/MainAbility/pages/testImageKnifeOptionChangedPage2.ets b/entry/src/main/ets/MainAbility/pages/testImageKnifeOptionChangedPage2.ets new file mode 100644 index 0000000..5503b4b --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testImageKnifeOptionChangedPage2.ets @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestImageKnifeOptionChangedPage2 { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button("网络资源jpg") + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button("网络资源png") + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button("网络资源bmp") + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: "https://img-blog.csdn.net/20140514114029140", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button("网络资源webp") + .onClick(()=>{ + this.imageKnifeOption1 = { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + } + .margin({top:15}) + + Text("下面为展示图片区域").margin({top:5}) + Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + }.width(400).height(400).margin({top:10}).backgroundColor(Color.Pink) + + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testMultiThreadWorkerPage2.ets b/entry/src/main/ets/MainAbility/pages/testMultiThreadWorkerPage2.ets new file mode 100644 index 0000000..c0a93c2 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testMultiThreadWorkerPage2.ets @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 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 ArkWorker from '@ohos.worker' + +@Entry +@Component +struct TestMultiThreadWorkerPage2 { + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("创建Worker向子线程发送携带Arraybuffer数据") + .margin({ top: 20 }) + .onClick(() => { + let worker = new ArkWorker.Worker("workers/worker1.js", { type: "classic", name: "zhangsan" }) + worker.onerror = function (data) { + console.info("worker:: receive onerror " + data.lineno + ", msg = " + data.message + ", filename = " + data.filename + ", colno = " + data.colno); + } + + worker.onmessageerror = function (e) { + console.log("worker:: receive onmessageerror "); + } + + worker.onexit = function () { + console.log("worker:: receive onexit"); + } + + worker.onmessage = function (e) { + var data = e.data; + switch (data.type) { + case "normal": + console.log("worker:: onmessage " + data.data); + break; + case "buffer": + console.log("worker:: receive buffer length is " + data.data.byteLength); + break; + default: + console.log("worker:: worker.js receive unknow type"); + break + } + worker.terminate(); + } + + console.log("worker:: start post buffer"); + + let uint8array = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]) + let buffer = uint8array.buffer.slice(uint8array.byteOffset, uint8array.byteLength + uint8array.byteOffset) + + var obj = { type: "buffer", data: buffer }; + console.log("worker:: before post, buffer length is " + obj.data.byteLength); + worker.postMessage(obj, [buffer]); + console.log("worker:: after post, buffer length is " + obj.data.byteLength); + console.info("end post buffer"); + + + }); + + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/testPreloadPage.ets b/entry/src/main/ets/MainAbility/pages/testPreloadPage.ets new file mode 100644 index 0000000..c7edc86 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testPreloadPage.ets @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RequestOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' + +@Entry +@Component +struct TestPreloadPage { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State imageKnifeOption5: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State imageKnifeOption6: ImageKnifeOption = + { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源gif') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.gifSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源gif 出现错误! err=' + err) + } else { + console.log('预加载本地资源gif成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源gif') + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('预加载本地资源gif静态') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.gifSample')) + .setImageViewSize({ width: 300, height: 300 }) + .dontAnimate() + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源gif静态 出现错误! err=' + err) + } else { + console.log('预加载本地资源gif静态成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('本地资源gif静态') + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 }, + dontAnimateFlag: true + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源gif') + .onClick(() => { + let request = new RequestOption(); + request.load('https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源gif 出现错误! err=' + err) + } else { + console.log('预加载网络资源gif成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源gif') + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('预加载网络资源gif静态') + .onClick(() => { + let request = new RequestOption(); + request.load('https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700') + .setImageViewSize({ width: 300, height: 300 }) + .dontAnimate() + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源gif静态 出现错误! err=' + err) + } else { + console.log('预加载网络资源gif静态成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源gif静态') + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 }, + dontAnimateFlag: true + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源svg') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.svgSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源svg 出现错误! err=' + err) + } else { + console.log('预加载本地资源svg成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源svg') + .onClick(() => { + this.imageKnifeOption2 = { + loadSrc: $r('app.media.svgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源svg') + .onClick(() => { + let request = new RequestOption(); + request.load('http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/4dc8463e-8ac6-4eb4-862c-783bf486a242.svg') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源gif 出现错误! err=' + err) + } else { + console.log('预加载网络资源gif成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源svg') + .onClick(() => { + this.imageKnifeOption2 = { + loadSrc: 'http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/4dc8463e-8ac6-4eb4-862c-783bf486a242.svg', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源webp') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.webpSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源webp 出现错误! err=' + err) + } else { + console.log('预加载本地资源webp成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源webp') + .onClick(() => { + this.imageKnifeOption3 = { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源webp') + .onClick(() => { + let request = new RequestOption(); + request.load('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源webp 出现错误! err=' + err) + } else { + console.log('预加载网络资源webp成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源webp') + .onClick(() => { + this.imageKnifeOption3 = { + loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源bmp') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.bmpSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源bmp 出现错误! err=' + err) + } else { + console.log('预加载本地资源bmp成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源bmp') + .onClick(() => { + this.imageKnifeOption4 = { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源bmp') + .onClick(() => { + let request = new RequestOption(); + request.load('https://img-blog.csdn.net/20140514114029140') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源bmp 出现错误! err=' + err) + } else { + console.log('预加载网络资源bmp成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源bmp') + .onClick(() => { + this.imageKnifeOption4 = { + loadSrc: 'https://img-blog.csdn.net/20140514114029140', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源png') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.pngSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源png 出现错误! err=' + err) + } else { + console.log('预加载本地资源png成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源png') + .onClick(() => { + this.imageKnifeOption5 = { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源png') + .onClick(() => { + let request = new RequestOption(); + request.load('https://img-blog.csdnimg.cn/20191215043500229.png') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源bmp 出现错误! err=' + err) + } else { + console.log('预加载网络资源bmp成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源png') + .onClick(() => { + this.imageKnifeOption5 = { + loadSrc: 'https://img-blog.csdnimg.cn/20191215043500229.png', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption5 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源jpg') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.jpgSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源jpg 出现错误! err=' + err) + } else { + console.log('预加载本地资源jpg成功! imageKnifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源jpg') + .onClick(() => { + this.imageKnifeOption6 = { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源jpg') + .onClick(() => { + let request = new RequestOption(); + request.load('https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源jpg 出现错误! err=' + err) + } else { + console.log('预加载网络资源jpg成功! imageknifedata=' + JSON.stringify(data)) + } + return false; + }) + ImageKnife.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源jpg') + .onClick(() => { + this.imageKnifeOption6 = { + loadSrc: 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption6 }) + + } + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log('aboutToAppear()') + } +} + + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testResourceManagerPage.ets b/entry/src/main/ets/MainAbility/pages/testResourceManagerPage.ets new file mode 100644 index 0000000..e70cb69 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testResourceManagerPage.ets @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 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 '@ohos/imageknife' +import{NONE} from '@ohos/imageknife' +import {Base64} from '@ohos/imageknife' +import {FileTypeUtil} from '@ohos/imageknife' +import {ImageKnifeData} from '@ohos/imageknife' + +import resourceManager from '@ohos.resourceManager'; +@Entry +@Component +struct TestResourceManagerPage { + + @State imageKnifeData: ImageKnifeData = new ImageKnifeData(); + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.imageKnifeData.imageKnifeType) + .fontSize(20) + .backgroundColor(Color.Pink) + .width(300) + .height(300) + Button("点击执行ResourceManager的Base64") + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMediaBase64($r('app.media.jpgSample').id) + .then(data => { + console.log("jpgSample data=" + data) + let matchUseLess = ";base64,"; + var matchUseLessIndex = data.indexOf(matchUseLess) + data = data.substring(matchUseLessIndex + matchUseLess.length, data.length) + console.log("jpgSample prepare save data=" + data) + let arrayBuffer = Base64.getInstance().decode(data); + console.log("arrayBuffer data=" + arrayBuffer) + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arrayBuffer); + console.log("typeValue data=" + typeValue) + let newImageKnifeData = new ImageKnifeData(); + newImageKnifeData.imageKnifeType = typeValue + + this.imageKnifeData = newImageKnifeData; + }) + + }) + }) + Button("点击执行ResourceManager的非Base64") + .margin({top:25}) + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.pngSample').id) + .then(data => { + console.log("arrayBuffer data=" + data) + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(this.typedArrayToBuffer(data)); + console.log("typeValue data=" + typeValue) + let newImageKnifeData = new ImageKnifeData(); + newImageKnifeData.imageKnifeType = typeValue + this.imageKnifeData = newImageKnifeData; + }) + + }) + }) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } + +} + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/transformPixelMapPage.ets b/entry/src/main/ets/MainAbility/pages/transformPixelMapPage.ets new file mode 100644 index 0000000..995e35b --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/transformPixelMapPage.ets @@ -0,0 +1,879 @@ +/* + * Copyright (C) 2021 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 '@ohos/imageknife' +import {CropCircleTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' +import {CropCircleWithBorderTransformation} from '@ohos/imageknife/src/main/ets/components/imageknife/transform/CropCircleWithBorderTransformation' +import {RotateImageTransformation} from '@ohos/imageknife' +import {CropSquareTransformation} from '@ohos/imageknife' +import {CropTransformation} from '@ohos/imageknife' +import {CropType} from '@ohos/imageknife' +import {GrayscaleTransformation} from '@ohos/imageknife' +import {BrightnessFilterTransformation} from '@ohos/imageknife' +import {ContrastFilterTransformation} from '@ohos/imageknife' +import {InvertFilterTransformation} from '@ohos/imageknife' +import {SepiaFilterTransformation} from '@ohos/imageknife' +import {SketchFilterTransformation} from '@ohos/imageknife' +import {BlurTransformation} from '@ohos/imageknife' +import {PixelationFilterTransformation} from '@ohos/imageknife' +import {MaskTransformation} from '@ohos/imageknife' +import {SwirlFilterTransformation} from '@ohos/imageknife' +import {PixelMapPack} from '@ohos/imageknife' + +/** + * PixelMap transform 示例 + */ +let mRotate: number = 0; +//let mUrl = "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB" +let mUrl = $r('app.media.check_big'); + +@Entry +@Component +struct TransformPixelMapPage { + @State url: string= ""; + @State mCropPixelMap: PixelMapPack= new PixelMapPack(); + @State mRoundPixelMap: PixelMapPack= new PixelMapPack(); + @State mCirclePixelMap: PixelMapPack= new PixelMapPack(); + @State mCircleBorderPixelMap: PixelMapPack= new PixelMapPack(); + @State mRotatePixelMap: PixelMapPack= new PixelMapPack(); + @State mSquarePixelMap: PixelMapPack= new PixelMapPack(); + @State mClipTopPixelMap: PixelMapPack= new PixelMapPack(); + @State mClipCenterPixelMap: PixelMapPack= new PixelMapPack(); + @State mClipBottomPixelMap: PixelMapPack= new PixelMapPack(); + @State mGrayscalePixelMap: PixelMapPack= new PixelMapPack(); + @State mBrightnessPixelMap: PixelMapPack= new PixelMapPack(); + @State mContrastPixelMap: PixelMapPack= new PixelMapPack(); + @State mInvertPixelMap: PixelMapPack= new PixelMapPack(); + @State mSepiaPixelMap: PixelMapPack= new PixelMapPack(); + @State mSketchPixelMap: PixelMapPack= new PixelMapPack(); + @State mBlurPixelMap: PixelMapPack= new PixelMapPack(); + @State mPixelPixelMap: PixelMapPack= new PixelMapPack(); + @State mSwirlPixelMap: PixelMapPack= new PixelMapPack(); + @State mMaskPixelMap: PixelMapPack= new PixelMapPack(); + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { + Scroll() { + Column() { + Column() { + Text("基础变换").fontColor(Color.Gray).fontSize(16); + Row({ space: 1 }) { + Button() { + Text("CenterCrop").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(100) + .onClick(() => { + this.centerCrop(); + }); + Button() { + Text("CenterInside").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(100) + .onClick(() => { + this.centerInside(); + }); + Button() { + Text("fitCenter").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(100) + .onClick(() => { + this.fitCenter(); + }); + }.margin({ top: 10 }) + + Image(this.mCropPixelMap.pixelMap) + .objectFit(ImageFit.None) + .width(100) + .height(100) + .backgroundColor("#23d1de") + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("RoundedCornersTransformation").fontColor(Color.Gray).fontSize(16); + Row({ space: 1 }) { + Button() { + Text($r("app.string.left_top_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(10, 0, 0, 0); + }); + Button() { + Text($r("app.string.r_top_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(0, 0, 10, 0); + }); + Button() { + Text($r("app.string.left_bottom_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(0, 10, 0, 0); + }); + Button() { + Text($r("app.string.r_bottom_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(0, 0, 0, 10); + }); + Button("All") + .fontSize(13) + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(10, 10, 10, 10); + }); + }.margin({ top: 10 }) + + Image(this.mRoundPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropCircleTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_circle")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.circleTransformation(); + }); + Image(this.mCirclePixelMap.pixelMap) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropCircleWithBorderTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_circle_border")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.circleBorderTransformation(5); + }); + Image(this.mCircleBorderPixelMap.pixelMap) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("RotateImageTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_rotate")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + mRotate += 45; + if (mRotate > 360) { + mRotate = 0; + } + this.transformRotate(mRotate); + }); + Image(this.mRotatePixelMap.pixelMap) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropSquareTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_square")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.transformSquare(); + }); + Image(this.mSquarePixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropTransformation").fontColor(Color.Gray).fontSize(16); + Row({ space: 1 }) { + Button() { + Text($r("app.string.trans_clip_top")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.clipPixelMap(25, 25, CropType.TOP); + }); + Button() { + Text($r("app.string.trans_clip_center")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.clipPixelMap(25, 25, CropType.CENTER); + }); + Button() { + Text($r("app.string.trans_clip_bottom")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.clipPixelMap(25, 25, CropType.BOTTOM); + }); + }.margin({ top: 10 }) + + Row({ space: 1 }) { + Image(this.mClipTopPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + Image(this.mClipCenterPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + Image(this.mClipBottomPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + } + }.margin({ top: 10 }); + + Column() { + Text("GrayscaleTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_grayscale")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.grayscalePixelMap(); + }); + Image(this.mGrayscalePixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("BrightnessFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Brightness")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.brightnessPixelMap(0.8); + }); + Image(this.mBrightnessPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("ContrastFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Contrast")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.contrastPixelMap(4); + }); + Image(this.mContrastPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("InvertFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Invert")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.invertPixelMap(); + }); + Image(this.mInvertPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("SepiaFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Sepia")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.sepiaPixelMap(); + }); + Image(this.mSepiaPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("SketchFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Sketch")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.sketchPixelMap(); + }); + Image(this.mSketchPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("BlurTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_blur")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.blurHandlePixelMap(20); + }); + Image(this.mBlurPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + + Column() { + Text("PixelationFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_pixel")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.pixelHandlePixelMap(20); + }); + Image(this.mPixelPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("SwirlFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text("图片Swirl").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.swirlHandlePixelMap(); + }); + Image(this.mSwirlPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("MaskTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text("图片mask").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.maskHandlePixelMap($r('app.media.mask_starfish')); + }); + Image(this.mMaskPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + }.margin({ bottom: 30 }); + + } + }.width('100%').height('100%'); + } + + aboutToAppear() { + + } + +/** + * centerCrop + */ + centerCrop() { + var imageKnifeOption = new RequestOption(); + imageKnifeOption.load($r('app.media.photo5')) + // imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mCropPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.imageKnifeValue as PixelMap; + this.mCropPixelMap = result2; + }, 100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .centerCrop(); + ImageKnife.call(imageKnifeOption); + } + +/** + * centerInside + */ + centerInside() { + var imageKnifeOption = new RequestOption(); + imageKnifeOption.load($r('app.media.Back')) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mCropPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.imageKnifeValue as PixelMap; + this.mCropPixelMap = result2; + }, 100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .centerInside(); + ImageKnife.call(imageKnifeOption); + } + +/** + * centerInside + */ + fitCenter() { + var imageKnifeOption = new RequestOption() + imageKnifeOption.load($r('app.media.Back')) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mCropPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.imageKnifeValue as PixelMap; + this.mCropPixelMap = result2; + }, 100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .fitCenter(); + ImageKnife.call(imageKnifeOption); + } +/** + * 圆角设置 + */ + roundedCornersTransformation(top_left: number, + bottom_left: number, top_right: number, bottom_right: number) { + + var imageKnifeOption = new RequestOption(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mRoundPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.imageKnifeValue as PixelMap; + this.mRoundPixelMap = result2; + }, 100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .roundedCorners({ top_left: top_left, top_right: top_right, bottom_left: bottom_left, bottom_right: bottom_right }) + ImageKnife.call(imageKnifeOption); + } + +/** + * 裁剪圆 + */ + circleTransformation() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mCirclePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .cropCircle() + ImageKnife.call(imageKnifeOption); + } + +/** + * 圆环裁剪 + */ + circleBorderTransformation(border: number) { + let imageKnifeOption = new RequestOption(); + var circleTransformation = new CropCircleWithBorderTransformation(border, + { r_color: 255, g_color: 204, b_color: 204 }); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mCircleBorderPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .cropCircleWithBorder(border, + { r_color: 255, g_color: 204, b_color: 204 }) + ImageKnife.call(imageKnifeOption); + } + +/** + * 旋转 + */ + transformRotate(angled: number) { + let imageKnifeOption = new RequestOption(); + var transformation = new RotateImageTransformation(angled); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mRotatePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .rotateImage(angled) + ImageKnife.call(imageKnifeOption); + } + +/** + * 正方形裁剪 + */ + transformSquare() { + let imageKnifeOption = new RequestOption(); + var transformation = new CropSquareTransformation(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mSquarePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .cropSquare() + ImageKnife.call(imageKnifeOption); + } + +/** + * 区域裁剪 + */ + clipPixelMap(width: number, height: number, cropType: CropType) { + let imageKnifeOption = new RequestOption(); + var transformation = new CropTransformation(width, height, cropType); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + if (cropType == CropType.TOP) { + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mClipTopPixelMap = result; + } else if (cropType == CropType.CENTER) { + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mClipCenterPixelMap = result; + } else if (cropType == CropType.BOTTOM) { + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mClipBottomPixelMap = result; + } + return false; + }) + .setImageViewSize({ width: width, height: height }) + .skipMemoryCache(true) + .crop(width, height, cropType) + ImageKnife.call(imageKnifeOption); + + } + +/** + * 灰度 + */ + grayscalePixelMap() { + let imageKnifeOption = new RequestOption(); + var transformation = new GrayscaleTransformation(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mGrayscalePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .grayscale() + ImageKnife.call(imageKnifeOption); + + } + +/** + *亮度b + */ + brightnessPixelMap(brightness: number) { + let imageKnifeOption = new RequestOption(); + var transformation = new BrightnessFilterTransformation(brightness); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mBrightnessPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .brightnessFilter(brightness) + ImageKnife.call(imageKnifeOption); + + } + +/** + *对比度 + */ + contrastPixelMap(contrast: number) { + let imageKnifeOption = new RequestOption(); + var transformation = new ContrastFilterTransformation(contrast); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mContrastPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .contrastFilter(contrast) + ImageKnife.call(imageKnifeOption); + + } + +/** + *反转处理 + */ + invertPixelMap() { + let imageKnifeOption = new RequestOption(); + var transformation = new InvertFilterTransformation(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mInvertPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .invertFilter() + ImageKnife.call(imageKnifeOption); + + } + +/** + *照片老旧出来(黑褐色) + */ + sepiaPixelMap() { + let imageKnifeOption = new RequestOption(); + var transformation = new SepiaFilterTransformation(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mSepiaPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .sepiaFilter() + ImageKnife.call(imageKnifeOption); + + } + +/** + *素描 + */ + sketchPixelMap() { + let imageKnifeOption = new RequestOption(); + var transformation = new SketchFilterTransformation(); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mSketchPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .sketchFilter() + ImageKnife.call(imageKnifeOption); + + } + +/** + *模糊 + */ + blurHandlePixelMap(radius: number) { + let imageKnifeOption = new RequestOption(); + var transformation = new BlurTransformation(radius); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mBlurPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .blur(radius) + ImageKnife.call(imageKnifeOption); + + } +/** + *马赛克 + */ + pixelHandlePixelMap(pixel: number) { + let imageKnifeOption = new RequestOption(); + var transformation = new PixelationFilterTransformation(pixel); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mPixelPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .pixelationFilter(pixel) + ImageKnife.call(imageKnifeOption); + + } + +/** + *扭曲 + */ + swirlHandlePixelMap() { + let imageKnifeOption = new RequestOption(); + var transformation = new SwirlFilterTransformation(80); + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mSwirlPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .swirlFilter(80) + // .diskCacheStrategy(new NONE()) + ImageKnife.call(imageKnifeOption); + + } +/** + *遮罩 + */ + maskHandlePixelMap(maskResource: Resource) { + let imageKnifeOption = new RequestOption(); + var transformation = new MaskTransformation(maskResource); + // imageKnifeOption.load($r('app.media.photo6')) + imageKnifeOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap = data.imageKnifeValue as PixelMap; + this.mMaskPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(200), height: vp2px(200) }) + .skipMemoryCache(true) + .mask(maskResource) + // .diskCacheStrategy(new NONE()) + ImageKnife.call(imageKnifeOption); + + } +} + +var ImageKnife = globalThis.exports.default.data.imageKnife \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/transformTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/transformTestCasePage.ets new file mode 100644 index 0000000..5f73e41 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/transformTestCasePage.ets @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 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 dibistributed 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 {ImageKnifeComponent} from '@ohos/imageknife' +import {ImageKnifeOption} from '@ohos/imageknife' +import {RotateImageTransformation} from '@ohos/imageknife' +import {RoundedCornersTransformation} from '@ohos/imageknife' +import {TransformType} from '@ohos/imageknife' + +@Entry +@Component +struct Index { + @State imageKnifeOption1: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + @State imageKnifeOption2: ImageKnifeOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RoundedCornersTransformation, + roundedCorners:{ + top_left: 30, + top_right: 30, + bottom_left: 30, + bottom_right: 30 + } + } + + }; + @State imageKnifeOption3: ImageKnifeOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RotateImageTransformation, + rotateImage:180 + } + }; + @State imageKnifeOption4: ImageKnifeOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transform: { + transformType:TransformType.RoundedCornersTransformation, + roundedCorners:{ + top_left: 130, + top_right: 130, + bottom_left: 130, + bottom_right: 130 + } + } + }; + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption1 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption2 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption3 }) + ImageKnifeComponent({ imageKnifeOption: $imageKnifeOption4 }) + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + diff --git a/entry/src/main/ets/MainAbility/workers/worker1.js b/entry/src/main/ets/MainAbility/workers/worker1.js new file mode 100644 index 0000000..19464a1 --- /dev/null +++ b/entry/src/main/ets/MainAbility/workers/worker1.js @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 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 arkWorker from '@ohos.worker'; +import {handler} from '@ohos/imageknife/src/main/ets/components/imageknife/pngj/PngWork' + +arkWorker.parentPort.onmessage = handler + +//import arkWorker from '@ohos.worker'; +//import {UPNG} from '@ohos/imageknife/src/main/ets/components/imageknife/pngj/UPNG' +// +//arkWorker.parentPort.onmessage = function (e) { +// var data = e.data; +// switch (data.type) { +// case 'readPngImageAsync': +// console.log('readPngImageAsync worker start 1') +// var png = UPNG.decode(data.data); +// let array = png.data; +// let arrayData = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) +// png.data = arrayData; +// let dataObj = { type: 'readPngImageAsync', data: png, receiver: data.data} +// arkWorker.parentPort.postMessage(dataObj, [png.data, data.data]); +// console.log('readPngImageAsync worker to main 1') +// break; +// case 'writePngWithStringAsync': +// console.log('writePngWithStringAsync worker start 1') +// let addInfo = data.info; +// let pngDecode = UPNG.decode(data.data); +// let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0) +// let dataObj2 = { type: 'writePngWithStringAsync', data: newPng, receiver: data.data} +// arkWorker.parentPort.postMessage(dataObj2, [newPng, data.data]); +// console.log('writePngWithStringAsync worker to main 1') +// break; +// case 'writePngAsync': +// console.log('writePngAsync worker start 1') +// let pngDecode3 = UPNG.decode(data.data); +// let newPng3 = UPNG.encode(UPNG.toRGBA8(pngDecode3), pngDecode3.width, pngDecode3.height, 0) +// let dataObj3 = { type: 'writePngAsync', data: newPng3, receiver: data.data} +// arkWorker.parentPort.postMessage(dataObj3, [newPng3, data.data]); +// console.log('writePngAsync worker to main 1') +// break; +// case 'normal': +// arkWorker.parentPort.postMessage(data); +// break; +// case 'error': +// throw new Error('123'); +// break; +// case 'buffer': +// let uint8Array = new Uint8Array(data.data); +// arkWorker.parentPort.postMessage(data, [data.data]); +// +// break; +// default: +// +// break +// } +//} + diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000..6146fec --- /dev/null +++ b/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "test_color", + "value": "#3d2564" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000..e847707 --- /dev/null +++ b/entry/src/main/resources/base/element/string.json @@ -0,0 +1,104 @@ +{ + "string": [ + { + "name": "ImageKnife_OHOS", + "value": "ImageKnife_OHOS" + }, + { + "name": "mainability_description", + "value": "ETS_Empty Ability" + }, + { + "name": "left_top_corner", + "value": "左上角" + }, + { + "name": "r_top_corner", + "value": "右上角" + }, + { + "name": "left_bottom_corner", + "value": "左下角" + }, + { + "name": "r_bottom_corner", + "value": "右下角" + }, + { + "name": "trans_circle", + "value": "裁剪-圆" + }, + { + "name": "trans_circle_border", + "value": "裁剪-圆环" + }, + { + "name": "trans_rotate", + "value": "旋转" + }, + { + "name": "trans_square", + "value": "正方形裁剪" + }, + { + "name": "trans_clip_top", + "value": "上方裁剪" + }, + { + "name": "trans_clip_center", + "value": "中间裁剪" + }, + { + "name": "trans_clip_bottom", + "value": "底下裁剪" + }, + { + "name": "resource_image_compress", + "value": "资源图片压缩" + }, + { + "name": "file_image_compress", + "value": "本地文件图片压缩" + }, + { + "name": "image_transform", + "value": "图片变换" + }, + { + "name": "image_compress", + "value": "图片压缩" + }, + { + "name": "image_grayscale", + "value": "灰度处理" + }, + { + "name": "image_Brightness", + "value": "亮度处理" + }, + { + "name": "image_Contrast", + "value": "对比度处理" + }, + { + "name": "image_Invert", + "value": "反转处理" + }, + { + "name": "image_Sepia", + "value": "黑褐色处理" + }, + { + "name": "image_Sketch", + "value": "素描处理" + }, + { + "name": "image_blur", + "value": "模糊处理" + }, + { + "name": "image_pixel", + "value": "马赛克处理" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/Avocado.png b/entry/src/main/resources/base/media/Avocado.png new file mode 100644 index 0000000..33dfdd7 Binary files /dev/null and b/entry/src/main/resources/base/media/Avocado.png differ diff --git a/entry/src/main/resources/base/media/Back.png b/entry/src/main/resources/base/media/Back.png new file mode 100644 index 0000000..2b0806c Binary files /dev/null and b/entry/src/main/resources/base/media/Back.png differ diff --git a/entry/src/main/resources/base/media/Blueberry.png b/entry/src/main/resources/base/media/Blueberry.png new file mode 100644 index 0000000..a07421e Binary files /dev/null and b/entry/src/main/resources/base/media/Blueberry.png differ diff --git a/entry/src/main/resources/base/media/Crab.png b/entry/src/main/resources/base/media/Crab.png new file mode 100644 index 0000000..b71a627 Binary files /dev/null and b/entry/src/main/resources/base/media/Crab.png differ diff --git a/entry/src/main/resources/base/media/Cucumber.png b/entry/src/main/resources/base/media/Cucumber.png new file mode 100644 index 0000000..6dd7477 Binary files /dev/null and b/entry/src/main/resources/base/media/Cucumber.png differ diff --git a/entry/src/main/resources/base/media/IceCream.png b/entry/src/main/resources/base/media/IceCream.png new file mode 100644 index 0000000..13a8674 Binary files /dev/null and b/entry/src/main/resources/base/media/IceCream.png differ diff --git a/entry/src/main/resources/base/media/Index.png b/entry/src/main/resources/base/media/Index.png new file mode 100644 index 0000000..5c57223 Binary files /dev/null and b/entry/src/main/resources/base/media/Index.png differ diff --git a/entry/src/main/resources/base/media/IndexGray.png b/entry/src/main/resources/base/media/IndexGray.png new file mode 100644 index 0000000..942eceb Binary files /dev/null and b/entry/src/main/resources/base/media/IndexGray.png differ diff --git a/entry/src/main/resources/base/media/Kiwi.png b/entry/src/main/resources/base/media/Kiwi.png new file mode 100644 index 0000000..0b4b6ed Binary files /dev/null and b/entry/src/main/resources/base/media/Kiwi.png differ diff --git a/entry/src/main/resources/base/media/Mushroom.png b/entry/src/main/resources/base/media/Mushroom.png new file mode 100644 index 0000000..3e984ee Binary files /dev/null and b/entry/src/main/resources/base/media/Mushroom.png differ diff --git a/entry/src/main/resources/base/media/NoRecord.png b/entry/src/main/resources/base/media/NoRecord.png new file mode 100644 index 0000000..724b2e1 Binary files /dev/null and b/entry/src/main/resources/base/media/NoRecord.png differ diff --git a/entry/src/main/resources/base/media/Onion.png b/entry/src/main/resources/base/media/Onion.png new file mode 100644 index 0000000..9c1c5a8 Binary files /dev/null and b/entry/src/main/resources/base/media/Onion.png differ diff --git a/entry/src/main/resources/base/media/Pitaya.png b/entry/src/main/resources/base/media/Pitaya.png new file mode 100644 index 0000000..2770b34 Binary files /dev/null and b/entry/src/main/resources/base/media/Pitaya.png differ diff --git a/entry/src/main/resources/base/media/Statistics.png b/entry/src/main/resources/base/media/Statistics.png new file mode 100644 index 0000000..28099ad Binary files /dev/null and b/entry/src/main/resources/base/media/Statistics.png differ diff --git a/entry/src/main/resources/base/media/StatisticsGray.png b/entry/src/main/resources/base/media/StatisticsGray.png new file mode 100644 index 0000000..018f9c3 Binary files /dev/null and b/entry/src/main/resources/base/media/StatisticsGray.png differ diff --git a/entry/src/main/resources/base/media/Strawberry.png b/entry/src/main/resources/base/media/Strawberry.png new file mode 100644 index 0000000..a8d2394 Binary files /dev/null and b/entry/src/main/resources/base/media/Strawberry.png differ diff --git a/entry/src/main/resources/base/media/Switch.png b/entry/src/main/resources/base/media/Switch.png new file mode 100644 index 0000000..51aa0fc Binary files /dev/null and b/entry/src/main/resources/base/media/Switch.png differ diff --git a/entry/src/main/resources/base/media/Tomato.png b/entry/src/main/resources/base/media/Tomato.png new file mode 100644 index 0000000..93ad983 Binary files /dev/null and b/entry/src/main/resources/base/media/Tomato.png differ diff --git a/entry/src/main/resources/base/media/Walnut.png b/entry/src/main/resources/base/media/Walnut.png new file mode 100644 index 0000000..8187a42 Binary files /dev/null and b/entry/src/main/resources/base/media/Walnut.png differ diff --git a/entry/src/main/resources/base/media/baidu.png b/entry/src/main/resources/base/media/baidu.png new file mode 100644 index 0000000..510f111 Binary files /dev/null and b/entry/src/main/resources/base/media/baidu.png differ diff --git a/entry/src/main/resources/base/media/bmpNet.bmp b/entry/src/main/resources/base/media/bmpNet.bmp new file mode 100644 index 0000000..a343af9 Binary files /dev/null and b/entry/src/main/resources/base/media/bmpNet.bmp differ diff --git a/entry/src/main/resources/base/media/bmpSample.bmp b/entry/src/main/resources/base/media/bmpSample.bmp new file mode 100644 index 0000000..94b0a91 Binary files /dev/null and b/entry/src/main/resources/base/media/bmpSample.bmp differ diff --git a/entry/src/main/resources/base/media/check_big.png b/entry/src/main/resources/base/media/check_big.png new file mode 100644 index 0000000..3262131 Binary files /dev/null and b/entry/src/main/resources/base/media/check_big.png differ diff --git a/entry/src/main/resources/base/media/check_big_test.png b/entry/src/main/resources/base/media/check_big_test.png new file mode 100644 index 0000000..64059ab Binary files /dev/null and b/entry/src/main/resources/base/media/check_big_test.png differ diff --git a/entry/src/main/resources/base/media/delete.png b/entry/src/main/resources/base/media/delete.png new file mode 100644 index 0000000..f3c3705 Binary files /dev/null and b/entry/src/main/resources/base/media/delete.png differ diff --git a/entry/src/main/resources/base/media/deletebackground.png b/entry/src/main/resources/base/media/deletebackground.png new file mode 100644 index 0000000..59490bd Binary files /dev/null and b/entry/src/main/resources/base/media/deletebackground.png differ diff --git a/entry/src/main/resources/base/media/demo_org.jpg b/entry/src/main/resources/base/media/demo_org.jpg new file mode 100644 index 0000000..8374680 Binary files /dev/null and b/entry/src/main/resources/base/media/demo_org.jpg differ diff --git a/entry/src/main/resources/base/media/gifNet.gif b/entry/src/main/resources/base/media/gifNet.gif new file mode 100644 index 0000000..511f667 Binary files /dev/null and b/entry/src/main/resources/base/media/gifNet.gif differ diff --git a/entry/src/main/resources/base/media/gifSample.gif b/entry/src/main/resources/base/media/gifSample.gif new file mode 100644 index 0000000..6dab2d1 Binary files /dev/null and b/entry/src/main/resources/base/media/gifSample.gif differ diff --git a/entry/src/main/resources/base/media/icon.png b/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000..ce307a8 Binary files /dev/null and b/entry/src/main/resources/base/media/icon.png differ diff --git a/entry/src/main/resources/base/media/icon_failed.png b/entry/src/main/resources/base/media/icon_failed.png new file mode 100644 index 0000000..6eadcfd Binary files /dev/null and b/entry/src/main/resources/base/media/icon_failed.png differ diff --git a/entry/src/main/resources/base/media/icon_loading.png b/entry/src/main/resources/base/media/icon_loading.png new file mode 100644 index 0000000..6eb4e9a Binary files /dev/null and b/entry/src/main/resources/base/media/icon_loading.png differ diff --git a/entry/src/main/resources/base/media/icon_retry.jpg b/entry/src/main/resources/base/media/icon_retry.jpg new file mode 100644 index 0000000..19911b6 Binary files /dev/null and b/entry/src/main/resources/base/media/icon_retry.jpg differ diff --git a/entry/src/main/resources/base/media/jpgNet.jpg b/entry/src/main/resources/base/media/jpgNet.jpg new file mode 100644 index 0000000..f430168 Binary files /dev/null and b/entry/src/main/resources/base/media/jpgNet.jpg differ diff --git a/entry/src/main/resources/base/media/jpgSample.jpg b/entry/src/main/resources/base/media/jpgSample.jpg new file mode 100644 index 0000000..dad4caa Binary files /dev/null and b/entry/src/main/resources/base/media/jpgSample.jpg differ diff --git a/entry/src/main/resources/base/media/mask_starfish.png b/entry/src/main/resources/base/media/mask_starfish.png new file mode 100644 index 0000000..3cb4bcc Binary files /dev/null and b/entry/src/main/resources/base/media/mask_starfish.png differ diff --git a/entry/src/main/resources/base/media/photo5.jpg b/entry/src/main/resources/base/media/photo5.jpg new file mode 100644 index 0000000..ccf589d Binary files /dev/null and b/entry/src/main/resources/base/media/photo5.jpg differ diff --git a/entry/src/main/resources/base/media/photo6.jpg b/entry/src/main/resources/base/media/photo6.jpg new file mode 100644 index 0000000..aed456f Binary files /dev/null and b/entry/src/main/resources/base/media/photo6.jpg differ diff --git a/entry/src/main/resources/base/media/picture1.jpg b/entry/src/main/resources/base/media/picture1.jpg new file mode 100644 index 0000000..8374680 Binary files /dev/null and b/entry/src/main/resources/base/media/picture1.jpg differ diff --git a/entry/src/main/resources/base/media/pngNet.png b/entry/src/main/resources/base/media/pngNet.png new file mode 100644 index 0000000..cba0bad Binary files /dev/null and b/entry/src/main/resources/base/media/pngNet.png differ diff --git a/entry/src/main/resources/base/media/pngSample.png b/entry/src/main/resources/base/media/pngSample.png new file mode 100644 index 0000000..bda2612 Binary files /dev/null and b/entry/src/main/resources/base/media/pngSample.png differ diff --git a/entry/src/main/resources/base/media/svgNet.svg b/entry/src/main/resources/base/media/svgNet.svg new file mode 100644 index 0000000..cee5c31 --- /dev/null +++ b/entry/src/main/resources/base/media/svgNet.svg @@ -0,0 +1,17 @@ + + + 蒙版 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/svgSample.svg b/entry/src/main/resources/base/media/svgSample.svg new file mode 100644 index 0000000..063bd30 --- /dev/null +++ b/entry/src/main/resources/base/media/svgSample.svg @@ -0,0 +1,26 @@ + + + 蒙版 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/svgSample2.svg b/entry/src/main/resources/base/media/svgSample2.svg new file mode 100644 index 0000000..cee5c31 --- /dev/null +++ b/entry/src/main/resources/base/media/svgSample2.svg @@ -0,0 +1,17 @@ + + + 蒙版 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/tiger.jpg b/entry/src/main/resources/base/media/tiger.jpg new file mode 100644 index 0000000..bf4f798 Binary files /dev/null and b/entry/src/main/resources/base/media/tiger.jpg differ diff --git a/entry/src/main/resources/base/media/transformBase.bmp b/entry/src/main/resources/base/media/transformBase.bmp new file mode 100644 index 0000000..cee0930 Binary files /dev/null and b/entry/src/main/resources/base/media/transformBase.bmp differ diff --git a/entry/src/main/resources/base/media/user.txt b/entry/src/main/resources/base/media/user.txt new file mode 100644 index 0000000..710e1c6 --- /dev/null +++ b/entry/src/main/resources/base/media/user.txt @@ -0,0 +1,9 @@ +syntax = "proto3"; +package User; + +message UserLoginResponse{ + string sessionId = 1; + string userPrivilege = 2; + int64 servTimesTemp = 3; + string formatTimestamp = 4; +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/webpSample.webp b/entry/src/main/resources/base/media/webpSample.webp new file mode 100644 index 0000000..bcf109c Binary files /dev/null and b/entry/src/main/resources/base/media/webpSample.webp differ diff --git a/entry/src/ohosTest/config.json b/entry/src/ohosTest/config.json new file mode 100644 index 0000000..b97e860 --- /dev/null +++ b/entry/src/ohosTest/config.json @@ -0,0 +1,68 @@ +{ + "app": { + "bundleName": "com.example.imageknifegiteepro", + "vendor": "example", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.entry_test", + "name": ".entry_test", + "mainAbility": ".TestAbility", + "srcPath": "", + "deviceType": [ + "phone", + "tablet" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry_test", + "moduleType": "feature", + "installationFree": false + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "visible": true, + "srcPath": "TestAbility", + "name": ".TestAbility", + "srcLanguage": "ets", + "icon": "$media:icon", + "description": "$string:description_TestAbility", + "formsEnabled": false, + "label": "$string:entry_TestAbility", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "mode": { + "syntax": "ets", + "type": "pageAbility" + }, + "pages": [ + "pages/index" + ], + "name": ".TestAbility", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/TestAbility/app.ets b/entry/src/ohosTest/ets/TestAbility/app.ets new file mode 100644 index 0000000..4db82cf --- /dev/null +++ b/entry/src/ohosTest/ets/TestAbility/app.ets @@ -0,0 +1,18 @@ +import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' +import { Hypium } from 'hypium/index' +import testsuite from '../test/List.test' + +export default { + onCreate() { + console.info('Application onCreate') + var abilityDelegator: any + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() + var abilityDelegatorArguments: any + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() + console.info('start run testcase!!!') + Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) + }, + onDestroy() { + console.info('Application onDestroy') + }, +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/TestAbility/pages/index.ets b/entry/src/ohosTest/ets/TestAbility/pages/index.ets new file mode 100644 index 0000000..539eb9a --- /dev/null +++ b/entry/src/ohosTest/ets/TestAbility/pages/index.ets @@ -0,0 +1,35 @@ +import router from '@system.router'; + +@Entry +@Component +struct Index { + aboutToAppear() { + console.info('TestAbility index aboutToAppear') + } + + @State message: string = 'Hello World' + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button() { + Text('next page') + .fontSize(20) + .fontWeight(FontWeight.Bold) + }.type(ButtonType.Capsule) + .margin({ + top: 20 + }) + .backgroundColor('#0D9FFB') + .width('35%') + .height('5%') + .onClick(()=>{ + }) + } + .width('100%') + } + .height('100%') + } + } \ No newline at end of file diff --git a/entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts b/entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts new file mode 100644 index 0000000..ed3ba0d --- /dev/null +++ b/entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts @@ -0,0 +1,63 @@ +import TestRunner from '@ohos.application.testRunner' +import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' + +var abilityDelegator = undefined +var abilityDelegatorArguments = undefined + +function translateParamsToString(parameters) { + const keySet = new Set([ + '-s class', '-s notClass', '-s suite', '-s itName', + '-s level', '-s testType', '-s size', '-s timeout', + '-s package' + ]) + let targetParams = ''; + for (const key in parameters) { + if (keySet.has(key)) { + targetParams += ' ' + key + ' ' + parameters[key] + } + } + return targetParams.trim() +} + +async function onAbilityCreateCallback() { + console.log('onAbilityCreateCallback'); +} + +async function addAbilityMonitorCallback(err: any) { + console.info('addAbilityMonitorCallback : ' + JSON.stringify(err)) +} + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + console.info('OpenHarmonyTestRunner OnPrepare') + } + + onRun() { + console.log('OpenHarmonyTestRunner onRun run') + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() + + let lMonitor = { + abilityName: testAbilityName, + onAbilityCreate: onAbilityCreateCallback, + }; + var testAbilityName = abilityDelegatorArguments.parameters['-p'] + '.TestAbility' + abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback) + var cmd = 'aa start -d 0 -a ' + testAbilityName + ' -b ' + abilityDelegatorArguments.bundleName + cmd += ' '+translateParamsToString(abilityDelegatorArguments.parameters) + console.info('cmd : '+cmd) + abilityDelegator.executeShellCommand(cmd, + (err: any, d: any) => { + console.info('executeShellCommand : err : ' + JSON.stringify(err)); + console.info('executeShellCommand : data : ' + d.stdResult); + console.info('executeShellCommand : data : ' + d.exitCode); + }) + console.info('OpenHarmonyTestRunner onRun call abilityDelegator.getAppContext') + var context = abilityDelegator.getAppContext() + console.info('getAppContext : ' + JSON.stringify(context)) + console.info('OpenHarmonyTestRunner onRun end') + } +}; \ No newline at end of file diff --git a/entry/src/ohosTest/ets/test/Ability.test.ets b/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000..1236e0c --- /dev/null +++ b/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,13 @@ +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'hypium/index' + +export default function abilityTest() { + describe('ActsAbilityTest', function () { + it('assertContain',0, function () { + console.info("it begin") + let a = 'abc' + let b = 'b' + expect(a).assertContain(b) + expect(a).assertEqual(a) + }) + }) +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/test/List.test.ets b/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000..d766fe2 --- /dev/null +++ b/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test' + +export default function testsuite() { + abilityTest() +} \ No newline at end of file diff --git a/entry/src/ohosTest/resources/base/element/string.json b/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000..a0901cf --- /dev/null +++ b/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,12 @@ +{ + "string": [ + { + "name": "description_TestAbility", + "value": "eTS_Empty Ability" + }, + { + "name": "entry_TestAbility", + "value": "entry_TestAbility" + } + ] +} \ No newline at end of file diff --git a/entry/src/ohosTest/resources/base/media/icon.png b/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000..ce307a8 Binary files /dev/null and b/entry/src/ohosTest/resources/base/media/icon.png differ diff --git a/hvigorfile.js b/hvigorfile.js new file mode 100644 index 0000000..cff9f0d --- /dev/null +++ b/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').legacyAppTasks \ No newline at end of file diff --git a/imageknife/.gitignore b/imageknife/.gitignore new file mode 100644 index 0000000..4f9a973 --- /dev/null +++ b/imageknife/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/.preview +/build \ No newline at end of file diff --git a/imageknife/build-profile.json5 b/imageknife/build-profile.json5 new file mode 100644 index 0000000..107d8c7 --- /dev/null +++ b/imageknife/build-profile.json5 @@ -0,0 +1,5 @@ +{ + "apiType": "faMode", + "buildOption": { + } +} diff --git a/imageknife/hvigorfile.js b/imageknife/hvigorfile.js new file mode 100644 index 0000000..3a7c40c --- /dev/null +++ b/imageknife/hvigorfile.js @@ -0,0 +1,3 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').legacyHarTasks + diff --git a/imageknife/index.ets b/imageknife/index.ets new file mode 100644 index 0000000..3e206bc --- /dev/null +++ b/imageknife/index.ets @@ -0,0 +1,84 @@ +/** + * cache + */ + +export * from './src/main/ets/components/cache/FileUtils' +export * from './src/main/ets/components/cache/Md5' +export * from './src/main/ets/components/cache/Base64' +export * from './src/main/ets/components/cache/LruCache' +export * from './src/main/ets/components/cache/DiskLruCache' +export * from './src/main/ets/components/cache/diskstrategy/enum/ALL' +export * from './src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC' +export * from './src/main/ets/components/cache/diskstrategy/enum/DATA' +export * from './src/main/ets/components/cache/diskstrategy/enum/NONE' +export * from './src/main/ets/components/cache/diskstrategy/enum/RESOURCE' + +/** + * compress + */ +export * from './src/main/ets/components/imageknife/compress/CompressBuilder' +export * from './src/main/ets/components/imageknife/compress/listener/OnCompressListener' +export * from './src/main/ets/components/imageknife/compress/listener/OnRenameListener' +export * from './src/main/ets/components/imageknife/compress/listener/CompressDataListener' +export * from './src/main/ets/components/imageknife/compress/listener/CompressionPredicate' +export * from './src/main/ets/components/imageknife/compress/provider/CompressAdapter' +export * from './src/main/ets/components/imageknife/compress/provider/CompressProvider' +export * from './src/main/ets/components/imageknife/compress/provider/DataStringPathProvider' +export * from './src/main/ets/components/imageknife/compress/provider/RecourseProvider' + +/** + * crop + */ +export * from './src/main/ets/components/imageknife/crop/Crop' +export * from './src/main/ets/components/imageknife/crop/CropImage' +export * from './src/main/ets/components/imageknife/crop/CropOptions' + +/** + * transform + */ +export * from './src/main/ets/components/imageknife/transform/BaseTransform' +export * from './src/main/ets/components/imageknife/transform/BlurTransformation' +export * from './src/main/ets/components/imageknife/transform/BrightnessFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/ContrastFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/CropCircleTransformation' +export * from './src/main/ets/components/imageknife/transform/CropCircleWithBorderTransformation' +export * from './src/main/ets/components/imageknife/transform/CropSquareTransformation' +export * from './src/main/ets/components/imageknife/transform/CropTransformation' +export * from './src/main/ets/components/imageknife/transform/GrayscaleTransformation' +export * from './src/main/ets/components/imageknife/transform/InvertFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/PixelationFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/RotateImageTransformation' +export * from './src/main/ets/components/imageknife/transform/RoundedCornersTransformation' +export * from './src/main/ets/components/imageknife/transform/SepiaFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/SketchFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/MaskTransformation' +export * from './src/main/ets/components/imageknife/transform/SwirlFilterTransformation' +export * from './src/main/ets/components/imageknife/transform/TransformUtils' +export * from './src/main/ets/components/imageknife/transform/TransformType' +export * from './src/main/ets/components/imageknife/transform/pixelmap/CenterCrop' +export * from './src/main/ets/components/imageknife/transform/pixelmap/CenterInside' +export * from './src/main/ets/components/imageknife/transform/pixelmap/FitCenter' + +/** + * pngj + */ +export * from './src/main/ets/components/imageknife/pngj/Pngj' +export {handler} from './src/main/ets/components/imageknife/pngj/PngWork' +export * from './src/main/ets/components/imageknife/pngj/UPNG' + +/** + * ImageKnife + */ +export * from './src/main/ets/components/imageknife/ImageKnife' +export * from './src/main/ets/components/imageknife/RequestOption' +export * from './src/main/ets/components/imageknife/ImageKnifeComponent' +export * from './src/main/ets/components/imageknife/ImageKnifeOption' +export * from './src/main/ets/components/imageknife/ImageKnifeData' +export * from './src/main/ets/components/imageknife/PixelMapPack' +export * from './src/main/ets/components/imageknife/interface/IAllCacheInfoCallback' +export * from './src/main/ets/components/imageknife/interface/IParseImage' +export * from './src/main/ets/components/imageknife/networkmanage/IDataFetch' +export * from './src/main/ets/components/imageknife/requestmanage/ICache' +export * from './src/main/ets/components/imageknife/utils/FileTypeUtil' +export * from './src/main/ets/components/imageknife/utils/ParseImageUtil' + diff --git a/imageknife/package-lock.json b/imageknife/package-lock.json new file mode 100644 index 0000000..9209c18 --- /dev/null +++ b/imageknife/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "@ohos/imageknife", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "pako": { + "version": "1.0.11", + "resolved": "http://mirrors.tools.huawei.com/npm/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + } + } +} diff --git a/imageknife/package.json b/imageknife/package.json new file mode 100644 index 0000000..ed58448 --- /dev/null +++ b/imageknife/package.json @@ -0,0 +1,25 @@ +{ + "types": "", + "keywords": [ + "openharmony", + "imageknife" + ], + "author": "ohos_tpc", + "description": "专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单", + "ohos": { + "org": "opensource" + }, + "main": "index.ets", + "repository": "https://gitee.com/openharmony-tpc/imageknife.git", + "version": "1.0.1", + "dependencies": { + "pako": "^1.0.5" + }, + "tags": [ + "openharmony", + "imageknife" + ], + "license": "Apache-2.0", + "devDependencies": {}, + "name": "@ohos/imageknife" +} diff --git a/imageknife/src/main/config.json b/imageknife/src/main/config.json new file mode 100644 index 0000000..0d64e9a --- /dev/null +++ b/imageknife/src/main/config.json @@ -0,0 +1,24 @@ +{ + "app": { + "bundleName": "com.example.imageknifegiteepro", + "vendor": "example", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.imageknife", + "deviceType": [ + "phone", + "tablet" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "imageknife", + "moduleType": "har" + }, + "uiSyntax": "ets" + } +} diff --git a/imageknife/src/main/ets/components/cache/Base64.ets b/imageknife/src/main/ets/components/cache/Base64.ets new file mode 100644 index 0000000..e219975 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/Base64.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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 class Base64 { + lookup: Uint8Array = new Uint8Array(256) + chars: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + private static sInstance: Base64; + + public static getInstance(): Base64{ + if (!this.sInstance) { + this.sInstance = new Base64(); + } + return this.sInstance; + } + + private constructor() { + console.log("Base64 - constructor init!") + for (var index = 0; index < this.chars.length; index++) { + this.lookup[this.chars.charCodeAt(index)] = index; + } + } + + encode(arraybuffer: ArrayBuffer): string { + let bytes = new Uint8Array(arraybuffer), + i, + len = bytes.length, + base64 = ''; + for (i = 0; i < len; i += 3) { + base64 += this.chars[bytes[i] >> 2]; + base64 += this.chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; + base64 += this.chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; + base64 += this.chars[bytes[i + 2] & 63]; + } + if (len % 3 === 2) { + base64 = base64.substring(0, base64.length - 1) + '='; + } else if (len % 3 === 1) { + base64 = base64.substring(0, base64.length - 2) + '=='; + } + return base64; + } + + decode(base64: string): ArrayBuffer{ + let bufferLength = base64.length * 0.75, + len = base64.length, + i, + p = 0, + encoded1, + encoded2, + encoded3, + encoded4; + + if (base64[base64.length - 1] === '=') { + bufferLength--; + if (base64[base64.length - 2] === '=') { + bufferLength--; + } + } + + const arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i += 4) { + encoded1 = this.lookup[base64.charCodeAt(i)]; + encoded2 = this.lookup[base64.charCodeAt(i + 1)]; + encoded3 = this.lookup[base64.charCodeAt(i + 2)]; + encoded4 = this.lookup[base64.charCodeAt(i + 3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + } + + return arraybuffer; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/CustomMap.ets b/imageknife/src/main/ets/components/cache/CustomMap.ets new file mode 100644 index 0000000..7190d6b --- /dev/null +++ b/imageknife/src/main/ets/components/cache/CustomMap.ets @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 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 class CustomMap { + map: Map = new Map() + + // 获取键对应的值 + get(key: K): V | undefined{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + return this.map.get(key) + } + + /** + * 是否含有key的缓存 + */ + hasKey(key: K) { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + return this.map.has(key) + } + + // 添加键值对 + put(key: K, value: V): V | undefined{ + if (key == null || value == null) { + throw new Error('key or value is invalid,checking the parameter'); + } + var pre = this.map.get(key) + if (this.hasKey(key)) { + this.map.delete(key) + } + this.map.set(key, value); + return pre + } + + // 去除键值,(去除键数据中的键名及对应的值) + remove(key: K): boolean { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + return this.map.delete(key) + } + + /** + * 获取最先存储的数据的key + */ + getFirstKey(): K{ // keys()可以遍历后需要优化put()方法,暂时仅获取index=0的key + return this.map.keys().next().value + } + + // 判断键值元素是否为空 + isEmpty(): boolean{ + return this.map.size == 0; + } + // 获取键值元素大小 + size(): number{ + return this.map.size; + } + // 遍历Map,执行处理函数. 回调函数 function(key,value,index){..} + each(fn) { + this.map.forEach(fn) + } + // 清除键值对 + clear() { + this.map.clear() + } + // 遍历key + keys(): IterableIterator{ + return this.map.keys() + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/DiskCacheEntry.ets b/imageknife/src/main/ets/components/cache/DiskCacheEntry.ets new file mode 100644 index 0000000..ece37d8 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/DiskCacheEntry.ets @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 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 class DiskCacheEntry { + + // 缓存的key + key: string= '' + + // 缓存文件大小 + length: number= 0 + + constructor(key: string, length?: number) { + this.key = key + this.length = length + } + + setKey(key: string) { + this.key = key + } + + getkey(): string{ + return this.key + } + + setLength(length: number) { + this.length = length + } + + getLength(): number{ + return this.length + } + + toString(): string{ + return this.key + ' - ' + this.length + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/DiskLruCache.ets b/imageknife/src/main/ets/components/cache/DiskLruCache.ets new file mode 100644 index 0000000..f1e3a6c --- /dev/null +++ b/imageknife/src/main/ets/components/cache/DiskLruCache.ets @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2021 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 {CustomMap} from './CustomMap' +import {FileUtils} from './FileUtils' +import {FileReader} from './FileReader' +import {DiskCacheEntry} from './DiskCacheEntry' +import fileio from '@ohos.fileio'; +import featureability from '@ohos.ability.featureAbility' +import {Md5} from './Md5' + +export class DiskLruCache { + + // 缓存数据集合 + cacheMap: CustomMap = new CustomMap() + fileUtils: FileUtils = FileUtils.getInstance() + diskCacheFolder: string = 'ImageKnifeDiskCache' + + // 缓存文件路劲地址 + dirPath: string= '' + + // 缓存数据最大值 + maxSize: number = 30 * 1024 * 1024 + + // 当前缓存数据值 + size: number = 0 + + // 缓存journal文件名称 + + journal: string = 'journal' + + // 缓存journal备份文件名称 + journalTemp: string = 'journal_temp' + + // 缓存journal文件路径 + journalPath: string = '' + + // 缓存journal备份文件路径 + journalPathTemp: string = '' + + constructor(maxSize: number, direction?: string) { + if (maxSize > 0) { + this.maxSize = maxSize + } + if (!this.isNull(direction)) { + if (direction.endsWith('/')) { + this.dirPath = direction + } else { + this.dirPath = direction + '/' + } + } else { + featureability.getContext() + .getFilesDir() + .then((data) => { + console.log('DiskLruCache - FileDir= ' + data) + let dirPathFolder = data + '/' + this.diskCacheFolder + this.dirPath = dirPathFolder; + FileUtils.getInstance() + .createFolder(dirPathFolder) + this.init() + }) + .catch((error) => { + console.log('DiskLruCache FileDir Error Cause:' + error.message); + }) + } + } + + /** + * 初始化缓存文件 + */ + private init() { + if (this.dirPath.endsWith('/')) { + this.dirPath = this.dirPath + } else { + this.dirPath = this.dirPath + '/' + } + this.journalPath = this.dirPath + this.journal + this.journalPathTemp = this.dirPath + this.journalTemp + try { + var stat = fileio.statSync(this.journalPath) + if (stat.isFile() && stat.size > 0) { + this.fileUtils.createFile(this.journalPathTemp) + this.fileUtils.copyFile(this.journalPath, this.journalPathTemp) + this.readJournal(this.journalPathTemp) + this.resetJournalFile() + } else { + this.fileUtils.createFile(this.journalPath) + } + } catch (e) { + console.log('DiskLruCache - init e ' + e) + this.fileUtils.createFile(this.journalPath) + } + } + + /** + * 重置journal文件数据 + */ + resetJournalFile(){ + this.fileUtils.clearFile(this.journalPath) + for(let key of this.cacheMap.keys()){ + this.fileUtils.writeData(this.journalPath, 'save ' + key + '\n') + } + } + + /** + * 读取journal文件的缓存数据 + */ + readJournal(path: string) { + var fileReader = new FileReader(path) + var line: string = '' + while (!fileReader.isEnd()) { + line = fileReader.readLine() + line = line.replace('\n', '').replace('\r', '') + this.dealwithJournal(line) + } + this.fileUtils.deleteFile(this.journalPathTemp) + this.trimToSize() + } + + /** + * 处理journal文件数据 + */ + dealwithJournal(line: string) { + var picPath = '' + try { + var datas = line.split(' ') + if (datas.length > 1) { + if (datas[0] != 'remove') { + picPath = this.dirPath + datas[1] + var picstat = fileio.statSync(picPath) + if (picstat.isFile() && picstat.size > 0) { + this.size = this.size + picstat.size + this.fileUtils.writeData(this.journalPath, line + '\n') + this.putCacheMap(datas[1], picstat.size) + } + } else { + if (this.cacheMap.hasKey(datas[1])) { + var cacheEntry: DiskCacheEntry = this.cacheMap.get(datas[1]) + this.size = this.size - cacheEntry.getLength() + this.cacheMap.remove(datas[1]) + } + } + } + } catch (e) { + console.log('DiskLruCache - dealwithJournal e = ' + e) + } + } + + /** + * 设置disk缓存最大数据值 + */ + setMaxSize(max: number) { + this.maxSize = max + } + + /** + * 缓存数据map集合 + */ + private putCacheMap(key: string, length?: number) { + if (this.cacheMap.hasKey(key)) { + this.cacheMap.remove(key) + } + if (length > 0) { + this.cacheMap.put(key, new DiskCacheEntry(key, length)) + } else { + this.cacheMap.put(key, new DiskCacheEntry(key)) + } + } + + /** + * 存储disk缓存数据 + */ + putCacheData(key: string, content?: ArrayBuffer, path?: string) { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + var fileSize = 0 + var isvalid: boolean = false + key = Md5.hashStr(key) + if (content != null && content.byteLength > 0) { + isvalid = true + var tempPath = this.dirPath + key + fileSize = content.byteLength + this.fileUtils.writePic(tempPath, content) + } + if (!this.isNull(path) && this.fileUtils.exist(path)) { + isvalid = true + fileSize = this.fileUtils.getFileSize(path) + this.fileUtils.copyFile(path, this.dirPath + key) + } + if (isvalid) { + this.size = this.size + fileSize + this.putCacheMap(key, fileSize) + this.fileUtils.writeData(this.journalPath, 'save ' + key + '\n') + this.trimToSize() + } else { + throw ('putCacheData() key or content or path is invalid') + } + + } + + /** + * 根据LRU算法删除多余缓存数据 + */ + private trimToSize() { + while (this.size > this.maxSize) { + var tempkey: string = this.cacheMap.getFirstKey() + var fileSize = this.fileUtils.getFileSize(this.dirPath + tempkey) + if (fileSize > 0) { + this.size = this.size - fileSize + } + this.fileUtils.deleteFile(this.dirPath + tempkey) + this.cacheMap.remove(tempkey) + this.fileUtils.writeData(this.journalPath, 'remove ' + tempkey + '\n') + } + } + + /** + * 获取key缓存数据 + */ + getCacheDataByKey(key: string): ArrayBuffer{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + key = Md5.hashStr(key) + var path = this.dirPath + key; + if (this.fileUtils.exist(path)) { + var ab: ArrayBuffer = this.fileUtils.readFilePic(path) + this.putCacheMap(key, ab.byteLength) + this.fileUtils.writeData(path, 'read ' + key + '\n') + return ab + } else { + return null; + } + } + + /** + * 获取key缓存数据绝对路径 + */ + getCacheFileByKey(key: string): string{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + key = Md5.hashStr(key) + if (this.dirPath.endsWith('/')) { + this.dirPath = this.dirPath + } else { + this.dirPath = this.dirPath + '/' + } + var path = this.dirPath + key; + if (this.fileUtils.exist(path)) { + this.fileUtils.writeData(path, 'read ' + key + '\n') + return path + } else { + return null + } + } + + /** + * 删除key缓存数据 + */ + deleteCacheDataBykey(key: string): DiskCacheEntry{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + key = Md5.hashStr(key) + var path = this.dirPath + key; + if (this.fileUtils.exist(path)) { + var ab = this.fileUtils.readFilePic(path) + this.size = this.size - ab.byteLength + this.cacheMap.remove(key) + this.fileUtils.writeData(this.journalPath, 'remove ' + key + '\n') + this.fileUtils.deleteFile(path) + } + return this.cacheMap.get(key) + } + + /** + * 清除所有disk缓存数据 + */ + cleanCacheData() { + var length = this.cacheMap.size() + for (var index = 0; index < length; index++) { + this.fileUtils.deleteFile(this.dirPath + this.cacheMap[index]) + } + this.fileUtils.deleteFile(this.journalPath) + this.cacheMap.clear() + this.size = 0 + } + + /** + * 空字符串判断 + */ + private isNull(str: string): boolean{ + if (!str || Object.keys(str).length == 0) { + return true + } else { + return false + } + } + + foreachDiskLruCache(fn){ + this.cacheMap.each(fn) + } + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/FileReader.ets b/imageknife/src/main/ets/components/cache/FileReader.ets new file mode 100644 index 0000000..10969e0 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/FileReader.ets @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 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 fileio from '@ohos.fileio'; + +export class FileReader { + + // 文件大小 + fileLength: number = 0 + + // 读取的长度 + length: number = 0 + + // 读写stream + stream: any = null + // 缓存buf + buf: ArrayBuffer = new ArrayBuffer(1) + + constructor(path: string) { + if (!path || Object.keys(path).length == 0) { + return + } + try { + this.stream = fileio.createStreamSync(path, 'r+'); + var stat = fileio.statSync(path) + this.fileLength = stat.size + } catch (e) { + } + } + + /** + * 循环读取文件数据 + */ + readLine(): string{ + var line = '' + while (this.length <= this.fileLength) { + this.stream.readSync(this.buf, { position: this.length }) + this.length++ + var temp = String.fromCharCode.apply(null, new Uint8Array(this.buf)); + line = line + temp + if (temp == '\n' || temp == '\r') { + return line + } + } + return line + } + + /** + * 判断文件是否结束 + */ + isEnd() { + return this.fileLength <= 0 || this.length == this.fileLength + } + + /** + * 关闭stream + */ + close() { + this.stream.closeSync() + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/FileUtils.ets b/imageknife/src/main/ets/components/cache/FileUtils.ets new file mode 100644 index 0000000..7430bcb --- /dev/null +++ b/imageknife/src/main/ets/components/cache/FileUtils.ets @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2021 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 resmgr from '@ohos.resourceManager' +import fileio from '@ohos.fileio'; + +export class FileUtils { + base64Str: string= '' + + private static sInstance: FileUtils; + + public static getInstance(): FileUtils{ + if (!this.sInstance) { + this.sInstance = new FileUtils(); + } + return this.sInstance; + } + + private constructor() { + console.error("FileUtils - FileUtils constructor") + } + + /** + * 新建文件 + * @param path 文件绝对路径及文件名 + * @return number 文件句柄id + */ + createFile(path: string): number{ + return fileio.openSync(path, 0o100, 0o666) + } + + /** + * 删除文件 + * @param path 文件绝对路径及文件名 + */ + deleteFile(path: string):void { + fileio.unlinkSync(path); + } + + /** + * 同步删除文件目录 必须保证文件夹里面没有文件 + * @param path 待删除目录的绝对路径 + */ + deleteFolderSync(path: string):void { + if (this.existFolder(path)) { + fileio.rmdirSync(path); + } + } + + /** + * 异步删除文件目录 必须保证文件夹里面没有文件 + * @param path 待删除目录的绝对路径 + */ + deleteFolderAsync(path: string, deleteComplete, deleteError) { + if (this.existFolder(path)) { + fileio.rmdir(path) + .then(deleteComplete).catch(deleteError); + } + } + + /** + * 拷贝文件 + * @param path 文件绝对路径及文件名 + */ + copyFile(oriPath: string, newPath: string) { + fileio.copyFileSync(oriPath, newPath); + } + + /** + * 清空已有文件数据 + */ + clearFile(path: string):number { + return fileio.openSync(path, 0o1000) + } + + /** + * 向path写入content数据,覆盖旧数据 + */ + writeFile(path: string, content: ArrayBuffer | string) { + try { + let fd = fileio.openSync(path, 0o102, 0o666) + fileio.ftruncateSync(fd) + fileio.writeSync(fd, content) + fileio.fsyncSync(fd) + fileio.closeSync(fd) + } catch (e) { + console.log("FileUtils - Failed to writeFile for " + e) + } + } + + /** + * 向path写入数据 + */ + writeData(path: string, content: ArrayBuffer | string) { + try { + console.info("FileUtils - writeData size 1= " + path) + let fd = fileio.openSync(path, 0o102, 0o666) + console.info("FileUtils - writeData size 2= ") + let stat = fileio.statSync(path) + console.info("FileUtils - writeData size = " + stat.size) + fileio.writeSync(fd, content, { position: stat.size }) + let length = 0 + if (content instanceof ArrayBuffer) { + length = content.byteLength + } else { + length = content.length + } + fileio.closeSync(fd) + } catch (e) { + console.log("FileUtils - Failed to writeData for " + e) + } + } + + /** + * 判断path文件是否存在 + */ + exist(path: string): boolean{ + try { + let stat = fileio.statSync(path) + return stat.isFile() + } catch (e) { + console.debug("FileUtils - fileutils exsit e" + e) + console.log("path=>" + path) + return false + } + } + + /** + * 向path写入数据 + */ + writePic(path: string, picData: ArrayBuffer) { + console.info("FileUtils - writepic 1") + this.createFile(path) + this.writeFile(path, picData) + console.info("FileUtils - writepic 3") + } + + /** + * 获取path的文件大小 + */ + getFileSize(path: string): number{ + try { + let stat = fileio.statSync(path) + return stat.size + } catch (e) { + console.error("FileUtils - FileUtils getFileSize e " + e) + return -1 + } + } + + /** + * 读取路径path的文件 + */ + readFilePic(path: string): ArrayBuffer { + try { + let stat = fileio.statSync(path) + console.info("FileUtils - readFilePic 1") + let fd = fileio.openSync(path, 0o2); + let length = fileio.statSync(path).size + console.info("FileUtils - readFilePic 2 length = " + length) + let buf = new ArrayBuffer(length); + console.info("FileUtils - readFilePic 3") + fileio.readSync(fd, buf) + return buf + } catch (e) { + console.log("FileUtils - readFilePic " + e) + return new ArrayBuffer(0) + } + } + + /** + * 读取media的资源文件 + */ + readMediaPic() { + resmgr.getResourceManager() + .then(result => { + result.getMediaBase64($r('app.media.icon') + .id) + .then(data => { + console.error("FileUtils - readPic data = " + data) + data = data.replace("data:image/png;base64,", "") + console.error("FileUtils - readPic this.data = " + data) + this.base64Str = data + console.error("FileUtils - readPic this.base64Str = " + this.base64Str) + }) + .catch(err => { + console.log("FileUtils - readPic err" + JSON.stringify(err)); + }) + }) + } + + /** + * stream式读取 + */ + readStream(path: string): string { + try { + let stat = fileio.statSync(path) + let length = stat.size + let buf = new ArrayBuffer(length); + let ss = fileio.createStreamSync(path, "r+"); + ss.readSync(buf) + ss.closeSync(); + return String.fromCharCode.apply(null, new Uint8Array(buf)) + } catch (e) { + console.log("FileUtils - readFilePic " + e) + return "" + } + } + + /** + * stream式写入 + */ + writeStream(path: string, tempArray: ArrayBuffer) { + try { + console.error("FileUtils - writeStream =1 ") + this.createFile(path) + console.error("FileUtils - writeStream 2 ") + let ss = fileio.createStreamSync(path, "r+"); + console.error("FileUtils - writeStream 3 " + tempArray.byteLength) + let num = ss.writeSync(tempArray, { + encoding: 'utf-8' + }); + console.error("FileUtils - write num = " + num) + ss.flushSync(); + ss.closeSync(); + } catch (e) { + console.log("FileUtils - Failed to writeStream for " + e) + } + } + + /** + * 创建文件夹 + * @param 文件夹绝对路径 + */ + createFolder(path: string) { + //创建文件夹 + if (!this.existFolder(path)) { + fileio.mkdirSync(path) + } + } + + /** + * 判断文件夹是否存在 + * @param 文件夹绝对路径 + */ + existFolder(path: string): boolean{ + try { + let stat = fileio.statSync(path) + return stat.isDirectory() + } catch (e) { + console.debug("fileutils folder exsit error=" + e) + return false + } + } + + /** + * 如果文件夹不存在则创建一个文件夹 然后在其中创建文件 并且将数据写入进文件 + * @param folder 文件夹绝对路径 + * @param file 文件绝对路径 + * @param content 文件内容数据 + */ + createFileProcess(folder: string, file: string, content: ArrayBuffer | string) { + //创建文件夹 + this.createFolder(folder); + //创建文件 + this.createFile(file); + //写入数据 + this.writeFile(file, content) + } + + /** + * string 转 Uint8Array + * @param str 输入String + */ + stringToUint8Array(str): Uint8Array{ + var arr = []; + for (var i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + var tmpUint8Array = new Uint8Array(arr); + return tmpUint8Array + } + + /** + * int 转 byte[] + * @param n 输入int + */ + intTobytes2(n) { + var bytes = []; + for (var i = 0; i < 2; i++) { + bytes[i] = n >> (8 - i * 8); + } + return bytes; + } + + + uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } + +} + +export interface AsyncCallback { + (err: string, data: T): void; +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/LruCache.ets b/imageknife/src/main/ets/components/cache/LruCache.ets new file mode 100644 index 0000000..3e8d14d --- /dev/null +++ b/imageknife/src/main/ets/components/cache/LruCache.ets @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2021 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 {CustomMap} from './CustomMap' + +export class LruCache { + maxsize: number = 0 + size: number = 0; + map: CustomMap = new CustomMap(); + + constructor(maxsize: number) { + this.trimToSize(-1) + this.maxsize = maxsize + this.size = 0; + } + + // 添加缓存键值对 + put(key: K, value: V) { + if (key == null || value == null) { + throw new Error('key or value is invalid '); + } + var pre = this.map.get(key) + if (pre == null) { + this.size++ + } + this.entryRemoved(key, pre, value) + this.trimToSize(this.maxsize) + } + + // 移除键为key的缓存 + remove(key: K): V | undefined{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + var preValue = this.map.get(key) + if (this.map.remove(key)) { + this.size-- + } + return preValue + } + + // 获取键为key的value + get(key: K): V { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + var preValue = this.map.get(key) + if (preValue != null) { + this.entryRemoved(key, preValue, preValue) + } + return preValue + } + + /* + * 替换或删除对应key键的数据 + * evicted:是否删除 + * key:对应的键值key + * preValue 对应key键的旧value值 + * value 对应key键的新value值 + */ + entryRemoved(key: K, preValue: V, value: V) { + if (preValue != null) { + this.map.remove(key) + } + if (value != null) { + this.map.put(key, value) + } + } + + // 移除较少使用的缓存数据 + trimToSize(tempsize: number) { + while (true) { + if (tempsize < 0) { + this.map.clear() + this.size = 0 + break + } + if (this.size <= tempsize || this.map.isEmpty()) { + break + } + var delkey = this.map.getFirstKey() + this.map.remove(delkey) + this.size-- + } + } + + // 缓存数据数量 + sizeLength(): number{ + return this.size + } + + // 缓存数据最大值 + maxSize(): number{ + return this.maxsize + } + + // 设置缓存数据量最大值 + resize(maxsize: number) { + if (maxsize < 0) { + throw new Error('maxsize <0 & maxsize invalid'); + } + this.maxsize = maxsize + this.trimToSize(maxsize) + } + + // 清除缓存 + evicAll() { + this.trimToSize(-1) + } + + print():string { + let printResult = ''; + if (this.map.isEmpty()) { + return printResult; + } + + + this.map.each(function (value, key, index) { + printResult +='LruCache:key=' + key + 'value= ' + value; + }) + return printResult; + } + + foreachLruCache(fn){ + this.map.each(fn); + } + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/Md5.ets b/imageknife/src/main/ets/components/cache/Md5.ets new file mode 100644 index 0000000..bbfb601 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/Md5.ets @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2021 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 class Md5 { + + // One time hashing functions + public static hashStr(str: string, raw?: false): string + + public static hashStr(str: string, raw: true): Int32Array + + public static hashStr(str: string, raw: boolean = false) { + return this.onePassHasher + .start() + .appendStr(str) + .end(raw); + } + + public static hashAsciiStr(str: string, raw?: false): string + + public static hashAsciiStr(str: string, raw: true): Int32Array + + public static hashAsciiStr(str: string, raw: boolean = false) { + return this.onePassHasher + .start() + .appendAsciiStr(str) + .end(raw); + } + + // Private Static Variables + private static stateIdentity = new Int32Array([1732584193, -271733879, -1732584194, 271733878]); + private static buffer32Identity = new Int32Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + private static hexChars = '0123456789abcdef'; + private static hexOut: string[] = []; + + // Permanent instance is to use for one-call hashing + private static onePassHasher = new Md5(); + + private static _hex(x: any): string { + const hc = Md5.hexChars; + const ho = Md5.hexOut; + let n; + let offset; + let j; + let i; + + for (i = 0; i < 4; i += 1) { + offset = i * 8; + n = x[i]; + for (j = 0; j < 8; j += 2) { + ho[offset + 1 + j] = hc.charAt(n & 0x0F); + n >>>= 4; + ho[offset + 0 + j] = hc.charAt(n & 0x0F); + n >>>= 4; + } + } + return ho.join(''); + } + + private static _md5cycle(x: Int32Array | Uint32Array, k: Int32Array | Uint32Array) { + let a = x[0]; + let b = x[1]; + let c = x[2]; + let d = x[3]; + // ff() + a += (b & c | ~b & d) + k[0] - 680876936 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[1] - 389564586 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[2] + 606105819 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[3] - 1044525330 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[4] - 176418897 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[5] + 1200080426 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[6] - 1473231341 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[7] - 45705983 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[8] + 1770035416 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[9] - 1958414417 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[10] - 42063 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[11] - 1990404162 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[12] + 1804603682 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[13] - 40341101 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[14] - 1502002290 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[15] + 1236535329 | 0; + b = (b << 22 | b >>> 10) + c | 0; + // gg() + a += (b & d | c & ~d) + k[1] - 165796510 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[6] - 1069501632 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[11] + 643717713 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[0] - 373897302 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[5] - 701558691 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[10] + 38016083 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[15] - 660478335 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[4] - 405537848 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[9] + 568446438 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[14] - 1019803690 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[3] - 187363961 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[8] + 1163531501 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[13] - 1444681467 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[2] - 51403784 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[7] + 1735328473 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[12] - 1926607734 | 0; + b = (b << 20 | b >>> 12) + c | 0; + // hh() + a += (b ^ c ^ d) + k[5] - 378558 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[8] - 2022574463 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[11] + 1839030562 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[14] - 35309556 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[1] - 1530992060 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[4] + 1272893353 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[7] - 155497632 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[10] - 1094730640 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[13] + 681279174 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[0] - 358537222 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[3] - 722521979 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[6] + 76029189 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[9] - 640364487 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[12] - 421815835 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[15] + 530742520 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[2] - 995338651 | 0; + b = (b << 23 | b >>> 9) + c | 0; + // ii() + a += (c ^ (b | ~d)) + k[0] - 198630844 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[5] - 57434055 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[10] - 1051523 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[15] - 30611744 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[4] - 145523070 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[2] + 718787259 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[9] - 343485551 | 0; + b = (b << 21 | b >>> 11) + c | 0; + + x[0] = a + x[0] | 0; + x[1] = b + x[1] | 0; + x[2] = c + x[2] | 0; + x[3] = d + x[3] | 0; + } + + private _dataLength: number; + private _bufferLength: number; + private _state: Int32Array = new Int32Array(4); + private _buffer: ArrayBuffer = new ArrayBuffer(68); + private _buffer8: Uint8Array; + private _buffer32: Uint32Array; + + constructor() { + this._buffer8 = new Uint8Array(this._buffer, 0, 68); + this._buffer32 = new Uint32Array(this._buffer, 0, 17); + this.start(); + } + + public start() { + this._dataLength = 0; + this._bufferLength = 0; + this._state.set(Md5.stateIdentity); + return this; + } + + // Char to code point to to array conversion: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt + // #Example.3A_Fixing_charCodeAt_to_handle_non-Basic-Multilingual-Plane_characters_if_their_presence_earlier_in_the_string_is_unknown + public appendStr(str: string) { + const buf8 = this._buffer8; + const buf32 = this._buffer32; + let bufLen = this._bufferLength; + let code; + let i; + + for (i = 0; i < str.length; i += 1) { + code = str.charCodeAt(i); + if (code < 128) { + buf8[bufLen++] = code; + } else if (code < 0x800) { + buf8[bufLen++] = (code >>> 6) + 0xC0; + buf8[bufLen++] = code & 0x3F | 0x80; + } else if (code < 0xD800 || code > 0xDBFF) { + buf8[bufLen++] = (code >>> 12) + 0xE0; + buf8[bufLen++] = (code >>> 6 & 0x3F) | 0x80; + buf8[bufLen++] = (code & 0x3F) | 0x80; + } else { + code = ((code - 0xD800) * 0x400) + (str.charCodeAt(++i) - 0xDC00) + 0x10000; + if (code > 0x10FFFF) { + throw new Error('Unicode standard supports code points up to U+10FFFF'); + } + buf8[bufLen++] = (code >>> 18) + 0xF0; + buf8[bufLen++] = (code >>> 12 & 0x3F) | 0x80; + buf8[bufLen++] = (code >>> 6 & 0x3F) | 0x80; + buf8[bufLen++] = (code & 0x3F) | 0x80; + } + if (bufLen >= 64) { + this._dataLength += 64; + Md5._md5cycle(this._state, buf32); + bufLen -= 64; + buf32[0] = buf32[16]; + } + } + this._bufferLength = bufLen; + return this; + } + + public appendAsciiStr(str: string) { + const buf8 = this._buffer8; + const buf32 = this._buffer32; + let bufLen = this._bufferLength; + let i; + let j = 0; + + for (;; ) { + i = Math.min(str.length - j, 64 - bufLen); + while (i--) { + buf8[bufLen++] = str.charCodeAt(j++); + } + if (bufLen < 64) { + break; + } + this._dataLength += 64; + Md5._md5cycle(this._state, buf32); + bufLen = 0; + } + this._bufferLength = bufLen; + return this; + } + + public appendByteArray(input: Uint8Array) { + const buf8 = this._buffer8; + const buf32 = this._buffer32; + let bufLen = this._bufferLength; + let i; + let j = 0; + + for (;; ) { + i = Math.min(input.length - j, 64 - bufLen); + while (i--) { + buf8[bufLen++] = input[j++]; + } + if (bufLen < 64) { + break; + } + this._dataLength += 64; + Md5._md5cycle(this._state, buf32); + bufLen = 0; + } + this._bufferLength = bufLen; + return this; + } + + public getState() { + const self = this; + const s = self._state; + + return { + buffer: String.fromCharCode.apply(null, self._buffer8), + buflen: self._bufferLength, + length: self._dataLength, + state: [s[0], s[1], s[2], s[3]] + }; + } + + public setState(state: any) { + const buf = state.buffer; + const x = state.state; + const s = this._state; + let i; + + this._dataLength = state.length; + this._bufferLength = state.buflen; + s[0] = x[0]; + s[1] = x[1]; + s[2] = x[2]; + s[3] = x[3]; + + for (i = 0; i < buf.length; i += 1) { + this._buffer8[i] = buf.charCodeAt(i); + } + } + + public end(raw: boolean = false) { + const bufLen = this._bufferLength; + const buf8 = this._buffer8; + const buf32 = this._buffer32; + const i = (bufLen >> 2) + 1; + let dataBitsLen; + + this._dataLength += bufLen; + + buf8[bufLen] = 0x80; + buf8[bufLen + 1] = buf8[bufLen + 2] = buf8[bufLen + 3] = 0; + buf32.set(Md5.buffer32Identity.subarray(i), i); + + if (bufLen > 55) { + Md5._md5cycle(this._state, buf32); + buf32.set(Md5.buffer32Identity); + } + + // Do the final computation based on the tail and length + // Beware that the final length may not fit in 32 bits so we take care of that + dataBitsLen = this._dataLength * 8; + if (dataBitsLen <= 0xFFFFFFFF) { + buf32[14] = dataBitsLen; + } else { + const matches = dataBitsLen.toString(16).match(/(.*?)(.{0,8})$/); + if (matches === null) { + return; + } + + const lo = parseInt(matches[2], 16); + const hi = parseInt(matches[1], 16) || 0; + + buf32[14] = lo; + buf32[15] = hi; + } + + Md5._md5cycle(this._state, buf32); + + return raw ? this._state : Md5._hex(this._state); + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/DataSrc.ets b/imageknife/src/main/ets/components/cache/diskstrategy/DataSrc.ets new file mode 100644 index 0000000..60ad54b --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/DataSrc.ets @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/** Indicates the origin of some retrieved data. */ + +export enum DataSrc { + + /** + * Indicates data was probably retrieved locally from the device, although it may have been + * obtained through a content provider that may have obtained the data from a remote source. + */ + + LOCAL, + + /** Indicates data was retrieved from a remote source other than the device. */ + + REMOTE, + + /** Indicates data was retrieved unmodified from the on device cache. */ + + DATA_DISK_CACHE, + + /** Indicates data was retrieved from modified content in the on device cache. */ + + RESOURCE_DISK_CACHE, + + /** Indicates data was retrieved from the in memory cache. */ + + MEMORY_CACHE, +} diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/DiskStrategy.ets b/imageknife/src/main/ets/components/cache/diskstrategy/DiskStrategy.ets new file mode 100644 index 0000000..b5b4606 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/DiskStrategy.ets @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 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{DataSrc} from "../diskstrategy/DataSrc" +import{EncodeStrategy} from "../diskstrategy/EncodeStrategy" + +export interface DiskStrategy { + + isDataCacheable(dataSource: DataSrc): boolean + + isResourceCacheable(isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean; + + decodeCachedResource(): boolean; + + decodeCachedData(): boolean; + + getName(): string; +} + + diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/EncodeStrategy.ets b/imageknife/src/main/ets/components/cache/diskstrategy/EncodeStrategy.ets new file mode 100644 index 0000000..780c9ec --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/EncodeStrategy.ets @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 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 EncodeStrategy { + + /** + * Writes the original unmodified data for the resource to disk, not include downsampling or + * transformations. + */ + + SOURCE, + + /** Writes the decoded, downsampled and transformed data for the resource to disk. */ + + TRANSFORMED, + + /** Will write no data. */ + + NONE, +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/enum/ALL.ets b/imageknife/src/main/ets/components/cache/diskstrategy/enum/ALL.ets new file mode 100644 index 0000000..8086159 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/enum/ALL.ets @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class ALL implements DiskStrategy { + getName(): string{ + return 'ALL'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return dataSource == DataSrc.REMOTE; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return ((isFromAlternateCacheKey && dataSource == DataSrc.DATA_DISK_CACHE) + || dataSource == DataSrc.LOCAL) + && encodeStrategy == EncodeStrategy.TRANSFORMED; + } + + decodeCachedResource(): boolean { + return true; + } + + decodeCachedData(): boolean{ + return true; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC.ets b/imageknife/src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC.ets new file mode 100644 index 0000000..a1c4305 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC.ets @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class AUTOMATIC implements DiskStrategy { + getName(): string{ + return 'AUTOMATIC'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return dataSource == DataSrc.REMOTE; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return ((isFromAlternateCacheKey && dataSource == DataSrc.DATA_DISK_CACHE) + || dataSource == DataSrc.LOCAL) + && encodeStrategy == EncodeStrategy.TRANSFORMED; + } + + decodeCachedResource(): boolean { + return true; + } + + decodeCachedData(): boolean{ + return true; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/enum/DATA.ets b/imageknife/src/main/ets/components/cache/diskstrategy/enum/DATA.ets new file mode 100644 index 0000000..9e86616 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/enum/DATA.ets @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class DATA implements DiskStrategy { + getName(): string{ + return 'DATA'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return dataSource != DataSrc.DATA_DISK_CACHE && dataSource != DataSrc.MEMORY_CACHE; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return false; + } + + decodeCachedResource(): boolean { + return false; + } + + decodeCachedData(): boolean{ + return true; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/enum/NONE.ets b/imageknife/src/main/ets/components/cache/diskstrategy/enum/NONE.ets new file mode 100644 index 0000000..25e6757 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/enum/NONE.ets @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class NONE implements DiskStrategy { + getName(): string{ + return 'NONE'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return false; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return false; + } + + decodeCachedResource(): boolean { + return false; + } + + decodeCachedData(): boolean{ + return false; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/diskstrategy/enum/RESOURCE.ets b/imageknife/src/main/ets/components/cache/diskstrategy/enum/RESOURCE.ets new file mode 100644 index 0000000..928a029 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/diskstrategy/enum/RESOURCE.ets @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class RESOURCE implements DiskStrategy { + getName(): string{ + return 'RESOURCE'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return false; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return dataSource != DataSrc.RESOURCE_DISK_CACHE + && dataSource != DataSrc.MEMORY_CACHE; + } + + decodeCachedResource(): boolean { + return true; + } + + decodeCachedData(): boolean{ + return false; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/cache/key/EngineKey.ets b/imageknife/src/main/ets/components/cache/key/EngineKey.ets new file mode 100644 index 0000000..601abb1 --- /dev/null +++ b/imageknife/src/main/ets/components/cache/key/EngineKey.ets @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 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 {Key} from "../key/Key" +import {RequestOption} from '../../imageknife/RequestOption' +import {BaseTransform} from '../../imageknife/transform/BaseTransform' + +export class EngineKey implements Key { + private request: RequestOption; + + constructor( + request + ) { + this.request = request; + } + + // 内存缓存 缓存生成规则:是否会影响图片内容,不影响则通用(strategy onlyRetrieveFromCache isCacheable)为通用项目 + // 生成规则 加载数据原 各类参数(排除监听 排除 占位图 失败占位图) + generateCacheKey(): string{ + console.log('generateCacheKey 1'); + let loadSrc = JSON.stringify(this.request.loadSrc); + console.log('generateCacheKey 2'); + let size = JSON.stringify(this.request.size); + console.log('generateCacheKey 3'); + let transformationsStr; + if(this.request && this.request.transformations) { + for (let i = 0; i < this.request.transformations.length; i++) { + if (i == this.request.transformations.length - 1) { + transformationsStr += this.request.transformations[i].getName() + ""; + } else { + transformationsStr += this.request.transformations[i].getName() + ","; + } + } + } + console.log('generateCacheKey 4'); + let dontAnimateFlag = JSON.stringify(this.request.dontAnimateFlag); + console.log('generateCacheKey 5'); + let key = "loadSrc=" + loadSrc + ";" + + "size=" + size + ";" + + "transformations=" + transformationsStr + ";" + + "dontAnimateFlag=" + dontAnimateFlag + ";" + console.log('generateCacheKey 6'); + return key; + } + // 磁盘缓存 缓存生成规则:是否会影响图片内容,不影响则通用(strategy onlyRetrieveFromCache isCacheable)为通用项目 + // 生成规则 加载数据原 各类参数(排除监听 排除 占位图 失败占位图) + generateResourceKey(): string{ + console.log('generateResourceKey 1'); + let loadSrc = JSON.stringify(this.request.loadSrc); + console.log('generateResourceKey 2'); + let size = JSON.stringify(this.request.size); + console.log('generateResourceKey 3'); + let transformationsStr; + if(this.request && this.request.transformations) { + for (let i = 0; i < this.request.transformations.length; i++) { + if (i == this.request.transformations.length - 1) { + transformationsStr += this.request.transformations[i].getName() + ""; + } else { + transformationsStr += this.request.transformations[i].getName() + ","; + } + } + } + console.log('generateResourceKey 4'); + let dontAnimateFlag = JSON.stringify(this.request.dontAnimateFlag); + console.log('generateResourceKey 5'); + let key = "loadSrc=" + loadSrc + ";" + + "size=" + size + ";" + + "transformations=" + transformationsStr + ";" + + "dontAnimateFlag=" + dontAnimateFlag + ";" + console.log('generateResourceKey 6'); + return key; + } + + // 磁盘缓存 + // 生成网络加载数据 原始数据存于磁盘的key + generateDataKey(): string{ + let loadSrc = JSON.stringify(this.request.loadSrc); + let key = "loadSrc=" + loadSrc + ";" + return key; + } + + updateDiskCacheKey(info: Object) { + + } +} diff --git a/imageknife/src/main/ets/components/cache/key/EngineKeyFactories.ets b/imageknife/src/main/ets/components/cache/key/EngineKeyFactories.ets new file mode 100644 index 0000000..f81f0ce --- /dev/null +++ b/imageknife/src/main/ets/components/cache/key/EngineKeyFactories.ets @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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 {EngineKey} from '../key/EngineKey' + +export class EngineKeyFactories { + buildCacheKey( + request) { + return new EngineKey(request).generateCacheKey(); + } + + buildDataKey( + request + ) { + return new EngineKey(request).generateDataKey() + } + + buildResourceKey( + request + ) { + return new EngineKey(request).generateResourceKey() + } +} + + + diff --git a/imageknife/src/main/ets/components/cache/key/Key.ets b/imageknife/src/main/ets/components/cache/key/Key.ets new file mode 100644 index 0000000..5f17ffb --- /dev/null +++ b/imageknife/src/main/ets/components/cache/key/Key.ets @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 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 interface Key { + + /** + * Adds all uniquely identifying information to the given digest. + * + *

Note - Using {@link MessageDigest#reset()} inside of this method will result + * in undefined behavior. + * @param messageDigest + */ + updateDiskCacheKey(info: Object); + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnife.ets b/imageknife/src/main/ets/components/imageknife/ImageKnife.ets new file mode 100644 index 0000000..8336431 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/ImageKnife.ets @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2021 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 {DiskLruCache} from "../cache/DiskLruCache" +import {LruCache} from "../cache/LruCache" +import {EngineKeyFactories} from "../cache/key/EngineKeyFactories" +import {RequestOption} from "../imageknife/RequestOption" +import {AsyncCallback} from "../imageknife/interface/asynccallback" +import {PlaceHolderManager} from "../imageknife/holder/PlaceHolderManager" +import {ErrorHolderManager} from "../imageknife/holder/ErrorHolderManager" +import {RequestManager} from "../imageknife/requestmanage/RequstManager" +import {NONE} from "../cache/diskstrategy/enum/NONE" +import {FileTypeUtil} from '../imageknife/utils/FileTypeUtil' +import {DownloadClient} from '../imageknife/networkmanage/DownloadClient' +import {IDataFetch} from '../imageknife/networkmanage/IDataFetch' +import {ParseResClient} from '../imageknife/resourcemanage/ParseResClient' +import {IResourceFetch} from '../imageknife/resourcemanage/IResourceFetch' +import {ImageKnifeData} from '../imageknife/ImageKnifeData' +import {FileUtils} from '../cache/FileUtils' +import {FileReader} from '../cache/FileReader' +import image from "@ohos.multimedia.image" +import featureAbility from '@ohos.ability.featureAbility'; +import {CompressBuilder} from "../imageknife/compress/CompressBuilder" + +export class ImageKnife { + private memoryCache: LruCache; + private diskMemoryCache: DiskLruCache; + private dataFetch: IDataFetch; + private resourceFetch: IResourceFetch; + private filesPath: string = ""; // data/data/包名/files目录 + + + private placeholderCache: string = "placeholderCache" + private runningRequest: Array; + private pendingRequest: Array; + private fileTypeUtil: FileTypeUtil; // 通用文件格式辨别 + private svgAndGifFolder: string = "svgAndGifFolder"; // svg和gif的文件路径地址 + private svgAndGifCommitFile: string = "svgAndGifCommitFile" // svg和gif提交记录 + + private defaultListener:AsyncCallback; // 全局监听器 + + getMemoryCache(): LruCache{ + return this.memoryCache; + } + + setMemoryCache(lrucache: LruCache){ + this.memoryCache = lrucache; + } + + getDiskMemoryCache(): DiskLruCache{ + return this.diskMemoryCache; + }; + + setDiskMemoryCache(diskLruCache: DiskLruCache) { + this.diskMemoryCache = diskLruCache; + }; + + getFileTypeUtil(): FileTypeUtil{ + return this.fileTypeUtil; + } + + + + getSvgAndGifFolder(): string{ + return this.svgAndGifFolder; + } + + setSvgAndGifFolder(folderPath: string){ + this.svgAndGifFolder = folderPath; + } + + getDefaultListener(){ + return this.defaultListener; + } + + setDefaultListener(newDefaultListener:AsyncCallback){ + this.defaultListener = newDefaultListener; + } + + private constructor() { + + // 构造方法传入size 为保存文件个数 + this.memoryCache = new LruCache(100); + + // 创建disk缓存 传入的size 为多少比特 比如20KB 传入20*1024 + this.diskMemoryCache = new DiskLruCache(30 * 1024 * 1024); + + // 创建网络下载能力 + this.dataFetch = new DownloadClient(); + + // 创建本地数据解析能力 + this.resourceFetch = new ParseResClient(); + + // 初始化本地 文件保存 + featureAbility.getContext() + .getFilesDir() + .then((data) => { + this.filesPath = data + this.initSvgAndGifEnvironment(); + }) + .catch((error) => { + console.error('ImageKnife Failed to obtain the filesPath directory. Cause:' + error.message); + }) + + this.runningRequest = new Array(); + this.pendingRequest = new Array(); + + // 通用文件格式识别初始化 + this.fileTypeUtil = new FileTypeUtil(); + } + + private initSvgAndGifEnvironment() { + let folderExist = FileUtils.getInstance().existFolder(this.filesPath + "/" + this.svgAndGifFolder) + let fileExist = + FileUtils.getInstance() + .exist(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile) + if (folderExist && fileExist) { + // 创建完成,需要删除上次使用的文件 + var fileReader = new FileReader(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile) + var line: string = '' + while (!fileReader.isEnd()) { + line = fileReader.readLine() + line = line.replace('\n', "").replace('\r', "") + FileUtils.getInstance().deleteFile(this.filesPath + "/" + this.svgAndGifFolder + "/" + line) + } + FileUtils.getInstance().clearFile(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile) + } else { + if (!folderExist) { + FileUtils.getInstance().createFolder(this.filesPath + "/" + this.svgAndGifFolder); + } + if (!fileExist) { + FileUtils.getInstance().createFile(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile) + } + } + + } + + private static sInstance: ImageKnife; + + public static with(): ImageKnife{ + if (!this.sInstance) { + this.sInstance = new ImageKnife(); + } + return this.sInstance; + } + + public compressBuilder(): CompressBuilder{ + return new CompressBuilder(); + } + + // 替代原来的LruCache + public replaceLruCache(size:number){ + if(this.memoryCache.map.size() <= 0) { + this.memoryCache = new LruCache(size); + }else{ + let newLruCache = new LruCache(size); + this.memoryCache.foreachLruCache(function (value, key, map) { + newLruCache.put(key, value); + }) + this.memoryCache = newLruCache; + } + } + + public replaceDataFetch(fetch:IDataFetch){ + this.dataFetch = fetch; + } + + // 替代原来的DiskLruCache + public replaceDiskLruCache(size:number){ + this.diskMemoryCache = new DiskLruCache(size); + + if(this.diskMemoryCache.cacheMap.size() <= 0) { + this.diskMemoryCache = new DiskLruCache(size); + }else{ + let newDiskLruCache = new DiskLruCache(size); + this.diskMemoryCache.foreachDiskLruCache(function (value, key, map) { + newDiskLruCache.putCacheData(key, value, null); + }) + this.diskMemoryCache = newDiskLruCache; + } + } + + // 预加载 resource资源一级缓存,string资源实现二级缓存 + preload(request: RequestOption) { + // 每个request 公共信息补充 + request.setFilesPath(this.filesPath); + // svg特殊处理 + request._svgAndGifFolder = this.svgAndGifFolder; + request._svgAndGifCommitFile = this.svgAndGifCommitFile; + return this.parseSource(request); + } + + // 正常加载 + call(request: RequestOption) { + console.log("ImageKnife call") + // 添加全局监听 + if(this.defaultListener) { + request.addListener(this.defaultListener) + } + + // 每个request 公共信息补充 + request.setFilesPath(this.filesPath); + + // svg特殊处理 + request._svgAndGifFolder = this.svgAndGifFolder; + request._svgAndGifCommitFile = this.svgAndGifCommitFile; + + // 首先执行占位图 解析任务 + if (request.placeholderSrc) { + PlaceHolderManager.execute(request) + } + + // 其次解析错误占位图 + if (request.errorholderSrc) { + ErrorHolderManager.execute(request) + } + return this.parseSource(request); + } + + loadResources(request: RequestOption) { + console.log("ImageKnife loadResources") + let factories; + let cacheKey; + let transferKey; + let dataKey; + try { + factories = new EngineKeyFactories(); + }catch(err){ + console.log('ImageKnife loadResources1 err='+ err); + } + // 生成内存缓存key 内存 变换后磁盘 + try { + cacheKey = factories.buildCacheKey(request); + }catch(err){ + console.log('ImageKnife loadResources2 err='+ err); + } + // 生成磁盘缓存变换后数据key 变换后数据保存在磁盘 + try{ + transferKey = factories.buildResourceKey(request); + }catch(err){ + console.log('ImageKnife loadResources3 err='+ err); + } + // 生成磁盘缓存源数据key 原始数据保存在磁盘 + try{ + dataKey = factories.buildDataKey(request); + }catch(err){ + console.log('ImageKnife loadResources4 err='+ err); + } + request.generateCacheKey = cacheKey; + request.generateResourceKey = transferKey; + request.generateDataKey = dataKey; + + this.loadCacheManager(request); + } + + // 删除执行结束的running + removeRunning(request: RequestOption) { + console.log('removeRunning request key='+ + 'request.generateCacheKey =' + request.generateCacheKey+ + 'request.generateResourceKey =' + request.generateResourceKey+ + 'request.generateDataKey =' + request.generateDataKey + ) + let index = -1; + for (let i = 0; i < this.runningRequest.length; i++) { + let tempRunning = this.runningRequest[i]; + if (this.keyEqual(request, tempRunning)) { + // 如果key相同 说明目前有任务正在执行,我们记录下当前request 放入pendingRunning + index = i; + break; + } + } + if (index >= 0) { + let request = this.runningRequest.splice(index, 1)[0]; + this.loadNextPending(request); + } + } + + // 执行相同key的pending队列请求 + keyEqualPendingToRun(index:number){ + let nextPending = this.pendingRequest.splice(index, 1)[0]; + this.runningRequest.push(nextPending) + RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch) + } + + searchNextKeyToRun(){ + // 其次则寻找pending中第一个和running不重复的key + let index2 = -1; + for (let i = 0; i < this.pendingRequest.length; i++) { + let temppending = this.pendingRequest[i]; + let hasKeyEqual = false; + for (let j = 0; j < this.runningRequest.length; j++) { + let temprunning = this.runningRequest[j]; + if (this.keyEqual(temppending, temprunning)) { + hasKeyEqual = true; + break; + } + } + if (!hasKeyEqual) { + index2 = i; + } + } + if (index2 >= 0) { + let nextPending = this.pendingRequest.splice(index2, 1)[0]; + this.runningRequest.push(nextPending) + RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch) + } else { + // 不执行 + } + } + + + // 加载下一个key的请求 + loadNextPending(request) { + // 首先寻找被移除key相同的request + let index = -1; + for (let i = 0; i < this.pendingRequest.length; i++) { + let temppending = this.pendingRequest[i]; + if (this.keyEqual(request, temppending)) { + // 如果key相同 说明目前有任务正在执行,我们记录下当前request 放入pendingRunning + index = i; + break; + } + } + if (index >= 0) { + this.keyEqualPendingToRun(index); + } else { + this.searchNextKeyToRun(); + } + } + + // 启动新线程 去磁盘取 去网络取 + loadCacheManager(request: RequestOption) { + console.log("ImageKnife loadCacheManager") + console.log("ImageKnife request ="+JSON.stringify(request)) + if (this.keyNotEmpty(request)) { + let hasRunningRequest = false; + for (let i = 0; i < this.runningRequest.length; i++) { + let tempRunning = this.runningRequest[i]; + if (this.keyEqual(request, tempRunning)) { + + // 如果key相同 说明目前有任务正在执行,我们记录下当前request 放入pendingRunning + hasRunningRequest = true; + break; + } + } + if (hasRunningRequest) { + this.pendingRequest.push(request); + console.log('pendingRequest +1 !') + console.log('pendingRequest request key='+ + 'request.generateCacheKey =' + request.generateCacheKey+ + 'request.generateResourceKey =' + request.generateResourceKey+ + 'request.generateDataKey =' + request.generateDataKey + ) + } else { + this.runningRequest.push(request); + console.log('runningRequest +1 ! RequestManager.execute') + console.log('runningRequest request key='+ + 'request.generateCacheKey =' + request.generateCacheKey+ + 'request.generateResourceKey =' + request.generateResourceKey+ + 'request.generateDataKey =' + request.generateDataKey + ) + // 不存在相同key的 任务可以并行 + RequestManager.execute(request, this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch) + } + } + else { + console.log("key没有生成无法进入存取!") + } + + + } + + private keyNotEmpty(request: RequestOption): boolean{ + if ( + request.generateCacheKey != null && request.generateCacheKey.length > 0 && + request.generateDataKey != null && request.generateDataKey.length > 0 && + request.generateResourceKey != null && request.generateResourceKey.length > 0 + ) { + return true; + } + return false; + } + + private keyEqual(request1: RequestOption, request2: RequestOption): boolean{ + if ( + request1.generateCacheKey == request2.generateCacheKey && + request1.generateResourceKey == request2.generateResourceKey && + request1.generateDataKey == request2.generateDataKey + ) { + return true; + } + return false; + } + + parseSource(request: RequestOption) { + console.log("ImageKnife parseSource") + + if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') { + console.log("ImageKnife parseSource PixelMap") + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = ImageKnifeData.PIXELMAP + imageKnifeData.imageKnifeValue = request.loadSrc as PixelMap + request.loadComplete(imageKnifeData); + } else + if (typeof request.loadSrc == 'string') { + // 进入三级缓存模型 + console.log("ImageKnife parseSource string") + return this.loadResources(request); + } else { + console.log("ImageKnife parseSource Resource") + let res = request.loadSrc as Resource; + console.log("ImageKnife parseSource res="+JSON.stringify(res)) + if (typeof res.id != 'undefined' && typeof res.type != 'undefined') { + //进入三级缓存模型 本地资源不参与磁盘缓存 + let none = new NONE(); + request.diskCacheStrategy(none); + this.loadResources(request); + } else { + console.error("输入参数有问题!") + } + } + } +} + + + diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets b/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets new file mode 100644 index 0000000..69a5c23 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeOption} from '../imageknife/ImageKnifeOption' +import {TransformType} from '../imageknife/transform/TransformType' +import {RequestOption} from '../imageknife/RequestOption' +import {ImageKnifeData} from '../imageknife/ImageKnifeData' +import {PixelMapPack} from '../imageknife/PixelMapPack' + +@Component +export struct ImageKnifeComponent { + @Watch('watchImageKnifeOption') @Link imageKnifeOption: ImageKnifeOption; + @State imageKnifePixelMapPack: PixelMapPack = new PixelMapPack(); + @State imageKnifeResource: Resource = $r('app.media.icon_loading') + @State imageKnifeString: string = '' + @State normalPixelMap: boolean = false; + @State normalResource: boolean = true; + previousData: ImageKnifeData = null; + nowData: ImageKnifeData = null; + @State percentVisible: Visibility = Visibility.Visible + @State retryVisible: Visibility = Visibility.Visible + @State imageVisible: Visibility = Visibility.Visible + @State percent: string = '0%' + @State percentWidth: string = '0%'; + @State percentHeight: string = '0%'; + @State retryWidth: string = '0%'; + @State retryHeight: string = '0%'; + @State imageWidth: string = '100%'; + @State imageHeight: string = '100%'; + + hasRetry:boolean = false; + + build() { + Stack() { + + Text(this.percent) + .fontSize(this.imageKnifeOption.size ? Math.min(this.imageKnifeOption.size.height, this.imageKnifeOption.size.width) / 2 : 24) + .fontWeight(FontWeight.Bold) + .visibility(this.retryVisible) + .width(this.percentWidth) + .height(this.percentHeight) + + Image($r('app.media.icon_retry')) + .onClick(()=>{ + this.retryClick(); + }) + .visibility(this.retryVisible) + .width(this.retryWidth) + .height(this.retryHeight) + + + + Image(this.normalPixelMap ? this.imageKnifePixelMapPack.pixelMap : (this.normalResource ? this.imageKnifeResource : this.imageKnifeString)) + .objectFit(this.imageKnifeOption.imageFit ? this.imageKnifeOption.imageFit : ImageFit.Fill) + .visibility(this.imageVisible) + .width(this.imageWidth) + .height(this.imageHeight) + } + .width(this.imageKnifeOption.size ? this.imageKnifeOption.size.width : '100%') + .height(this.imageKnifeOption.size ? this.imageKnifeOption.size.height : '100%') + .backgroundColor(this.imageKnifeOption.backgroundColor ? this.imageKnifeOption.backgroundColor : Color.White) + .margin(this.imageKnifeOption.margin ? this.imageKnifeOption.margin : { left: 0, top: 0, right: 0, bottom: 0 }) + } + + watchImageKnifeOption() { + this.imageKnifeExecute(); + } + + retryClick(){ + this.hasRetry = true; + this.imageKnifeExecute(); + } + + aboutToAppear() { + console.log('imageKnifeComponent aboutToAppear happened!') + this.imageKnifeExecute(); + } + + configNecessary(request: RequestOption){ + request.load(this.imageKnifeOption.loadSrc) + .addListener((err, data) => { + console.log('request.load callback') + this.imageKnifeChangeSource(data) + this.animateTo('image'); + return false; + }) + + if (this.imageKnifeOption.size) { + request.setImageViewSize(this.imageKnifeOption.size) + } + } + + configCacheStrategy(request: RequestOption){ + if (this.imageKnifeOption.onlyRetrieveFromCache) { + request.retrieveDataFromCache(this.imageKnifeOption.onlyRetrieveFromCache) + } + + if (this.imageKnifeOption.isCacheable) { + request.skipMemoryCache(!this.imageKnifeOption.isCacheable) + } + + if (this.imageKnifeOption.strategy) { + request.diskCacheStrategy(this.imageKnifeOption.strategy) + } + if (this.imageKnifeOption.allCacheInfoCallback) { + request.addAllCacheInfoCallback(this.imageKnifeOption.allCacheInfoCallback) + } + } + + configDisplay(request: RequestOption){ + if(this.imageKnifeOption.animateDuration >= 0){ + request.animateDuration = this.imageKnifeOption.animateDuration; + } + if (this.imageKnifeOption.placeholderSrc) { + request.placeholder(this.imageKnifeOption.placeholderSrc, (data) => { + console.log('request.placeholder callback') + this.imageKnifeChangeSource(data) + this.animateTo('image'); + }) + } + if (this.imageKnifeOption.thumbSizeMultiplier) { + request.thumbnail(this.imageKnifeOption.thumbSizeMultiplier, (data) => { + console.log('request.thumbnail callback') + this.imageKnifeChangeSource(data) + this.animateTo('image'); + }) + } + if (this.imageKnifeOption.errorholderSrc) { + request.errorholder(this.imageKnifeOption.errorholderSrc, (data) => { + console.log('request.errorholder callback') + this.imageKnifeChangeSource(data) + this.animateTo('image'); + }) + } + if (this.imageKnifeOption.transform) { + this.requestAddTransform(request) + } + if (this.imageKnifeOption.dontAnimateFlag) { + request.dontAnimate() + } + + + if (this.imageKnifeOption.displayProgress) { + request.addProgressListener((percentValue: string) => { + // 如果进度条百分比 未展示大小,展示其动画 + this.percent = percentValue; + if(this.imageKnifeOption.displayProgressListener){ + this.imageKnifeOption.displayProgressListener(percentValue); + } + this.animateTo('progress'); + }) + } + + if(this.imageKnifeOption.retryLoad){ + request.addRetryListener((error: any) => { + console.log("RetryListener callback!") + this.animateTo('retry'); + }) + } + } + // imageknife 第一次启动和数据刷新后重新发送请求 + imageKnifeExecute() { + + if(ImageKnife){ + }else{ + ImageKnife = globalThis.exports.default.data.imageKnife; + } + + if(ImageKnife){ + }else{ + console.log('ImageKnife Singleton Initialization Not Completed!') + } + + let request = new RequestOption(); + this.configNecessary(request); + this.configCacheStrategy(request); + this.configDisplay(request); + + ImageKnife.call(request); + } + + imageKnifeChangeSource(data:ImageKnifeData) { + this.imageKnifeSpecialFixed(data); + } + + displayPixelMap(data:ImageKnifeData){ + console.log('displayPixelMap start') + let pixelMapPack2 = new PixelMapPack(); + pixelMapPack2.pixelMap = data.imageKnifeValue as PixelMap; + this.imageKnifePixelMapPack = pixelMapPack2; + this.normalPixelMap = true; + this.normalResource = true; + console.log('displayPixelMap end') + } + + displayResource(data:ImageKnifeData){ + console.log('displayResource start') + this.imageKnifeResource = data.imageKnifeValue as Resource; + this.normalPixelMap = false; + this.normalResource = true; + console.log('displayResource end') + } + + displayString(data:ImageKnifeData){ + console.log('displayString start') + let imageKnifeNeedStr = 'file://' + data.imageKnifeValue; + console.log('imageKnifeNeedStr='+imageKnifeNeedStr) + this.imageKnifeString = imageKnifeNeedStr; + this.normalPixelMap = false; + this.normalResource = false; + console.log('displayString end') + } + imageKnifeSpecialFixed(data:ImageKnifeData) { + if (data.isPixelMap()) { + this.displayPixelMap(data); + } + else if (data.isString()) { + this.displayString(data); + } else if (data.isResource()) { + this.displayResource(data); + } else { + } + } + + animateTo(name: string) { + if (name == 'progress') { + this.percentVisible = Visibility.Visible; + this.imageVisible = Visibility.Hidden; + this.retryVisible = Visibility.Hidden; + if (this.percentWidth == '0%' || this.percentHeight == '0%') { + animateTo({ duration: this.imageKnifeOption.animateDuration , curve: Curve.Linear }, () => { + this.percentWidth = '100%'; + this.percentHeight = '100%'; + this.imageWidth = '0%'; + this.imageHeight = '0%'; + this.retryWidth = '0%'; + this.retryHeight = '0%'; + }) + } + } else if (name == 'image') { + this.imageVisible = Visibility.Visible; + this.percentVisible = Visibility.Hidden; + this.retryVisible = Visibility.Hidden; + if (this.imageWidth == '0%' || this.imageHeight == '0%') { + animateTo({ duration: this.imageKnifeOption.animateDuration, curve: Curve.Linear }, () => { + this.imageWidth = '100%'; + this.imageHeight = '100%'; + this.percentWidth = '0%'; + this.percentHeight = '0%'; + this.retryWidth = '0%'; + this.retryHeight = '0%'; + }) + } + } else if (name == 'retry') { + this.retryVisible = Visibility.Visible; + this.imageVisible = Visibility.Hidden; + this.percentVisible = Visibility.Hidden; + if (this.retryWidth == '0%' || this.retryHeight == '0%') { + animateTo({ duration: this.imageKnifeOption.animateDuration, curve: Curve.Linear }, () => { + this.imageWidth = '0%'; + this.imageHeight = '0%'; + this.percentWidth = '0%'; + this.percentHeight = '0%'; + this.retryWidth = '100%'; + this.retryHeight = '100%'; + }) + } + } + } + + requestAddTransform(request:RequestOption){ + if(TransformType.BlurTransformation == this.imageKnifeOption.transform.transformType){ + request.blur(this.imageKnifeOption.transform.blur) + }else if(TransformType.BrightnessFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.brightnessFilter(this.imageKnifeOption.transform.brightnessFilter) + }else if(TransformType.ContrastFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.contrastFilter(this.imageKnifeOption.transform.contrastFilter) + }else if(TransformType.CropCircleTransformation == this.imageKnifeOption.transform.transformType){ + request.cropCircle() + }else if(TransformType.CropCircleWithBorderTransformation == this.imageKnifeOption.transform.transformType){ + request.cropCircleWithBorder(this.imageKnifeOption.transform.cropCircleWithBorder.border, this.imageKnifeOption.transform.cropCircleWithBorder.obj) + }else if(TransformType.CropSquareTransformation == this.imageKnifeOption.transform.transformType){ + request.cropSquare() + }else if(TransformType.CropTransformation == this.imageKnifeOption.transform.transformType){ + request.crop(this.imageKnifeOption.transform.crop.width,this.imageKnifeOption.transform.crop.height,this.imageKnifeOption.transform.crop.cropType) + }else if(TransformType.GrayscaleTransformation == this.imageKnifeOption.transform.transformType){ + request.grayscale() + }else if(TransformType.InvertFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.invertFilter() + }else if(TransformType.MaskTransformation == this.imageKnifeOption.transform.transformType){ + request.mask(this.imageKnifeOption.transform.mask) + }else if(TransformType.PixelationFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.pixelationFilter(this.imageKnifeOption.transform.pixelationFilter) + }else if(TransformType.RotateImageTransformation == this.imageKnifeOption.transform.transformType){ + request.rotateImage(this.imageKnifeOption.transform.rotateImage) + }else if(TransformType.RoundedCornersTransformation == this.imageKnifeOption.transform.transformType){ + request.roundedCorners(this.imageKnifeOption.transform.roundedCorners) + }else if(TransformType.SepiaFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.sepiaFilter() + }else if(TransformType.SketchFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.sketchFilter() + }else if(TransformType.SwirlFilterTransformation == this.imageKnifeOption.transform.transformType){ + request.swirlFilter(this.imageKnifeOption.transform.swirlFilter) + }else if(TransformType.CenterCrop == this.imageKnifeOption.transform.transformType){ + request.centerCrop() + }else if(TransformType.CenterInside == this.imageKnifeOption.transform.transformType){ + request.centerInside() + }else if(TransformType.FitCenter == this.imageKnifeOption.transform.transformType){ + request.fitCenter() + } + } + + aboutToDisappear() { + } + + onPageShow() { + } + + onPageHide() { + } + + onBackPress() { + } +} + +var ImageKnife; +var defaultTemp = globalThis.exports.default +if (defaultTemp != undefined) { + ImageKnife = defaultTemp.data.imageKnife; +} diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets b/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets new file mode 100644 index 0000000..cd0a4aa --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 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 class ImageKnifeData { + + static PIXELMAP = 'PixelMap' + static STRING = 'string' + static RESOURCE ='Resource' + + static SVG = 'svg'; + static GIF = 'gif'; + static JPG = 'jpg'; + static PNG = 'png'; + static BMP = 'bmp'; + static WEBP = 'webp'; + + + imageKnifeType:string = ''; + imageKnifeValue:PixelMap|string|Resource; + imageKnifeSourceType:string = '' + + isSvg():boolean{ + return ImageKnifeData.SVG == this.imageKnifeSourceType; + } + + isGif():boolean{ + return ImageKnifeData.GIF == this.imageKnifeSourceType; + } + + isJpg():boolean{ + return ImageKnifeData.JPG == this.imageKnifeSourceType; + } + + isPng():boolean{ + return ImageKnifeData.PNG == this.imageKnifeSourceType; + } + + isBmp():boolean{ + return ImageKnifeData.BMP == this.imageKnifeSourceType; + } + + isWebp():boolean{ + return ImageKnifeData.WEBP == this.imageKnifeSourceType; + } + + + isString():boolean{ + return ImageKnifeData.STRING == this.imageKnifeType; + } + isPixelMap():boolean{ + return ImageKnifeData.PIXELMAP == this.imageKnifeType; + } + isResource():boolean{ + return ImageKnifeData.RESOURCE == this.imageKnifeType; + } + + + can2PixelMap(){ // 可以转换为PixelMap的数据源 + return this.isPixelMap() || this.isBmp() || this.isJpg() || this.isWebp() || this.isPng(); + } + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnifeOption.ets b/imageknife/src/main/ets/components/imageknife/ImageKnifeOption.ets new file mode 100644 index 0000000..775a212 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/ImageKnifeOption.ets @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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 {AUTOMATIC} from "../cache/diskstrategy/enum/AUTOMATIC" +import {DiskStrategy} from "../cache/diskstrategy/DiskStrategy" +import {BaseTransform} from "../imageknife/transform/BaseTransform" +import {TransformType} from "../imageknife/transform/TransformType" +import {CropType} from "../imageknife/transform/CropTransformation" +import {AllCacheInfo, IAllCacheInfoCallback} from "../imageknife/interface/IAllCacheInfoCallback" + +export class ImageKnifeOption { + + // 主图资源 + loadSrc: string | PixelMap | Resource; + + // 磁盘缓存策略 + strategy?: DiskStrategy = new AUTOMATIC(); + + // gif加载展示一帧 + dontAnimateFlag? = false; + + // 占位图 + placeholderSrc?: PixelMap | Resource; + + // 失败占位图 + errorholderSrc?: PixelMap | Resource; + + // 缩略图,范围(0,1) + thumbSizeMultiplier?: number; + + // 进度条 + displayProgress?: boolean; + + // 进度条回调 + displayProgressListener?; + + // 重试图层 + retryLoad?: boolean; + + // 动画时长 + animateDuration?: number = 500; + + // 仅使用缓存加载数据 + onlyRetrieveFromCache?: boolean = false; + + // 是否开启第一级内存缓存 + isCacheable?: boolean = true; + + // 变换相关 + transform?:{ + transformType:number, + blur?:number, + roundedCorners?:{ top_left: number, top_right: number, bottom_left: number, bottom_right: number } + cropCircleWithBorder?:{border:number, obj:{ r_color: number, g_color: number, b_color: number }} + crop?:{width: number, height: number, cropType: CropType} + brightnessFilter?:number, + contrastFilter?:number, + pixelationFilter?:number, + swirlFilter?:number, + mask?:Resource, + rotateImage?:number + } + + + // 输出缓存相关内容和信息 + allCacheInfoCallback?: IAllCacheInfoCallback; + size: { + width: number, + height: number + }; + imageFit?: ImageFit; + backgroundColor?: Color | number | string | Resource; + margin?: { + top?: number | string | Resource, + right?: number | string | Resource, + bottom?: number | string | Resource, + left?: number | string | Resource + } | number | string | Resource + + + + constructor() { + + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/PixelMapPack.ets b/imageknife/src/main/ets/components/imageknife/PixelMapPack.ets new file mode 100644 index 0000000..c8b8dbc --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/PixelMapPack.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 class PixelMapPack { + pixelMap:PixelMap +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/RequestOption.ets b/imageknife/src/main/ets/components/imageknife/RequestOption.ets new file mode 100644 index 0000000..9304d76 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/RequestOption.ets @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2021 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 {DiskStrategy} from "../cache/diskstrategy/DiskStrategy" +import {AsyncCallback} from "../imageknife/interface/asynccallback" +import {AsyncSuccess} from "../imageknife/interface/AsyncSuccess" +import {IAllCacheInfoCallback} from "../imageknife/interface/IAllCacheInfoCallback" +import {AUTOMATIC} from "../cache/diskstrategy/enum/AUTOMATIC" +import {BaseTransform} from "../imageknife/transform/BaseTransform" +import {RotateImageTransformation} from "../imageknife/transform/RotateImageTransformation" +import {ImageKnifeData} from "../imageknife/ImageKnifeData" +import {CenterCrop} from '../imageknife/transform/pixelmap/CenterCrop' +import {CenterInside} from '../imageknife/transform/pixelmap/CenterInside' +import {FitCenter} from '../imageknife/transform/pixelmap/FitCenter' +import {RoundedCornersTransformation} from '../imageknife/transform/RoundedCornersTransformation' + +import {CropCircleTransformation} from '../imageknife/transform/CropCircleTransformation' + +import {CropCircleWithBorderTransformation} from '../imageknife/transform/CropCircleWithBorderTransformation' +import {CropSquareTransformation} from '../imageknife/transform/CropSquareTransformation' +import {CropTransformation} from '../imageknife/transform/CropTransformation' +import {CropType} from '../imageknife/transform/CropTransformation' +import {GrayscaleTransformation} from '../imageknife/transform/GrayscaleTransformation' +import {BrightnessFilterTransformation} from '../imageknife/transform/BrightnessFilterTransformation' +import {ContrastFilterTransformation} from '../imageknife/transform/ContrastFilterTransformation' +import {InvertFilterTransformation} from '../imageknife/transform/InvertFilterTransformation' +import {SepiaFilterTransformation} from '../imageknife/transform/SepiaFilterTransformation' +import {SketchFilterTransformation} from '../imageknife/transform/SketchFilterTransformation' +import {BlurTransformation} from '../imageknife/transform/BlurTransformation' +import {PixelationFilterTransformation} from '../imageknife/transform/PixelationFilterTransformation' +import {MaskTransformation} from '../imageknife/transform/MaskTransformation' +import {SwirlFilterTransformation} from '../imageknife/transform/SwirlFilterTransformation' + + +export class RequestOption { + loadSrc: string | PixelMap | Resource; + strategy: DiskStrategy = new AUTOMATIC(); + dontAnimateFlag = false; + placeholderSrc: PixelMap | Resource; + placeholderFunc: AsyncSuccess; + errorholderSrc: PixelMap | Resource; + errorholderFunc: AsyncSuccess; + errorholderData: ImageKnifeData; + thumbSizeMultiplier: number; + + // 如果存在缩略图,则主图延时3000ms加载 + thumbDelayTime: number = 3000 + thumbHolderFunc: AsyncSuccess; + requestListeners: Array>; + + // 进度条 + progressFunc: AsyncSuccess; + + // 重试图层 + retryFunc: AsyncSuccess + + // 图层切换时长 + animateDuration: number = 500; + size: { + width: number, + height: number + } = { width: -1, height: -1 }; + + // 网络下载数据回调 + allCacheInfoCallback: IAllCacheInfoCallback; + onlyRetrieveFromCache: boolean = false; + isCacheable: boolean = true; + + // 变换相关 + transformations: Array> = new Array(); + generateCacheKey: string = ""; + generateResourceKey: string = ""; + generateDataKey: string = ""; + private filesPath: string = ""; // data/data/包名/files目录 + private cachesPath: string = ""; // 网络下载默认存储在data/data/包名/cache/ImageKnifeNetworkFolder/目标md5.img下面 + + // 下载原始文件地址 + downloadFilePath: string = ""; + + // 网络文件下载统一存放 + networkCacheFolder: string = "ImageKnifeNetworkFolder" + + + // 主线图片 状态变化 是否加载完成 + // 主图未加载成功 显示占位图 主图加载成功不展示占位图 + loadMainReady = false; + + // 失败占位图展示状态 当true 表示主图加载失败需要展示失败占位图 + loadErrorReady = false + + // 缩略图展示 + loadThumbnailReady = false; + _svgAndGifFolder: string = "svgAndGifFolder"; // svg和gif的文件路径地址 + _svgAndGifCommitFile: string = "svgAndGifCommitFile"; // svg和gif提交记录 + + constructor() { + // 初始化全局监听 + this.requestListeners = new Array(); + } + + /** + * set image Component size + */ + setImageViewSize(imageSize: { + width: number, + height: number + }) { + this.size.width = imageSize.width; + this.size.height = imageSize.height; + return this; + } + + getFilesPath() { + return this.filesPath; + } + + setFilesPath(path: string) { + this.filesPath = path; + } + + getCachesPath() { + return this.cachesPath; + } + + setCachesPath(path: string) { + this.cachesPath = path; + } + + load(src: string | PixelMap | Resource) { + this.loadSrc = src; + return this; + } + + diskCacheStrategy(strategy: DiskStrategy) { + this.strategy = strategy; + return this; + } + + dontAnimate() { + this.dontAnimateFlag = true; + return this; + } + + // 仅支持 本地图片 + placeholder(src: PixelMap | Resource, func?: AsyncSuccess) { + this.placeholderSrc = src; + this.placeholderFunc = func; + return this; + } + + errorholder(src: PixelMap | Resource, func?: AsyncSuccess) { + this.errorholderSrc = src; + this.errorholderFunc = func; + return this; + } + + thumbnail(sizeMultiplier: number, func?: AsyncSuccess) { + this.thumbSizeMultiplier = sizeMultiplier; + this.thumbHolderFunc = func; + return this; + } + + addProgressListener(func?: AsyncSuccess) { + this.progressFunc = func; + return this; + } + + addRetryListener(func?: AsyncSuccess) { + this.retryFunc = func; + return this; + } + + addListener(func: AsyncCallback) { + this.requestListeners.push(func); + return this; + } + + addAllCacheInfoCallback(func: IAllCacheInfoCallback) { + this.allCacheInfoCallback = func; + return this; + } + + skipMemoryCache(skip: boolean) { + this.isCacheable = !skip; + return this; + } + + retrieveDataFromCache(flag: boolean) { + this.onlyRetrieveFromCache = flag; + } + + rotateImage(degreesToRotate: number) { + let rotateImage = new RotateImageTransformation(degreesToRotate); + this.transformations.push(rotateImage); + return this; + } + + centerCrop() { + this.transformations.push(new CenterCrop()); + return this; + } + centerInside() { + this.transformations.push(new CenterInside()); + return this; + } + fitCenter() { + this.transformations.push(new FitCenter()); + return this; + } + + roundedCorners(obj:{ top_left: number, top_right: number, bottom_left: number, bottom_right: number }){ + let transformation = new RoundedCornersTransformation({top_left: obj.top_left, top_right: obj.top_right, bottom_left: obj.bottom_left, bottom_right: obj.bottom_right}) + this.transformations.push(transformation); + return this; + } + + cropCircle(){ + let transformation = new CropCircleTransformation() + this.transformations.push(transformation); + return this; + } + + cropCircleWithBorder(border:number, obj:{ r_color: number, g_color: number, b_color: number }){ + let transformation = new CropCircleWithBorderTransformation(border,obj) + this.transformations.push(transformation); + return this; + } + + cropSquare(){ + let transformation = new CropSquareTransformation() + this.transformations.push(transformation); + return this; + } + + crop(width: number, height: number, cropType: CropType){ + let transformation = new CropTransformation(width, height, cropType) + this.transformations.push(transformation); + return this; + } + + grayscale(){ + let transformation = new GrayscaleTransformation() + this.transformations.push(transformation); + return this; + } + + brightnessFilter(brightness:number){ + let transformation = new BrightnessFilterTransformation(brightness) + this.transformations.push(transformation); + return this; + } + + contrastFilter(contrast:number){ + let transformation = new ContrastFilterTransformation(contrast) + this.transformations.push(transformation); + return this; + } + + invertFilter(){ + let transformation = new InvertFilterTransformation() + this.transformations.push(transformation); + return this; + } + + sepiaFilter(){ + let transformation = new SepiaFilterTransformation() + this.transformations.push(transformation); + return this; + } + + sketchFilter(){ + let transformation = new SketchFilterTransformation() + this.transformations.push(transformation); + return this; + } + + blur(radius: number){ + let transformation = new BlurTransformation(radius) + this.transformations.push(transformation); + return this; + } + + pixelationFilter(pixel: number){ + let transformation = new PixelationFilterTransformation(pixel) + this.transformations.push(transformation); + return this; + } + + swirlFilter(degree: number){ + let transformation = new SwirlFilterTransformation(degree) + this.transformations.push(transformation); + return this; + } + mask(maskResource: Resource){ + let transformation = new MaskTransformation(maskResource) + this.transformations.push(transformation); + return this; + } + + + // 占位图解析成功 + placeholderOnComplete(imageKnifeData: ImageKnifeData) { + console.log("placeholderOnComplete has called!"); + console.log("Main Image is Ready:" + this.loadMainReady); + if (!this.loadMainReady && !this.loadErrorReady && !this.loadThumbnailReady) { + // 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 + this.placeholderFunc(imageKnifeData) + } + } + + // 占位图解析失败 + placeholderOnError(error) { + console.log("占位图解析失败 error =" + error) + } + + // 缩略图解析成功 + thumbholderOnComplete(imageKnifeData: ImageKnifeData) { + if (!this.loadMainReady && !this.loadErrorReady) { + //主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 + this.thumbHolderFunc(imageKnifeData) + } + } + + // 缩略图解析失败 + thumbholderOnError(error) { + console.log("缩略图解析失败 error =" + error) + } + + // 加载失败 占位图解析成功 + errorholderOnComplete(imageKnifeData: ImageKnifeData) { + // 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用 + this.errorholderData = imageKnifeData; + if (this.loadErrorReady) { + this.errorholderFunc(imageKnifeData) + } + } + + //加载失败 占位图解析失败 + errorholderOnError(error) { + console.log("失败占位图解析失败 error =" + error) + } + + loadComplete(imageKnifeData: ImageKnifeData) { + this.loadMainReady = true; + // 三级缓存数据加载成功 + for (let requestListener of this.requestListeners) { + var ret = requestListener("", imageKnifeData); + if (ret) { + break; + } + } + + if(ImageKnife){ + }else{ + ImageKnife = globalThis.exports.default.data.imageKnife; + } + + if(ImageKnife){ + }else{ + console.log('ImageKnife Singleton Initialization Not Completed!') + } + + // 加载成功之后 + ImageKnife.removeRunning(this); + } + + loadError(err) { + console.log("loadError:"+err); + //失败占位图展示规则 + this.loadErrorReady = true; + if (this.retryFunc) { + // 重试图层优先于加载失败展示 + this.retryFunc(err) + } else { + if (this.errorholderData != null) { + this.errorholderFunc(this.errorholderData) + } + } + + // 加载失败之后 + if(ImageKnife){ + }else{ + ImageKnife = globalThis.exports.default.data.imageKnife; + } + + if(ImageKnife){ + }else{ + console.log('ImageKnife Singleton Initialization Not Completed!') + } + + ImageKnife.removeRunning(this); + } +} + + +var ImageKnife; +var defaultTemp = globalThis.exports.default +if (defaultTemp != undefined) { + ImageKnife = defaultTemp.data.imageKnife; +} diff --git a/imageknife/src/main/ets/components/imageknife/compress/CompressBuilder.ets b/imageknife/src/main/ets/components/imageknife/compress/CompressBuilder.ets new file mode 100644 index 0000000..08e7796 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/CompressBuilder.ets @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2021 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 {OnRenameListener} from '../compress/listener/OnRenameListener' +import {OnCompressListener} from '../compress/listener/OnCompressListener' +import {CompressionPredicate} from '../compress/listener/CompressionPredicate' +import fileio from '@ohos.fileio'; +import {CompressAdapter} from '../compress/provider/CompressAdapter' +import {DataStringPathProvider} from '../compress/provider/DataStringPathProvider' +import {RecourseProvider} from '../compress/provider/RecourseProvider' +import featureability from '@ohos.ability.featureAbility' +import {Engine} from '../compress/Engine' + +export class CompressBuilder { + private _mTargetDir: string; + private _mLeastCompressSize: number= 100; //KB + private _mRenameListener: OnRenameListener; + private _mCompressListener: OnCompressListener; + private _mCompressionPredicate: CompressionPredicate + private _mStreamProviders: Array; + private _mFocusAlpha: boolean; + private _outFilePath: string; + constructor() { + this._mStreamProviders = new Array(); + } + + public setRenameListener(listener: OnRenameListener): CompressBuilder { + this._mRenameListener = listener; + return this; + } + + public setCompressListener(listener: OnCompressListener): CompressBuilder { + this._mCompressListener = listener; + return this; + } + + public filter(compressionPredicate: CompressionPredicate): CompressBuilder { + this._mCompressionPredicate = compressionPredicate; + return this; + } + + public setTargetDir(targetDir: string): CompressBuilder { + this._mTargetDir = targetDir; + if (this._mTargetDir) { + var timestamp = (new Date()).valueOf(); + this._outFilePath = this._mTargetDir + "/" + timestamp + (Math.random() * 100).toFixed(0) + ".jpg"; + } + return this; + } + + public load(list: Array): CompressBuilder { + for (var i = 0; i < list.length; i++) { + let element = list[i]; + if (typeof element === "string") { + this.loadString(element); + } else { + this.loadRecourse(element) + } + } + return this; + } + + /** + * load string file path; + */ + private loadString(path: string) { + this._mStreamProviders.push(new DataStringPathProvider(path)); + } + + /** + * load resource; + */ + private loadRecourse(data: Resource) { + this._mStreamProviders.push(new RecourseProvider(data)); + } + + public setFocusAlpha(focusAlpha: boolean): CompressBuilder { + this._mFocusAlpha = focusAlpha; + return this; + } + + public ignoreBy(size: number): CompressBuilder { + this._mLeastCompressSize = size; + return this; + } + + public launch() { + if (!this._mTargetDir) { + this.getImageCacheFile(); + } else { + this.startCompress(); + } + } + + public async get():Promise { + if (!this._mTargetDir) { + let path = await featureability.getContext().getFilesDir(); + var timestamp = (new Date()).valueOf(); + this._outFilePath = path + "/compress/" + timestamp + (Math.random() * 100).toFixed(0) + ".jpg"; + let result =await this.startAsyncCompress(); + return result; + } else { + let result =await this.startAsyncCompress(); + return result; + } + } + + private async startAsyncCompress():Promise { + let compressPromise = new Promise((resolve, reject) => { + + let compressListener: OnCompressListener = { + start() { + }, + onScuccess(p: PixelMap, path: string) { + resolve(path); + }, + onError(s: string) { + } + } + + compressListener.start(); + + if (this._mStreamProviders == null || this._mStreamProviders.length == 0) { + compressListener.onError("this compress path is empty"); + return; + } + + for (var i = 0; i < this._mStreamProviders.length; i++) { + let element = this._mStreamProviders[i]; + let isOpenfilter = false; + if (this._mCompressionPredicate) { + isOpenfilter = this._mCompressionPredicate.apply(element.getRecoursePath()); + } + + + if (!isOpenfilter) { + new Engine(element, this._outFilePath, this._mFocusAlpha, this._mLeastCompressSize, + compressListener, this._mCompressionPredicate).compress(); + } else { + resolve(element.getRecoursePath()); + } + } + + }) + let result = await compressPromise + return (result as string) + } + + + /** + * start compress + */ + private startCompress() { + if (this._mStreamProviders == null || this._mStreamProviders.length == 0) { + if (this._mCompressListener) { + this._mCompressListener.onError("this compress path is empty"); + } + return; + } + if (this._mRenameListener) { + var name = this._mRenameListener.reName(); + if (this._outFilePath && name) { + var start = this._outFilePath.lastIndexOf("/") + 1 + var end = this._outFilePath.length; + var replaceStr = this._outFilePath.substring(start, end); + this._outFilePath = this._outFilePath.replace(replaceStr, name); + } + } + if (this._mCompressListener) { + this._mCompressListener.start(); + } + + for (var i = 0; i < this._mStreamProviders.length; i++) { + let element = this._mStreamProviders[i]; + let isOpenfilter = false; + if (this._mCompressionPredicate) { + isOpenfilter = this._mCompressionPredicate.apply(element.getRecoursePath()); + } + if (!isOpenfilter) { + new Engine(element, this._outFilePath, this._mFocusAlpha, this._mLeastCompressSize, + this._mCompressListener, this._mCompressionPredicate).compress(); + } else { + if (this._mCompressListener) { + this._mCompressListener.onScuccess(null, element.getRecoursePath()); + } + } + } + } + + private getImageCacheFile() { + featureability.getContext() + .getFilesDir() + .then(path => { + var timestamp = (new Date()).valueOf(); + this._outFilePath = path + "/compress/" + timestamp + (Math.random() * 100).toFixed(0) + ".jpg"; + this.startCompress(); + }) + .catch(error => { + throw new Error("getImageCacheFile happened error:" + JSON.stringify(error)); + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/Engine.ets b/imageknife/src/main/ets/components/imageknife/compress/Engine.ets new file mode 100644 index 0000000..432216b --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/Engine.ets @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2021 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 {OnCompressListener} from '../compress/listener/OnCompressListener' +import {CompressionPredicate} from '../compress/listener/CompressionPredicate' +import {CompressAdapter} from "../compress/provider/CompressAdapter" +import {DataStringPathProvider} from '../compress/provider/DataStringPathProvider' +import {RecourseProvider} from '../compress/provider/RecourseProvider' +import {FileUtils} from '../../cache/FileUtils' +import image from "@ohos.multimedia.image" +import fileio from '@ohos.fileio'; + +export class Engine { + private mFocusAlpha: boolean; + private mCompressListener: OnCompressListener + private mPredicate: CompressionPredicate + private mCompressAdapter: CompressAdapter + private mPath: string + private _mLeastCompressSize: number; //KB + + constructor(compressAdapter: CompressAdapter, + outPath: string, + focusAlpha: boolean, + leastSize: number, + compressListener: OnCompressListener, + predicate: CompressionPredicate) { + this.mCompressAdapter = compressAdapter; + this.mPath = outPath; + this.mFocusAlpha = focusAlpha; + this.mCompressListener = compressListener; + this.mPredicate = predicate; + this._mLeastCompressSize = leastSize; + } + + private computeSize(srcWidth: number, srcHeight: number): number { + srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth; + srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight; + + var longSide = Math.max(srcWidth, srcHeight); + var shortSide = Math.min(srcWidth, srcHeight); + + var scale = shortSide / longSide; + if (scale <= 1 && scale > 0.5625) { + if (longSide < 1664) { + return 1; + } else if (longSide < 4990) { + return 2; + } else if (longSide > 4990 && longSide < 10240) { + return 4; + } else { + return longSide / 1280 == 0 ? 1 : longSide / 1280; + } + } else if (scale <= 0.5625 && scale > 0.5) { + return longSide / 1280 == 0 ? 1 : longSide / 1280; + } else { + return Math.ceil(longSide / (1280.0 / scale)); + } + } + + compress() { + console.info("asasd compress()") + if (this.mCompressAdapter instanceof DataStringPathProvider) { + // file + this.mCompressAdapter.openInternal((buffer) => { + if (!buffer) { + if (this.mCompressListener) { + this.mCompressListener.onError("file read fail,and date is empty") + } + return; + } + if (!this.checkNeedCompress(buffer)) { + return; + } + + var imageResource = image.createImageSource(buffer as any); + imageResource.getImageInfo() + .then(info => { + var height = info.size.height; + var width = info.size.width; + var computeSize = this.computeSize(width, height); + console.info("asasd compress computeSize:" + computeSize); + let options = { + editable: true, + sampleSize: computeSize, + desiredPixelFormat: image.PixelMapFormat.RGB_565, + } + imageResource.createPixelMap(options) + .then(bitmap => { + + }) + .catch(error => { + this.mCompressListener.onError("ptah createPixelMap fail,because error:" + JSON.stringify(error)) + }) + + + }) + .catch(error => { + this.mCompressListener.onError("ptah getImageInfo fail,because error:" + JSON.stringify(error)) + }) + + }) + } else if (this.mCompressAdapter instanceof RecourseProvider) { + // resource + this.mCompressAdapter.openInternal((buffer) => { + if (!buffer) { + if (this.mCompressListener) { + this.mCompressListener.onError("resource read fail,and date is empty") + } + return; + } + if (!this.checkNeedCompress(buffer)) { + return; + } + var imageResource = image.createImageSource(buffer as any); + imageResource.getImageInfo() + .then(info => { + var height = info.size.height; + var width = info.size.width; + var computeSize = this.computeSize(width, height); + let packer = { + format: ["image/jpeg"], + quality: computeSize, + } + var imagePacker = image.createImagePacker(); + imagePacker.packing(imageResource, packer as any, (err,compressBuffer)=>{ + if(err){ + this.mCompressListener.onError("resource packing fail,because error:" + err); + } + + console.log("compressBuffer is null ="+ (compressBuffer==null)); + console.log("compressBuffer is undefined ="+ (compressBuffer == undefined) ); + let dirPath = this.mPath.substring(0, this.mPath.lastIndexOf("/") + 1); + var isDirectory = this.checkDirExist(dirPath); + if (isDirectory) { + this.saveFile(this.mPath, compressBuffer); + this.handResult(compressBuffer, this.mPath); + } else { + fileio.mkdir(dirPath) + .then(() => { + this.saveFile(this.mPath, compressBuffer); + this.handResult(compressBuffer, this.mPath); + }); + } + }) + + + }) + }) + + + + } + } + + private handResult(buffer: ArrayBuffer, path: string) { + var imageRes = image.createImageSource(buffer as any); + let a={ + editable: true, + } + imageRes.createPixelMap(a) + .then(bitmap => { + if (this.mCompressListener) { + this.mCompressListener.onScuccess(bitmap, path); + } + }) + .catch(error => { + if (this.mCompressListener) { + this.mCompressListener.onError("buffer generated pixelMap fail,because error:" + JSON.stringify(error)) + } + }) + } + + private checkNeedCompress(buf: ArrayBuffer): boolean{ + if (!buf) { + return false; + } + var length = buf.byteLength / 1024; + return length > this._mLeastCompressSize; + } + + private saveFile(path: string, content: ArrayBuffer) { + FileUtils.getInstance().writeFile(path,content); + } + + private checkDirExist(dirPath: string): boolean{ + var isExist; + try { + fileio.accessSync(dirPath, 0) + isExist = true; + } catch (e) { + //不符合条件则进入 + isExist = false; + } + return isExist; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/listener/CompressDataListener.ets b/imageknife/src/main/ets/components/imageknife/compress/listener/CompressDataListener.ets new file mode 100644 index 0000000..fc072f7 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/listener/CompressDataListener.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 interface CompressDataListener { + (t: T); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/listener/CompressionPredicate.ets b/imageknife/src/main/ets/components/imageknife/compress/listener/CompressionPredicate.ets new file mode 100644 index 0000000..79bec3c --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/listener/CompressionPredicate.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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. + */ + +/** + * filter out unsupported + */ +export interface CompressionPredicate { + apply(path: string): boolean; +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/listener/OnCompressListener.ets b/imageknife/src/main/ets/components/imageknife/compress/listener/OnCompressListener.ets new file mode 100644 index 0000000..87b40d7 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/listener/OnCompressListener.ets @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 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. + */ +/** + * compress listener + */ +export interface OnCompressListener { + /** + * compress start + */ + start(); + /** + * compress success + */ + onScuccess(p: PixelMap, path: string); + /** + * compress fail + */ + onError(s: string); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/listener/OnRenameListener.ets b/imageknife/src/main/ets/components/imageknife/compress/listener/OnRenameListener.ets new file mode 100644 index 0000000..5be73d7 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/listener/OnRenameListener.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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. + */ + +/** + * rename listener + */ +export interface OnRenameListener { + reName():string; +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/provider/CompressAdapter.ets b/imageknife/src/main/ets/components/imageknife/compress/provider/CompressAdapter.ets new file mode 100644 index 0000000..ff7a7e9 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/provider/CompressAdapter.ets @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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 {CompressProvider} from "../provider/CompressProvider" +import {CompressDataListener} from "../listener/CompressDataListener" + +export abstract class CompressAdapter implements CompressProvider { + mData: ArrayBuffer; + mPath: string; + + close() { + } + + openData(): ArrayBuffer{ + return this.mData; + } + + getPath(): string{ + return this.mPath; + }; + + abstract openInternal(callback: CompressDataListener); + + abstract getRecoursePath(): string; + + abstract getPixelMapFormat(): PixelMapFormat; + + getFormat(s: string): PixelMapFormat{ + if (!s) { + return undefined; + } + if (s == "jpg" || s == "JPG") { + return PixelMapFormat.JPG; + } else if (s == "png" || s == "PNG") { + return PixelMapFormat.PNG; + } else if (s == "jpeg" || s == "JPEG") { + return PixelMapFormat.JPEG; + } else if (s == "gif" || s == "GIF") { + return PixelMapFormat.GIF; + } else if (s == "webp" || s == "WEBP" || s == "WebP") { + return PixelMapFormat.WEBP; + } else if (s == "bmg" || s == "BMG") { + return PixelMapFormat.BMG; + } else { + return PixelMapFormat.NONE; + } + } +} + +export enum PixelMapFormat { + JPG, + PNG, + JPEG, + WEBP, + BMG, + GIF, + NONE +} + diff --git a/imageknife/src/main/ets/components/imageknife/compress/provider/CompressProvider.ets b/imageknife/src/main/ets/components/imageknife/compress/provider/CompressProvider.ets new file mode 100644 index 0000000..6b74795 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/provider/CompressProvider.ets @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 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 interface CompressProvider { + close(); + + openData():ArrayBuffer; + + getPath(): string; + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/provider/DataStringPathProvider.ets b/imageknife/src/main/ets/components/imageknife/compress/provider/DataStringPathProvider.ets new file mode 100644 index 0000000..7d75c0e --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/provider/DataStringPathProvider.ets @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 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 {CompressAdapter, PixelMapFormat} from '../provider/CompressAdapter' +import {CompressDataListener} from '../listener/CompressDataListener' +import {FileUtils} from '../../../cache/FileUtils' + +export class DataStringPathProvider extends CompressAdapter { + constructor(s: string) { + super() + this.mPath = s; + } + + getRecoursePath(): string{ + return this.mPath; + } + + openInternal(callback: CompressDataListener) { + if (!this.mPath) { + throw new Error('DataStringPathProvider error path is empty'); + } + var buffer = FileUtils.getInstance().readFilePic(this.mPath); + this.mData = buffer; + if (callback) { + callback(buffer); + } + } + + getPixelMapFormat(): PixelMapFormat{ + if (!this.mPath) { + return PixelMapFormat.NONE; + } + let lastIndex = this.mPath.lastIndexOf('/') + let s = this.mPath.substring(lastIndex + 1, this.mPath.length); + return this.getFormat(s); + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/compress/provider/RecourseProvider.ets b/imageknife/src/main/ets/components/imageknife/compress/provider/RecourseProvider.ets new file mode 100644 index 0000000..eb0cc03 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/compress/provider/RecourseProvider.ets @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 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 {CompressAdapter, PixelMapFormat} from "../provider/CompressAdapter" +import resmgr from '@ohos.resourceManager' +import {CompressDataListener} from "../listener/CompressDataListener" +import {FileTypeUtil} from '../../../imageknife/utils/FileTypeUtil' + +export class RecourseProvider extends CompressAdapter { + private static CHARS: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + private static DEFAULT_RESOURCE_PATH: string= "Resource" + private _mLookup: Uint8Array = new Uint8Array(256); + private _mResourceData: Resource; + private _mPixelMapHeader: string; + + constructor(s: Resource) { + super() + this._mResourceData = s; + this.mPath = RecourseProvider.DEFAULT_RESOURCE_PATH; + for (var index = 0; index < RecourseProvider.CHARS.length; index++) { + this._mLookup[RecourseProvider.CHARS.charCodeAt(index)] = index; + } + } + + getRecoursePath(): string{ + return this.mPath; + } + + openInternal(callback: CompressDataListener) { + console.info("asasd compress openInternal _mData"); + if (!this._mResourceData) { + throw Error("compress resource is empty"); + } + resmgr.getResourceManager() + .then(result => { + result.getMedia(this._mResourceData + .id) + .then(data => { + let buffer = this.uint8ArrayToBuffer(data); + let fileTypeUtil = new FileTypeUtil() + this._mPixelMapHeader = fileTypeUtil.getFileType(buffer); + callback(buffer); + }) + .catch(err => { + console.log("RecourseProvider openInternal err" + JSON.stringify(err)); + }) + }) + } + + getPixelMapFormat(): PixelMapFormat{ + if (!this._mPixelMapHeader) { + return PixelMapFormat.NONE; + } + return this.getFormat(this._mPixelMapHeader); + } + /** + * data decode + */ + decode(base64: string, callback: CompressDataListener) { + let bufferLength = base64.length, + len = base64.length, + i, + p = 0, + encoded1, + encoded2, + encoded3, + encoded4; + + if (base64[base64.length - 1] === '=') { + bufferLength--; + if (base64[base64.length - 2] === '=') { + bufferLength--; + } + } + + const arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i += 4) { + encoded1 = this._mLookup[base64.charCodeAt(i)]; + encoded2 = this._mLookup[base64.charCodeAt(i + 1)]; + encoded3 = this._mLookup[base64.charCodeAt(i + 2)]; + encoded4 = this._mLookup[base64.charCodeAt(i + 3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + + } + this.mData = arraybuffer; + if (callback) { + callback(arraybuffer); + } + } + + uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/constants/Constants.ets b/imageknife/src/main/ets/components/imageknife/constants/Constants.ets new file mode 100644 index 0000000..e9a5b77 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/constants/Constants.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 class Constants { + public static PROJECT_TAG: string= "ImageKnife_js" +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/constants/ResourceTypeEts.ets b/imageknife/src/main/ets/components/imageknife/constants/ResourceTypeEts.ets new file mode 100644 index 0000000..5c3fdee --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/constants/ResourceTypeEts.ets @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 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 ResourceTypeEts { + COLOR = 10001, + FLOAT, + STRING, + PLURAL, + BOOLEAN, + INTARRAY, + INTEGER, + PATTERN, + STRARRAY, + MEDIA = 20000, + RAWFILE = 30000 +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/crop/Crop.ets b/imageknife/src/main/ets/components/imageknife/crop/Crop.ets new file mode 100644 index 0000000..c171b4c --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/crop/Crop.ets @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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 {AsyncTransform} from "../transform/AsyncTransform" +import image from "@ohos.multimedia.image" +import {TransformUtils} from "../transform/TransformUtils" + +export namespace Crop { + + export function crop(buf: ArrayBuffer, x: number, y: number, cropWidth: number, cropHeight: number, func?: AsyncTransform, colorRatio?: number) { + if (!buf || buf.byteLength <= 0) { + console.log("Crop buf is empty"); + if (func) { + func("Crop buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + if (x < 0 || x > pixelMapWidth) { + func("Crop error x must be less than pixelMapWidth ", null) + return; + } + if (y < 0 || y > pixelMapHeight) { + func("Crop error x must be less than pixelMapHeight ", null) + return; + } + var options = { + editable: true, + rotate: 0, + desiredSize: { + width: pixelMapWidth, + height: pixelMapHeight + }, + desiredRegion: { size: { width: cropWidth, height: cropHeight }, + x: x, + y: y, + }, + } + imageSource.createPixelMap(options) + .then((data) => { + if (colorRatio && colorRatio <= 1) { + colorRatioPixelMap(data, pixelMapWidth, pixelMapHeight, colorRatio, func); + } else { + func("", data); + } + }) + .catch((e) => { + func(e, null); + }) + }) + } + + async function colorRatioPixelMap(data: any, width: number, height: number, colorRatio: number, func?: AsyncTransform) { + if (!data) { + func("colorRatio pixelMap is null", null); + return; + } + if (colorRatio > 1) { + throw new Error("the colorRatio must be <= 1"); + } + var buffer = new ArrayBuffer(width * height * 5); + var bytes = new Uint8Array(buffer); + var buffer1B = new ArrayBuffer(width * height * 5); + var bytes1B = new Uint8Array(buffer1B); + + let readPromise = data.readPixelsToBuffer(buffer) + await readPromise; + for (let i = 0;i < bytes.length; i++) { + bytes1B[i] = bytes[i] * colorRatio; + } + let writePromise = data.writeBufferToPixels(buffer1B) + await writePromise; + func("", data); + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/crop/CropImage.ets b/imageknife/src/main/ets/components/imageknife/crop/CropImage.ets new file mode 100644 index 0000000..aa4c682 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/crop/CropImage.ets @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 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 {CropOptions} from "../crop/CropOptions"; + +@Component +export struct CropImage { + @Link _mOptions: CropOptions; + @State _rotate: number= 0; + @State _scale: number= 1; + + build() { + Stack() { + Image(this._mOptions.src) + .width(this._mOptions.size.width) + .height(this._mOptions.size.height) + .objectFit(ImageFit.None) + .rotate({ + z: 1, + centerX: this._mOptions.size.width / 2, + centerY: this._mOptions.size.height / 2, + angle: this._rotate + }) + .scale({ x: this._scale, y: this._scale, z: 1.0 }) + .gesture(GestureGroup(GestureMode.Parallel, + RotationGesture({ fingers: 1 }).onActionUpdate(event => { + this._rotate = event.angle; + }), PinchGesture({ fingers: 2 }).onActionUpdate(event => { + this._scale = event.scale; + }) + ).onCancel(() => { + console.log("CropImage gesture cancel"); + }) + ) + }.width(this._mOptions.size.width).height(this._mOptions.size.height); + } +} diff --git a/imageknife/src/main/ets/components/imageknife/crop/CropOptions.ets b/imageknife/src/main/ets/components/imageknife/crop/CropOptions.ets new file mode 100644 index 0000000..37e0214 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/crop/CropOptions.ets @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2021 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 class CropOptions { + src: string | PixelMap | Resource; + size: { + width: number, + height: number; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/entry/ArcPoint.ets b/imageknife/src/main/ets/components/imageknife/entry/ArcPoint.ets new file mode 100644 index 0000000..1754f7f --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/entry/ArcPoint.ets @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 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 class ArcPoint { + private x: number; + private y: number; + + constructor(x: number, y: number) { + this.y = y; + this.x = x; + } + + getX(): number{ + return this.x; + } + + getY(): number{ + return this.y + } +} diff --git a/imageknife/src/main/ets/components/imageknife/entry/PixelEntry.ets b/imageknife/src/main/ets/components/imageknife/entry/PixelEntry.ets new file mode 100644 index 0000000..b14b30d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/entry/PixelEntry.ets @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 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 class PixelEntry { + a: number; + b: number; + r: number; + g: number; + f: number; + pixel: number; + + public toString(): string { + return "PixelEntry a:" + this.a + ";b:" + this.b + ";r:" + this.r + ";g:" + this.g + ";f:" + this.f; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/holder/ErrorHolderManager.ets b/imageknife/src/main/ets/components/imageknife/holder/ErrorHolderManager.ets new file mode 100644 index 0000000..242a650 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/holder/ErrorHolderManager.ets @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 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 "../../imageknife/RequestOption" +import {FileTypeUtil} from "../../imageknife/utils/FileTypeUtil" +import {ImageKnifeData} from "../ImageKnifeData" +import {ParseImageUtil} from '../utils/ParseImageUtil' +import {ParseResClient} from '../resourcemanage/ParseResClient' +import image from "@ohos.multimedia.image" + +export class ErrorHolderManager { + private options: RequestOption; + + constructor(option: RequestOption) { + this.options = option; + } + + static execute(option: RequestOption) { + let manager = new ErrorHolderManager(option); + return new Promise(manager.process.bind(manager)) + .then(option.errorholderOnComplete.bind(option)).catch(option.errorholderOnError.bind(option)); + } + + process(onComplete, onError) { + this.displayErrorholder(onComplete, onError); + } + + private displayErrorholder(onComplete, onError) { + console.log("displayErrorholder") + if ((typeof (this.options.errorholderSrc as image.PixelMap).isEditable) == 'boolean') { + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = ImageKnifeData.PIXELMAP + imageKnifeData.imageKnifeValue = this.options.placeholderSrc as PixelMap + onComplete(imageKnifeData); + } else if (typeof this.options.errorholderSrc == 'string') { + + } else { + let res = this.options.errorholderSrc as Resource; + if (typeof res.id != 'undefined' && typeof res.id != 'undefined') { + let resourceFetch = new ParseResClient(); + let suc = (arraybuffer) => { + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arraybuffer); + if ("gif" == typeValue || "svg" == typeValue) { + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = "Resource" + imageKnifeData.imageKnifeValue = this.options.errorholderSrc as Resource + imageKnifeData.imageKnifeSourceType = typeValue; + onComplete(imageKnifeData); + } else { + let parseImageUtils = new ParseImageUtil(); + let success = (value: PixelMap) => { + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = "PixelMap" + imageKnifeData.imageKnifeValue = value + imageKnifeData.imageKnifeSourceType = typeValue; + onComplete(imageKnifeData); + } + parseImageUtils.parseImage(arraybuffer, success, onError) + } + } + resourceFetch.loadResource(res, suc, onError) + } else { + onError("ErrorHolderManager 输入参数有问题!") + } + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/holder/PlaceHolderManager.ets b/imageknife/src/main/ets/components/imageknife/holder/PlaceHolderManager.ets new file mode 100644 index 0000000..56d711d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/holder/PlaceHolderManager.ets @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 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 "../../imageknife/RequestOption" +import {ResourceTypeEts} from "../../imageknife/constants/ResourceTypeEts" +import {Base64} from "../../cache/Base64" +import {FileTypeUtil} from "../../imageknife/utils/FileTypeUtil" +import {ImageKnifeData} from "../ImageKnifeData" +import {ParseImageUtil} from '../utils/ParseImageUtil' +import {ParseResClient} from '../resourcemanage/ParseResClient' +import resourceManager from '@ohos.resourceManager'; +import image from "@ohos.multimedia.image" + +export class PlaceHolderManager { + private options: RequestOption; + + constructor(option: RequestOption) { + this.options = option; + } + + static execute(option: RequestOption) { + let manager = new PlaceHolderManager(option); + return new Promise(manager.process.bind(manager)) + .then(option.placeholderOnComplete.bind(option)).catch(option.placeholderOnError.bind(option)); + } + + process(onComplete, onError) { + this.displayPlaceholder(onComplete, onError); + } + + private displayPlaceholder(onComplete, onError) { + console.log("displayPlaceholder") + if ((typeof (this.options.placeholderSrc as image.PixelMap).isEditable) == 'boolean') { + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = ImageKnifeData.PIXELMAP + imageKnifeData.imageKnifeValue = this.options.placeholderSrc as PixelMap + onComplete(imageKnifeData); + } else if (typeof this.options.placeholderSrc == 'string') { + + } else { + let res = this.options.placeholderSrc as Resource; + if (typeof res.id != 'undefined' && typeof res.id != 'undefined') { + let resourceFetch = new ParseResClient(); + let suc = (arraybuffer) => { + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arraybuffer); + if ("gif" == typeValue || "svg" == typeValue) { + let imageKnifeData = this.createImageKnifeData("Resource", this.options.placeholderSrc as Resource, typeValue); + onComplete(imageKnifeData); + } else { + let parseImageUtils = new ParseImageUtil(); + let success = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData('PixelMap', value, typeValue); + onComplete(imageKnifeData); + } + parseImageUtils.parseImage(arraybuffer, success, onError) + } + } + resourceFetch.loadResource(res, suc, onError) + } else { + onError("PlaceHolderManager 输入参数有问题!") + } + } + } + private createImageKnifeData(imageKnifeType:string, imageKnifeValue:PixelMap|string|Resource, imageKnifeSourceType:string):ImageKnifeData{ + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = imageKnifeType; + imageKnifeData.imageKnifeValue = imageKnifeValue; + imageKnifeData.imageKnifeSourceType = imageKnifeSourceType; + return imageKnifeData; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/interface/AsyncCallback.ets b/imageknife/src/main/ets/components/imageknife/interface/AsyncCallback.ets new file mode 100644 index 0000000..0097fc0 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/interface/AsyncCallback.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 interface AsyncCallback { + (err: string, data: T): boolean; +} diff --git a/imageknife/src/main/ets/components/imageknife/interface/AsyncSuccess.ets b/imageknife/src/main/ets/components/imageknife/interface/AsyncSuccess.ets new file mode 100644 index 0000000..816e3d4 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/interface/AsyncSuccess.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 interface AsyncSuccess { + (data: T); +} diff --git a/imageknife/src/main/ets/components/imageknife/interface/DataCallBack.ets b/imageknife/src/main/ets/components/imageknife/interface/DataCallBack.ets new file mode 100644 index 0000000..0ccd3ba --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/interface/DataCallBack.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 interface DataCallBack { + callback(data: T); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/interface/IAllCacheInfoCallback.ets b/imageknife/src/main/ets/components/imageknife/interface/IAllCacheInfoCallback.ets new file mode 100644 index 0000000..9643f5f --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/interface/IAllCacheInfoCallback.ets @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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 {ImageKnifeData} from "../../imageknife/ImageKnifeData" + +export class AllCacheInfo { + memoryCacheInfo: { + key: string, + data: ImageKnifeData + } + + resourceCacheInfo: { + path: string, + key: string + } + + dataCacheInfo: { + path: string, + key: string + } +} + +export interface IAllCacheInfoCallback { + (cacheInfo: AllCacheInfo); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/interface/IParseImage.ets b/imageknife/src/main/ets/components/imageknife/interface/IParseImage.ets new file mode 100644 index 0000000..96024a4 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/interface/IParseImage.ets @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 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 interface IParseImage { + parseImage(imageinfo:ArrayBuffer, onCompleteFunction, onErrorFunction); + parseImageThumbnail(scale:number, imageinfo:ArrayBuffer, onCompleteFunction, onErrorFunction); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/networkmanage/DownloadClient.ets b/imageknife/src/main/ets/components/imageknife/networkmanage/DownloadClient.ets new file mode 100644 index 0000000..f4713c6 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/networkmanage/DownloadClient.ets @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2021 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 {IDataFetch} from "../networkmanage/IDataFetch" +import {RequestOption} from "../RequestOption" +import {Md5} from "../../cache/Md5" +import{FileUtils} from "../../cache/FileUtils" + +import loadRequest from '@ohos.request'; + +export class DownloadClient implements IDataFetch { + loadData(request: RequestOption, onCompleteFunction, onErrorFunction) { + + let requestUrl = request.loadSrc as string; + if (requestUrl.startsWith("http") || requestUrl.startsWith("https")) { + let filename = Md5.hashStr(request.generateDataKey); + let downloadFolder = request.getFilesPath() + "/" + request.networkCacheFolder; + let allpath = request.getFilesPath() + "/" + request.networkCacheFolder + "/" + filename + ".img"; + + if (!FileUtils.getInstance().existFolder(downloadFolder)) { + FileUtils.getInstance().createFolder(downloadFolder) + } + + if (FileUtils.getInstance().exist(allpath)) { + FileUtils.getInstance().deleteFile(allpath) + } + + let desc = filename + ".img"; + + var downloadConfig = { + url: (request.loadSrc as string), + filePath: allpath, + header: {}, + enableMetered: true, + enableRoaming: true, + description: desc, + networkType: 1, + title: filename, + }; + + let loadTask = null; + loadRequest.download(downloadConfig, (err, downloadTask) =>{ + if(err){ + onErrorFunction(err) + }else { + if (downloadTask) { + loadTask = downloadTask; + + loadTask.on('progress', (err, receivedSize, totalSize) => { + let percent = Math.round(((receivedSize * 1.0) / (totalSize * 1.0)) * 100) + "%" + if (request.progressFunc) { + request.progressFunc(percent); + } + }); + + loadTask.on('complete', () => { + let downloadPath = allpath; + request.downloadFilePath = downloadPath; + let arraybuffer = FileUtils.getInstance().readFilePic(downloadPath) + onCompleteFunction(arraybuffer); + FileUtils.getInstance().deleteFile(downloadPath); + + loadTask.off('complete', () => { + loadTask = null; + }) + + loadTask.off('pause', () => { + }) + + loadTask.off('remove', () => { + }) + + loadTask.off('progress', () => { + }) + + loadTask.off('fail', () => { + }) + }) + + loadTask.on('pause', () => { + }) + + loadTask.on('remove', () => { + }) + + loadTask.on('fail', (err) => { + onErrorFunction('DownloadClient Download task fail err =' + err) + if (loadTask) { + loadTask.remove().then(result => { + loadTask.off('complete', () => { + }) + + loadTask.off('pause', () => { + }) + + loadTask.off('remove', () => { + }) + + loadTask.off('progress', () => { + }) + + loadTask.off('fail', () => { + }) + loadTask = null + }).catch(err => { + loadTask = null; + console.log('DownloadClient Download task fail err =' + err); + }) + } + }) + + } else { + onErrorFunction('DownloadClient downloadTask dismiss!') + } + } + }) + + } else { + onErrorFunction("DownloadClient 暂不支持除http之外的uri加载") + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/networkmanage/IDataFetch.ets b/imageknife/src/main/ets/components/imageknife/networkmanage/IDataFetch.ets new file mode 100644 index 0000000..cb25d56 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/networkmanage/IDataFetch.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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" + +// 网络接口 +export interface IDataFetch { + loadData(request: RequestOption, onCompleteFunction, onErrorFunction); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/PngCallback.ets b/imageknife/src/main/ets/components/imageknife/pngj/PngCallback.ets new file mode 100644 index 0000000..54d0bbd --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/PngCallback.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 interface PngCallback{ + (sender:R, receover:T) +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/PngReader.ets b/imageknife/src/main/ets/components/imageknife/pngj/PngReader.ets new file mode 100644 index 0000000..26c2934 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/PngReader.ets @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 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 {Closeable} from "/imageknife/pngj/io/Closeable" +import {ImageInfo} from "/imageknife/pngj/entry/ImageInfo" + +export class PngReader implements Closeable { + private static LOG_TAG: string= "PngReader"; + private static MAX_TOTAL_BYTES_READ_DEFAULT: number= 901001001; + private static MAX_BYTES_METADATA_DEFAULT: number= 5024024; + private static MAX_CHUNK_SIZE_SKIP: number= 2024024; + public imgInfo: ImageInfo; + public interlaced: boolean; + + constructor(shouldCloseStream: boolean) { + + } + + close(): void { + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/PngWork.js b/imageknife/src/main/ets/components/imageknife/pngj/PngWork.js new file mode 100644 index 0000000..a4d7deb --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/PngWork.js @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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 arkWorker from '@ohos.worker'; +import {UPNG} from '../../imageknife/pngj/UPNG' + +export function handler (e) { + var data = e.data; + switch (data.type) { + case 'readPngImageAsync': + console.log('readPngImageAsync worker start') + var png = UPNG.decode(data.data); + let array = png.data; + let arrayData = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + png.data = arrayData; + let dataObj = { type: 'readPngImageAsync', data: png, receiver: data.data} + arkWorker.parentPort.postMessage(dataObj, [png.data, data.data]); + console.log('readPngImageAsync worker to main') + break; + case 'writePngWithStringAsync': + console.log('writePngWithStringAsync worker start') + let addInfo = data.info; + let pngDecode = UPNG.decode(data.data); + let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0) + let dataObj2 = { type: 'writePngWithStringAsync', data: newPng, receiver: data.data} + arkWorker.parentPort.postMessage(dataObj2, [newPng, data.data]); + console.log('writePngWithStringAsync worker to main') + break; + case 'writePngAsync': + console.log('writePngAsync worker start') + let pngDecode3 = UPNG.decode(data.data); + let newPng3 = UPNG.encode(UPNG.toRGBA8(pngDecode3), pngDecode3.width, pngDecode3.height, 0) + let dataObj3 = { type: 'writePngAsync', data: newPng3, receiver: data.data} + arkWorker.parentPort.postMessage(dataObj3, [newPng3, data.data]); + console.log('writePngAsync worker to main') + break; + case 'normal': + arkWorker.parentPort.postMessage(data); + break; + case 'error': + throw new Error('123'); + break; + case 'buffer': + let uint8Array = new Uint8Array(data.data); + arkWorker.parentPort.postMessage(data, [data.data]); + + break; + default: + + break + } +} + + diff --git a/imageknife/src/main/ets/components/imageknife/pngj/Pngj.ets b/imageknife/src/main/ets/components/imageknife/pngj/Pngj.ets new file mode 100644 index 0000000..2f1b87f --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/Pngj.ets @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2021 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 {UPNG} from '../pngj/UPNG'; +import {PngCallback} from '../pngj/PngCallback'; +import image from '@ohos.multimedia.image'; +import resourceManager from '@ohos.resourceManager'; +import featureability from '@ohos.ability.featureAbility' +import ArkWorker from '@ohos.worker' + +export class Pngj { + readPngImageInfo(arraybuffer: ArrayBuffer, callback:PngCallback) { + let imageSource = image.createImageSource(arraybuffer as any); + imageSource.getImageInfo((err, value) => { + if (err) { + return; + } + callback(arraybuffer, value); + }); + } + + /** + * + * @param pngBuffer ArrayBuffer containing the PNG file + * @param callback + * returns an image object with following properties: + * width: the width of the image + * height: the height of the image + * depth: number of bits per channel + * ctype: color type of the file (Truecolor, Grayscale, Palette ...) + * frames: additional info about frames (frame delays etc.) + * tabs: additional chunks of the PNG file + * data: pixel data of the image + */ + readPngImage(pngBuffer: ArrayBuffer, callback:PngCallback) { + var png = UPNG.decode(pngBuffer); + callback(pngBuffer, png) + } + + writePngWithString(addInfo:string, pngBuffer: ArrayBuffer,callback:PngCallback) { + var pngDecode = UPNG.decode(pngBuffer); + var newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0) + callback(pngBuffer, newPng); + } + + writePng(pngBuffer: ArrayBuffer,callback:PngCallback) { + var pngDecode = UPNG.decode(pngBuffer); + var newPng = UPNG.encode(UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0) + callback(pngBuffer, newPng); + } + + readPngImageAsync(worker:ArkWorker.Worker, pngBuffer: ArrayBuffer, callback:PngCallback){ + console.log('readPngImageAsync start') +// let worker = new ArkWorker.Worker('workers/worker1.js', { type: 'classic', name: 'readPngImageAsync'}) + worker.onerror = function(data){ + + } + + worker.onmessageerror = function(e){ + + } + + worker.onexit = function(){ + + } + + worker.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case 'readPngImageAsync': + callback(data.receiver, data.data) + break; + default: + break + } + worker.terminate(); + } + + var obj = { type: 'readPngImageAsync', data:pngBuffer} + worker.postMessage(obj, [pngBuffer]) + console.log('readPngImageAsync to worker') + } + + + writePngWithStringAsync(worker:ArkWorker.Worker,addInfo:string, pngBuffer:ArrayBuffer, callback:PngCallback) { + console.log('writePngWithStringAsync start') +// let worker = new ArkWorker.Worker('workers/worker1.js', { type: 'classic', name: 'writePngWithStringAsync'}) + worker.onerror = function(data){ + + } + + worker.onmessageerror = function(e){ + + } + + worker.onexit = function(){ + + } + + worker.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case 'writePngWithStringAsync': + callback(data.receiver, data.data) + break; + default: + break + } + worker.terminate(); + } + + var obj = { type: 'writePngWithStringAsync', data:pngBuffer, info: addInfo} + worker.postMessage(obj, [pngBuffer]) + console.log('writePngWithStringAsync to worker') + } + + + writePngAsync(worker:ArkWorker.Worker,pngBuffer:ArrayBuffer, callback:PngCallback) { + console.log('writePngAsync start') +// let worker = new ArkWorker.Worker('workers/worker1.js', { type: 'classic', name: 'writePngAsync'}) + worker.onerror = function(data){ + + } + + worker.onmessageerror = function(e){ + + } + + worker.onexit = function(){ + + } + + worker.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case 'writePngAsync': + callback(data.receiver, data.data) + break; + default: + break + } + worker.terminate(); + } + + var obj = { type: 'writePngAsync', data:pngBuffer} + worker.postMessage(obj, [pngBuffer]) + console.log('writePngAsync to worker') + } + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/PngjException.ets b/imageknife/src/main/ets/components/imageknife/pngj/PngjException.ets new file mode 100644 index 0000000..d35951c --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/PngjException.ets @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 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 class PngjException extends Error { + constructor(s: string) { + super(s) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/UPNG.js b/imageknife/src/main/ets/components/imageknife/pngj/UPNG.js new file mode 100644 index 0000000..f5bd3ec --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/UPNG.js @@ -0,0 +1,1906 @@ +/** +* MIT License +* +*Copyright (c) 2017 Photopea +* +*Permission is hereby granted, free of charge, to any person obtaining a copy +*of this software and associated documentation files (the 'Software'), to deal +*in the Software without restriction, including without limitation the rights +*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +*copies of the Software, and to permit persons to whom the Software is +*furnished to do so, subject to the following conditions: +* +*The above copyright notice and this permission notice shall be included in all +*copies or substantial portions of the Software. +* +*THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +*SOFTWARE.*/ +const pako = require('pako'); +const UZIP = null; + +export { + UPNG +} + +var UPNG = {}; + + +UPNG.toRGBA8 = function (out) { + var w = out.width, h = out.height; + if (out.tabs.acTL == null) return [UPNG.toRGBA8.decodeImage(out.data, w, h, out).buffer]; + + var frms = []; + if (out.frames[0].data == null) out.frames[0].data = out.data; + + var len = w * h * 4, img = new Uint8Array(len), empty = new Uint8Array(len), prev = new Uint8Array(len); + for (var i = 0; i < out.frames.length; i++) { + var frm = out.frames[i]; + var fx = frm.rect.x, fy = frm.rect.y, fw = frm.rect.width, fh = frm.rect.height; + var fdata = UPNG.toRGBA8.decodeImage(frm.data, fw, fh, out); + + if (i != 0) for (var j = 0; j < len; j++) prev[j] = img[j]; + + if (frm.blend == 0) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 0); + else if (frm.blend == 1) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 1); + + frms.push(img.buffer.slice(0)); + + if (frm.dispose == 0) { + } + else if (frm.dispose == 1) UPNG._copyTile(empty, fw, fh, img, w, h, fx, fy, 0); + else if (frm.dispose == 2) for (var j = 0; j < len; j++) img[j] = prev[j]; + } + return frms; +} +UPNG.toRGBA8.decodeImage = function (data, w, h, out) { + var area = w * h, bpp = UPNG.decode._getBPP(out); + var bpl = Math.ceil(w * bpp / 8); // bytes per line + + var bf = new Uint8Array(area * 4), bf32 = new Uint32Array(bf.buffer); + var ctype = out.ctype, depth = out.depth; + var rs = UPNG._bin.readUshort; + + var time = Date.now(); + + if (ctype == 6) { // RGB + alpha + var qarea = area << 2; + if (depth == 8) for (var i = 0; i < qarea; i += 4) { + bf[i] = data[i]; + bf[i+1] = data[i+1]; + bf[i+2] = data[i+2]; + bf[i+3] = data[i+3]; + } + if (depth == 16) for (var i = 0; i < qarea; i++) { + bf[i] = data[i<<1]; + } + } + else if (ctype == 2) { // RGB + var ts = out.tabs['tRNS']; + if (ts == null) { + if (depth == 8) for (var i = 0; i < area; i++) { + var ti = i * 3; + bf32[i] = (255 << 24) | (data[ti+2] << 16) | (data[ti+1] << 8) | data[ti]; + } + if (depth == 16) for (var i = 0; i < area; i++) { + var ti = i * 6; + bf32[i] = (255 << 24) | (data[ti+4] << 16) | (data[ti+2] << 8) | data[ti]; + } + } + else { + var tr = ts[0], tg = ts[1], tb = ts[2]; + if (depth == 8) for (var i = 0; i < area; i++) { + var qi = i << 2, ti = i * 3; + bf32[i] = (255 << 24) | (data[ti+2] << 16) | (data[ti+1] << 8) | data[ti]; + if (data[ti] == tr && data[ti+1] == tg && data[ti+2] == tb) bf[qi+3] = 0; + } + if (depth == 16) for (var i = 0; i < area; i++) { + var qi = i << 2, ti = i * 6; + bf32[i] = (255 << 24) | (data[ti+4] << 16) | (data[ti+2] << 8) | data[ti]; + if (rs(data, ti) == tr && rs(data, ti + 2) == tg && rs(data, ti + 4) == tb) bf[qi+3] = 0; + } + } + } + else if (ctype == 3) { // palette + var p = out.tabs['PLTE'], ap = out.tabs['tRNS'], tl = ap ? ap.length : 0; + if (depth == 1) for (var y = 0; y < h; y++) { + var s0 = y * bpl, t0 = y * w; + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, j = ((data[s0+(i >> 3)] >> (7 - ((i & 7) << 0))) & 1), cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + if (depth == 2) for (var y = 0; y < h; y++) { + var s0 = y * bpl, t0 = y * w; + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, j = ((data[s0+(i >> 2)] >> (6 - ((i & 3) << 1))) & 3), cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + if (depth == 4) for (var y = 0; y < h; y++) { + var s0 = y * bpl, t0 = y * w; + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, j = ((data[s0+(i >> 1)] >> (4 - ((i & 1) << 2))) & 15), cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + if (depth == 8) for (var i = 0; i < area; i++) { + var qi = i << 2, j = data[i], cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + else if (ctype == 4) { // gray + alpha + if (depth == 8) for (var i = 0; i < area; i++) { + var qi = i << 2, di = i << 1, gr = data[di]; + bf[qi] = gr; + bf[qi+1] = gr; + bf[qi+2] = gr; + bf[qi+3] = data[di+1]; + } + if (depth == 16) for (var i = 0; i < area; i++) { + var qi = i << 2, di = i << 2, gr = data[di]; + bf[qi] = gr; + bf[qi+1] = gr; + bf[qi+2] = gr; + bf[qi+3] = data[di+2]; + } + } + else if (ctype == 0) { // gray + var tr = out.tabs['tRNS'] ? out.tabs['tRNS'] : -1; + for (var y = 0; y < h; y++) { + var off = y * bpl, to = y * w; + if (depth == 1) for (var x = 0; x < w; x++) { + var gr = 255 * ((data[off+(x >>> 3)] >>> (7 - ((x & 7)))) & 1), al = (gr == tr * 255) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 2) for (var x = 0; x < w; x++) { + var gr = 85 * ((data[off+(x >>> 2)] >>> (6 - ((x & 3) << 1))) & 3), al = (gr == tr * 85) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 4) for (var x = 0; x < w; x++) { + var gr = 17 * ((data[off+(x >>> 1)] >>> (4 - ((x & 1) << 2))) & 15), al = (gr == tr * 17) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 8) for (var x = 0; x < w; x++) { + var gr = data[off+ x], al = (gr == tr) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 16) for (var x = 0; x < w; x++) { + var gr = data[off+(x << 1)], al = (rs(data, off + (x << 1)) == tr) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + } + } + + return bf; +} + + +UPNG.decode = function (buff) { + var data = new Uint8Array(buff), offset = 8, bin = UPNG._bin, rUs = bin.readUshort, rUi = bin.readUint; + var out = { tabs: {}, frames: [] }; + var dd = new Uint8Array(data.length), doff = 0; // put all IDAT data into it + var fd, foff = 0; // frames + + var mgck = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; + for (var i = 0; i < 8; i++) if (data[i] != mgck[i]) throw 'The input is not a PNG file!'; + + while (offset < data.length) { + var len = bin.readUint(data, offset); + offset += 4; + var type = bin.readASCII(data, offset, 4); + offset += 4; + + + if (type == 'IHDR') { + UPNG.decode._IHDR(data, offset, out); + } + else if (type == 'CgBI') { + out.tabs[type] = data.slice(offset, offset + 4); + } + else if (type == 'IDAT') { + for (var i = 0; i < len; i++) dd[doff+i] = data[offset+i]; + doff += len; + } + else if (type == 'acTL') { + out.tabs[type] = { num_frames: rUi(data, offset), num_plays: rUi(data, offset + 4) }; + fd = new Uint8Array(data.length); + } + else if (type == 'fcTL') { + if (foff != 0) { + var fr = out.frames[out.frames.length-1]; + fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height); + foff = 0; + } + var rct = { + x: rUi(data, offset + 12), + y: rUi(data, offset + 16), + width: rUi(data, offset + 4), + height: rUi(data, offset + 8) + }; + var del = rUs(data, offset + 22); + del = rUs(data, offset + 20) / (del == 0 ? 100 : del); + var frm = { rect: rct, delay: Math.round(del * 1000), dispose: data[offset+24], blend: data[offset+25] }; + + out.frames.push(frm); + } + else if (type == 'fdAT') { + for (var i = 0; i < len - 4; i++) fd[foff+i] = data[offset + i+4]; + foff += len - 4; + } + else if (type == 'pHYs') { + out.tabs[type] = [bin.readUint(data, offset), bin.readUint(data, offset + 4), data[offset+8]]; + } + else if (type == 'cHRM') { + out.tabs[type] = []; + for (var i = 0; i < 8; i++) out.tabs[type].push(bin.readUint(data, offset + i * 4)); + } + else if (type == 'tEXt' || type == 'zTXt') { + if (out.tabs[type] == null) out.tabs[type] = {}; + var nz = bin.nextZero(data, offset); + var keyw = bin.readASCII(data, offset, nz - offset); + var text, tl = offset + len - nz - 1; + if (type == 'tEXt') text = bin.readASCII(data, nz + 1, tl); + else { + var bfr = UPNG.decode._inflate(data.slice(nz + 2, nz + 2 + tl)); + text = bin.readUTF8(bfr, 0, bfr.length); + } + out.tabs[type][keyw] = text; + } + else if (type == 'iTXt') { + if (out.tabs[type] == null) out.tabs[type] = {}; + var nz = 0, off = offset; + nz = bin.nextZero(data, off); + var keyw = bin.readASCII(data, off, nz - off); + off = nz + 1; + var cflag = data[off], cmeth = data[off+1]; + off += 2; + nz = bin.nextZero(data, off); + var ltag = bin.readASCII(data, off, nz - off); + off = nz + 1; + nz = bin.nextZero(data, off); + var tkeyw = bin.readUTF8(data, off, nz - off); + off = nz + 1; + var text, tl = len - (off - offset); + if (cflag == 0) text = bin.readUTF8(data, off, tl); + else { + var bfr = UPNG.decode._inflate(data.slice(off, off + tl)); + text = bin.readUTF8(bfr, 0, bfr.length); + } + out.tabs[type][keyw] = text; + } + else if (type == 'PLTE') { + out.tabs[type] = bin.readBytes(data, offset, len); + } + else if (type == 'hIST') { + var pl = out.tabs['PLTE'].length / 3; + out.tabs[type] = []; + for (var i = 0; i < pl; i++) out.tabs[type].push(rUs(data, offset + i * 2)); + } + else if (type == 'tRNS') { + if (out.ctype == 3) out.tabs[type] = bin.readBytes(data, offset, len); + else if (out.ctype == 0) out.tabs[type] = rUs(data, offset); + else if (out.ctype == 2) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)]; + + } + else if (type == 'gAMA') out.tabs[type] = bin.readUint(data, offset) / 100000; + else if (type == 'sRGB') out.tabs[type] = data[offset]; + else if (type == 'bKGD') { + if (out.ctype == 0 || out.ctype == 4) out.tabs[type] = [rUs(data, offset)]; + else if (out.ctype == 2 || out.ctype == 6) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)]; + else if (out.ctype == 3) out.tabs[type] = data[offset]; + } + else if (type == 'IEND') { + break; + } + + offset += len; + var crc = bin.readUint(data, offset); + offset += 4; + } + if (foff != 0) { + var fr = out.frames[out.frames.length-1]; + fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height); + } + out.data = UPNG.decode._decompress(out, dd, out.width, out.height); + + delete out.compress; + delete out.interlace; + delete out.filter; + return out; +} + +UPNG.decode._decompress = function (out, dd, w, h) { + var time = Date.now(); + var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w * bpp / 8), + buff = new Uint8Array((bpl + 1 + out.interlace) * h); + if (out.tabs['CgBI']) dd = UPNG.inflateRaw(dd, buff); + else dd = UPNG.decode._inflate(dd, buff); + + + var time = Date.now(); + if (out.interlace == 0) dd = UPNG.decode._filterZero(dd, out, 0, w, h); + else if (out.interlace == 1) dd = UPNG.decode._readInterlace(dd, out); + + return dd; +} + +UPNG.decode._inflate = function (data, buff) { + var out = UPNG['inflateRaw'](new Uint8Array(data.buffer, 2, data.length - 6), buff); + return out; +} +UPNG.inflateRaw = function(){ + var H = {}; + H.H = {}; + H.H.N = function (N, W) { + var R = Uint8Array, i = 0, m = 0, J = 0, h = 0, Q = 0, X = 0, u = 0, w = 0, d = 0, v, C; + if (N[0] == 3 && N[1] == 0)return W ? W : new R(0); + var V = H.H, n = V.b, A = V.e, l = V.R, M = V.n, I = V.A, e = V.Z, b = V.m, Z = W == null; + if (Z)W = new R(N.length >>> 2 << 5); + while (i == 0) { + i = n(N, d, 1); + m = n(N, d + 1, 2); + d += 3; + if (m == 0) { + if ((d & 7) != 0)d += 8 - (d & 7); + var D = (d >>> 3) + 4, q = N[D-4] | N[D-3] << 8; + if (Z)W = H.H.W(W, w + q); + W.set(new R(N.buffer, N.byteOffset + D, q), w); + d = D + q << 3; + w += q; + continue + } + if (Z)W = H.H.W(W, w + (1 << 17)); + if (m == 1) { + v = b.J; + C = b.h; + X = (1 << 9) - 1; + u = (1 << 5) - 1 + } + if (m == 2) { + J = A(N, d, 5) + 257; + h = A(N, d + 5, 5) + 1; + Q = A(N, d + 10, 4) + 4; + d += 14; + var E = d, j = 1; + for (var c = 0;c < 38; c += 2) { + b.Q[c] = 0; + b.Q[c+1] = 0 + } + for (var c = 0; c < Q; c++) { + var K = A(N, d + c * 3, 3); + b.Q[(b.X[c] << 1)+1] = K; + if (K > j)j = K + } + d += 3 * Q; + M(b.Q, j); + I(b.Q, j, b.u); + v = b.w; + C = b.d; + d = l(b.u, (1 << j) - 1, J + h, N, d, b.v); + var r = V.V(b.v, 0, J, b.C); + X = (1 << r) - 1; + var S = V.V(b.v, J, h, b.D); + u = (1 << S) - 1; + M(b.C, r); + I(b.C, r, v); + M(b.D, S); + I(b.D, S, C) + } + while (!0) { + var T = v[e(N, d)&X]; + d += T & 15; + var p = T >>> 4; + if (p >>> 8 == 0) { + W[w++] = p + } else if (p == 256) { + break + } else { + var z = w + p - 254; + if (p > 264) { + var _ = b.q[p-257]; + z = w + (_ >>> 3) + A(N, d, _ & 7); + d += _ & 7 + } + var $ = C[e(N, d)&u]; + d += $ & 15; + var s = $ >>> 4, Y = b.c[s], a = (Y >>> 4) + n(N, d, Y & 15); + d += Y & 15; + while (w < z) { + W[w] = W[w++-a]; + W[w] = W[w++-a]; + W[w] = W[w++-a]; + W[w] = W[w++-a] + } + w = z + } + } + } + return W.length == w ? W : W.slice(0, w) + }; + H.H.W = function (N, W) { + var R = N.length; + if (W <= R)return N; + var V = new Uint8Array(R << 1); + V.set(N, 0); + return V + }; + H.H.R = function (N, W, R, V, n, A) { + var l = H.H.e, M = H.H.Z, I = 0; + while (I < R) { + var e = N[M(V, n)&W]; + n += e & 15; + var b = e >>> 4; + if (b <= 15) { + A[I] = b; + I++ + } else { + var Z = 0, m = 0; + if (b == 16) { + m = 3 + l(V, n, 2); + n += 2; + Z = A[I-1] + } else if (b == 17) { + m = 3 + l(V, n, 3); + n += 3 + } else if (b == 18) { + m = 11 + l(V, n, 7); + n += 7 + } + var J = I + m; + while (I < J) { + A[I] = Z; + I++ + } + } + } + return n + }; + H.H.V = function (N, W, R, V) { + var n = 0, A = 0, l = V.length >>> 1; + while (A < R) { + var M = N[A+W]; + V[A<<1] = 0; + V[(A << 1)+1] = M; + if (M > n)n = M; + A++ + } + while (A < l) { + V[A<<1] = 0; + V[(A << 1)+1] = 0; + A++ + } + return n + }; + H.H.n = function (N, W) { + var R = H.H.m, V = N.length, n, A, l, M, I, e = R.j; + for (var M = 0;M <= W; M++)e[M] = 0; + for (M = 1; M < V; M += 2)e[N[M]]++; + var b = R.K; + n = 0; + e[0] = 0; + for (A = 1; A <= W; A++) { + n = n + e[A-1] << 1; + b[A] = n + } + for (l = 0; l < V; l += 2) { + I = N[l+1]; + if (I != 0) { + N[l] = b[I]; + b[I]++ + } + } + }; + H.H.A = function (N, W, R) { + var V = N.length, n = H.H.m, A = n.r; + for (var l = 0;l < V; l += 2)if (N[l+1] != 0) { + var M = l >> 1, I = N[l+1], e = M << 4 | I, b = W - I, Z = N[l] << b, m = Z + (1 << b); + while (Z != m) { + var J = A[Z] >>> 15 - W; + R[J] = e; + Z++ + } + } + }; + H.H.l = function (N, W) { + var R = H.H.m.r, V = 15 - W; + for (var n = 0;n < N.length; + n += 2) { + var A = N[n] << W - N[n+1]; + N[n] = R[A] >>> V + } + }; + H.H.M = function (N, W, R) { + R = R << (W & 7); + var V = W >>> 3; + N[V] |= R; + N[V+1] |= R >>> 8 + }; + H.H.I = function (N, W, R) { + R = R << (W & 7); + var V = W >>> 3; + N[V] |= R; + N[V+1] |= R >>> 8; + N[V+2] |= R >>> 16 + }; + H.H.e = function (N, W, R) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8) >>> (W & 7) & (1 << R) - 1 + }; + H.H.b = function (N, W, R) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8 | N[(W >>> 3)+2] << 16) >>> (W & 7) & (1 << R) - 1 + }; + H.H.Z = function (N, W) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8 | N[(W >>> 3)+2] << 16) >>> (W & 7) + }; + H.H.i = function (N, W) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8 | N[(W >>> 3)+2] << 16 | N[(W >>> 3)+3] << 24) >>> (W & 7) + }; + H.H.m = function(){ + var N = Uint16Array, W = Uint32Array; + return { + K: new N(16), + j: new N(16), + X: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], + S: [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 999, 999, 999], + T: [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0], + q: new N(32), + p: [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 65535, 65535], + z: [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0], + c: new W(32), + J: new N(512), + _: [], + h: new N(32), + $: [], + w: new N(32768), + C: [], + v: [], + d: new N(32768), + D: [], + u: new N(512), + Q: [], + r: new N(1 << 15), + s: new W(286), + Y: new W(30), + a: new W(19), + t: new W(15e3), + k: new N(1 << 16), + g: new N(1 << 15) + } + }(); + (function(){ + var N = H.H.m, W = 1 << 15; + for (var R = 0;R < W; R++) { + var V = R; + V = (V & 2863311530) >>> 1 | (V & 1431655765) << 1; + V = (V & 3435973836) >>> 2 | (V & 858993459) << 2; + V = (V & 4042322160) >>> 4 | (V & 252645135) << 4; + V = (V & 4278255360) >>> 8 | (V & 16711935) << 8; + N.r[R] = (V >>> 16 | V << 16) >>> 17 + } + + function n(A, l, M) { + while (l-- != 0)A.push(0, M) + } + + for (var R = 0;R < 32; R++) { + N.q[R] = N.S[R] << 3 | N.T[R]; + N.c[R] = N.p[R] << 4 | N.z[R] + } + n(N._, 144, 8); + n(N._, 255 - 143, 9); + n(N._, 279 - 255, 7); + n(N._, 287 - 279, 8); + H.H.n(N._, 9); + H.H.A(N._, 9, N.J); + H.H.l(N._, 9); + n(N.$, 32, 5); + H.H.n(N.$, 5); + H.H.A(N.$, 5, N.h); + H.H.l(N.$, 5); + n(N.Q, 19, 0); + n(N.C, 286, 0); + n(N.D, 30, 0); + n(N.v, 320, 0) + }()); + return H.H.N +}() + + +UPNG.decode._readInterlace = function (data, out) { + var w = out.width, h = out.height; + var bpp = UPNG.decode._getBPP(out), cbpp = bpp >> 3, bpl = Math.ceil(w * bpp / 8); + var img = new Uint8Array(h * bpl); + var di = 0; + + var starting_row = [0, 0, 4, 0, 2, 0, 1]; + var starting_col = [0, 4, 0, 2, 0, 1, 0]; + var row_increment = [8, 8, 8, 4, 4, 2, 2]; + var col_increment = [8, 8, 4, 4, 2, 2, 1]; + + var pass = 0; + while (pass < 7) { + var ri = row_increment[pass], ci = col_increment[pass]; + var sw = 0, sh = 0; + var cr = starting_row[pass]; + while (cr < h) { + cr += ri; + sh++; + } + var cc = starting_col[pass]; + while (cc < w) { + cc += ci; + sw++; + } + var bpll = Math.ceil(sw * bpp / 8); + UPNG.decode._filterZero(data, out, di, sw, sh); + + var y = 0, row = starting_row[pass]; + while (row < h) { + var col = starting_col[pass]; + var cdi = (di + y * bpll) << 3; + + while (col < w) { + if (bpp == 1) { + var val = data[cdi>>3]; + val = (val >> (7 - (cdi & 7))) & 1; + img[row * bpl + (col >> 3)] |= (val << (7 - ((col & 7) << 0))); + } + if (bpp == 2) { + var val = data[cdi>>3]; + val = (val >> (6 - (cdi & 7))) & 3; + img[row * bpl + (col >> 2)] |= (val << (6 - ((col & 3) << 1))); + } + if (bpp == 4) { + var val = data[cdi>>3]; + val = (val >> (4 - (cdi & 7))) & 15; + img[row * bpl + (col >> 1)] |= (val << (4 - ((col & 1) << 2))); + } + if (bpp >= 8) { + var ii = row * bpl + col * cbpp; + for (var j = 0; j < cbpp; j++) img[ii+j] = data[(cdi >> 3)+j]; + } + cdi += bpp; + col += ci; + } + y++; + row += ri; + } + if (sw * sh != 0) di += sh * (1 + bpll); + pass = pass + 1; + } + return img; +} + +UPNG.decode._getBPP = function (out) { + var noc = [1, null, 3, 1, 2, null, 4][out.ctype]; + return noc * out.depth; +} + +UPNG.decode._filterZero = function (data, out, off, w, h) { + var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w * bpp / 8), paeth = UPNG.decode._paeth; + bpp = Math.ceil(bpp / 8); + + var i, di, type = data[off], x = 0; + + if (type > 1) data[off] = [0, 0, 1][type-2]; + if (type == 3) for (x = bpp; x < bpl; x++) data[x+1] = (data[x+1] + (data[x + 1-bpp] >>> 1)) & 255; + + for (var y = 0; y < h; y++) { + i = off + y * bpl; + di = i + y + 1; + type = data[di-1]; + x = 0; + + if (type == 0) for (; x < bpl; x++) data[i+x] = data[di+x]; + else if (type == 1) { + for (; x < bpp; x++) data[i+x] = data[di+x]; + for (; x < bpl; x++) data[i+x] = (data[di+x] + data[i + x-bpp]); + } + else if (type == 2) { + for (; x < bpl; x++) data[i+x] = (data[di+x] + data[i + x-bpl]); + } + else if (type == 3) { + for (; x < bpp; x++) data[i+x] = (data[di+x] + (data[i + x-bpl] >>> 1)); + for (; x < bpl; x++) data[i+x] = (data[di+x] + ((data[i + x-bpl] + data[i + x-bpp]) >>> 1)); + } + else { + for (; x < bpp; x++) data[i+x] = (data[di+x] + paeth(0, data[i + x-bpl], 0)); + for (; x < bpl; x++) data[i+x] = (data[di+x] + paeth(data[i + x-bpp], data[i + x-bpl], data[i + x - bpp-bpl])); + } + } + return data; +} + +UPNG.decode._paeth = function (a, b, c) { + var p = a + b - c, pa = (p - a), pb = (p - b), pc = (p - c); + if (pa * pa <= pb * pb && pa * pa <= pc * pc) return a; + else if (pb * pb <= pc * pc) return b; + return c; +} + +UPNG.decode._IHDR = function (data, offset, out) { + var bin = UPNG._bin; + out.width = bin.readUint(data, offset); + offset += 4; + out.height = bin.readUint(data, offset); + offset += 4; + out.depth = data[offset]; + offset++; + out.ctype = data[offset]; + offset++; + out.compress = data[offset]; + offset++; + out.filter = data[offset]; + offset++; + out.interlace = data[offset]; + offset++; +} + +UPNG._bin = { + nextZero: function (data, p) { + while (data[p] != 0) p++; + return p; + }, + readUshort: function (buff, p) { + return (buff[p] << 8) | buff[p+1]; + }, + writeUshort: function (buff, p, n) { + buff[p] = (n >> 8) & 255; + buff[p+1] = n & 255; + }, + readUint: function (buff, p) { + return (buff[p] * (256 * 256 * 256)) + ((buff[p+1] << 16) | (buff[p+2] << 8) | buff[p+3]); + }, + writeUint: function (buff, p, n) { + buff[p] = (n >> 24) & 255; + buff[p+1] = (n >> 16) & 255; + buff[p+2] = (n >> 8) & 255; + buff[p+3] = n & 255; + }, + readASCII: function (buff, p, l) { + var s = ''; + for (var i = 0; i < l; i++) s += String.fromCharCode(buff[p+i]); + return s; + }, + writeASCII: function (data, p, s) { + for (var i = 0; i < s.length; i++) data[p+i] = s.charCodeAt(i); + }, + readBytes: function (buff, p, l) { + var arr = []; + for (var i = 0; i < l; i++) arr.push(buff[p+i]); + return arr; + }, + pad: function (n) { + return n.length < 2 ? '0' + n : n; + }, + readUTF8: function (buff, p, l) { + var s = '', ns; + for (var i = 0; i < l; i++) s += '%' + UPNG._bin.pad(buff[p+i].toString(16)); + try { + ns = decodeURIComponent(s); + } + catch (e) { + return UPNG._bin.readASCII(buff, p, l); + } + return ns; + } +} +UPNG._copyTile = function (sb, sw, sh, tb, tw, th, xoff, yoff, mode) { + var w = Math.min(sw, tw), h = Math.min(sh, th); + var si = 0, ti = 0; + for (var y = 0; y < h; y++) + for (var x = 0; x < w; x++) { + if (xoff >= 0 && yoff >= 0) { + si = (y * sw + x) << 2; + ti = ((yoff + y) * tw + xoff + x) << 2; + } + else { + si = ((-yoff + y) * sw - xoff + x) << 2; + ti = (y * tw + x) << 2; + } + + if (mode == 0) { + tb[ti] = sb[si]; + tb[ti+1] = sb[si+1]; + tb[ti+2] = sb[si+2]; + tb[ti+3] = sb[si+3]; + } + else if (mode == 1) { + var fa = sb[si+3] * (1 / 255), fr = sb[si] * fa, fg = sb[si+1] * fa, fb = sb[si+2] * fa; + var ba = tb[ti+3] * (1 / 255), br = tb[ti] * ba, bg = tb[ti+1] * ba, bb = tb[ti+2] * ba; + + var ifa = 1 - fa, oa = fa + ba * ifa, ioa = (oa == 0 ? 0 : 1 / oa); + tb[ti+3] = 255 * oa; + tb[ti+0] = (fr + br * ifa) * ioa; + tb[ti+1] = (fg + bg * ifa) * ioa; + tb[ti+2] = (fb + bb * ifa) * ioa; + } + else if (mode == 2) { // copy only differences, otherwise zero + var fa = sb[si+3], fr = sb[si], fg = sb[si+1], fb = sb[si+2]; + var ba = tb[ti+3], br = tb[ti], bg = tb[ti+1], bb = tb[ti+2]; + if (fa == ba && fr == br && fg == bg && fb == bb) { + tb[ti] = 0; + tb[ti+1] = 0; + tb[ti+2] = 0; + tb[ti+3] = 0; + } + else { + tb[ti] = fr; + tb[ti+1] = fg; + tb[ti+2] = fb; + tb[ti+3] = fa; + } + } + else if (mode == 3) { // check if can be blended + var fa = sb[si+3], fr = sb[si], fg = sb[si+1], fb = sb[si+2]; + var ba = tb[ti+3], br = tb[ti], bg = tb[ti+1], bb = tb[ti+2]; + if (fa == ba && fr == br && fg == bg && fb == bb) continue; + + if (fa < 220 && ba > 20) return false; + } + } + return true; + } + + +UPNG.encode = function (bufs, w, h, ps, dels, tabs, forbidPlte) { + if (ps == null) ps = 0; + if (forbidPlte == null) forbidPlte = false; + + var nimg = UPNG.encode.compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte, false]); + UPNG.encode.compressPNG(nimg, -1); + + return UPNG.encode._main(nimg, w, h, dels, tabs); +} +UPNG.encodeWithString = function (writeString, bufs, w, h, ps, dels, tabs, forbidPlte) { + if (ps == null) ps = 0; + if (forbidPlte == null) forbidPlte = false; + + var nimg = UPNG.encode.compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte, false]); + UPNG.encode.compressPNG(nimg, -1); + + return UPNG.encode._mainWithString(writeString, nimg, w, h, dels, tabs); +} + +UPNG.encodeLL = function (bufs, w, h, cc, ac, depth, dels, tabs) { + var nimg = { ctype: 0 + (cc == 1 ? 0 : 2) + (ac == 0 ? 0 : 4), depth: depth, frames: [] }; + + var time = Date.now(); + var bipp = (cc + ac) * depth, bipl = bipp * w; + for (var i = 0; i < bufs.length; i++) + nimg.frames.push({ + rect: { x: 0, y: 0, width: w, height: h }, + img: new Uint8Array(bufs[i]), + blend: 0, + dispose: 1, + bpp: Math.ceil(bipp / 8), + bpl: Math.ceil(bipl / 8) + }); + + UPNG.encode.compressPNG(nimg, 0, true); + + var out = UPNG.encode._main(nimg, w, h, dels, tabs); + return out; +} + +UPNG.encode._main = function (nimg, w, h, dels, tabs) { + try { + if (tabs == null) tabs = {}; + var crc = UPNG.crc.crc, wUi = UPNG._bin.writeUint, wUs = UPNG._bin.writeUshort, wAs = UPNG._bin.writeASCII; + var offset = 8, anim = nimg.frames.length > 1, pltAlpha = false; + + var leng = 8 + (16 + 5 + 4) /*+ (9+4)*/ + + (anim ? 20 : 0); + if (tabs['sRGB'] != null) leng += 8 + 1 + 4; + if (tabs['pHYs'] != null) leng += 8 + 9 + 4; + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + for (var i = 0; i < dl; i++) if ((nimg.plte[i] >>> 24) != 255) pltAlpha = true; + leng += (8 + dl * 3 + 4) + (pltAlpha ? (8 + dl * 1 + 4) : 0); + } + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) leng += 38; + leng += fr.cimg.length + 12; + if (j != 0) leng += 4; + } + leng += 12; + + var data = new Uint8Array(leng); + var wr = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; + for (var i = 0; i < 8; i++) data[i] = wr[i]; + + wUi(data, offset, 13); + offset += 4; + wAs(data, offset, 'IHDR'); + offset += 4; + wUi(data, offset, w); + offset += 4; + wUi(data, offset, h); + offset += 4; + data[offset] = nimg.depth; + offset++; // depth + data[offset] = nimg.ctype; + offset++; // ctype + data[offset] = 0; + offset++; // compress + data[offset] = 0; + offset++; // filter + data[offset] = 0; + offset++; // interlace + wUi(data, offset, crc(data, offset - 17, 17)); + offset += 4; // crc + + // 13 bytes to say, that it is sRGB + if (tabs['sRGB'] != null) { + wUi(data, offset, 1); + offset += 4; + wAs(data, offset, 'sRGB'); + offset += 4; + data[offset] = tabs['sRGB']; + offset++; + wUi(data, offset, crc(data, offset - 5, 5)); + offset += 4; // crc + } + if (tabs['pHYs'] != null) { + wUi(data, offset, 9); + offset += 4; + wAs(data, offset, 'pHYs'); + offset += 4; + wUi(data, offset, tabs['pHYs'][0]); + offset += 4; + wUi(data, offset, tabs['pHYs'][1]); + offset += 4; + data[offset] = tabs['pHYs'][2]; + offset++; + wUi(data, offset, crc(data, offset - 13, 13)); + offset += 4; // crc + } + + if (anim) { + wUi(data, offset, 8); + offset += 4; + wAs(data, offset, 'acTL'); + offset += 4; + wUi(data, offset, nimg.frames.length); + offset += 4; + wUi(data, offset, tabs['loop'] != null ? tabs['loop'] : 0); + offset += 4; + wUi(data, offset, crc(data, offset - 12, 12)); + offset += 4; // crc + } + + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + wUi(data, offset, dl * 3); + offset += 4; + wAs(data, offset, 'PLTE'); + offset += 4; + for (var i = 0; i < dl; i++) { + var ti = i * 3, c = nimg.plte[i], r = (c) & 255, g = (c >>> 8) & 255, b = (c >>> 16) & 255; + data[offset + ti+0] = r; + data[offset + ti+1] = g; + data[offset + ti+2] = b; + } + offset += dl * 3; + wUi(data, offset, crc(data, offset - dl * 3 - 4, dl * 3 + 4)); + offset += 4; // crc + + if (pltAlpha) { + wUi(data, offset, dl); + offset += 4; + wAs(data, offset, 'tRNS'); + offset += 4; + for (var i = 0; i < dl; i++) data[offset+i] = (nimg.plte[i] >>> 24) & 255; + offset += dl; + wUi(data, offset, crc(data, offset - dl - 4, dl + 4)); + offset += 4; // crc + } + } + + var fi = 0; + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) { + wUi(data, offset, 26); + offset += 4; + wAs(data, offset, 'fcTL'); + offset += 4; + wUi(data, offset, fi++); + offset += 4; + wUi(data, offset, fr.rect.width); + offset += 4; + wUi(data, offset, fr.rect.height); + offset += 4; + wUi(data, offset, fr.rect.x); + offset += 4; + wUi(data, offset, fr.rect.y); + offset += 4; + wUs(data, offset, dels[j]); + offset += 2; + wUs(data, offset, 1000); + offset += 2; + data[offset] = fr.dispose; + offset++; // dispose + data[offset] = fr.blend; + offset++; // blend + wUi(data, offset, crc(data, offset - 30, 30)); + offset += 4; // crc + } + + var imgd = fr.cimg, dl = imgd.length; + wUi(data, offset, dl + (j == 0 ? 0 : 4)); + offset += 4; + var ioff = offset; + wAs(data, offset, (j == 0) ? 'IDAT' : 'fdAT'); + offset += 4; + if (j != 0) { + wUi(data, offset, fi++); + offset += 4; + } + data.set(imgd, offset); + offset += dl; + wUi(data, offset, crc(data, ioff, offset - ioff)); + offset += 4; // crc + } + + wUi(data, offset, 0); + offset += 4; + wAs(data, offset, 'IEND'); + offset += 4; + wUi(data, offset, crc(data, offset - 4, 4)); + offset += 4; // crc + return data.buffer; + } + catch (err) { + } +} +UPNG.encode._mainWithString = function (writeString, nimg, w, h, dels, tabs) { + if (tabs == null) tabs = {}; + var crc = UPNG.crc.crc, wUi = UPNG._bin.writeUint, wUs = UPNG._bin.writeUshort, wAs = UPNG._bin.writeASCII; + var offset = 8, anim = nimg.frames.length > 1, pltAlpha = false; + + var leng = 8 + (16 + 5 + 4) /*+ (9+4)*/ + + (anim ? 20 : 0); + if (tabs['sRGB'] != null) leng += 8 + 1 + 4; + if (tabs['pHYs'] != null) leng += 8 + 9 + 4; + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + for (var i = 0; i < dl; i++) if ((nimg.plte[i] >>> 24) != 255) pltAlpha = true; + leng += (8 + dl * 3 + 4) + (pltAlpha ? (8 + dl * 1 + 4) : 0); + } + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) leng += 38; + leng += fr.cimg.length + 12; + if (j != 0) leng += 4; + } + + // 由于IEND数据块永远是 00 00 00 00 49 45 4E 44 AE 42 60 82 + // 其中 IEND 是 49 45 4E 44 因此CRC码也总是 AE 42 60 82 + + let writeUint8 = UPNG.encode._strToUint8Array(writeString); + + leng += 12 + writeUint8.byteLength; + + + var data = new Uint8Array(leng); + var wr = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; + for (var i = 0; i < 8; i++) data[i] = wr[i]; + + wUi(data, offset, 13); + offset += 4; + wAs(data, offset, 'IHDR'); + offset += 4; + wUi(data, offset, w); + offset += 4; + wUi(data, offset, h); + offset += 4; + data[offset] = nimg.depth; + offset++; // depth + data[offset] = nimg.ctype; + offset++; // ctype + data[offset] = 0; + offset++; // compress + data[offset] = 0; + offset++; // filter + data[offset] = 0; + offset++; // interlace + wUi(data, offset, crc(data, offset - 17, 17)); + offset += 4; // crc + + // 13 bytes to say, that it is sRGB + if (tabs['sRGB'] != null) { + wUi(data, offset, 1); + offset += 4; + wAs(data, offset, 'sRGB'); + offset += 4; + data[offset] = tabs['sRGB']; + offset++; + wUi(data, offset, crc(data, offset - 5, 5)); + offset += 4; // crc + } + if (tabs['pHYs'] != null) { + wUi(data, offset, 9); + offset += 4; + wAs(data, offset, 'pHYs'); + offset += 4; + wUi(data, offset, tabs['pHYs'][0]); + offset += 4; + wUi(data, offset, tabs['pHYs'][1]); + offset += 4; + data[offset] = tabs['pHYs'][2]; + offset++; + wUi(data, offset, crc(data, offset - 13, 13)); + offset += 4; // crc + } + + if (anim) { + wUi(data, offset, 8); + offset += 4; + wAs(data, offset, 'acTL'); + offset += 4; + wUi(data, offset, nimg.frames.length); + offset += 4; + wUi(data, offset, tabs['loop'] != null ? tabs['loop'] : 0); + offset += 4; + wUi(data, offset, crc(data, offset - 12, 12)); + offset += 4; // crc + } + + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + wUi(data, offset, dl * 3); + offset += 4; + wAs(data, offset, 'PLTE'); + offset += 4; + for (var i = 0; i < dl; i++) { + var ti = i * 3, c = nimg.plte[i], r = (c) & 255, g = (c >>> 8) & 255, b = (c >>> 16) & 255; + data[offset + ti+0] = r; + data[offset + ti+1] = g; + data[offset + ti+2] = b; + } + offset += dl * 3; + wUi(data, offset, crc(data, offset - dl * 3 - 4, dl * 3 + 4)); + offset += 4; // crc + + if (pltAlpha) { + wUi(data, offset, dl); + offset += 4; + wAs(data, offset, 'tRNS'); + offset += 4; + for (var i = 0; i < dl; i++) data[offset+i] = (nimg.plte[i] >>> 24) & 255; + offset += dl; + wUi(data, offset, crc(data, offset - dl - 4, dl + 4)); + offset += 4; // crc + } + } + + var fi = 0; + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) { + wUi(data, offset, 26); + offset += 4; + wAs(data, offset, 'fcTL'); + offset += 4; + wUi(data, offset, fi++); + offset += 4; + wUi(data, offset, fr.rect.width); + offset += 4; + wUi(data, offset, fr.rect.height); + offset += 4; + wUi(data, offset, fr.rect.x); + offset += 4; + wUi(data, offset, fr.rect.y); + offset += 4; + wUs(data, offset, dels[j]); + offset += 2; + wUs(data, offset, 1000); + offset += 2; + data[offset] = fr.dispose; + offset++; // dispose + data[offset] = fr.blend; + offset++; // blend + wUi(data, offset, crc(data, offset - 30, 30)); + offset += 4; // crc + } + + var imgd = fr.cimg, dl = imgd.length; + wUi(data, offset, dl + (j == 0 ? 0 : 4)); + offset += 4; + var ioff = offset; + wAs(data, offset, (j == 0) ? 'IDAT' : 'fdAT'); + offset += 4; + if (j != 0) { + wUi(data, offset, fi++); + offset += 4; + } + data.set(imgd, offset); + offset += dl; + wUi(data, offset, crc(data, ioff, offset - ioff)); + offset += 4; // crc + } + + wUi(data, offset, 0); + offset += 4; + + wAs(data, offset, 'IEND'); + offset += 4; + wUi(data, offset, crc(data, offset - (4), 4)); + offset += 4; // crc + wAs(data, offset, writeString); + offset += writeUint8.byteLength; + return data.buffer; +} + +UPNG.encode.compressPNG = function (out, filter, levelZero) { + try { + for (var i = 0; i < out.frames.length; i++) { + var frm = out.frames[i], nw = frm.rect.width, nh = frm.rect.height; + var fdata = new Uint8Array(nh * frm.bpl + nh); + frm.cimg = UPNG.encode._filterZero(frm.img, nh, frm.bpp, frm.bpl, fdata, filter, levelZero); + } + } catch (err) { + } +} + + +UPNG.encode.compress = function (bufs, w, h, ps, prms) // prms: onlyBlend, minBits, forbidPlte +{ + try { + + var onlyBlend = prms[0], evenCrd = prms[1], forbidPrev = prms[2], minBits = prms[3], forbidPlte = prms[4], + dither = prms[5]; + + var ctype = 6, depth = 8, alphaAnd = 255 + + for (var j = 0; j < bufs.length; j++) { // when not quantized, other frames can contain colors, that are not in an initial frame + var img = new Uint8Array(bufs[j]), ilen = img.length; + for (var i = 0; i < ilen; i += 4) alphaAnd &= img[i+3]; + } + var gotAlpha = (alphaAnd != 255); + + var frms = UPNG.encode.framize(bufs, w, h, onlyBlend, evenCrd, forbidPrev); + + var cmap = {}, plte = [], inds = []; + + if (ps != 0) { + var nbufs = []; + for (var i = 0; i < frms.length; i++) nbufs.push(frms[i].img.buffer); + + var abuf = UPNG.encode.concatRGBA(nbufs), qres = UPNG.quantize(abuf, ps); + + for (var i = 0; i < qres.plte.length; i++) plte.push(qres.plte[i].est.rgba); + + var cof = 0; + for (var i = 0; i < frms.length; i++) { + var frm = frms[i], bln = frm.img.length, ind = new Uint8Array(qres.inds.buffer, cof >> 2, bln >> 2); + inds.push(ind); + var bb = new Uint8Array(qres.abuf, cof, bln); + + if (dither) UPNG.encode.dither(frm.img, frm.rect.width, frm.rect.height, plte, bb, ind); + + frm.img.set(bb); + cof += bln; + } + } + else { + // what if ps==0, but there are <=256 colors? we still need to detect, if the palette could be used + for (var j = 0; j < frms.length; j++) { // when not quantized, other frames can contain colors, that are not in an initial frame + var frm = frms[j], img32 = new Uint32Array(frm.img.buffer), nw = frm.rect.width, ilen = img32.length; + var ind = new Uint8Array(ilen); + inds.push(ind); + for (var i = 0; i < ilen; i++) { + var c = img32[i]; + if (i != 0 && c == img32[i- 1]) ind[i] = ind[i-1]; + else if (i > nw && c == img32[i-nw]) ind[i] = ind[i-nw]; + else { + var cmc = cmap[c]; + if (cmc == null) { + cmap[c] = cmc = plte.length; + plte.push(c); + if (plte.length >= 300) break; + } + ind[i] = cmc; + } + } + } + } + + var cc = plte.length; + if (cc <= 256 && forbidPlte == false) { + if (cc <= 2) depth = 1; else if (cc <= 4) depth = 2; else if (cc <= 16) depth = 4; else depth = 8; + depth = Math.max(depth, minBits); + } + + for (var j = 0; j < frms.length; j++) { + var frm = frms[j], nx = frm.rect.x, ny = frm.rect.y, nw = frm.rect.width, nh = frm.rect.height; + var cimg = frm.img, cimg32 = new Uint32Array(cimg.buffer); + var bpl = 4 * nw, bpp = 4; + if (cc <= 256 && forbidPlte == false) { + bpl = Math.ceil(depth * nw / 8); + var nimg = new Uint8Array(bpl * nh); + var inj = inds[j]; + for (var y = 0; y < nh; y++) { + var i = y * bpl, ii = y * nw; + if (depth == 8) for (var x = 0; x < nw; x++) nimg[i+(x)] = (inj[ii+x]); + else if (depth == 4) for (var x = 0; x < nw; x++) nimg[i+(x >> 1)] |= (inj[ii+x] << (4 - (x & 1) * 4)); + else if (depth == 2) for (var x = 0; x < nw; x++) nimg[i+(x >> 2)] |= (inj[ii+x] << (6 - (x & 3) * 2)); + else if (depth == 1) for (var x = 0; x < nw; x++) nimg[i+(x >> 3)] |= (inj[ii+x] << (7 - (x & 7) * 1)); + } + cimg = nimg; + ctype = 3; + bpp = 1; + } + else if (gotAlpha == false && frms.length == 1) { // some next 'reduced' frames may contain alpha for blending + var nimg = new Uint8Array(nw * nh * 3), area = nw * nh; + for (var i = 0; i < area; i++) { + var ti = i * 3, qi = i * 4; + nimg[ti] = cimg[qi]; + nimg[ti+1] = cimg[qi+1]; + nimg[ti+2] = cimg[qi+2]; + } + cimg = nimg; + ctype = 2; + bpp = 3; + bpl = 3 * nw; + } + frm.img = cimg; + frm.bpl = bpl; + frm.bpp = bpp; + } + return { ctype: ctype, depth: depth, plte: plte, frames: frms }; + } catch (err) { + } +} +UPNG.encode.framize = function (bufs, w, h, alwaysBlend, evenCrd, forbidPrev) { + + try { + var frms = []; + for (var j = 0; j < bufs.length; j++) { + var cimg = new Uint8Array(bufs[j]), cimg32 = new Uint32Array(cimg.buffer); + var nimg; + + var nx = 0, ny = 0, nw = w, nh = h, blend = alwaysBlend ? 1 : 0; + if (j != 0) { + var tlim = (forbidPrev || alwaysBlend || j == 1 || frms[j-2].dispose != 0) ? 1 : 2, tstp = 0, + tarea = 1e9; + for (var it = 0; it < tlim; it++) { + var pimg = new Uint8Array(bufs[j - 1-it]), p32 = new Uint32Array(bufs[j - 1-it]); + var mix = w, miy = h, max = -1, may = -1; + for (var y = 0; y < h; y++) for (var x = 0; x < w; x++) { + var i = y * w + x; + if (cimg32[i] != p32[i]) { + if (x < mix) mix = x; + if (x > max) max = x; + if (y < miy) miy = y; + if (y > may) may = y; + } + } + if (max == -1) mix = miy = max = may = 0; + if (evenCrd) { + if ((mix & 1) == 1)mix--; + if ((miy & 1) == 1)miy--; + } + var sarea = (max - mix + 1) * (may - miy + 1); + if (sarea < tarea) { + tarea = sarea; + tstp = it; + nx = mix; + ny = miy; + nw = max - mix + 1; + nh = may - miy + 1; + } + } + + // alwaysBlend: pokud zjistím, že blendit nelze, nastavím předchozímu snímku dispose=1. Zajistím, aby obsahoval můj obdélník. + var pimg = new Uint8Array(bufs[j - 1-tstp]); + if (tstp == 1) frms[j-1].dispose = 2; + + nimg = new Uint8Array(nw * nh * 4); + UPNG._copyTile(pimg, w, h, nimg, nw, nh, -nx, -ny, 0); + + blend = UPNG._copyTile(cimg, w, h, nimg, nw, nh, -nx, -ny, 3) ? 1 : 0; + if (blend == 1) UPNG.encode._prepareDiff(cimg, w, h, nimg, { x: nx, y: ny, width: nw, height: nh }); + else UPNG._copyTile(cimg, w, h, nimg, nw, nh, -nx, -ny, 0); + } + else nimg = cimg.slice(0); // img may be rewritten further ... don't rewrite input + + frms.push({ rect: { x: nx, y: ny, width: nw, height: nh }, img: nimg, blend: blend, dispose: 0 }); + } + + if (alwaysBlend) for (var j = 0; j < frms.length; j++) { + var frm = frms[j]; + if (frm.blend == 1) continue; + var r0 = frm.rect, r1 = frms[j-1].rect + var miX = Math.min(r0.x, r1.x), miY = Math.min(r0.y, r1.y); + var maX = Math.max(r0.x + r0.width, r1.x + r1.width), maY = Math.max(r0.y + r0.height, r1.y + r1.height); + var r = { x: miX, y: miY, width: maX - miX, height: maY - miY }; + + frms[j-1].dispose = 1; + if (j - 1 != 0) + UPNG.encode._updateFrame(bufs, w, h, frms, j - 1, r, evenCrd); + UPNG.encode._updateFrame(bufs, w, h, frms, j, r, evenCrd); + } + var area = 0; + if (bufs.length != 1) for (var i = 0; i < frms.length; i++) { + var frm = frms[i]; + area += frm.rect.width * frm.rect.height; + } + return frms; + } catch (err) { + } +} +UPNG.encode._updateFrame = function (bufs, w, h, frms, i, r, evenCrd) { + var U8 = Uint8Array, U32 = Uint32Array; + var pimg = new U8(bufs[i-1]), pimg32 = new U32(bufs[i-1]), nimg = i + 1 < bufs.length ? new U8(bufs[i+1]) : null; + var cimg = new U8(bufs[i]), cimg32 = new U32(cimg.buffer); + + var mix = w, miy = h, max = -1, may = -1; + for (var y = 0; y < r.height; y++) for (var x = 0; x < r.width; x++) { + var cx = r.x + x, cy = r.y + y; + var j = cy * w + cx, cc = cimg32[j]; + // no need to draw transparency, or to dispose it. Or, if writing the same color and the next one does not need transparency. + if (cc == 0 || (frms[i-1].dispose == 0 && pimg32[j] == cc && (nimg == null || nimg[j * 4+3] != 0)) /**/ + ) { + } + else { + if (cx < mix) mix = cx; + if (cx > max) max = cx; + if (cy < miy) miy = cy; + if (cy > may) may = cy; + } + } + if (max == -1) mix = miy = max = may = 0; + if (evenCrd) { + if ((mix & 1) == 1)mix--; + if ((miy & 1) == 1)miy--; + } + r = { x: mix, y: miy, width: max - mix + 1, height: may - miy + 1 }; + + var fr = frms[i]; + fr.rect = r; + fr.blend = 1; + fr.img = new Uint8Array(r.width * r.height * 4); + if (frms[i-1].dispose == 0) { + UPNG._copyTile(pimg, w, h, fr.img, r.width, r.height, -r.x, -r.y, 0); + UPNG.encode._prepareDiff(cimg, w, h, fr.img, r); + } + else + UPNG._copyTile(cimg, w, h, fr.img, r.width, r.height, -r.x, -r.y, 0); +} +UPNG.encode._prepareDiff = function (cimg, w, h, nimg, rec) { + UPNG._copyTile(cimg, w, h, nimg, rec.width, rec.height, -rec.x, -rec.y, 2); +} + +UPNG.encode._filterZero = function (img, h, bpp, bpl, data, filter, levelZero) { + var fls = [], ftry = [0, 1, 2, 3, 4]; + if (filter != -1) ftry = [filter]; + else if (h * bpl > 500000 || bpp == 1) ftry = [0]; + var opts; + if (levelZero) opts = { level: 0 }; + + + var CMPR = (data.length > 10e6 && UZIP != null) ? UZIP : pako; + + + var time = Date.now(); + for (var i = 0; i < ftry.length; i++) { + for (var y = 0; y < h; y++) UPNG.encode._filterLine(data, img, y, bpl, bpp, ftry[i]); + fls.push(CMPR['deflate'](data, opts)); + } + + var ti, tsize = 1e9; + for (var i = 0; i < fls.length; i++) if (fls[i].length < tsize) { + ti = i; + tsize = fls[i].length; + } + return fls[ti]; +} +UPNG.encode._filterLine = function (data, img, y, bpl, bpp, type) { + var i = y * bpl, di = i + y, paeth = UPNG.decode._paeth + data[di] = type; + di++; + + if (type == 0) { + if (bpl < 500) for (var x = 0; x < bpl; x++) data[di+x] = img[i+x]; + else data.set(new Uint8Array(img.buffer, i, bpl), di); + } + else if (type == 1) { + for (var x = 0; x < bpp; x++) data[di+x] = img[i+x]; + for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] - img[i + x-bpp] + 256) & 255; + } + else if (y == 0) { + for (var x = 0; x < bpp; x++) data[di+x] = img[i+x]; + + if (type == 2) for (var x = bpp; x < bpl; x++) data[di+x] = img[i+x]; + if (type == 3) for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] - (img[i + x-bpp] >> 1) + 256) & 255; + if (type == 4) for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] - paeth(img[i + x-bpp], 0, 0) + 256) & 255; + } + else { + if (type == 2) { + for (var x = 0; x < bpl; x++) data[di+x] = (img[i+x] + 256 - img[i + x-bpl]) & 255; + } + if (type == 3) { + for (var x = 0; x < bpp; x++) data[di+x] = (img[i+x] + 256 - (img[i + x-bpl] >> 1)) & 255; + for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] + 256 - ((img[i + x-bpl] + img[i + x-bpp]) >> 1)) & 255; + } + if (type == 4) { + for (var x = 0; x < bpp; x++) data[di+x] = (img[i+x] + 256 - paeth(0, img[i + x-bpl], 0)) & 255; + for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] + 256 - paeth(img[i + x-bpp], img[i + x-bpl], img[i + x - bpp-bpl])) & 255; + } + } +} + +UPNG.crc = { + table: (function () { + var tab = new Uint32Array(256); + for (var n = 0; n < 256; n++) { + var c = n; + for (var k = 0; k < 8; k++) { + if (c & 1) c = 0xedb88320 ^ (c >>> 1); + else c = c >>> 1; + } + tab[n] = c; + } + return tab; + })(), + update: function (c, buf, off, len) { + for (var i = 0; i < len; i++) c = UPNG.crc.table[(c ^ buf[off+i]) & 0xff] ^ (c >>> 8); + return c; + }, + crc: function (b, o, l) { + return UPNG.crc.update(0xffffffff, b, o, l) ^ 0xffffffff; + } +} + + +UPNG.quantize = function (abuf, ps) { + var sb = new Uint8Array(abuf), tb = sb.slice(0), tb32 = new Uint32Array(tb.buffer); + + var KD = UPNG.quantize.getKDtree(tb, ps); + var root = KD[0], leafs = KD[1]; + + var planeDst = UPNG.quantize.planeDst; + var len = sb.length; + + var inds = new Uint8Array(len >> 2), nd; + if (sb.length < 20e6) // precise, but slow :( + for (var i = 0; i < len; i += 4) { + var r = sb[i] * (1 / 255), g = sb[i+1] * (1 / 255), b = sb[i+2] * (1 / 255), a = sb[i+3] * (1 / 255); + + nd = UPNG.quantize.getNearest(root, r, g, b, a); + inds[i>>2] = nd.ind; + tb32[i>>2] = nd.est.rgba; + } + else + for (var i = 0; i < len; i += 4) { + var r = sb[i] * (1 / 255), g = sb[i+1] * (1 / 255), b = sb[i+2] * (1 / 255), a = sb[i+3] * (1 / 255); + + nd = root; + while (nd.left) nd = (planeDst(nd.est, r, g, b, a) <= 0) ? nd.left : nd.right; + inds[i>>2] = nd.ind; + tb32[i>>2] = nd.est.rgba; + } + return { abuf: tb.buffer, inds: inds, plte: leafs }; +} + +UPNG.quantize.getKDtree = function (nimg, ps, err) { + if (err == null) err = 0.0001; + var nimg32 = new Uint32Array(nimg.buffer); + + var root = { + i0: 0, + i1: nimg.length, + bst: null, + est: null, + tdst: 0, + left: null, + right: null + }; // basic statistic, extra statistic + root.bst = UPNG.quantize.stats(nimg, root.i0, root.i1); + root.est = UPNG.quantize.estats(root.bst); + var leafs = [root]; + + while (leafs.length < ps) { + var maxL = 0, mi = 0; + for (var i = 0; i < leafs.length; i++) if (leafs[i].est.L > maxL) { + maxL = leafs[i].est.L; + mi = i; + } + if (maxL < err) break; + var node = leafs[mi]; + + var s0 = UPNG.quantize.splitPixels(nimg, nimg32, node.i0, node.i1, node.est.e, node.est.eMq255); + var s0wrong = (node.i0 >= s0 || node.i1 <= s0); + if (s0wrong) { + node.est.L = 0; + continue; + } + + var ln = { + i0: node.i0, + i1: s0, + bst: null, + est: null, + tdst: 0, + left: null, + right: null + }; + ln.bst = UPNG.quantize.stats(nimg, ln.i0, ln.i1); + ln.est = UPNG.quantize.estats(ln.bst); + var rn = { + i0: s0, + i1: node.i1, + bst: null, + est: null, + tdst: 0, + left: null, + right: null + }; + rn.bst = { R: [], m: [], N: node.bst.N - ln.bst.N }; + for (var i = 0; i < 16; i++) rn.bst.R[i] = node.bst.R[i] - ln.bst.R[i]; + for (var i = 0; i < 4; i++) rn.bst.m[i] = node.bst.m[i] - ln.bst.m[i]; + rn.est = UPNG.quantize.estats(rn.bst); + + node.left = ln; + node.right = rn; + leafs[mi] = ln; + leafs.push(rn); + } + leafs.sort(function (a, b) { + return b.bst.N - a.bst.N; + }); + for (var i = 0; i < leafs.length; i++) leafs[i].ind = i; + return [root, leafs]; +} + +UPNG.quantize.getNearest = function (nd, r, g, b, a) { + if (nd.left == null) { + nd.tdst = UPNG.quantize.dist(nd.est.q, r, g, b, a); + return nd; + } + var planeDst = UPNG.quantize.planeDst(nd.est, r, g, b, a); + + var node0 = nd.left, node1 = nd.right; + if (planeDst > 0) { + node0 = nd.right; + node1 = nd.left; + } + + var ln = UPNG.quantize.getNearest(node0, r, g, b, a); + if (ln.tdst <= planeDst * planeDst) return ln; + var rn = UPNG.quantize.getNearest(node1, r, g, b, a); + return rn.tdst < ln.tdst ? rn : ln; +} +UPNG.quantize.planeDst = function (est, r, g, b, a) { + var e = est.e; + return e[0] * r + e[1] * g + e[2] * b + e[3] * a - est.eMq; +} +UPNG.quantize.dist = function (q, r, g, b, a) { + var d0 = r - q[0], d1 = g - q[1], d2 = b - q[2], d3 = a - q[3]; + return d0 * d0 + d1 * d1 + d2 * d2 + d3 * d3; +} + +UPNG.quantize.splitPixels = function (nimg, nimg32, i0, i1, e, eMq) { + var vecDot = UPNG.quantize.vecDot; + i1 -= 4; + var shfs = 0; + while (i0 < i1) { + while (vecDot(nimg, i0, e) <= eMq) i0 += 4; + while (vecDot(nimg, i1, e) > eMq) i1 -= 4; + if (i0 >= i1) break; + + var t = nimg32[i0>>2]; + nimg32[i0>>2] = nimg32[i1>>2]; + nimg32[i1>>2] = t; + + i0 += 4; + i1 -= 4; + } + while (vecDot(nimg, i0, e) > eMq) i0 -= 4; + return i0 + 4; +} +UPNG.quantize.vecDot = function (nimg, i, e) { + return nimg[i] * e[0] + nimg[i+1] * e[1] + nimg[i+2] * e[2] + nimg[i+3] * e[3]; +} +UPNG.quantize.stats = function (nimg, i0, i1) { + var R = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var m = [0, 0, 0, 0]; + var N = (i1 - i0) >> 2; + for (var i = i0; i < i1; i += 4) { + var r = nimg[i] * (1 / 255), g = nimg[i+1] * (1 / 255), b = nimg[i+2] * (1 / 255), a = nimg[i+3] * (1 / 255); + m[0] += r; + m[1] += g; + m[2] += b; + m[3] += a; + + R[0] += r * r; + R[1] += r * g; + R[2] += r * b; + R[3] += r * a; + R[5] += g * g; + R[6] += g * b; + R[7] += g * a; + R[10] += b * b; + R[11] += b * a; + R[15] += a * a; + } + R[4] = R[1]; + R[8] = R[2]; + R[9] = R[6]; + R[12] = R[3]; + R[13] = R[7]; + R[14] = R[11]; + + return { R: R, m: m, N: N }; +} +UPNG.quantize.estats = function (stats) { + var R = stats.R, m = stats.m, N = stats.N; + + // when all samples are equal, but N is large (millions), the Rj can be non-zero ( 0.0003.... - precission error) + var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], iN = (N == 0 ? 0 : 1 / N); + var Rj = [ + R[0] - m0 * m0 * iN, R[1] - m0 * m1 * iN, R[2] - m0 * m2 * iN, R[3] - m0 * m3 * iN, + R[4] - m1 * m0 * iN, R[5] - m1 * m1 * iN, R[6] - m1 * m2 * iN, R[7] - m1 * m3 * iN, + R[8] - m2 * m0 * iN, R[9] - m2 * m1 * iN, R[10] - m2 * m2 * iN, R[11] - m2 * m3 * iN, + R[12] - m3 * m0 * iN, R[13] - m3 * m1 * iN, R[14] - m3 * m2 * iN, R[15] - m3 * m3 * iN + ]; + + var A = Rj, M = UPNG.M4; + var b = [Math.random(), Math.random(), Math.random(), Math.random()], mi = 0, tmi = 0; + + if (N != 0) + for (var i = 0; i < 16; i++) { + b = M.multVec(A, b); + tmi = Math.sqrt(M.dot(b, b)); + b = M.sml(1 / tmi, b); + if (i != 0 && Math.abs(tmi - mi) < 1e-9) break; + mi = tmi; + } + var q = [m0 * iN, m1 * iN, m2 * iN, m3 * iN]; + var eMq255 = M.dot(M.sml(255, q), b); + + return { + Cov: Rj, + q: q, + e: b, + L: mi, + eMq255: eMq255, + eMq: M.dot(b, q), + rgba: (((Math.round(255 * q[3]) << 24) | (Math.round(255 * q[2]) << 16) | (Math.round(255 * q[1]) << 8) | (Math.round(255 * q[0]) << 0)) >>> 0) + }; +} +UPNG.M4 = { + multVec: function (m, v) { + return [ + m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * v[3], + m[4] * v[0] + m[5] * v[1] + m[6] * v[2] + m[7] * v[3], + m[8] * v[0] + m[9] * v[1] + m[10] * v[2] + m[11] * v[3], + m[12] * v[0] + m[13] * v[1] + m[14] * v[2] + m[15] * v[3] + ]; + }, + dot: function (x, y) { + return x[0] * y[0] + x[1] * y[1] + x[2] * y[2] + x[3] * y[3]; + }, + sml: function (a, y) { + return [a * y[0], a * y[1], a * y[2], a * y[3]]; + } +} + +UPNG.encode.concatRGBA = function (bufs) { + var tlen = 0; + for (var i = 0; i < bufs.length; i++) tlen += bufs[i].byteLength; + var nimg = new Uint8Array(tlen), noff = 0; + for (var i = 0; i < bufs.length; i++) { + var img = new Uint8Array(bufs[i]), il = img.length; + for (var j = 0; j < il; j += 4) { + var r = img[j], g = img[j+1], b = img[j+2], a = img[j+3]; + if (a == 0) r = g = b = 0; + nimg[noff+j] = r; + nimg[noff + j+1] = g; + nimg[noff + j+2] = b; + nimg[noff + j+3] = a; + } + noff += il; + } + return nimg.buffer; +} + +UPNG.encode.dither = function (sb, w, h, plte, tb, oind) { + + function addErr(er, tg, ti, f) { + tg[ti] += (er[0] * f) >> 4; + tg[ti+1] += (er[1] * f) >> 4; + tg[ti+2] += (er[2] * f) >> 4; + tg[ti+3] += (er[3] * f) >> 4; + } + + function N(x) { + return Math.max(0, Math.min(255, x)); + } + + function D(a, b) { + var dr = a[0] - b[0], dg = a[1] - b[1], db = a[2] - b[2], da = a[3] - b[3]; + return (dr * dr + dg * dg + db * db + da * da); + } + + + var pc = plte.length, nplt = [], rads = []; + for (var i = 0; i < pc; i++) { + var c = plte[i]; + nplt.push([((c >>> 0) & 255), ((c >>> 8) & 255), ((c >>> 16) & 255), ((c >>> 24) & 255)]); + } + for (var i = 0; i < pc; i++) { + var ne = 0xffffffff, ni = 0; + for (var j = 0; j < pc; j++) { + var ce = D(nplt[i], nplt[j]); + if (j != i && ce < ne) { + ne = ce; + ni = j; + } + } + var hd = Math.sqrt(ne) / 2; + rads[i] = ~~(hd * hd); + } + + var tb32 = new Uint32Array(tb.buffer); + var err = new Int16Array(w * h * 4); + + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + var i = (y * w + x) * 4; + + var cc = [N(sb[i] + err[i]), N(sb[i+1] + err[i+1]), N(sb[i+2] + err[i+2]), N(sb[i+3] + err[i+3])]; + + var ni = 0, nd = 0xffffff; + for (var j = 0; j < pc; j++) { + var cd = D(cc, nplt[j]); + if (cd < nd) { + nd = cd; + ni = j; + } + } + + var nc = nplt[ni]; + var er = [cc[0] - nc[0], cc[1] - nc[1], cc[2] - nc[2], cc[3] - nc[3]]; + + if (x != w - 1) addErr(er, err, i + 4, 7); + if (y != h - 1) { + if (x != 0) addErr(er, err, i + 4 * w - 4, 3); + addErr(er, err, i + 4 * w, 5); + if (x != w - 1) addErr(er, err, i + 4 * w + 4, 1); //*/ + } + + oind[i>>2] = ni; + tb32[i>>2] = plte[ni]; + } + } +} + +UPNG.encode._strToUint8Array = function (str) { + + var arr = []; + for (var i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + var tmpUint8Array = new Uint8Array(arr); + return tmpUint8Array +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/entry/ImageInfo.ets b/imageknife/src/main/ets/components/imageknife/pngj/entry/ImageInfo.ets new file mode 100644 index 0000000..9de32ec --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/entry/ImageInfo.ets @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 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 {PngjException} from "../PngjException" + +export class ImageInfo { + private static MAX_COLS_ROW: number= 16777216; + private cols: number; + private rows: number; + private bitDepth: number; + private channels: number; + private alpha: boolean; + private greyscale: boolean; + private indexed: boolean; + private packed: boolean; + private bitspPixel: number; + private bytesPixel: number; + private bytesPerRow: number; + private samplesPerRow: number; + private samplesPerRowPacked: number ; + private totalPixels: number= -1; + private totalRawBytes: number= -1; + + /** + * Full constructor + * + * @param cols + * Width in pixels + * @param rows + * Height in pixels + * @param bitdepth + * Bits per sample, in the buffer : 8-16 for RGB true color and + * greyscale + * @param alpha + * Flag: has an alpha channel (RGBA or GA) + * @param grayscale + * Flag: is gray scale (any bitdepth, with or without alpha) + * @param indexed + * Flag: has palette + */ + constructor(cols: number, rows: number, bitdepth: number + , alpha: boolean, grayscale: boolean, indexed: boolean) { + this.cols = cols; + this.rows = rows; + this.alpha = alpha; + this.indexed = indexed; + this.greyscale = grayscale; + + if (grayscale && indexed) { + throw new PngjException("palette and greyscale are mutually exclusive"); + } + this.channels = (grayscale || indexed) ? (alpha ? 2 : 1) : (alpha ? 4 : 3); + this.bitDepth = bitdepth; + this.packed = bitdepth < 8; + this.bitspPixel = (this.channels * this.bitDepth); + this.bytesPixel = (this.bitspPixel + 7) / 8; + this.bytesPerRow = (this.bitspPixel * cols + 7) / 8; + this.samplesPerRow = this.channels * this.cols; + this.samplesPerRowPacked = this.packed ? this.bytesPerRow : this.samplesPerRow; + + switch (this.bitDepth) { + case 1: + case 2: + case 4: + if (!(this.indexed || this.greyscale)) + throw new PngjException("only indexed or grayscale can have bitdepth=" + this.bitDepth); + break; + case 8: + break; + case 16: + if (this.indexed) { + throw new PngjException("indexed can't have bitdepth=" + this.bitDepth); + } + break; + default: + throw new PngjException("invalid bitdepth=" + this.bitDepth); + } + if (cols < 1 || cols > ImageInfo.MAX_COLS_ROW) { + throw new PngjException("invalid cols=" + cols + " ???"); + } + + if (rows < 1 || rows > ImageInfo.MAX_COLS_ROW) { + throw new PngjException("invalid rows=" + rows + " ???"); + } + if (this.samplesPerRow < 1) { + throw new PngjException("invalid image parameters (overflow?)"); + } + } + + /** + * returns a copy with different size + * + * @param cols + * if non-positive, the original is used + * @param rows + * if non-positive, the original is used + * @return a new copy with the specified size and same properties + */ + public withSize(cols: number, rows: number): ImageInfo { + return new ImageInfo(cols > 0 ? cols : this.cols, rows > 0 ? rows : this.rows, this.bitDepth, this.alpha, + this.greyscale, this.indexed); + } + + public getTotalPixels(): number { + if (this.totalPixels < 0) + this.totalPixels = this.cols * this.rows; + return this.totalPixels; + } + + public getTotalRawBytes(): number { + if (this.totalRawBytes < 0) + this.totalRawBytes = (this.bytesPerRow + 1) * this.rows; + return this.totalRawBytes; + } + + public toString(): string{ + return "ImageInfo [cols=" + this.cols + ", rows=" + this.rows + ", bitDepth=" + + this.bitDepth + ", channels=" + this.channels + + ", alpha=" + this.alpha + ", greyscale=" + + this.greyscale + ", indexed=" + this.indexed + "]"; + } + + public toStringBrief(): string{ + return this.cols + "x" + this.rows + (this.bitDepth != 8 ? ("d" + this.bitDepth) : "") + (this.alpha ? "a" : "") + + (this.indexed ? "p" : "") + (this.greyscale ? "g" : ""); + } + + public toStringDetail(): string{ + return "ImageInfo [cols=" + this.cols + ", rows=" + this.rows + ", bitDepth=" + + this.bitDepth + ", channels=" + this.channels + ", bitspPixel=" + this.bitspPixel + + ", bytesPixel=" + this.bytesPixel + ", bytesPerRow=" + this.bytesPerRow + + ", samplesPerRow=" + this.samplesPerRow + ", samplesPerRowP=" + this.samplesPerRowPacked + + ", alpha=" + this.alpha + ", greyscale=" + this.greyscale + ", indexed=" + this.indexed + + ", packed=" + this.packed + "]"; + } + + public hashCode(): number { + const prime: number = 31; + let result: number = 1; + result = prime * result + (this.alpha ? 1231 : 1237); + result = prime * result + this.bitDepth; + result = prime * result + this.cols; + result = prime * result + (this.greyscale ? 1231 : 1237); + result = prime * result + (this.indexed ? 1231 : 1237); + result = prime * result + this.rows; + return result; + } + + public equals(obj: ImageInfo): boolean { + if (this == obj) + return true; + if (obj == null) + return false; + var other = obj; + if (this.alpha != other.alpha) + return false; + if (this.bitDepth != other.bitDepth) + return false; + if (this.cols != other.cols) + return false; + if (this.greyscale != other.greyscale) + return false; + if (this.indexed != other.indexed) + return false; + if (this.rows != other.rows) + return false; + return true; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/interface/IBytesConsumer.ets b/imageknife/src/main/ets/components/imageknife/pngj/interface/IBytesConsumer.ets new file mode 100644 index 0000000..5607f29 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/interface/IBytesConsumer.ets @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 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 interface IBytesConsumer { + isDone(): boolean; + + consume(buf: ArrayBuffer, offset: number, len: number): number; +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/io/Closeable.ets b/imageknife/src/main/ets/components/imageknife/pngj/io/Closeable.ets new file mode 100644 index 0000000..0ba92ac --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/io/Closeable.ets @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2021 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 interface Closeable { + close(): void; +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/pngj/misc/Sandbox.ets b/imageknife/src/main/ets/components/imageknife/pngj/misc/Sandbox.ets new file mode 100644 index 0000000..b294cf9 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/pngj/misc/Sandbox.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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 class Sandbox { + + + public static convert(origFileName: string, destFileName: string) { + + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/requestmanage/DiskCacheProxy.ets b/imageknife/src/main/ets/components/imageknife/requestmanage/DiskCacheProxy.ets new file mode 100644 index 0000000..4da069b --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/requestmanage/DiskCacheProxy.ets @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 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 {ICache} from "../requestmanage/ICache" +import {DiskLruCache} from "../../cache/DiskLruCache" + +export class DiskCacheProxy implements ICache { + private mDiskLruCache: DiskLruCache; + + constructor(diskLruCache: DiskLruCache) { + this.mDiskLruCache = diskLruCache; + } + + // 缓存类型 + getName(): string{ + return "Level2DiskCache"; + } + + getCachePath():string{ + let folderPath = this.mDiskLruCache.dirPath + if (folderPath.endsWith('/')) { + return folderPath; + } else { + return folderPath + '/' + } + } + + getValue(key: string): ArrayBuffer{ + return this.mDiskLruCache.getCacheDataByKey(key); + } + + putValue(key: string, value: ArrayBuffer) { + this.mDiskLruCache.putCacheData(key, value, null) + } + + removeValue(key: string): ArrayBuffer{ + // Disk暂无实现 + return; + } + + clear() { + this.mDiskLruCache.cleanCacheData(); + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/requestmanage/ICache.ets b/imageknife/src/main/ets/components/imageknife/requestmanage/ICache.ets new file mode 100644 index 0000000..a108f84 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/requestmanage/ICache.ets @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 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 interface ICache { + + // 缓存类型 + getName(): string + + getValue(key: K): V; + + putValue(key: K, value: V); + + removeValue(key: K): V; + + clear(); + + +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/requestmanage/MemoryCacheProxy.ets b/imageknife/src/main/ets/components/imageknife/requestmanage/MemoryCacheProxy.ets new file mode 100644 index 0000000..691404d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/requestmanage/MemoryCacheProxy.ets @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 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 {ICache} from "../requestmanage/ICache" +import {LruCache} from "../../cache/LruCache" + +export class MemoryCacheProxy implements ICache { + private mLruCache: LruCache; + + constructor(lruCache: LruCache) { + this.mLruCache = lruCache; + } + + // 缓存类型 + getName() { + return "Level1MemoryCache" + } + + getValue(key: K): V{ + console.log("Level1MemoryCache getValue come in!"); + return this.mLruCache.get(key); + } + + putValue(key: K, value: V) { + this.mLruCache.put(key, value); + } + + removeValue(key: K): V{ + return this.mLruCache.remove(key); + } + + clear() { + this.mLruCache.evicAll(); + } + + + // 外界调用 + loadMemoryCache(key: K, isMemoryCacheable: boolean): V{ + // 是否开启内存缓存 + if (!isMemoryCacheable) { + return null; + } + let cached = this.getValue(key) + if (cached != null) { + return cached; + } + return null; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/requestmanage/RequstManager.ets b/imageknife/src/main/ets/components/imageknife/requestmanage/RequstManager.ets new file mode 100644 index 0000000..2d8af17 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/requestmanage/RequstManager.ets @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2021 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 "../../imageknife/RequestOption" +import {DiskLruCache} from "../../cache/DiskLruCache" +import {LruCache} from "../../cache/LruCache" +import {FileUtils} from "../../cache/FileUtils" +import {Md5} from "../../cache/Md5" +import{MemoryCacheProxy} from "../requestmanage/MemoryCacheProxy" +import{DiskCacheProxy} from "../requestmanage/DiskCacheProxy" +import{FileTypeUtil} from "../utils/FileTypeUtil" +import{IDataFetch} from "../../imageknife/networkmanage/IDataFetch" +import{IResourceFetch} from "../../imageknife/resourcemanage/IResourceFetch" +import{ImageKnifeData} from "../ImageKnifeData" +import {AllCacheInfo, IAllCacheInfoCallback} from "../../imageknife/interface/IAllCacheInfoCallback" +import{ParseImageUtil} from '../utils/ParseImageUtil' +import{IParseImage} from '../interface/IParseImage' +import image from "@ohos.multimedia.image" + +export interface AsyncString { + (data: string): void; +} + +export enum Stage { + + INITIALIZE, + + RESOURCE_CACHE, + + DATA_CACHE, + + SOURCE, + + ENCODE, + + FINISHED, +} + + +export enum RunReason { + + INITIALIZE, + + SWITCH_TO_SOURCE_SERVICE, + + DECODE_DATA, +} + +export class RequestManager { + private TAG: string = "RequestManager"; + private options: RequestOption; + private mMemoryCacheProxy: MemoryCacheProxy; + private mDiskCacheProxy: DiskCacheProxy; + private mIDataFetch: IDataFetch; + private mIResourceFetch: IResourceFetch; + private mParseImageUtil: IParseImage; + + constructor(option: RequestOption, memoryCache1: LruCache, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) { + this.options = option; + + // 缓存部分 + this.mMemoryCacheProxy = new MemoryCacheProxy(memoryCache1); + this.mDiskCacheProxy = new DiskCacheProxy(diskMemoryCache1); + + // 网络下载能力 + this.mIDataFetch = dataFetch; + + // 本地数据解析能力 + this.mIResourceFetch = resourceFetch; + + // 解析image能力 + this.mParseImageUtil = new ParseImageUtil(); + } + + static execute(option: RequestOption, memoryCache1: LruCache, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) { + console.log("RequestManager execute") + let manager = new RequestManager(option, memoryCache1, diskMemoryCache1, dataFetch, resourceFetch); + return new Promise(manager.process.bind(manager)) + .then(option.loadComplete.bind(option)) + .then(manager.loadCompleteAfter.bind(manager)) + .catch(option.loadError.bind(option)); + } + + loadCompleteAfter() { + try { // 内部消化问题 + console.log("loadCompleteAfter!") + if (this.options.allCacheInfoCallback) { + console.log("RequestOption =" + JSON.stringify(this.options)); + + // 内存缓存 + let allCacheInfo = new AllCacheInfo(); + let memoryCache = this.mMemoryCacheProxy.getValue(this.options.generateCacheKey); + allCacheInfo.memoryCacheInfo = { + key: this.options.generateCacheKey, + data: memoryCache + } + + // 变换后缓存 + allCacheInfo.resourceCacheInfo = { + key: Md5.hashStr(this.options.generateResourceKey), + path: (this.mDiskCacheProxy.getCachePath() + Md5.hashStr(this.options.generateResourceKey)) + }; + + // 原图缓存 + allCacheInfo.dataCacheInfo = { + key: Md5.hashStr(this.options.generateDataKey), + path: this.mDiskCacheProxy.getCachePath() + Md5.hashStr(this.options.generateDataKey) + } + this.options.allCacheInfoCallback(allCacheInfo) + } + } catch (err) { + console.log("after err =" + err) + } + } + + + // DecodeJob work + private mStage: Stage = Stage.INITIALIZE; + private mRunReason: RunReason = RunReason.INITIALIZE; + + process(onComplete, onError) { + console.log("RequestManager process !"); + this.loadLeve1MemoryCache(onComplete, onError) + } + + private runWrapped(request: RequestOption, runReason: RunReason, onComplete, onError) { + console.log("RequestManager runWrapped") + if (runReason == RunReason.INITIALIZE) { + this.mStage = this.getNextStage(request, this.mStage); + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); + } else { + throw new Error("Unrecognized run reason: " + runReason) + } + } + + private getNextStage(request: RequestOption, current: Stage): Stage{ + if (current == Stage.INITIALIZE) { + return request.strategy.decodeCachedResource() + ? Stage.RESOURCE_CACHE + : this.getNextStage(request, Stage.RESOURCE_CACHE); + } else if (current == Stage.RESOURCE_CACHE) { + return request.strategy.decodeCachedData() + ? Stage.DATA_CACHE + : this.getNextStage(request, Stage.DATA_CACHE); + } else if (current == Stage.DATA_CACHE) { + return request.onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; + } else if (current == Stage.SOURCE) { + return Stage.FINISHED; + } else if (current == Stage.FINISHED) { + return Stage.FINISHED; + } else { + throw new Error("Unrecognized stage: " + current); + } + } + + //究竟从哪里加载数据 + private searchLoadFrom(request: RequestOption, current: Stage, onComplete, onError) { + console.log("RequestManager searchLoadFrom") + if (current == Stage.RESOURCE_CACHE) { + this.loadDiskFromTransform(request, onComplete, onError); + } else if (current == Stage.DATA_CACHE) { + this.loadDiskFromSource(request, onComplete, onError); + } else if (current == Stage.SOURCE) { + this.parseSource(request, onComplete, onError) + } else if (current == Stage.FINISHED) { + onError("在仅从缓存获取数据中,未获取到数据!") + } else { + throw new Error("Unrecognized stage: " + current); + } + } + + // 加载网络资源 + private loadSourceFromNetwork(request: RequestOption, onComplete, onError) { + let success = (arraybuffer) => { + this.downloadSuccess(arraybuffer, onComplete, onError) + } + this.mIDataFetch.loadData(request, success, onError); + } + + // 加载本地资源 + private loadSourceFormNative(request: RequestOption, onComplete, onError) { + console.log("RequestManager loadSourceFormNative") + // 本地解析后进行一级缓存 + let success = (arrayBuffer) => { + // 使用媒体子系统 ImageSource解析文件 获取PixelMap + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arrayBuffer) + console.log("RequstManager - 文件类型为= " + typeValue) + if ((ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag) || ImageKnifeData.SVG == typeValue) { + // 将图片资源 转换为文件地址 + let folderPath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder; + let filePath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder + "/" + + Md5.hashStr(this.options.generateDataKey) + "." + typeValue; + let filename = Md5.hashStr(this.options.generateDataKey) + "." + typeValue; + new Promise((resolve, reject) => { + // 存文件至svg目录,并且记录文件名 + resolve("svg gif 文件开始本地保存!"); + }) + .then((res) => { + // 创建文件 + FileUtils.getInstance() + .createFileProcess(folderPath, filePath, arrayBuffer); + // 写入记录 + FileUtils.getInstance() + .writeData(this.options.getFilesPath() + + "/" + this.options._svgAndGifFolder + "/" + this.options._svgAndGifCommitFile, filename + "\n"); + console.log("svg gif 本地保存成功 输出!"); + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.STRING, filePath, typeValue); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + }) + .catch((err) => { + onError(err) + }) + } + else { + if (request.transformations[0]) { + request.transformations[0].transform(arrayBuffer, request, (error, pixelMap: PixelMap) => { + // 输出给Image + if (pixelMap) { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue); + this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } else { + onError(error); + } + }) + } + else { + let success = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue); + this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } + this.mParseImageUtil.parseImage(arrayBuffer, success, onError) + } + } + } + this.mIResourceFetch.loadResource(request.loadSrc as Resource, success, onError); + } + // 加载磁盘缓存 原图 + private loadDiskFromSource(request: RequestOption, onComplete, onError) { + console.log("RequestManager loadDiskFromSource") + let cached = this.mDiskCacheProxy.getValue(request.generateDataKey) + if (cached != null) { + this.parseDiskFile2PixelMap(request, cached, onComplete, onError) + } else { + this.mStage = Stage.SOURCE; + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); + } + } + + // 加载磁盘缓存 变换后图片 + private loadDiskFromTransform(request: RequestOption, onComplete, onError) { + console.log("RequestManager loadDiskFromTransform") + let cached = this.mDiskCacheProxy.getValue(request.generateResourceKey) + if (cached != null) { + this.parseDiskTransformFile2PixelMap(request, cached, onComplete, onError) + } else { + this.mStage = Stage.DATA_CACHE; + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); + } + } + + parseSource(request: RequestOption, onComplete, onError) { + console.log("RequestManager parseSource") + if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') { + // PixelMap 外层捕获效率更高,不会进入这里 + } else if (typeof request.loadSrc == 'string') { + this.loadSourceFromNetwork(request, onComplete, onError); + } else { + let res = request.loadSrc as Resource; + if (typeof res.id != 'undefined' && typeof res.id != 'undefined') { + this.loadSourceFormNative(request, onComplete, onError) + } else { + console.log("输入参数有问题!") + } + } + + } + + private loadLeve1MemoryCache(onComplete, onError) { + console.log("RequestManager loadLeve1MemoryCache") + // 一级缓存 内存获取 + let cache = this.mMemoryCacheProxy.loadMemoryCache(this.options.generateCacheKey, this.options.isCacheable); + if (cache == null || typeof cache == 'undefined') { + // 处理磁盘加载 网络加载 + this.runWrapped(this.options, this.mRunReason, onComplete, onError) + } else { + onComplete(cache); + return + + } + } + + // 解析磁盘文件变成PixeMap + private parseDiskFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete, onError) { + // 步骤一:文件转为pixelMap 然后变换 给Image组件 + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(source); + if (((ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag) || ImageKnifeData.SVG == typeValue)) { + // 将图片资源 转换为文件地址 + let folderPath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder; + let filePath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder + "/" + + Md5.hashStr(this.options.generateDataKey) + "." + typeValue; + let filename = Md5.hashStr(this.options.generateDataKey) + "." + typeValue; + new Promise((resolve, reject) => { + // 存文件至svg目录,并且记录文件名 + resolve("svg gif 文件开始本地保存!"); + }).then((res) => { + FileUtils.getInstance() + .createFileProcess(folderPath, filePath, source); + FileUtils.getInstance() + .writeData(this.options.getFilesPath() + + "/" + this.options._svgAndGifFolder + "/" + this.options._svgAndGifCommitFile, filename + "\n"); + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.STRING, filePath, typeValue) + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + }) + .catch((err) => { + onError(err) + }) + + } else { + if (this.options.transformations[0]) { + if (this.options.thumbSizeMultiplier) { + let thumbOption = new RequestOption(); + thumbOption.setImageViewSize({ + width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), + height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) + }) + let thumbCallback = this.options.thumbholderOnComplete.bind(this.options); + let thumbError = this.options.thumbholderOnError.bind(this.options); + this.options.transformations[0].transform(source, thumbOption, (error, pixelMap: PixelMap) => { + if (pixelMap) { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue); + thumbCallback(imageKnifeData); + } else { + thumbError(error); + } + }) + setTimeout(()=>{ + this.options.transformations[0].transform(source, request, (error, pixelMap: PixelMap) => { + if (pixelMap) { + // 保存一份变换后的图片PixelMap到MemoryCache + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } else { + onError(error); + } + }) + },this.options.thumbDelayTime); + } + else { + this.options.transformations[0].transform(source, request, (error, pixelMap: PixelMap) => { + if (pixelMap) { + // 保存一份变换后的图片PixelMap到MemoryCache + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } else { + onError(error); + } + }) + } + } else { + // thumbnail 缩略图部分 + if (request.thumbSizeMultiplier) { + let thumbCallback = this.options.thumbholderOnComplete.bind(this.options); + let thumbError = this.options.thumbholderOnError.bind(this.options); + let thumbSuccess = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue); + thumbCallback(imageKnifeData); + } + this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError); + setTimeout(()=>{ + let success = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } + this.mParseImageUtil.parseImage(source, success, onError) + },this.options.thumbDelayTime) + } + else { + let success = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } + this.mParseImageUtil.parseImage(source, success, onError) + } + } + } + } + + // 解析磁盘变换后文件变成PixeMap + private parseDiskTransformFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete, onError) { + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(source); + // thumbnail 缩略图部分 + if (request.thumbSizeMultiplier) { + let thumbCallback = this.options.thumbholderOnComplete.bind(this.options); + let thumbError = this.options.thumbholderOnError.bind(this.options); + let thumbSuccess = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue); + thumbCallback(imageKnifeData); + } + this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError); + setTimeout(()=>{ + let success = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } + this.mParseImageUtil.parseImage(source, success, onError) + },this.options.thumbDelayTime) + }else{ + let success = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue) + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + } + this.mParseImageUtil.parseImage(source, success, onError) + } + } + + private downloadSuccess(source: ArrayBuffer, onComplete, onError) { + console.info('Download task completed.'); + + if(source == null || source == undefined || source.byteLength <= 0){ + onError('Download task completed. but download file is empty!') + return + } + + // 下载成功之后 去data/data/包名/唯一路径/文件名 读取数据 + // 步骤一:文件转为pixelMap 然后变换 给Image组件 + // 步骤二: 文件名保存一份全局 + // 步骤三:查看文件是否支持 非支持类型直接返回 + let fileTypeUtil = new FileTypeUtil(); + let filetype = fileTypeUtil.getFileType(source); + if (!fileTypeUtil.isImage(source)) { + onError("暂不支持 下载文件类型!类型=" + filetype); + return; + } + if ((ImageKnifeData.GIF == filetype && !this.options.dontAnimateFlag) || ImageKnifeData.SVG == filetype) { + // 将图片资源 转换为文件地址 + let folderPath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder; + let filePath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder + "/" + + Md5.hashStr(this.options.generateDataKey) + "." + filetype; + let filename = Md5.hashStr(this.options.generateDataKey) + "." + filetype; + // 1.文件保存 2.内存缓存 3.输出结果 + new Promise((resolve, reject) => { + // 存文件至svg目录,并且记录文件名 + resolve("svg gif 文件开始本地保存!"); + }) + .then((res) => { + FileUtils.getInstance() + .createFileProcess(folderPath, filePath, source); + FileUtils.getInstance() + .writeData(this.options.getFilesPath() + + "/" + this.options._svgAndGifFolder + "/" + this.options._svgAndGifCommitFile, filename + "\n"); + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.STRING, filePath, filetype); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + onComplete(imageKnifeData); + }) + .catch((err) => { + onError(err) + }) + + // 保存二级磁盘缓存 + new Promise((resolve, reject) => { + resolve(source) + }) + .then((arraybuffer: ArrayBuffer) => { + this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer) + }) + .catch((err) => { + console.log("err=" + err); + }) + } else { + // 进行变换 + if (this.options.transformations[0]) { + // thumbnail 缩略图部分 + if (this.options.thumbSizeMultiplier) { + this.thumbnailProcess(source, filetype, onComplete, onError); + } else { + this.options.transformations[0].transform(source, this.options, (error, pixelMap: PixelMap) => { + if (pixelMap) { + this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); + } else { + onError(error); + } + }) + } + } else { + // thumbnail 缩略图部分 + if (this.options.thumbSizeMultiplier) { + let thumbCallback = this.options.thumbholderOnComplete.bind(this.options); + let thumbError = this.options.thumbholderOnError.bind(this.options); + let thumbSuccess = (value: PixelMap) => { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, filetype); + thumbCallback(imageKnifeData); + } + this.mParseImageUtil.parseImageThumbnail(this.options.thumbSizeMultiplier, source, thumbSuccess, thumbError); + setTimeout(() => { + let success = (value: PixelMap) => { + this.saveCacheAndDisk(value, filetype, onComplete, source); + } + this.mParseImageUtil.parseImage(source, success, onError) + }, this.options.thumbDelayTime) + } else { + let success = (value: PixelMap) => { + this.saveCacheAndDisk(value, filetype, onComplete, source); + } + this.mParseImageUtil.parseImage(source, success, onError) + } + } + } + } + + + createImageKnifeData(imageKnifeType:string, imageKnifeValue:PixelMap|string|Resource, imageKnifeSourceType:string):ImageKnifeData{ + let imageKnifeData = new ImageKnifeData(); + imageKnifeData.imageKnifeType = imageKnifeType; + imageKnifeData.imageKnifeValue = imageKnifeValue; + imageKnifeData.imageKnifeSourceType = imageKnifeSourceType; + return imageKnifeData; + } + + private saveCacheAndDisk(value: PixelMap, filetype:string, onComplete, source:ArrayBuffer){ + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, filetype); + this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); + let save2DiskCache = (arraybuffer) => { + this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer) + } + let runSave2Disk = (resolve, reject) => { + resolve(source); + } + let promise = new Promise(runSave2Disk); + promise.then(save2DiskCache); + onComplete(imageKnifeData); + } + + thumbnailProcess(source:ArrayBuffer, filetype:string, onComplete, onError){ + let thumbOption = new RequestOption(); + thumbOption.setImageViewSize({ + width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), + height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) + }) + let thumbCallback = this.options.thumbholderOnComplete.bind(this.options); + let thumbError = this.options.thumbholderOnError.bind(this.options); + this.options.transformations[0].transform(source, thumbOption, (error, pixelMap: PixelMap) => { + if (pixelMap) { + let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, filetype); + thumbCallback(imageKnifeData); + } else { + thumbError(error); + } + }) + setTimeout(() => { + this.options.transformations[0].transform(source, this.options, (error, pixelMap: PixelMap) => { + if (pixelMap) { + this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); + } else { + onError(error); + } + }) + }, this.options.thumbDelayTime) + } + +} + + diff --git a/imageknife/src/main/ets/components/imageknife/resourcemanage/IResourceFetch.ets b/imageknife/src/main/ets/components/imageknife/resourcemanage/IResourceFetch.ets new file mode 100644 index 0000000..3ed14c4 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/resourcemanage/IResourceFetch.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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" + +// 本地资源解析抽象接口 +export interface IResourceFetch { + loadResource(res: Resource, onCompleteFunction, onErrorFunction); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/resourcemanage/ParseResClient.ets b/imageknife/src/main/ets/components/imageknife/resourcemanage/ParseResClient.ets new file mode 100644 index 0000000..ab6b314 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/resourcemanage/ParseResClient.ets @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 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 {IResourceFetch} from '../resourcemanage/IResourceFetch' +import {ResourceTypeEts} from '../../imageknife/constants/ResourceTypeEts' + +import resourceManager from '@ohos.resourceManager'; + +export class ParseResClient implements IResourceFetch { + loadResource(res: Resource, onCompleteFunction, onErrorFunction) { + let resId = res.id; + let resType = res.type; + if (resType == ResourceTypeEts.MEDIA) { + resourceManager.getResourceManager() + .then(result => { + result.getMedia(resId) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + onCompleteFunction(arrayBuffer) + }) + .catch(err => { + onErrorFunction(err) + }) + }) + } + else if (resType == ResourceTypeEts.RAWFILE) { + onErrorFunction('ParseResClient 本地资源是rawfile暂时无法解析出错') + } else { + onErrorFunction('ParseResClient 本地资源不是media也不是rawfile无法解析出错') + } + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/resourcemanage/ParseResClientBase64.ets b/imageknife/src/main/ets/components/imageknife/resourcemanage/ParseResClientBase64.ets new file mode 100644 index 0000000..2ff7d02 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/resourcemanage/ParseResClientBase64.ets @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 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 {IResourceFetch} from '../resourcemanage/IResourceFetch' +import {ResourceTypeEts} from '../../imageknife/constants/ResourceTypeEts' +import {Base64} from '../../cache/Base64' + +import resourceManager from '@ohos.resourceManager'; + +export class ParseResClientBase64 implements IResourceFetch { + loadResource(res: Resource, onCompleteFunction, onErrorFunction) { + let resId = res.id; + let resType = res.type; + if (resType == ResourceTypeEts.MEDIA) { + resourceManager.getResourceManager() + .then(result => { + result.getMediaBase64(resId) + .then(data => { + let matchReg = ';base64,'; + var firstIndex = data.indexOf(matchReg) + data = data.substring(firstIndex + matchReg.length, data.length) + let arrayBuffer = Base64.getInstance() + .decode(data); + onCompleteFunction(arrayBuffer) + }) + .catch(err => { + onErrorFunction(err) + }) + }) + } + else if (resType == ResourceTypeEts.RAWFILE) { + onErrorFunction('ParseResClientBase64 本地资源是rawfile暂时无法解析出错') + } else { + onErrorFunction('ParseResClientBase64 本地资源不是media也不是rawfile无法解析出错') + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/AsyncTransform.ets b/imageknife/src/main/ets/components/imageknife/transform/AsyncTransform.ets new file mode 100644 index 0000000..80bfd74 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/AsyncTransform.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 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 interface AsyncTransform { + (err, data: T) +} diff --git a/imageknife/src/main/ets/components/imageknife/transform/BaseTransform.ets b/imageknife/src/main/ets/components/imageknife/transform/BaseTransform.ets new file mode 100644 index 0000000..522f57d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/BaseTransform.ets @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 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 {AsyncTransform} from "../transform/AsyncTransform" +import {RequestOption} from "../../imageknife/RequestOption" + +export interface BaseTransform { + //实现类 返回作为key生成的一部分 + getName(): string; + + transform(value: ArrayBuffer, request: RequestOption, func: AsyncTransform); +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets new file mode 100644 index 0000000..118b7f5 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/BlurTransformation.ets @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" +import image from "@ohos.multimedia.image" +import {fastBlur} from "../utils/FastBlur" + + +export class BlurTransformation implements BaseTransform { + private _mRadius: number; + + constructor(radius: number) { + this._mRadius = radius; + } + + getName() { + return "BlurTransformation _mRadius:" + this._mRadius; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";BlurTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";BlurTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + fastBlur.blur(data, this._mRadius, true, func); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets new file mode 100644 index 0000000..bbd837d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/BrightnessFilterTransformation.ets @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import image from "@ohos.multimedia.image" + + +/** + * brightness value ranges from -1.0 to 1.0, with 0.0 as the normal level + */ +export class BrightnessFilterTransformation implements BaseTransform { + private _mBrightness: number= 0.0; + + constructor(brightness: number) { + this._mBrightness = brightness; + } + + getName() { + return "BrightnessFilterTransformation:" + this._mBrightness; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + + let imageInfo = await imageSource.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("GrayscaleTransformation The image size does not exist."), null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + let data = await imageSource.createPixelMap(options); + + let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); + await data.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + + for (let index = 0; index < dataArray.length; index += 4) { + dataArray[index] = this.checkVisAble(dataArray[index] * this._mBrightness + dataArray[index]); + dataArray[index+1] = this.checkVisAble(dataArray[index+1] * this._mBrightness + dataArray[index+1]); + dataArray[index+2] = this.checkVisAble(dataArray[index+2] * this._mBrightness + dataArray[index+2]); + dataArray[index+3] = this.checkVisAble(dataArray[index+3] * this._mBrightness + dataArray[index+3]); + } + + await data.writeBufferToPixels(bufferData); + + if (func) { + func("", data); + } + } + + private checkVisAble(input: number) { + if (input > 255) { + input = 255; + } + if (input <= 0) { + input = 0; + } + return input; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets new file mode 100644 index 0000000..2eb7800 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/ContrastFilterTransformation.ets @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import image from "@ohos.multimedia.image" + + +/** + * 以24位色图像为例子,每种色彩都可以用0-255, + * 一共256种深度来表示。如果我们把它画在一个二维坐标上, + * 正好是一条直线。比如我们将像素的色深作为横坐标,输出色深作为纵坐标的画,正好是一条经过原点(0,0)的45度斜线 + * 那么很容易就可以写出它的直线方程:Out = In * 1 ,系数1就是对比度的概念.如果把条直线加上一个偏移量变成B,那么它的直线方程就成为: + * Out = In * 1 + (ab)偏移量(ab)就是亮度的增量。 + *只要有初中的代数知识就很容易看出它满足一条直线方程:Y= A * X + B。但是,我们这里要处理的情况稍微有些不同,在图像处理中,对比度和亮度要分别对待。不能因为改变而改变亮度,因为我们习惯上把灰色(127,127)这一点作为中心点。 + * + *直线公式修改成:Y=( X - 127 ) * A + B。A表示对比度,B表示亮度增量。 + * 只要亮度增量 B=0,无论怎么改变对比度 A,该直线始终通过中心点(127,127),也就是说改变对比度的同时,亮度没有改变 + * + *_mContrast value ranges from 0.0 to 4.0, with 1.0 as the normal level + * + * + */ +export class ContrastFilterTransformation implements BaseTransform { + private _mContrast: number; + + constructor(contrast: number) { + this._mContrast = contrast; + } + + getName() { + return "ContrastFilterTransformation:" + this._mContrast; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";ContrastFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";ContrastFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + + let imageInfo = await imageSource.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("ContrastFilterTransformation The image size does not exist."), null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + + let data = await imageSource.createPixelMap(options); + + let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); + await data.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + + let brightness = 0; //亮度的偏移量,可以默认0 + for (let index = 0; index < dataArray.length; index += 4) { + dataArray[index] = this.checkVisAble((dataArray[index] - 127) * this._mContrast + brightness + 127); + dataArray[index+1] = this.checkVisAble((dataArray[index+1] - 127) * this._mContrast + brightness + 127); + dataArray[index+2] = this.checkVisAble((dataArray[index+2] - 127) * this._mContrast + brightness + 127); + dataArray[index+3] = this.checkVisAble((dataArray[index+3] - 127) * this._mContrast + brightness + 127); + } + + await data.writeBufferToPixels(bufferData); + if (func) { + func("", data); + } + } + + private checkVisAble(input: number) { + if (input > 255) { + input = 255; + } + if (input <= 0) { + input = 0; + } + return input; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/CropCircleTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/CropCircleTransformation.ets new file mode 100644 index 0000000..6bec794 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/CropCircleTransformation.ets @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" +import image from "@ohos.multimedia.image" + +export class CropCircleTransformation implements BaseTransform { + private static TAG: string= "CropCircleTransformation"; + private mCenterX: number= 0; + private mCenterY: number= 0; + private mRadius: number= 0; + + getName() { + return CropCircleTransformation.TAG + ";mCenterX:" + this.mCenterX + + ";mCenterY:" + this.mCenterY + + ";mRadius:" + this.mRadius; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.error(Constants.PROJECT_TAG + CropCircleTransformation.TAG + " buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + CropCircleTransformation.TAG + " buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + var that = this; + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + that.updatePixelMapSize(imageSource, targetWidth, targetHeight, func); + }) + } + + private updatePixelMapSize(imageSource: any, outWith: number, outHeight: number, func?: AsyncTransform) { + var options = { + editable: true, + desiredSize: { + width: outWith, + height: outHeight + } + } + imageSource.createPixelMap(options) + .then(p => { + this.transformCircle(p, func); + }) + .catch(e => { + console.error(Constants.PROJECT_TAG + CropCircleTransformation.TAG + " transform e:" + e); + if (func) { + func(Constants.PROJECT_TAG + CropCircleTransformation.TAG + "e" + e, null); + } + }) + } + + private async transformCircle(data: any, func?: AsyncTransform) { + let imageInfo = await data.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("CropCircleTransformation The image size does not exist."), null) + return; + } + var height = size.height; + var width = size.width; + this.mRadius = 0; + if (width > height) { + this.mRadius = height / 2; + } else { + this.mRadius = width / 2; + } + this.mCenterX = width / 2; + this.mCenterY = height / 2; + + let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); + await data.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + + for (var h = 0;h <= height; h++) { + for (var w = 0;w <= width; w++) { + if (this.isContainsCircle(w, h)) { + continue; + } + //针对的点 + let index = (h * width + w) * 4; + dataArray[index] = 0; + dataArray[index+1] = 0; + dataArray[index+2] = 0; + dataArray[index+3] = 0; + } + } + await data.writeBufferToPixels(bufferData); + if (func) { + func("", data); + } + } + + isContainsCircle(x: number, y: number): boolean { + var a = Math.pow((this.mCenterX - x), 2); + var b = Math.pow((this.mCenterY - y), 2); + var c = Math.sqrt((a + b)); + return c <= this.mRadius; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/CropCircleWithBorderTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/CropCircleWithBorderTransformation.ets new file mode 100644 index 0000000..7024890 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/CropCircleWithBorderTransformation.ets @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" +import image from "@ohos.multimedia.image" + +export class CropCircleWithBorderTransformation implements BaseTransform { + private static TAG: string= "CropCircleTransformation"; + private mBorderSize: number= 5; + private mCenterX: number= 0; + private mCenterY: number= 0; + private mRadius: number= 0; + private mRColor: number= 0; + private mGColor: number= 0; + private mBColor: number= 0; + + constructor(border_size: number, value: { + r_color?: number, + g_color?: number, + b_color?: number, + }) { + this.mRColor = value.g_color; + this.mGColor = value.g_color; + this.mBColor = value.b_color; + this.mBorderSize = border_size; + } + + getName() { + return CropCircleWithBorderTransformation.TAG + ";mBorderSize:" + this.mBorderSize + + ";mCenterX:" + this.mCenterX + + ";mCenterY:" + this.mCenterY + + ";mRadius:" + this.mRadius + + ";mRColor:" + this.mRColor + + ";mGColor:" + this.mGColor + + ";mBColor:" + this.mBColor; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + var that = this; + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + that.updatePixelMapSize(imageSource, targetWidth, targetHeight, func); + }) + } + + private updatePixelMapSize(imageSource: any, outWith: number, outHeight: number, func?: AsyncTransform) { + var options = { + editable: true, + desiredSize: { + width: outWith, + height: outHeight + } + } + imageSource.createPixelMap(options) + .then((pixelMap) => { + this.transformPixelMap(pixelMap, outWith, outHeight, func); + }) + .catch(e => { + console.log(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation e:" + e); + if (func) { + func(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation e:" + e, null); + } + }) + } + + private async transformPixelMap(pixelMap: any, width: number, height: number, func?: AsyncTransform) { + this.mRadius = 0; + if (width > height) { + this.mRadius = height / 2; + } else { + this.mRadius = width / 2; + } + this.mCenterX = width / 2; + this.mCenterY = height / 2; + + + let bufferData = new ArrayBuffer(pixelMap.getPixelBytesNumber()); + await pixelMap.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + + for (let h = 0;h <= height; h++) { + for (let w = 0;w <= width; w++) { + //不在大圆之内的设置透明 + //在大圆与小圆之间的 设置rgb值 + //小圆之内的不变 + let isSmallCircle: boolean = this.isContainsSmallCircle(w, h); + let isBigCircle: boolean = this.isContainsCircle(w, h); + if (isSmallCircle) { + continue; + } + + let index = (h * width + w) * 4; + if (!isBigCircle) { + //设置透明 + dataArray[index] = 0; + dataArray[index+1] = 0; + dataArray[index+2] = 0; + dataArray[index+3] = 0; + } else { + //设置broke + dataArray[index] = this.mRColor; + dataArray[index+1] = this.mGColor; + dataArray[index+2] = this.mBColor; + } + } + } + + await pixelMap.writeBufferToPixels(bufferData); + if (func) { + func("", pixelMap); + } + } + + isContainsCircle(x: number, y: number): boolean { + var a = Math.pow((this.mCenterX - x), 2); + var b = Math.pow((this.mCenterY - y), 2); + var c = Math.sqrt((a + b)); + return c <= this.mRadius; + } + + isContainsSmallCircle(x: number, y: number): boolean { + var a = Math.pow((this.mCenterX - x), 2); + var b = Math.pow((this.mCenterY - y), 2); + var c = Math.sqrt((a + b)); + return c <= (this.mRadius - this.mBorderSize); + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/CropSquareTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/CropSquareTransformation.ets new file mode 100644 index 0000000..8c3f3e8 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/CropSquareTransformation.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" + +import image from "@ohos.multimedia.image" + +export class CropSquareTransformation implements BaseTransform { + private static TAG: string= "CropSquareTransformation"; + + getName() { + return CropSquareTransformation.TAG + ";CropSquareTransformation:" + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";CropSquareTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";CropSquareTransformation buf is empty", null); + } + return; + } + this.squareCrop(buf, request, func); + } + + squareCrop(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + var imageSource = image.createImageSource(buf as any); + imageSource.getImageInfo() + .then((p) => { + var pw = p.size.width; + var ph = p.size.height; + var outWidth = request.size.width; + var outHeight = request.size.height; + if (pw < outWidth) { + outWidth = pw; + } + if (ph < outHeight) { + outHeight = ph; + } + var targetSize = outWidth > outHeight ? outHeight : outWidth; + var options = { + editable: true, + rotate: 0, + desiredSize: { + width: outWidth, + height: outHeight + }, + desiredRegion: { size: { width: targetSize, height: targetSize }, + x: pw / 2 - targetSize / 2, + y: ph / 2 - targetSize / 2, + }, + } + imageSource.createPixelMap(options) + .then(data => { + if (func) { + func("", data); + } + }) + .catch(e => { + if (func) { + func(Constants.PROJECT_TAG + ";CropSquareTransformation e:" + e, null); + } + }) + }) + .catch((error) => { + if (func) { + func(Constants.PROJECT_TAG + ";CropSquareTransformation error:" + error, null); + } + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/CropTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/CropTransformation.ets new file mode 100644 index 0000000..fef3a54 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/CropTransformation.ets @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" +import image from "@ohos.multimedia.image" + +export class CropTransformation implements BaseTransform { + private static TAG: string= "CropCircleTransformation"; + private mWidth: number; + private mHeight: number; + private mCropType: CropType= CropType.CENTER; + + constructor(width: number, height: number, cropType?: CropType) { + this.mWidth = width; + this.mHeight = height; + this.mCropType = cropType; + } + + getName() { + return CropTransformation.TAG + ";mWidth:" + this.mWidth + + ";mHeight:" + this.mHeight + + ";mCropType:" + this.mCropType; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";CropTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";CropTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + + this.mWidth = this.mWidth == 0 ? pixelMapWidth : this.mWidth; + this.mHeight = this.mHeight == 0 ? pixelMapHeight : this.mHeight; + + var scaleX = this.mWidth / pixelMapWidth; + var scaleY = this.mHeight / pixelMapHeight; + var scale = Math.max(scaleX, scaleY); + + var scaledWidth = scale * pixelMapWidth; + var scaledHeight = scale * pixelMapHeight; + var left = (this.mWidth - scaledWidth) / 2; + var top = Math.abs(this.getTop(pixelMapHeight)); + var options = { + editable: true, + desiredRegion: { + size: { + width: scaledWidth > pixelMapWidth ? pixelMapWidth : scaledWidth, + height: scaledHeight > pixelMapHeight ? pixelMapHeight : scaledHeight + }, + x: left < 0 ? 0 : left, + y: top < 0 ? 0 : top, + }, + } + imageSource.createPixelMap(options) + .then((data) => { + func("", data); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } + + private getTop(scaledHeight: number): number{ + switch (this.mCropType.valueOf()) { + case CropType.TOP.valueOf(): + return 0; + case CropType.CENTER.valueOf(): + return (this.mHeight - scaledHeight) / 2; + case CropType.BOTTOM.valueOf(): + return this.mHeight - scaledHeight; + default: + return 0; + } + } +} + +export enum CropType { + TOP, + CENTER, + BOTTOM +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets new file mode 100644 index 0000000..02a437d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/GrayscaleTransformation.ets @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" +import image from "@ohos.multimedia.image" + +export class GrayscaleTransformation implements BaseTransform { + getName() { + return "GrayscaleTransformation:" + this; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + + let imageInfo = await imageSource.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("GrayscaleTransformation The image size does not exist."), null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + let data = await imageSource.createPixelMap(options); + + let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); + let bufferNewData = new ArrayBuffer(data.getPixelBytesNumber()); + await data.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + var dataNewArray = new Uint8Array(bufferNewData); + + for (let index = 0; index < dataArray.length; index += 4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + //b g r + dataNewArray[index] = this.grayscale(r, g, b); + dataNewArray[index+1] = this.grayscale(r, g, b); + dataNewArray[index+2] = this.grayscale(r, g, b); + dataNewArray[index+3] = f; + } + + await data.writeBufferToPixels(bufferNewData); + if (func) { + func('', data); + } + } + + /** + * 将读取的像素点的rgb值,全部灰度化,得到灰度图片(黑白图片)加权平均法 + */ + private grayscale(r: number, g: number, b: number): number{ + return (r * 28 + g * 151 + b * 77) >> 8; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets new file mode 100644 index 0000000..462121e --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/InvertFilterTransformation.ets @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import image from "@ohos.multimedia.image" + +/** + ** Image inversion is particularly useful for enhancing white or gray detail in + * dark areas of an embedded image, especially when black areas dominate in size.The formula for image inversion is as follows: + * Reverse Formula + * s=L-l-r; + * Where, s is the gray level value of a point in the inverted target image, r is the gray level value of the corresponding point in the original image, and L is the number of gray levels. + */ + +export class InvertFilterTransformation implements BaseTransform { + getName() { + return "InvertFilterTransformation"; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";InvertFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";InvertFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + + let imageInfo = await imageSource.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("InvertFilterTransformation The image size does not exist."), null) + return; + } + + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + + let data = await imageSource.createPixelMap(options); + + let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); + await data.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + + for (let index = 0; index < dataArray.length; index += 4) { + dataArray[index] = this.checkVisAble(255 - dataArray[index]); + dataArray[index+1] = this.checkVisAble(255 - dataArray[index+1]); + dataArray[index+2] = this.checkVisAble(255 - dataArray[index+2]); + } + await data.writeBufferToPixels(bufferData); + if (func) { + func('', data); + } + } + + private checkVisAble(input: number) { + if (input > 255) { + input = 255; + } + if (input <= 0) { + input = 0; + } + return input; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/MaskTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/MaskTransformation.ets new file mode 100644 index 0000000..273efb3 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/MaskTransformation.ets @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {MaskUtils} from "../utils/MaskUtils.ets" +import image from "@ohos.multimedia.image" +import resmgr from "@ohos.resourceManager" + +export class MaskTransformation implements BaseTransform { + private _mResourceData: Resource; + + constructor(maskBitmap: Resource) { + this._mResourceData = maskBitmap; + } + + getName() { + return "MaskTransformation:" + this._mResourceData; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";MaskTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";MaskTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + + let imageInfo = await imageSource.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("MaskTransformation The image size does not exist."), null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then(data => { + this.openInternal(data, targetWidth, targetHeight, func) + }) + .catch(e => { + func(e, null); + }) + } + + private openInternal(bitmap: any, width: number, height: number, func: AsyncTransform) { + if (!this._mResourceData) { + throw new Error("MaskTransformation resource is empty"); + } + resmgr.getResourceManager() + .then(result => { + result.getMedia(this._mResourceData + .id) + .then(array => { + let buffer = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset); + var imageSource = image.createImageSource(buffer as any); + var options = { + editable: true, + desiredSize: { + width: width, + height: height + } + } + imageSource.createPixelMap(options) + .then(maskBitmap => { + MaskUtils.mask(bitmap, maskBitmap, func) + }) + }) + .catch(err => { + func("MaskTransformation openInternal error" + err, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets new file mode 100644 index 0000000..9e55bc5 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/PixelationFilterTransformation.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" +import image from "@ohos.multimedia.image" +import {pixelUtils} from "../utils/PixelUtils" + +/** + * Applies a Pixelation effect to the image. + * The pixel with a default of 10.0. + */ +export class PixelationFilterTransformation implements BaseTransform { + private _mPixel: number= 10.0; + + constructor(pixel?: number) { + if (pixel) { + this._mPixel = pixel; + } + } + + getName() { + return "PixelationFilterTransformation" + this._mPixel; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";PixelationFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";PixelationFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + pixelUtils.pixel(data, this._mPixel, func); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/RotateImageTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/RotateImageTransformation.ets new file mode 100644 index 0000000..ddb9c9a --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/RotateImageTransformation.ets @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" + +import image from "@ohos.multimedia.image" + +export class RotateImageTransformation implements BaseTransform { + private mDegreesToRotate: number; + + constructor(degreesToRotate: number) { + this.mDegreesToRotate = degreesToRotate; + } + + getName() { + return "RotateImageTransformation" + ";degreesToRotate:" + this.mDegreesToRotate; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";RotateImageTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";RotateImageTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + rotate: this.mDegreesToRotate%360, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + func("", data); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/RoundedCornersTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/RoundedCornersTransformation.ets new file mode 100644 index 0000000..9220f5e --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/RoundedCornersTransformation.ets @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {ArcPoint} from "../entry/ArcPoint.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" + +import image from "@ohos.multimedia.image" + +export class RoundedCornersTransformation implements BaseTransform { + private mTop_left: number= 0; + private mTop_right: number= 0; + private mBottom_left: number= 0; + private mBottom_right: number= 0; + private mTransform_pixelMap: any; + private mPoint: ArcPoint[]; + + constructor(value: { + top_left?: number, + top_right?: number, + bottom_left?: number, + bottom_right?: number + }) { + this.mTop_left = value.top_left; + this.mTop_right = value.top_right; + this.mBottom_left = value.bottom_left; + this.mBottom_right = value.bottom_right; + } + + getName() { + return "RoundedCornersTransformation" + ";mTop_left:" + this.mTop_left + + ";mTop_right:" + this.mTop_right + + ";mBottom_left:" + this.mBottom_left + + ";mBottom_right:" + this.mBottom_right + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + console.log('RoundedCornersTransformation = '+ this.getName() + + 'buf is null ='+ (buf == null)); + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";RoundedCornersTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";RoundedCornersTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + var that = this; + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + that.transformPixelMap(imageSource, targetWidth, targetHeight, func); + }) + } + + private transformPixelMap(imageSource: any, outWith: number, outHeight: number, func?: AsyncTransform) { + var options = { + editable: true, + desiredSize: { + width: outWith, + height: outHeight + } + } + imageSource.createPixelMap(options) + .then((pixelMap) => { + this.mTransform_pixelMap = pixelMap; + this.mTransform_pixelMap.getImageInfo() + .then((data) => { + let width = data.size.width; + let height = data.size.height; + if (this.mTop_left > 0) { + this.top_left_corners(); + } + if (this.mTop_right > 0) { + this.top_right_corners(width); + } + if (this.mBottom_left > 0) { + this.bottom_left_corners(width, height); + } + if (this.mBottom_right > 0) { + this.bottom_right_corners(width, height); + } + if (func) { + func("", this.mTransform_pixelMap); + } + }) + .catch((error) => { + console.log(Constants.PROJECT_TAG + "RoundedCornersTransformation error:" + error); + }); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + if (func) { + func(e, null); + } + }) + + } + + private top_left_corners() { + this.mPoint = new Array(); + for (var time = 180; time < 270; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = this.mTop_left + Math.sin(hudu) * this.mTop_left; + var y = this.mTop_left + Math.cos(hudu) * this.mTop_left; + this.mPoint.push(new ArcPoint(x, y)); + } + this.hand_pixel_point(this.mPoint); + } + + private top_right_corners(width: number) { + this.mPoint = new Array(); + for (var time = 0; time < 90; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = (width - this.mTop_right) + Math.cos(hudu) * this.mTop_right; + var y = this.mTop_right - Math.sin(hudu) * this.mTop_right; + this.mPoint.push(new ArcPoint(x, y)); + } + + this.hand_right_pixel_point(this.mPoint, width); + } + + private bottom_left_corners(width: number, height: number) { + this.mPoint = new Array(); + for (var time = 90; time < 180; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = this.mBottom_left + Math.cos(hudu) * this.mBottom_left; + var y = height - this.mBottom_left + Math.sin(hudu) * this.mBottom_left; + this.mPoint.push(new ArcPoint(x, y)); + } + this.hand_pixel_point(this.mPoint); + } + + private bottom_right_corners(width: number, height: number) { + this.mPoint = new Array(); + for (var time = 0; time < 90; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = width - this.mBottom_right + Math.cos(hudu) * this.mBottom_right; + var y = height - this.mBottom_right + Math.sin(hudu) * this.mBottom_right; + this.mPoint.push(new ArcPoint(x, y)); + } + this.hand_right_pixel_point(this.mPoint, width); + } + + private hand_pixel_point(points: ArcPoint[]) { + for (var index = 0; index < points.length; index++) { + const element = points[index]; + let x = element.getX(); + let y = element.getY(); + + for (var i = 0; i <= x; i++) { + var buffer1 = new ArrayBuffer(5); + var bytes1 = new Uint8Array(buffer1); + var writePositionRen = { + pixels: buffer1, + offset: 1, + stride: 1024, + region: { size: { width: 1, height: 1 }, + x: i, + y: y + } + } + for (let j = 0;j < 5; j++) { + bytes1[j] = 0; + } + this.mTransform_pixelMap.writePixels(writePositionRen); + } + } + } + + private hand_right_pixel_point(points: ArcPoint[], width: number) { + for (var index = 0; index < points.length; index++) { + const element = points[index]; + let x = element.getX(); + let y = element.getY(); + + for (var i = x; i <= width; i++) { + var buffer1 = new ArrayBuffer(5); + var bytes1 = new Uint8Array(buffer1); + var writePositionRen = { + pixels: buffer1, + offset: 0, + stride: 4, + region: { size: { width: 1, height: 1 }, + x: i, + y: y + } + } + for (let j = 0;j < 5; j++) { + bytes1[j] = 0; + } + this.mTransform_pixelMap.writePixels(writePositionRen); + } + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets new file mode 100644 index 0000000..de3d9e9 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/SepiaFilterTransformation.ets @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../imageknife/RequestOption.ets" +import image from "@ohos.multimedia.image" + +/** + * Applies a simple sepia effect. + *

+ * The intensity with a default of 1.0. + */ +export class SepiaFilterTransformation implements BaseTransform { + getName() { + return "SepiaFilterTransformation"; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";SepiaFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";SepiaFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + + let imageInfo = await imageSource.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("SepiaFilterTransformation The image size does not exist."), null) + return; + } + + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + let data = await imageSource.createPixelMap(options); + + let bufferData = new ArrayBuffer(data.getPixelBytesNumber()); + let bufferNewData = new ArrayBuffer(data.getPixelBytesNumber()); + await data.readPixelsToBuffer(bufferData); + + var dataArray = new Uint8Array(bufferData); + var dataNewArray = new Uint8Array(bufferNewData); + + for (let index = 0; index < dataArray.length; index += 4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + + dataNewArray[index+2] = this.checkVisAble(this.colorBlend(this.noise() + , (r * 0.272) + (g * 0.534) + (b * 0.131) + , b)); + dataNewArray[index+1] = this.checkVisAble(this.colorBlend(this.noise() + , (r * 0.349) + (g * 0.686) + (b * 0.168) + , g)); + dataNewArray[index] = this.checkVisAble(this.colorBlend(this.noise() + , (r * 0.393) + (g * 0.769) + (b * 0.189) + , r)); + dataNewArray[index+3] = f; + } + + await data.writeBufferToPixels(bufferNewData); + if (func) { + func("", data); + } + } + + private checkVisAble(input: number) { + if (input > 255) { + input = 255; + } + if (input <= 0) { + input = 0; + } + return input; + } + + private colorBlend(scale: number, dest: number, src: number): number { + return (scale * dest + (1.0 - scale) * src); + } + + private noise(): number { + return Math.random() * 0.5 + 0.5; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets new file mode 100644 index 0000000..d074c80 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/SketchFilterTransformation.ets @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from '../transform/BaseTransform.ets' +import {AsyncTransform} from '../transform/AsyncTransform.ets' +import {Constants} from '../constants/Constants.ets' +import {RequestOption} from '../../imageknife/RequestOption.ets' +import {TransformUtils} from '../transform/TransformUtils.ets' +import image from '@ohos.multimedia.image' +import {CalculatePixelUtils} from '../utils/CalculatePixelUtils' + +export class SketchFilterTransformation implements BaseTransform { + getName() { + return 'SketchFilterTransformation'; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';SketchFilterTransformation buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';SketchFilterTransformation buf is empty', null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + CalculatePixelUtils.sketch(data, func); + }) + .catch((e) => { + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets b/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets new file mode 100644 index 0000000..4dad54e --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/SwirlFilterTransformation.ets @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from '../transform/BaseTransform.ets' +import {AsyncTransform} from '../transform/AsyncTransform.ets' +import {Constants} from '../constants/Constants.ets' +import {RequestOption} from '../../imageknife/RequestOption.ets' +import {TransformUtils} from '../transform/TransformUtils.ets' +import image from '@ohos.multimedia.image' +import {PixelEntry} from '../entry/PixelEntry' +import {ColorUtils} from '../utils/ColorUtils' +import {CalculatePixelUtils} from '../utils/CalculatePixelUtils' + +export class SwirlFilterTransformation implements BaseTransform { + private _degree: number; + + constructor(degree: number) { + this._degree = degree; + } + + getName() { + return 'SwirlFilterTransformation' + this._degree; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';SwirlFilterTransformation buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';SwirlFilterTransformation buf is empty', null); + } + return; + } + var imageSource = image.createImageSource(buf as any); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + this.swirl(data, this._degree, func); + }) + .catch((e) => { + func(e, null); + }) + }) + } + + private async swirl(bitmap: any, degree: number, func?: AsyncTransform) { + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + return; + } + let width = size.width; + let height = size.height; + let pixEntry: Array = new Array(); + + + let rgbData = CalculatePixelUtils.createInt2DArray(height, width); + + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let dataArray = new Uint8Array(bufferData); + + let ph = 0; + let pw = 0; + for (let index = 0; index < dataArray.length; index += 4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + + let entry = new PixelEntry(); + entry.a = 0; + entry.b = b; + entry.g = g; + entry.r = r; + entry.f = f; + entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b); + pixEntry.push(entry); + rgbData[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b); + if (pw == width - 1) { + pw = 0; + ph++; + } else { + pw++; + } + } + + let k = degree / 3600; + let cenX = width / 2; + let cenY = height / 2; + + let radius = 0; + for (let h = 0;h < height; h++) { + for (let w = 0; w < width; w++) { + + let offerX = w - cenX; + let offerY = h - cenY; + let radian = Math.atan2(offerY, offerX) + radius = Math.floor(Math.sqrt(offerX * offerX + offerY * offerY)); + + let newX = Math.floor(radius * Math.cos(radian + k * radius)) + cenX; + let newY = Math.floor(radius * Math.sin(radian + k * radius)) + cenY; + + newX = Math.floor(Math.min(width - 1, Math.max(0, newX))); + newY = Math.floor(Math.min(height - 1, Math.max(0, newY))); + + rgbData[h][w] = rgbData[newY][newX]; + } + } + + + let bufferNewData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + let dataNewArray = new Uint8Array(bufferNewData); + let index = 0; + let mh = 0; + let nw = 0; + + for (let i = 0; i < dataNewArray.length; i += 4) { + let pixel_1 = rgbData[mh][nw]; + + if (nw == width - 1) { + nw = 0; + mh++; + } else { + nw++; + } + + let p_r = ColorUtils.red(pixel_1); + let p_g = ColorUtils.green(pixel_1); + let p_b = ColorUtils.blue(pixel_1); + + dataNewArray[i] = p_r; + dataNewArray[i+1] = p_g; + dataNewArray[i+2] = p_b; + dataNewArray[i+3] = pixEntry[index].f; + index++; + } + await bitmap.writeBufferToPixels(bufferNewData); + if (func) { + func("", bitmap); + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/TransformType.ets b/imageknife/src/main/ets/components/imageknife/transform/TransformType.ets new file mode 100644 index 0000000..bde5ccc --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/TransformType.ets @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 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 TransformType { + BlurTransformation, + BrightnessFilterTransformation, + ContrastFilterTransformation, + CropCircleTransformation, + CropCircleWithBorderTransformation, + CropSquareTransformation, + CropTransformation, + GrayscaleTransformation, + InvertFilterTransformation, + MaskTransformation, + PixelationFilterTransformation, + RotateImageTransformation, + RoundedCornersTransformation, + SepiaFilterTransformation, + SketchFilterTransformation, + SwirlFilterTransformation, + CenterCrop, + CenterInside, + FitCenter +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/TransformUtils.ets b/imageknife/src/main/ets/components/imageknife/transform/TransformUtils.ets new file mode 100644 index 0000000..14653b9 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/TransformUtils.ets @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2021 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 {AsyncTransform} from '../transform/AsyncTransform' +import image from '@ohos.multimedia.image' + +export class TransformUtils { + static centerCrop(buf: ArrayBuffer, outWidth: number, outHeihgt: number, + callback?: AsyncTransform>) { + var imageSource = image.createImageSource(buf as any); + imageSource.getImageInfo() + .then((p) => { + var sw; + var sh; + var scale; + var pw = p.size.width; + var ph = p.size.height; + if (pw == outWidth && ph == outHeihgt) { + sw = outWidth; + sh = outHeihgt; + } else { + if (pw * outHeihgt > outWidth * ph) { + scale = outHeihgt / ph; + } else { + scale = outWidth / pw; + } + sw = pw * scale; + sh = ph * scale; + } + var options = { + editable: true, + rotate: 0, + desiredRegion: { size: { width: sw, height: sh }, + x: pw / 2 - sw / 2, + y: ph / 2 - sh / 2, + }, + } + if (callback) { + callback('', imageSource.createPixelMap(options)); + } + }) + .catch((error) => { + callback(error, null); + }) + + } + + static rotateImage(buf: ArrayBuffer, degreesToRotate: number): Promise{ + var imageSource = image.createImageSource(buf as any); + var options = { + editable: true, + rotate: degreesToRotate + } + return imageSource.createPixelMap(options); + } + + static centerInside(buf: ArrayBuffer, outWidth: number, outHeihgt: number, + callback?: AsyncTransform>) { + var imageSource = image.createImageSource(buf as any); + imageSource.getImageInfo() + .then((p) => { + var pw = p.size.width; + var ph = p.size.height; + if (pw <= outWidth && ph <= outHeihgt) { + callback('', imageSource.createPixelMap()); + } else { + this.fitCenter(buf, outWidth, outHeihgt, callback); + } + }) + .catch((error) => { + callback(error, null); + }) + + } + + static fitCenter(buf: ArrayBuffer, outWidth: number, outHeihgt: number + , callback?: AsyncTransform>) { + var imageSource = image.createImageSource(buf as any); + imageSource.getImageInfo() + .then((p) => { + var pw = p.size.width; + var ph = p.size.height; + var widthPercentage = outWidth / pw; + var heightPercentage = outHeihgt / ph; + var minPercentage = Math.min(widthPercentage, heightPercentage); + + var targetWidth = Math.round(minPercentage * pw); + var targetHeight = Math.round(minPercentage * ph); + + if (pw == targetWidth && ph == targetHeight) { + targetWidth = pw; + targetHeight = ph; + } else { + targetWidth = minPercentage * pw; + targetHeight = minPercentage * ph; + } + var options = { + editable: true, + rotate: 0, + desiredSize: { width: targetWidth, height: targetHeight } + } + if (callback) { + callback('', imageSource.createPixelMap(options)); + } + }) + .catch(e => { + if (callback) { + callback(e, null); + } + }) + } + + static getPixelMapSize(imageSource: any, func: AsyncTransform<{ + width: number, + height: number + }>) { + if (!imageSource) { + return; + } + imageSource.getImageInfo((err, value) => { + if (err) { + func(err, null) + return; + } + var pWidth = value.size.width; + var pHeight = value.size.height; + func('', { width: pWidth, height: pHeight }); + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/pixelmap/CenterCrop.ets b/imageknife/src/main/ets/components/imageknife/transform/pixelmap/CenterCrop.ets new file mode 100644 index 0000000..28349dc --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/pixelmap/CenterCrop.ets @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from '../BaseTransform' +import {AsyncTransform} from '../AsyncTransform' +import {Constants} from '../../constants/Constants' +import {TransformUtils} from '../TransformUtils' +import {RequestOption} from '../../../imageknife/RequestOption' + +export class CenterCrop implements BaseTransform { + getName() { + return 'CenterCrop:' + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';CenterCrop buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';CenterCrop buf is empty', null); + } + return; + } + TransformUtils.centerCrop(buf, request.size.width, request.size.height, (error, data) => { + data.then(p => { + func('', p); + }).catch(e => { + func(Constants.PROJECT_TAG + ';CenterCrop error:' + e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/pixelmap/CenterInside.ets b/imageknife/src/main/ets/components/imageknife/transform/pixelmap/CenterInside.ets new file mode 100644 index 0000000..c3b8b43 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/pixelmap/CenterInside.ets @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from '../BaseTransform' +import {AsyncTransform} from '../AsyncTransform' +import {Constants} from '../../constants/Constants' +import {TransformUtils} from '../TransformUtils' +import {RequestOption} from '../../../imageknife/RequestOption' + +export class CenterInside implements BaseTransform { + getName() { + return 'CenterInside:' + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';CenterInside buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';CenterInside buf is empty', null); + } + return; + } + TransformUtils.centerInside(buf, request.size.width, request.size.height, (error, data) => { + data.then(p => { + func('', p); + }).catch(e => { + func(Constants.PROJECT_TAG + ';CenterInside error:' + e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/transform/pixelmap/FitCenter.ets b/imageknife/src/main/ets/components/imageknife/transform/pixelmap/FitCenter.ets new file mode 100644 index 0000000..2330b0d --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/transform/pixelmap/FitCenter.ets @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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 {BaseTransform} from '../BaseTransform' +import {AsyncTransform} from '../AsyncTransform' +import {Constants} from '../../constants/Constants' +import {TransformUtils} from '../TransformUtils' +import {RequestOption} from '../../../imageknife/RequestOption' + +export class FitCenter implements BaseTransform { + getName() { + return 'FitCenter:' + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';FitCenter buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';FitCenter buf is empty', null); + } + return; + } + TransformUtils.fitCenter(buf, request.size.width, request.size.height, (error, data) => { + data.then(p => { + func('', p); + }).catch(e => { + func(Constants.PROJECT_TAG + ';FitCenter error:' + e, null); + }) + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets b/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets new file mode 100644 index 0000000..e7a6684 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/CalculatePixelUtils.ets @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2021 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 {PixelEntry} from "../entry/PixelEntry" +import {AsyncTransform} from "../transform/AsyncTransform" +import {ColorUtils} from "./ColorUtils" + +export namespace CalculatePixelUtils { + export async function sketch(p: any, func: AsyncTransform) { + let imageInfo = await p.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + func(new Error("sketch The image size does not exist."), null) + return; + } + + let pos, row, col, clr: number; + let width = size.width; + let height = size.height; + var pixEntry: Array = new Array() + var pixSrc: Array = new Array() + var pixNvt: Array = new Array() + + let bufferData = new ArrayBuffer(p.getPixelBytesNumber()); + await p.readPixelsToBuffer(bufferData); + let dataArray = new Uint8Array(bufferData); + + for (let index = 0; index < dataArray.length; index += 4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + + let entry = new PixelEntry(); + entry.a = 0; + entry.b = b; + entry.g = g; + entry.r = r; + entry.f = f; + entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b); + pixEntry.push(entry); + pixSrc.push(ColorUtils.rgb(entry.r, entry.g, entry.b)); + pixNvt.push(0); + } + + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + pos = row * width + col; + pixSrc[pos] = (pixEntry[pos].r + pixEntry[pos].g + pixEntry[pos].b) / 3; + pixNvt[pos] = 255 - pixSrc[pos]; + } + } + // 对取反的像素进行高斯模糊, 强度可以设置,暂定为5.0 + gaussGray(pixNvt, 5.0, 5.0, width, height); + // 灰度颜色和模糊后像素进行差值运算 + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + pos = row * width + col; + clr = pixSrc[pos] << 8; + clr /= 256 - pixNvt[pos]; + clr = Math.min(clr, 255); + pixSrc[pos] = ColorUtils.rgb(clr, clr, clr); + } + } + + let bufferNewData = new ArrayBuffer(p.getPixelBytesNumber()); + let dataNewArray = new Uint8Array(bufferNewData); + let index = 0; + + for (let i = 0; i < dataNewArray.length; i += 4) { + dataNewArray[i] = ColorUtils.red(pixSrc[index]); + dataNewArray[i+1] = ColorUtils.green(pixSrc[index]); + dataNewArray[i+2] = ColorUtils.blue(pixSrc[index]); + dataNewArray[i+3] = pixEntry[index].f; + index++; + } + await p.writeBufferToPixels(bufferNewData); + + if (func) { + func("success", p); + } + } + + function gaussGray(psrc: Array, horz: number, vert: number, + width: number, height: number): number { + let dst, src, n_p, n_m, d_p, d_m, bd_p, bd_m, val_p, val_m, initial_p, initial_m: Array; + let i, j, t, k, row, col, terms, std_dev, sp_p_idx, sp_m_idx, vp_idx, vm_idx: number; + let row_stride = width; + let max_len = Math.max(width, height); + val_p = createIntArray(max_len); + val_m = createIntArray(max_len); + n_p = createIntArray(5); + n_m = createIntArray(5); + d_p = createIntArray(5); + d_m = createIntArray(5); + bd_p = createIntArray(5); + bd_m = createIntArray(5); + src = createIntArray(max_len); + dst = createIntArray(max_len); + initial_p = createIntArray(4); + initial_m = createIntArray(4); + // 垂直方向 + if (vert > 0.0) { + vert = Math.abs(vert) + 1.0; + std_dev = Math.sqrt(-(vert * vert) / (2 * Math.log(1.0 / 255.0))); + // 初试化常量 + findConstants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + for (col = 0; col < width; col++) { + for (k = 0; k < max_len; k++) { + val_m[k] = val_p[k] = 0; + } + for (t = 0; t < height; t++) { + src[t] = psrc[t * row_stride + col]; + } + sp_p_idx = 0; + sp_m_idx = height - 1; + vp_idx = 0; + vm_idx = height - 1; + initial_p[0] = src[0]; + initial_m[0] = src[height - 1]; + for (row = 0; row < height; row++) { + terms = (row < 4) ? row : 4; + for (i = 0; i <= terms; i++) { + val_p[vp_idx] += n_p[i] * src[sp_p_idx - i] - d_p[i] + * val_p[vp_idx - i]; + val_m[vm_idx] += n_m[i] * src[sp_m_idx + i] - d_m[i] + * val_m[vm_idx + i]; + } + for (j = i; j <= 4; j++) { + val_p[vp_idx] += (n_p[j] - bd_p[j]) * initial_p[0]; + val_m[vm_idx] += (n_m[j] - bd_m[j]) * initial_m[0]; + } + sp_p_idx++; + sp_m_idx--; + vp_idx++; + vm_idx--; + } + transferGaussPixels(val_p, val_m, dst, 1, height); + for (t = 0; t < height; t++) { + psrc[t * row_stride + col] = dst[t]; + } + } + } + // 水平方向 + if (horz > 0.0) { + horz = Math.abs(horz) + 1.0; + if (horz != vert) { + std_dev = Math.sqrt(-(horz * horz) + / (2 * Math.log(1.0 / 255.0))); + // 初试化常量 + findConstants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + } + for (row = 0; row < height; row++) { + for (k = 0; k < max_len; k++) { + val_m[k] = val_p[k] = 0; + } + for (t = 0; t < width; t++) { + src[t] = psrc[row * row_stride + t]; + } + sp_p_idx = 0; + sp_m_idx = width - 1; + vp_idx = 0; + vm_idx = width - 1; + initial_p[0] = src[0]; + initial_m[0] = src[width - 1]; + for (col = 0; col < width; col++) { + terms = (col < 4) ? col : 4; + for (i = 0; i <= terms; i++) { + val_p[vp_idx] += n_p[i] * src[sp_p_idx - i] - d_p[i] + * val_p[vp_idx - i]; + val_m[vm_idx] += n_m[i] * src[sp_m_idx + i] - d_m[i] + * val_m[vm_idx + i]; + } + for (j = i; j <= 4; j++) { + val_p[vp_idx] += (n_p[j] - bd_p[j]) * initial_p[0]; + val_m[vm_idx] += (n_m[j] - bd_m[j]) * initial_m[0]; + } + sp_p_idx++; + sp_m_idx--; + vp_idx++; + vm_idx--; + } + transferGaussPixels(val_p, val_m, dst, 1, width); + for (t = 0; t < width; t++) { + psrc[row * row_stride + t] = dst[t]; + } + } + } + return 0; + } + + function findConstants(n_p: Array, n_m: Array, d_p: Array, + d_m: Array, bd_p: Array + , bd_m: Array, std_dev: number) { + let div = Math.sqrt(2 * 3.141593) * std_dev; + let x0 = -1.783 / std_dev; + let x1 = -1.723 / std_dev; + let x2 = 0.6318 / std_dev; + let x3 = 1.997 / std_dev; + let x4 = 1.6803 / div; + let x5 = 3.735 / div; + let x6 = -0.6803 / div; + let x7 = -0.2598 / div; + let i; + n_p[0] = x4 + x6; + n_p[1] = (Math.exp(x1) + * (x7 * Math.sin(x3) - (x6 + 2 * x4) * Math.cos(x3)) + Math + .exp(x0) * (x5 * Math.sin(x2) - (2 * x6 + x4) * Math.cos(x2))); + n_p[2] = (2 + * Math.exp(x0 + x1) + * ((x4 + x6) * Math.cos(x3) * Math.cos(x2) - x5 * Math.cos(x3) + * Math.sin(x2) - x7 * Math.cos(x2) * Math.sin(x3)) + x6 + * Math.exp(2 * x0) + x4 * Math.exp(2 * x1)); + n_p[3] = (Math.exp(x1 + 2 * x0) + * (x7 * Math.sin(x3) - x6 * Math.cos(x3)) + Math.exp(x0 + 2 + * x1) + * (x5 * Math.sin(x2) - x4 * Math.cos(x2))); + n_p[4] = 0.0; + d_p[0] = 0.0; + d_p[1] = -2 * Math.exp(x1) * Math.cos(x3) - 2 * Math.exp(x0) + * Math.cos(x2); + d_p[2] = 4 * Math.cos(x3) * Math.cos(x2) * Math.exp(x0 + x1) + + Math.exp(2 * x1) + Math.exp(2 * x0); + d_p[3] = -2 * Math.cos(x2) * Math.exp(x0 + 2 * x1) - 2 * Math.cos(x3) + * Math.exp(x1 + 2 * x0); + d_p[4] = Math.exp(2 * x0 + 2 * x1); + for (i = 0; i <= 4; i++) { + d_m[i] = d_p[i]; + } + n_m[0] = 0.0; + for (i = 1; i <= 4; i++) { + n_m[i] = n_p[i] - d_p[i] * n_p[0]; + } + let sum_n_p, sum_n_m, sum_d, a, b: number; + sum_n_p = 0.0; + sum_n_m = 0.0; + sum_d = 0.0; + for (i = 0; i <= 4; i++) { + sum_n_p += n_p[i]; + sum_n_m += n_m[i]; + sum_d += d_p[i]; + } + a = sum_n_p / (1.0 + sum_d); + b = sum_n_m / (1.0 + sum_d); + for (i = 0; i <= 4; i++) { + bd_p[i] = d_p[i] * a; + bd_m[i] = d_m[i] * b; + } + } + + function transferGaussPixels(src1: Array, src2: Array, + dest: Array, bytes: number, width: number) { + let i, j, k, b, sum: number; + let bend = bytes * width; + i = j = k = 0; + for (b = 0; b < bend; b++) { + sum = src1[i++] + src2[j++]; + if (sum > 255) + sum = 255; + else if (sum < 0) + sum = 0; + dest[k++] = sum; + } + } + + export function createIntArray(len: number): Array { + let array = new Array(); + for (var index = 0; index < len; index++) { + array.push(0); + } + return array; + } + + export function createInt2DArray(first_len: number, second_len: number): Array> { + let array = new Array>(); + for (let f = 0; f < first_len; f++) { + let s1 = new Array(); + for (let s = 0; s < second_len; s++) { + s1.push(0); + } + array.push(s1); + } + return array; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/ColorUtils.ets b/imageknife/src/main/ets/components/imageknife/utils/ColorUtils.ets new file mode 100644 index 0000000..4254369 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/ColorUtils.ets @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 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 resmgr from '@ohos.resourceManager' +import {DataCallBack} from "../interface/DataCallBack" + +export namespace ColorUtils { + +/** + * 本地颜色值解析 + * ColorUtils.parseColor("color_name",callback) + */ + export function parseColor(c: string, callback: DataCallBack) { + resmgr.getResourceManager() + .then(result => { + var reColor = 'sys.color.' + c; + result.getString($r(reColor) + .id, (err, color) => { + if (!err) { + var cos = JSON.stringify(color); + callback.callback(cos) + } else { + callback.callback(err.message) + } + }); + }) + .catch((error) => { + callback.callback(error.message) + }) + } + + export function red(color: number): number { + return (color >> 16) & 0xFF; + } + + export function green(color: number): number { + return (color >> 8) & 0xFF; + } + + export function blue(color: number): number { + return color & 0xFF; + } + + export function alpha(color: number): number { + return color >>> 24; + } + + export function rgb(red: number, green: number, blue: number): number { + return 0xff000000 | (red << 16) | (green << 8) | blue; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets b/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets new file mode 100644 index 0000000..57bf3bd --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/FastBlur.ets @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2021 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 {CalculatePixelUtils} from "./CalculatePixelUtils" +import {PixelEntry} from "../entry/PixelEntry" +import {AsyncTransform} from "../transform/AsyncTransform" +import {ColorUtils} from "./ColorUtils" + + +export namespace fastBlur { + + + export async function blur(bitmap: any, radius: number, canReuseInBitmap: boolean, func: AsyncTransform) { + + // Stack Blur v1.0 from + // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + // + // Java Author: Mario Klingemann + // http://incubator.quasimondo.com + // created Feburary 29, 2004 + // port : Yahel Bouaziz + // http://www.kayenko.com + // ported april 5th, 2012 + + // This is a compromise between Gaussian Blur and Box blur + // It creates much better looking blurs than Box Blur, but is + // 7x faster than my Gaussian Blur implementation. + // + // I called it Stack Blur because this describes best how this + // filter works internally: it creates a kind of moving stack + // of colors whilst scanning through the image. Thereby it + // just has to add one new block of color to the right side + // of the stack and remove the leftmost color. The remaining + // colors on the topmost layer of the stack are either added on + // or reduced by one, depending on if they are on the right or + // on the left side of the stack. + // + // If you are using this algorithm in your code please add + // the following line: + // + // Stack Blur Algorithm by Mario Klingemann + if (radius < 1) { + func("error,radius must be greater than 1 ", null); + return; + } + + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("fastBlur The image size does not exist."), null) + return; + } + + let w = size.width; + let h = size.height; + var pixEntry: Array = new Array() + var pix: Array = new Array() + + + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let dataArray = new Uint8Array(bufferData); + + for (let index = 0; index < dataArray.length; index+=4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + + let entry = new PixelEntry(); + entry.a = 0; + entry.b = b; + entry.g = g; + entry.r = r; + entry.f = f; + entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b); + pixEntry.push(entry); + pix.push(ColorUtils.rgb(entry.r, entry.g, entry.b)); + } + + let wm = w - 1; + let hm = h - 1; + let wh = w * h; + let div = radius + radius + 1; + + let r = CalculatePixelUtils.createIntArray(wh); + let g = CalculatePixelUtils.createIntArray(wh); + let b = CalculatePixelUtils.createIntArray(wh); + + let rsum, gsum, bsum, x, y, i, p, yp, yi, yw: number; + let vmin = CalculatePixelUtils.createIntArray(Math.max(w, h)); + + let divsum = (div + 1) >> 1; + divsum *= divsum; + let dv = CalculatePixelUtils.createIntArray(256 * divsum); + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + let stack = CalculatePixelUtils.createInt2DArray(div, 3); + let stackpointer, stackstart, rbs, routsum, goutsum, boutsum, rinsum, ginsum, binsum: number; + let sir: Array; + let r1 = radius + 1; + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + rbs = r1 - Math.abs(i); + rsum += sir[0] * rbs; + gsum += sir[1] * rbs; + bsum += sir[2] * rbs; + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + r[yi] = dv[rsum]; + g[yi] = dv[gsum]; + b[yi] = dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (y == 0) { + vmin[x] = Math.min(x + radius + 1, wm); + } + p = pix[yw + vmin[x]]; + + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[(stackpointer) % div]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + yi = Math.max(0, yp) + x; + + sir = stack[i + radius]; + + sir[0] = r[yi]; + sir[1] = g[yi]; + sir[2] = b[yi]; + + rbs = r1 - Math.abs(i); + + rsum += r[yi] * rbs; + gsum += g[yi] * rbs; + bsum += b[yi] * rbs; + + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + + if (i < hm) { + yp += w; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + // Preserve alpha channel: ( 0xff000000 & pix[yi] ) + pix[yi] = (0xff000000 & pix[Math.round(yi)]) | (dv[Math.round(rsum)] << 16) | (dv[ + Math.round(gsum)] << 8) | dv[Math.round(bsum)]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (x == 0) { + vmin[y] = Math.min(y + r1, hm) * w; + } + p = x + vmin[y]; + + sir[0] = r[p]; + sir[1] = g[p]; + sir[2] = b[p]; + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[stackpointer]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi += w; + } + } + + + let bufferNewData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + let dataNewArray = new Uint8Array(bufferNewData); + let index = 0; + + for (let i = 0; i < dataNewArray.length; i += 4) { + dataNewArray[i] = ColorUtils.red(pix[index]); + dataNewArray[i+1] = ColorUtils.green(pix[index]); + dataNewArray[i+2] = ColorUtils.blue(pix[index]); + dataNewArray[i+3] = pixEntry[index].f; + index++; + } + await bitmap.writeBufferToPixels(bufferNewData); + if (func) { + func("success", bitmap); + } + } +} diff --git a/imageknife/src/main/ets/components/imageknife/utils/FileTypeUtil.ets b/imageknife/src/main/ets/components/imageknife/utils/FileTypeUtil.ets new file mode 100644 index 0000000..fb8babc --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/FileTypeUtil.ets @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2021 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 class FileTypeUtil { + private map = new Map(); + + constructor() { + this.initImageType(); + this.initMediaType(); + this.initOtherType(); + } + + private initImageType(){ + this.map.set("FFD8FF", "JPG") + this.map.set("89504E47", "PNG") + this.map.set("47494638", "GIF") + this.map.set("49492A00", "TIF") + this.map.set("52494646", "RIFF") + this.map.set("57454250", "WEBP") + this.map.set("3C3F786D6C", "SVG") + this.map.set("424D", "BMP") + this.map.set("424D228C010000000000", "BMP") // 16色位图(bmp) + this.map.set("424D8240090000000000", "BMP") // 24位位图(bmp) + this.map.set("424D8E1B030000000000", "BMP") // 256色位图(bmp) + } + + private initMediaType(){ + this.map.set("57415645", "WAV") + this.map.set("41564920", "AVI") + this.map.set("00000020667479706D70", "MP4") + this.map.set("49443303000000002176", "MP3") + this.map.set("464C5601050000000900", "FLV") + } + + private initOtherType(){ + this.map.set("41433130", "DWG") + this.map.set("38425053", "PSD") + this.map.set("7B5C727466", "RTF") + /** XML */ + // this.map.set("3C3F786D6C", "XML") + this.map.set("68746D6C3E", "HTML") + this.map.set("44656C69766572792D646174653A", "EML") + this.map.set("CFAD12FEC5FD746F", "DBX") + this.map.set("2142444E", "PST") + this.map.set("0xD0CF11E0A1B11AE1", "OLE2") + /** Microsoft Word/Excel 注意:word 和 excel的文件头一样 */ + this.map.set("D0CF11E0", "XLS") + + // this.map.set("DOC", "D0CF11E0") + + // this.map.set("504B0304", "DOCX") + + this.map.set("504B0304", "XLSX") + this.map.set("5374616E64617264204A", "MDB") + this.map.set("FF575043", "WPB") + this.map.set("252150532D41646F6265", "EPS") + this.map.set("252150532D41646F6265", "PS") + this.map.set("255044462D312E", "PDF") + this.map.set("AC9EBD8F", "qdf") + this.map.set("458600000600", "qbb") + this.map.set("E3828596", "PWL") + this.map.set("504B0304", "ZIP") + this.map.set("52617221", "ARAR") + this.map.set("2E7261FD", "RAM") + this.map.set("2E524D46", "RM") + this.map.set("2E524D46000000120001", "RMVB") + this.map.set("000001BA", "MPG") + this.map.set("6D6F6F76", "MOV") + this.map.set("3026B2758E66CF11", "ASF") + this.map.set("60EA", "ARJ") + this.map.set("4D546864", "MID") + + this.map.set("1F8B08", "GZ") + this.map.set("48544D4C207B0D0A0942", "CSS") + this.map.set("696B2E71623D696B2E71", "JS") + this.map.set("d0cf11e0a1b11ae10000", "VSD") + this.map.set("d0cf11e0a1b11ae10000", "WPS") + this.map.set("6431303A637265617465", "TORRENT") + this.map.set("3C2540207061676520", "JSP") + this.map.set("7061636B61676520", "JAVA") + this.map.set("CAFEBABE0000002E00", "CLASS") + this.map.set("504B03040A000000", "JAR") + this.map.set("4D616E69666573742D56", "MF") + this.map.set("4D5A9000030000000400", "EXE") + this.map.set("7F454C4601010100", "ELF") + this.map.set("2000604060", "WK1") + this.map.set("00001A0000100400", "WK3") + this.map.set("00001A0002100400", "WK4") + this.map.set("576F726450726F", "LWP") + this.map.set("53520100", "SLY") + } + + + getMaxKeyLength() { + let length = 0; + this.map.forEach((value, key, map) => { + let keyName = key; + length = Math.max(keyName.length, length); + }) + return length; + } + + isImage(arraybuffer: ArrayBuffer) { + + let value = this.getFileType(arraybuffer) + if ( + value == "jpg" || + value == "png" || + value == "riff" || + value == "webp" || + value == "bmp" || + value == "gif" || + value == "svg" + ) { + return true; + } + + return false; + } + + isPixelMapType(arraybuffer: ArrayBuffer) { + + let value = this.getFileType(arraybuffer) + if ( + value == "jpg" || + value == "png" || + value == "riff" || + value == "webp" || + value == "bmp" + ) { + return true; + } + + return false; + } + + isGif(arraybuffer: ArrayBuffer) { + let value = this.getFileType(arraybuffer) + if ( + value == "gif" + ) { + return true; + } + return false; + } + + isSvg(arraybuffer: ArrayBuffer) { + let value = this.getFileType(arraybuffer) + if ( + value == "svg" + ) { + return true; + } + return false; + } + + getFileType(arraybuffer: ArrayBuffer) { + if(arraybuffer == null || arraybuffer == undefined || arraybuffer.byteLength <= this.getMaxKeyLength()){ + return undefined; + } + let maxlen = this.getMaxKeyLength() / 2; + let dataView = new DataView(arraybuffer); + let searchKey = ""; + for (let i = 0; i < maxlen; i++) { + searchKey = searchKey + this.dec2Hex(dataView.getUint8(i)); + let value = this.map.get(searchKey); + if (value != undefined) { + return (value as string).toLowerCase(); + } + } + } + + dec2Hex(uint8: number) { + let hex = uint8.toString(16); + if (hex.length <= 1) { + hex = "0" + hex; + } + return hex.toUpperCase(); + } +} diff --git a/imageknife/src/main/ets/components/imageknife/utils/K2DArray.ets b/imageknife/src/main/ets/components/imageknife/utils/K2DArray.ets new file mode 100644 index 0000000..60977ba --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/K2DArray.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 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 class K2DArray { + private _2dArray: Array> = new Array>(); + private rows: number; + private columns: number; + + public constructor(r: number, c: number, value: number) { + this.rows = r; + this.columns = c; + this.initRows(r); + this.initColumns(c, value); + } + + private initRows(row: number) { + if (row < 1) { + return; + } + for (var i = 0; i < row; i++) { + this._2dArray.push(new Array()) + } + } + + private initColumns(c: number, value: number) { + if (c < 1) { + return; + } + for (var i = 0; i < this._2dArray.length; i++) { + for (var j = 0; j < c; j++) { + this._2dArray[i].push(value); + } + } + } + + /** + * 获取数组 + */ + public getArray(): Array>{ + return this._2dArray; + } + + /** + * 获取数组 + */ + public getColumnsArray(r: number): Array{ + if (r < 0 || r >= this.rows) { + return null; + } + return this._2dArray[r]; + } + + /** + * 获取值 + */ + public getValue(r: number, c: number): number { + if (r < 0 || c < 0 || r >= this.rows || c >= this.columns) { + return; + } + return this._2dArray[r][c]; + } + + /** + * 设置值 + */ + public setValye(r: number, c: number, value: number) { + if (r < 0 || c < 0 || r >= this.rows || c >= this.columns) { + return; + } + this._2dArray[r][c] = value; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/MaskUtils.ets b/imageknife/src/main/ets/components/imageknife/utils/MaskUtils.ets new file mode 100644 index 0000000..756a94b --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/MaskUtils.ets @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2021 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 {PixelEntry} from "../entry/PixelEntry" +import {AsyncTransform} from "../transform/AsyncTransform" +import {ColorUtils} from "./ColorUtils" +import {CalculatePixelUtils} from "./CalculatePixelUtils" + +export class MaskUtils { + static async mask(bitmap: any, maskBitmap: any, func?: AsyncTransform) { + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + return; + } + let width = size.width; + let height = size.height; + + let rgbData = CalculatePixelUtils.createInt2DArray(height, width); + + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let dataArray = new Uint8Array(bufferData); + + let ph = 0; + let pw = 0; + for (let index = 0; index < dataArray.length; index += 4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + + let entry = new PixelEntry(); + entry.a = 0; + entry.b = b; + entry.g = g; + entry.r = r; + entry.f = f; + entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b); + rgbData[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b); + if (pw == width - 1) { + pw = 0; + ph++; + } else { + pw++; + } + } + + + let imageInfoMask = await maskBitmap.getImageInfo(); + let sizeMask = { + width: imageInfoMask.size.width, + height: imageInfoMask.size.height + } + if (!sizeMask) { + return; + } + let widthMask = sizeMask.width; + let heightMask = sizeMask.height; + let rgbDataMask = CalculatePixelUtils.createInt2DArray(heightMask, widthMask); + let pixEntry: Array = new Array(); + + let bufferData_m = new ArrayBuffer(maskBitmap.getPixelBytesNumber()); + await maskBitmap.readPixelsToBuffer(bufferData_m); + let dataArray_m = new Uint8Array(bufferData_m); + + let ph_m = 0; + let pw_m = 0; + + for (let index = 0; index < dataArray_m.length; index += 4) { + const r = dataArray_m[index]; + const g = dataArray_m[index+1]; + const b = dataArray_m[index+2]; + const f = dataArray_m[index+3]; + + let entry = new PixelEntry(); + entry.a = 0; + entry.b = b; + entry.g = g; + entry.r = r; + entry.f = f; + entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b); + pixEntry.push(entry); + if (entry.r == 0 && entry.g == 0 && entry.b == 0) { + rgbDataMask[ph_m][pw_m] = rgbData[ph_m][pw_m]; + } else { + rgbDataMask[ph_m][pw_m] = ColorUtils.rgb(entry.r, entry.g, entry.b); + } + + if (pw_m == widthMask - 1) { + pw_m = 0; + ph_m++; + } else { + pw_m++; + } + } + + + let bufferNewData = new ArrayBuffer(maskBitmap.getPixelBytesNumber()); + let dataNewArray = new Uint8Array(bufferNewData); + let index = 0; + let mh = 0; + let nw = 0; + + for (let i = 0; i < dataNewArray.length; i += 4) { + let pixel_1 = rgbDataMask[mh][nw]; + + if (nw == widthMask - 1) { + nw = 0; + mh++; + } else { + nw++; + } + + let p_r = ColorUtils.red(pixel_1); + let p_g = ColorUtils.green(pixel_1); + let p_b = ColorUtils.blue(pixel_1); + + dataNewArray[i] = p_r; + dataNewArray[i+1] = p_g; + dataNewArray[i+2] = p_b; + dataNewArray[i+3] = pixEntry[index].f; + index++; + } + await maskBitmap.writeBufferToPixels(bufferNewData); + if (func) { + func("", maskBitmap); + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets b/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets new file mode 100644 index 0000000..d4dbd5f --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 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{IParseImage} from '../interface/IParseImage' +import image from '@ohos.multimedia.image'; + +export class ParseImageUtil implements IParseImage { + parseImage(imageinfo: ArrayBuffer, onCompleteFunction, onErrorFunction) { + this.parseImageThumbnail(1, imageinfo, onCompleteFunction, onErrorFunction) + } + + // scale(0,1) + parseImageThumbnail(scale: number, imageinfo: ArrayBuffer, onCompleteFunction, onErrorFunction) { + let imageSource = image.createImageSource(imageinfo as any); // 步骤一:文件转为pixelMap 然后变换 给Image组件 + imageSource.getImageInfo((err, value) => { + if (err) { + onErrorFunction(err); + return; + } + let hValue = Math.round(value.size.height * scale); + let wValue = Math.round(value.size.width * scale); + let defaultSize = { + 'height': hValue, + 'width': wValue + }; + + let opts = { + editable: true, + desiredSize: defaultSize + }; + + + imageSource.createPixelMap(opts, (err, pixelmap) => { + if (err) { + onErrorFunction(err); + } else { + onCompleteFunction(pixelmap); + } + }) + + }) + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets b/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets new file mode 100644 index 0000000..03fd923 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/PixelUtils.ets @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2021 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 {CalculatePixelUtils} from "./CalculatePixelUtils" +import {PixelEntry} from "../entry/PixelEntry" +import {AsyncTransform} from "../transform/AsyncTransform" +import {ColorUtils} from "./ColorUtils" + +export namespace pixelUtils { + + export async function pixel(bitmap: any, pixel: number, func: AsyncTransform) { + + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + func(new Error("GrayscaleTransformation The image size does not exist."), null) + return; + } + let targetWidth = size.width; + let targetHeight = size.height; + + var pixEntry: Array = new Array() + let inPixels: Array> = CalculatePixelUtils.createInt2DArray(targetHeight, targetWidth); + + let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + await bitmap.readPixelsToBuffer(bufferData); + let dataArray = new Uint8Array(bufferData); + + let ph = 0; + let pw = 0; + + + for (let index = 0; index < dataArray.length; index += 4) { + const r = dataArray[index]; + const g = dataArray[index+1]; + const b = dataArray[index+2]; + const f = dataArray[index+3]; + + let entry = new PixelEntry(); + entry.a = 0; + entry.b = b; + entry.g = g; + entry.r = r; + entry.f = f; + entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b); + pixEntry.push(entry); + inPixels[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b); + if (pw == targetWidth - 1) { + pw = 0; + ph++; + } else { + pw++; + } + } + + var realPixel_W = pixel > targetWidth ? targetWidth : pixel; + var realPixel_H = pixel > targetHeight ? targetHeight : pixel; + + //横排的正方形个数 + var x_index = Math.floor(targetWidth / realPixel_W); + //纵排的正方形个数 + var y_index = Math.floor(targetHeight / realPixel_H); + + for (let ch = 0; ch < y_index; ch++) { + for (let cw = 0; cw < x_index; cw++) { + + let max_x = (cw + 1) * realPixel_W > targetWidth ? targetWidth : (cw + 1) * realPixel_W; + let max_y = (ch + 1) * realPixel_H > targetHeight ? targetHeight : (ch + 1) * realPixel_H; + + + let min_x = cw * realPixel_W; + let min_y = ch * realPixel_H; + + //取左上角的像素值 + let center_p = inPixels[min_y+1][min_x+1]; + //设置该正方形里的像素统一 + for (let zh = min_y; zh < max_y; zh++) { + for (let zw = min_x; zw < max_x; zw++) { + inPixels[zh][zw] = center_p; + } + } + } + } + + + let bufferNewData = new ArrayBuffer(bitmap.getPixelBytesNumber()); + let dataNewArray = new Uint8Array(bufferNewData); + let index = 0; + let mh = 0; + let nw = 0; + + for (let i = 0; i < dataNewArray.length; i += 4) { + let pixel_1 = inPixels[mh][nw]; + + if (nw == targetWidth - 1) { + nw = 0; + mh++; + } else { + nw++; + } + + let p_r = ColorUtils.red(pixel_1); + let p_g = ColorUtils.green(pixel_1); + let p_b = ColorUtils.blue(pixel_1); + + dataNewArray[i] = p_r; + dataNewArray[i+1] = p_g; + dataNewArray[i+2] = p_b; + dataNewArray[i+3] = pixEntry[index].f; + index++; + } + await bitmap.writeBufferToPixels(bufferNewData); + if (func) { + func("success", bitmap); + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/resources/base/media/icon_failed.png b/imageknife/src/main/resources/base/media/icon_failed.png new file mode 100644 index 0000000..6eadcfd Binary files /dev/null and b/imageknife/src/main/resources/base/media/icon_failed.png differ diff --git a/imageknife/src/main/resources/base/media/icon_loading.png b/imageknife/src/main/resources/base/media/icon_loading.png new file mode 100644 index 0000000..6eb4e9a Binary files /dev/null and b/imageknife/src/main/resources/base/media/icon_loading.png differ diff --git a/imageknife/src/main/resources/base/media/icon_retry.jpg b/imageknife/src/main/resources/base/media/icon_retry.jpg new file mode 100644 index 0000000..19911b6 Binary files /dev/null and b/imageknife/src/main/resources/base/media/icon_retry.jpg differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..336d297 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1657 @@ +{ + "name": "imageknifegiteepro", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ohos/hvigor": { + "version": "1.0.6", + "resolved": "https://cmc.centralrepo.rnd.huawei.com/artifactory/api/npm/product_npm/@ohos/hvigor/-/@ohos/hvigor-1.0.6.tgz", + "integrity": "sha512-jjp7vpvUOMW1Nf7TdyhOtonwWHoSyBJLUiZTQqIx/GJV4UJyIqsiURUOqFwncQ4L7PDdeHuWly4uEelknYeWhg==", + "requires": { + "@ohos/hvigor-base": "1.0.6", + "interpret": "1.4.0", + "liftoff": "4.0.0", + "mute-stdout": "1.0.0", + "pretty-hrtime": "1.0.0", + "v8flags": "3.2.0", + "yargs": "7.1.0" + } + }, + "@ohos/hvigor-base": { + "version": "1.0.6", + "resolved": "https://cmc.centralrepo.rnd.huawei.com/artifactory/api/npm/product_npm/@ohos/hvigor-base/-/@ohos/hvigor-base-1.0.6.tgz", + "integrity": "sha512-cRDnWICTxmpNiFb9clIioqP5Oik1seLCICztXVhZqultrHuxwTheCRUZrHwlpyWdkSB2Al+FFBqmSwzIgZX4IQ==", + "requires": { + "json5": "2.2.0", + "log4js": "6.4.1", + "undertaker": "1.2.1" + } + }, + "@ohos/hvigor-ohos-plugin": { + "version": "1.0.6", + "resolved": "https://cmc.centralrepo.rnd.huawei.com/artifactory/api/npm/product_npm/@ohos/hvigor-ohos-plugin/-/@ohos/hvigor-ohos-plugin-1.0.6.tgz", + "integrity": "sha512-MAAi8uJxMzODUoSSNfBr+fU4HQ20dfQtkje9I+X4asc7qY2kAplW/q9f5XS8IOvv8zhC8OcSgsAXOAJuLMstOQ==", + "requires": { + "@ohos/hvigor-base": "1.0.6", + "@ohos/sdkmanager-common": "1.1.3", + "ajv": "8.10.0", + "archiver": "5.3.0", + "execa": "5.1.1", + "fs-extra": "10.0.0", + "glob": "7.2.0", + "iconv-lite": "0.6.3", + "json5": "2.2.0", + "lodash": "4.17.21", + "pretty-hrtime": "1.0.3", + "resolve-package-path": "4.0.3" + }, + "dependencies": { + "fs-extra": { + "version": "10.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + } + } + }, + "@ohos/sdkmanager-common": { + "version": "1.1.3", + "resolved": "https://cmc.centralrepo.rnd.huawei.com/artifactory/api/npm/product_npm/@ohos/sdkmanager-common/-/@ohos/sdkmanager-common-1.1.3.tgz", + "integrity": "sha512-d2uhVauDDJZIUvyyaWWoavG4N/jLyfF5IH5kEXKV6R8HNf3606H1zDQzA+UZtOfwwJFXhD9djRjnVFNB8xc7aw==" + }, + "ajv": { + "version": "8.10.0", + "resolved": "http://mirrors.tools.huawei.com/npm/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "archiver": { + "version": "5.3.0", + "resolved": "http://mirrors.tools.huawei.com/npm/archiver/-/archiver-5.3.0.tgz", + "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.0", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "http://mirrors.tools.huawei.com/npm/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-map": { + "version": "2.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "requires": { + "make-iterator": "^1.0.0" + } + }, + "array-each": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, + "array-initial": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "requires": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + } + }, + "array-last": { + "version": "1.3.0", + "resolved": "http://mirrors.tools.huawei.com/npm/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "requires": { + "is-number": "^4.0.0" + } + }, + "array-slice": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "async": { + "version": "3.2.3", + "resolved": "http://mirrors.tools.huawei.com/npm/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "async-done": { + "version": "1.3.2", + "resolved": "http://mirrors.tools.huawei.com/npm/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + } + }, + "async-settle": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "requires": { + "async-done": "^1.2.2" + } + }, + "bach": { + "version": "1.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "http://mirrors.tools.huawei.com/npm/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "http://mirrors.tools.huawei.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "http://mirrors.tools.huawei.com/npm/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "http://mirrors.tools.huawei.com/npm/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collection-map": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "compress-commons": { + "version": "4.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "crc-32": { + "version": "1.2.1", + "resolved": "http://mirrors.tools.huawei.com/npm/crc-32/-/crc-32-1.2.1.tgz", + "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.3.1" + } + }, + "crc32-stream": { + "version": "4.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "d": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "date-format": { + "version": "4.0.6", + "resolved": "http://mirrors.tools.huawei.com/npm/date-format/-/date-format-4.0.6.tgz", + "integrity": "sha512-B9vvg5rHuQ8cbUXE/RMWMyX2YA5TecT3jKF5fLtGNlzPlU7zblSPmAm2OImDbWL+LDOQ6pUm+4LOFz+ywS41Zw==" + }, + "debug": { + "version": "4.3.4", + "resolved": "http://mirrors.tools.huawei.com/npm/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "http://mirrors.tools.huawei.com/npm/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "http://mirrors.tools.huawei.com/npm/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "http://mirrors.tools.huawei.com/npm/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.59", + "resolved": "http://mirrors.tools.huawei.com/npm/es5-ext/-/es5-ext-0.10.59.tgz", + "integrity": "sha512-cOgyhW0tIJyQY1Kfw6Kr0viu9ZlUctVchRMZ7R0HiH3dxTSp5zJDLecwxUqPUrGKMsgBI1wd1FL+d9Jxfi4cLw==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "http://mirrors.tools.huawei.com/npm/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "ext": { + "version": "1.6.0", + "resolved": "http://mirrors.tools.huawei.com/npm/ext/-/ext-1.6.0.tgz", + "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "requires": { + "type": "^2.5.0" + }, + "dependencies": { + "type": { + "version": "2.6.0", + "resolved": "http://mirrors.tools.huawei.com/npm/type/-/type-2.6.0.tgz", + "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "http://mirrors.tools.huawei.com/npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "5.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + } + }, + "flagged-respawn": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==" + }, + "flatted": { + "version": "3.2.5", + "resolved": "http://mirrors.tools.huawei.com/npm/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "10.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "glob": { + "version": "7.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "http://mirrors.tools.huawei.com/npm/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "has": { + "version": "1.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "http://mirrors.tools.huawei.com/npm/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "human-signals": { + "version": "2.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "hypium": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/hypium/-/hypium-1.0.0.tgz", + "integrity": "sha512-nl+RQVv2AU/5FvFRhsXyWO5wh+2huhdqRZ3bszBWZzW+kpNI3AT4ydvVRYIfaQbYwV4UlX/rSc7BtFjLAezhow==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "http://mirrors.tools.huawei.com/npm/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "http://mirrors.tools.huawei.com/npm/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "http://mirrors.tools.huawei.com/npm/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "http://mirrors.tools.huawei.com/npm/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "http://mirrors.tools.huawei.com/npm/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "interpret": { + "version": "1.4.0", + "resolved": "http://mirrors.tools.huawei.com/npm/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "http://mirrors.tools.huawei.com/npm/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "http://mirrors.tools.huawei.com/npm/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "4.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "http://mirrors.tools.huawei.com/npm/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "json5": { + "version": "2.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "last-run": { + "version": "1.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazystream": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "http://mirrors.tools.huawei.com/npm/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "liftoff": { + "version": "4.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/liftoff/-/liftoff-4.0.0.tgz", + "integrity": "sha512-rMGwYF8q7g2XhG2ulBmmJgWv25qBsqRbDn5gH0+wnuyeFt7QBJlHJmtg5qEdn4pN6WVAUMgXnIxytMFRX9c1aA==", + "requires": { + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "object.map": "^1.0.1", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "http://mirrors.tools.huawei.com/npm/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "http://mirrors.tools.huawei.com/npm/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "http://mirrors.tools.huawei.com/npm/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "http://mirrors.tools.huawei.com/npm/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.union": { + "version": "4.6.0", + "resolved": "http://mirrors.tools.huawei.com/npm/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + }, + "log4js": { + "version": "6.4.1", + "resolved": "http://mirrors.tools.huawei.com/npm/log4js/-/log4js-6.4.1.tgz", + "integrity": "sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg==", + "requires": { + "date-format": "^4.0.3", + "debug": "^4.3.3", + "flatted": "^3.2.4", + "rfdc": "^1.3.0", + "streamroller": "^3.0.2" + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "http://mirrors.tools.huawei.com/npm/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "http://mirrors.tools.huawei.com/npm/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "http://mirrors.tools.huawei.com/npm/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "ms": { + "version": "2.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mute-stdout": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/mute-stdout/-/mute-stdout-1.0.0.tgz", + "integrity": "sha1-WzLqB+tDyd7WEwQ0z5JvRrKn/U0=" + }, + "next-tick": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "http://mirrors.tools.huawei.com/npm/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "now-and-later": { + "version": "2.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "requires": { + "once": "^1.3.2" + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "http://mirrors.tools.huawei.com/npm/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "http://mirrors.tools.huawei.com/npm/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "http://mirrors.tools.huawei.com/npm/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "http://mirrors.tools.huawei.com/npm/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "http://mirrors.tools.huawei.com/npm/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "http://mirrors.tools.huawei.com/npm/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "http://mirrors.tools.huawei.com/npm/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pretty-hrtime": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/pretty-hrtime/-/pretty-hrtime-1.0.0.tgz", + "integrity": "sha1-9ualItPmBwRSK/Db5oVu0g515Nw=" + }, + "printj": { + "version": "1.3.1", + "resolved": "http://mirrors.tools.huawei.com/npm/printj/-/printj-1.3.1.tgz", + "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "http://mirrors.tools.huawei.com/npm/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-glob": { + "version": "1.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/readdir-glob/-/readdir-glob-1.1.1.tgz", + "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "requires": { + "minimatch": "^3.0.4" + } + }, + "rechoir": { + "version": "0.8.0", + "resolved": "http://mirrors.tools.huawei.com/npm/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "requires": { + "resolve": "^1.20.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "resolve": { + "version": "1.22.0", + "resolved": "http://mirrors.tools.huawei.com/npm/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-package-path": { + "version": "4.0.3", + "resolved": "http://mirrors.tools.huawei.com/npm/resolve-package-path/-/resolve-package-path-4.0.3.tgz", + "integrity": "sha512-SRpNAPW4kewOaNUt8VPqhJ0UMxawMwzJD8V7m1cJfdSTK9ieZwS6K7Dabsm4bmLFM96Z5Y/UznrpG5kt1im8yA==", + "requires": { + "path-root": "^0.1.1" + } + }, + "rfdc": { + "version": "1.3.0", + "resolved": "http://mirrors.tools.huawei.com/npm/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "http://mirrors.tools.huawei.com/npm/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "http://mirrors.tools.huawei.com/npm/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "http://mirrors.tools.huawei.com/npm/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", + "resolved": "http://mirrors.tools.huawei.com/npm/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==" + }, + "streamroller": { + "version": "3.0.6", + "resolved": "http://mirrors.tools.huawei.com/npm/streamroller/-/streamroller-3.0.6.tgz", + "integrity": "sha512-Qz32plKq/MZywYyhEatxyYc8vs994Gz0Hu2MSYXXLD233UyPeIeRBZARIIGwFer4Mdb8r3Y2UqKkgyDghM6QCg==", + "requires": { + "date-format": "^4.0.6", + "debug": "^4.3.4", + "fs-extra": "^10.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://mirrors.tools.huawei.com/npm/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + }, + "dependencies": { + "is-number": { + "version": "7.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + } + } + }, + "type": { + "version": "1.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "http://mirrors.tools.huawei.com/npm/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "undertaker": { + "version": "1.2.1", + "resolved": "http://mirrors.tools.huawei.com/npm/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=" + }, + "universalify": { + "version": "2.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "http://mirrors.tools.huawei.com/npm/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "v8flags": { + "version": "3.2.0", + "resolved": "http://mirrors.tools.huawei.com/npm/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "http://mirrors.tools.huawei.com/npm/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "http://mirrors.tools.huawei.com/npm/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "http://mirrors.tools.huawei.com/npm/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "http://mirrors.tools.huawei.com/npm/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "3.2.2", + "resolved": "http://mirrors.tools.huawei.com/npm/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" + }, + "yargs": { + "version": "7.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.1", + "resolved": "http://mirrors.tools.huawei.com/npm/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "requires": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + }, + "zip-stream": { + "version": "4.1.0", + "resolved": "http://mirrors.tools.huawei.com/npm/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..282d2d2 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"imageknifegiteepro", + "ohos":{ + "org":"huawei", + "directoryLevel":"project", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{ + "@ohos/hvigor-ohos-plugin":"1.0.6", + "hypium":"^1.0.0", + "@ohos/hvigor":"1.0.6" + } +} \ No newline at end of file