ImageKnife版本v1.0.0提交

Signed-off-by: zhoulisheng1 <zhoulisheng1@huawei.com>
This commit is contained in:
zhoulisheng1 2022-03-16 21:57:35 +08:00
parent 7da838a541
commit 91d81d5210
207 changed files with 17023 additions and 63 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
/entry/.preview
.cxx
/node_modules
.idea

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@ -1,36 +0,0 @@
# ImageKnife
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

306
README.md
View File

@ -1,39 +1,291 @@
# ImageKnife # GlideJS
#### 介绍 **专门为OpenHarmony打造的一款图像加载缓存库致力于更高效、更轻便、更简单**
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
#### 软件架构 ## 简介
软件架构说明
- 支持内存缓存使用LRUCache算法对图片数据进行内存缓存
- 支持磁盘缓存,对于下载图片会保存一份至磁盘当中。
- 支持进行图片变换。
- 支持用户配置参数使用:(例如:配置是否开启第一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等)。
- 推荐使用GlideImage组件配合GlideOption参数来实现功能
- 支持用户自定义配置实现能力参考GlideImage组件中对于入参GlideOption的处理
## 目录
```
/entry/src/
- main/ets/default
- 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算法
- glide # glide主要内容
- compress # 压缩相关
- constants # 常量相关
- entry # 部分数据结构
- holder # 占位图相关解析
- interface # 接口相关
- networkmanage # 网络相关
- pngj # pngj相关
- requestmanage # Glide请求相关
- resourcemanage # 本地资源解析相关
- transform # 图片变换相关
- utils # 工具类相关
- Glide.ets # Glide门面app持久化类
- GlideData.ets # 数据封装
- GlideImage.ets # 自定义控件封装
- GlideOption.ets # 用户传参数封装
- PixelMapPack.ets # PixelMap封装
- RequestOption.ets # 用户设置参数封装
- pages # 测试page页面列表
- basicTestFeatureAbilityPage.ets # 测试元能力
- basicTestFileIOPage.ets # 测试fileio
- basicTestMediaImage.ets # 测试媒体image
- basicTestResourceManagerPage.ets # 测试本地资源解析
- CompressPage.ets # 压缩页面
- frescoImageTestCasePage.ets # 测试属性动画组件切换
- frescoLayerTestCasePage.ets # 测试GlideImage组件切换配合属性动画
- frescoRetryTestCasePage.ets # 测试GlideImage加载失败重试
- index.ets # 测试页面入口
- indexFresco.ets # 二级测试页面入口
- loadNetworkTestCasePage.ets # 网络加载测试
- loadResourceTestCasePage.ets # 本地加载测试
- showErrorholderTestCasePage.ets # 加载失败占位图测试
- storageTestDiskLruCache.ets # 磁盘缓存测试
- storageTestLruCache.ets # 内存缓存测试
- testAllCacheInfoPage.ets # 所有缓存信息获取测试
- testAllTypeGlideImagePage.ets # 所有类型图片加载测试
- testAllTypeNativeImagePage.ets # 所有类型本地图片加载测试
- testGifDontAnimatePage.ets # gif加载静态图片测试
- testGlideOptionChangedPage.ets # GlideOption数据切换测试
- testGlideOptionChangedPage2.ets # GlideOption数据切换测试
- testMultiThreadWorkerPage2.ets # 多线程测试
- testPlaceholderPage.ets # 加载占位图测试
- testPreloadPage.ets # 预加载测试
- testResourceManagerPage.ets # 解析本地资源测试
- TransformPixelMapPage.ets # 所有类型变换测试
- transformTestCasePage.ets # 所有类型变换配合GlideImage测试
- 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<PixelMap>) | src: PixelMap \| Resource, func?: AsyncSuccess<PixelMap> | 配置占位图其中func为数据回调函数 |
| errorholder(src: PixelMap \| Resource, func?: AsyncSuccess<PixelMap>) | src: PixelMap \| Resource, func?: AsyncSuccess<PixelMap> | 配置加载失败占位图其中func为数据回调函数 |
| addListener(func: AsyncCallback<PixelMap>) | func: AsyncCallback<PixelMap> | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 |
| thumbnail(sizeMultiplier:number, func?: AsyncSuccess<GlideData>) | sizeMultiplier:number, func?: AsyncSuccess<GlideData> | 设置缩略图比例,缩略图返回后,加载并展示缩略图 |
| addProgressListener(func?: AsyncSuccess<string>){ this.progressFunc = func; return this; } | func?: AsyncSuccess<string> | 设置网络下载百分比监听,返回数据加载百分比数值 |
| addRetryListener(func?: AsyncSuccess<any>){ this.retryFunc = func; return this; } | func?: AsyncSuccess<any> | 设置重试监听 |
| addAllCacheInfoCallback(func: IAllCacheInfoCallback) | func: IAllCacheInfoCallback | 设置获取所有缓存信息监听 |
| skipMemoryCache(skip: boolean) | skip: boolean | 配置是否跳过内存缓存 |
| retrieveDataFromCache(flag: boolean) | flag: boolean | 配置仅从缓存中加载数据 |
| transform(transform: BaseTransform<PixelMap>) | transform: BaseTransform<PixelMap> | 配置自定义变换类型 |
| centerCrop(fd: number, out_width: number, out_height: number, callback?: AsyncTransform<Promise<PixelMap>>) | fd: number, out_width: number, out_height: number, callback?: AsyncTransform<Promise<PixelMap>> | 静态方法可以根据图片文件目标显示大小进行对应centerCrop |
| rotateImage(fd: number, degreesToRotate: number) | fd: number, degreesToRotate: number | 静态方法可以根据图片文件和旋转角度进行对应rotateImaroge |
| centerInside(fd: number, out_width: number, out_height: number, callback?: AsyncTransform<Promise<PixelMap>>) | fd: number, out_width: number, out_height: number, callback?: AsyncTransform<Promise<PixelMap>> | 静态方法可以根据图片文件目标显示大小进行对应centerInside |
| fitCenter(fd: number, out_width: number, out_height: number , callback?: AsyncTransform<Promise<PixelMap>>) | fd: number, out_width: number, out_height: number , callback?: AsyncTransform<Promise<PixelMap>> | 静态方法可以根据图片文件目标显示大小进行对应fitCenter |
### Glide 启动器/门面类
| 方法名 | 入参 | 接口描述 |
| ------------------------------- | ---------------------- | ---------------------------------- |
| 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.transforms(new BlurTransformation()) | BlurTransformation | 模糊处理 |
| request.transforms(new BrightnessFilterTransformation()) | BrightnessFilterTransformation | 亮度滤波器 |
| request.transforms(new ContrastFilterTransformation()) | ContrastFilterTransformation | 对比度滤波器 |
| request.transforms(new CropCircleTransformation()) | CropCircleTransformation | 圆形剪裁显示 |
| request.transforms(new CropCircleWithBorderTransformation()) | CropCircleWithBorderTransformation | 圆环展示 |
| request.transforms(new CropSquareTransformation()) | CropSquareTransformation | 正方形剪裁 |
| request.transforms(new CropTransformation()) | CropTransformation | 自定义矩形剪裁 |
| request.transforms(new GrayscaleTransformation()) | GrayscaleTransformation | 灰度级转换 |
| request.transforms(new InvertFilterTransformation()) | InvertFilterTransformation | 反转滤波器 |
| request.transforms(new PixelationFilterTransformation()) | PixelationFilterTransformation | 像素化滤波器 |
| request.transforms(new RotateImageTransformation()) | RotateImageTransformation | 图片旋转 |
| request.transforms(new RoundedCornersTransformation()) | RoundedCornersTransformation | 圆角剪裁 |
| request.transforms(new SepiaFilterTransformation()) | SepiaFilterTransformation | 乌墨色滤波器 |
| request.transforms(new SketchFilterTransformation()) | SketchFilterTransformation | 素描滤波器 |
#### 安装教程
1. xxxx ## 代码示例
2. xxxx
3. xxxx
#### 使用说明 1.首先初始化全局Glide实例在app.ets中调用Glide.with()进行初始化
1. xxxx ```
2. xxxx import {Glide} from './glide/Glide.ets'
3. xxxx export default {
data: {
glide: {} // Glide全局占位符
},
onCreate() {
this.data.glide = Glide.with();// Glide占位符全局初始化赋值
}
}
```
#### 参与贡献 2.在页面index.ets中使用Glide
1. Fork 本仓库 ```
2. 新建 Feat_xxx 分支 @Entry
3. 提交代码 @Component
4. 新建 Pull Request struct Index {
build() {
}
// 页面初始化完成,生命周期回调函数中 进行调用Glide
aboutToAppear() {
let requestOption = new RequestOption();
requestOptin.load($r('app.media.IceCream'))
.addListener((err,data) => {
//加载成功/失败回调监听
})
...
Glide.call(requestOption)
}
}
var Glide;
var defaultTemp = globalThis.exports.default
if (defaultTemp != undefined) {
Glide = defaultTemp.data.glide;
}
```
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md #### 推荐使用:
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 使用GlideOption作为入参配合自定义组件GlideImage使用。
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) ```typescript
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) @Entry
@Component
struct Index {
@State glideOption1: GlideOption =
{
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'),
};
build() {
Scroll() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
GlideImage({ glideOption: $glideOption1 })
}
}
.width('100%')
.height('100%')
}
}
```
#### 自定义实现:
使用原生Image组件配合用户配置参数实现。
##### 步骤1
定义一个入参 PixelMap
```typescript
@State tomatoPixelMap:PixelMap = new PixelMap();
width:number = 200;
height:number = 200;
```
##### 步骤2
在你的component组件中写下一个Image组件将基础参数入参PixelMap组件的宽、高配置好
```
Image(this.tomatoPixelMap)
.backgroundColor(Color.Grey)
.objectFit(ImageFit.Contain)
.width(this.width)
.height(this.height)
```
##### 步骤3
在aboutToAppear() 函数中调用加载流程
```typescript
//配置参数
let requestOptin = new RequestOption();
//加载本地图片
requestOptin.load($r('app.media.IceCream'))
.addListener((err,data) => {
//加载成功/失败回调监听
})
.placeholder( $r('app.media.icon_loading'), (data)=>{
// 占位图回调监听
})
.errorholder(this.glideOption.errorholderSrc, (data)=>{
// 失败占位图回调监听
})
.thumbnail(this.glideOption.thumbSizeMultiplier, (data) => {
// 缩略图加载成功回调
})
// 一定要把控件大小传给RequestOption,图片变换必须
.setImageViewSize({width:this.width, height:this.height})
// 设置缓存策略
.diskCacheStrategy(new Strategy())
.addProgressListener((percentValue: string) => {
// 图片网络加载进度条百分比回调
})
.addRetryListener((error: any) => {
// 加载失败重试监听 图片加载失败时优先展示重试图层,点击重试图层,会重新进行一次加载流程
})
.transforms(new RoundedCornersTransformation({top:10}))
// 启动加载流程,执行结果将会返回到上面的回调接口中
Glide.call(requestOptin);
```
##### 步骤4
更多细节设置请参考自定义Component的GlideImage实现
## 演示
<img src="screenshot/g3.gif" width="50%"/>
<img src="screenshot/g1.gif" width="50%"/><img src="screenshot/g2.gif" width="50%"/>

35
build.gradle Normal file
View File

@ -0,0 +1,35 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply plugin: 'com.huawei.ohos.app'
//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510
ohos {
compileSdkVersion 8
supportSystem "standard"
}
buildscript {
repositories {
maven {
url 'https://repo.huaweicloud.com/repository/maven/'
}
maven {
url 'https://developer.huawei.com/repo/'
}
}
dependencies {
classpath 'com.huawei.ohos:hap:3.0.5.2'
classpath 'com.huawei.ohos:decctest:1.2.7.2'
}
}
allprojects {
repositories {
maven {
url 'https://repo.huaweicloud.com/repository/maven/'
}
maven {
url 'https://developer.huawei.com/repo/'
}
}
}

2
entry/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build
/node_modules

21
entry/build.gradle Normal file
View File

@ -0,0 +1,21 @@
apply plugin: 'com.huawei.ohos.hap'
//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510
ohos {
compileSdkVersion 8
defaultConfig {
compatibleSdkVersion 8
}
buildTypes {
release {
proguardOpt {
proguardEnabled false
rulesFiles 'proguard-rules.pro'
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
testImplementation 'junit:junit:4.13.1'
}

1
entry/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1 @@
# config module specific ProGuard rules here.

144
entry/src/main/config.json Normal file
View File

@ -0,0 +1,144 @@
{
"app": {
"bundleName": "com.huawei.mydemoall",
"vendor": "huawei",
"version": {
"code": 1000000,
"name": "1.0.0"
}
},
"deviceConfig": {
"default": {
"network": {
"cleartextTraffic": true
}
}
},
"module": {
"package": "com.bumptech.glidejs_ohos",
"name": ".MyApplication",
"mainAbility": ".MainAbility",
"srcPath": "",
"deviceType": [
"phone",
"tablet",
"default"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "entry",
"moduleType": "entry",
"installationFree": false
},
"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:mainability_description",
"formsEnabled": false,
"label": "$string:GlideJS_OHOS",
"type": "page",
"launchType": "standard"
}
],
"reqPermissions": [
{
"name": "ohos.permission.READ_USER_STORAGE"
},
{
"name": "ohos.permission.INTERNET",
"reason": "Api call",
"usedScene": {
"ability": [
"com.zls.glidejscache.MainAbility"
],
"when": "always"
}
},
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
},
{
"name": "ohos.permission.READ_MEDIA",
"reason": "location background",
"usedScene": {
"when": "always",
"ability": [
"com.zls.glidejscache.MainAbility"
]
}
},
{
"name": "ohos.permission.WRITE_MEDIA",
"reason": "location background",
"usedScene": {
"when": "always",
"ability": [
"com.zls.glidejscache.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/testMemoryCachePage",
"pages/transformTestCasePage",
"pages/pngjTestCasePage",
"pages/testAllTypeGlideImagePage",
"pages/testAllTypeNativeImagePage",
"pages/loadResourceTestCasePage",
"pages/loadNetworkTestCasePage",
"pages/showErrorholderTestCasePage",
"pages/TransformPixelMapPage",
"pages/testGifDontAnimatePage",
"pages/testPreloadPage",
"pages/testGlideOptionChangedPage",
"pages/testGlideOptionChangedPage2",
"pages/CompressPage",
"pages/testAllCacheInfoPage",
"pages/testResourceManagerPage",
"pages/testMultiThreadWorkerPage2",
"pages/testGlideOptionChangedPage",
"pages/CropImagePage",
"pages/networkTestCasePage",
"pages/jpegProgressTestCasePage"
],
"name": ".MainAbility",
"window": {
"designWidth": 720,
"autoDesignWidth": false
}
}
]
}
}

View File

@ -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 app from '@system.app';
import {Glide} from './glide/Glide.ets'
export default {
data: {
glide: {} // Glide
},
onCreate() {
this.data.glide = Glide.with();
app.setImageCacheCount(100);
app.setImageRawDataCacheSize(104857600)
app.setImageFileCacheSize(209715200)
},
onDestroy() {
},
}

View File

@ -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;
}
}

View File

@ -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 <K, V> {
map: Map<K, V> = new Map<K, V>()
// 获取键对应的值
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<K>{
return this.map.keys()
}
}

View File

@ -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
}
}

View File

@ -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.ets'
export class DiskLruCache {
// 缓存数据集合
cacheMap: CustomMap<string, DiskCacheEntry> = new CustomMap<string, DiskCacheEntry>()
fileUtils: FileUtils = FileUtils.getInstance()
diskCacheFolder: string = 'GlideDiskCache'
// 缓存文件路劲地址
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)
}
}

View File

@ -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()
}
}

View File

@ -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<T> {
(err: string, data: T): void;
}

View File

@ -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 <K, V> {
maxsize: number = 0
size: number = 0;
map: CustomMap<K, V> = new CustomMap<K, V>();
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);
}
}

View File

@ -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);
}
}

View File

@ -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,
}

View File

@ -0,0 +1,53 @@
/*
* 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 {
/**
* Returns true if this request should cache the original unmodified data.
*
* @param dataSource Indicates where the data was originally retrieved.
* @return boolean
*/
isDataCacheable(dataSource: DataSrc): boolean
/**
* Returns true if this request should cache the final transformed resource.
*
* @param isFromAlternateCacheKey {@code true} if the resource we've decoded was loaded using an
* alternative, rather than the primary, cache key.
* @param dataSource Indicates where the data used to decode the resource was originally
* retrieved.
* @param encodeStrategy The {@link EncodeStrategy} the {@link
* com.bumptech.glide.load.ResourceEncoder} will use to encode the resource.
* @return boolean
*/
isResourceCacheable(isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean;
/** Returns true if this request should attempt to decode cached resource data.
* @return boolean
*/
decodeCachedResource(): boolean;
/** Returns true if this request should attempt to decode cached source data.
* @return boolean
*/
decodeCachedData(): boolean;
getName(): string;
}

View File

@ -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,
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 {Key} from "../key/Key"
import {RequestOption} from '../../glide/RequestOption.ets'
export class EngineKey implements Key {
private request: RequestOption;
constructor(
request
) {
this.request = request;
}
// 内存缓存 缓存生成规则:是否会影响图片内容,不影响则通用(strategy onlyRetrieveFromCache isCacheable)为通用项目
// 生成规则 加载数据原 各类参数(排除监听 排除 占位图 失败占位图)
generateCacheKey(): string{
let loadSrc = JSON.stringify(this.request.loadSrc);
let size = JSON.stringify(this.request.size);
let transformations;
for (let i = 0; i < this.request.transformtions.length; i++) {
if (i == 0) {
transformations = this.request.transformtions[i].getName() + ",";
} else if (i == this.request.transformtions.length - 1) {
transformations += this.request.transformtions[i].getName() + "";
} else {
transformations += this.request.transformtions[i].getName() + ",";
}
}
let dontAnimateFlag = JSON.stringify(this.request.dontAnimateFlag);
let key = "loadSrc=" + loadSrc + ";" +
"size=" + size + ";" +
"transformations=" + transformations + ";" +
"dontAnimateFlag=" + dontAnimateFlag + ";"
return key;
}
// 磁盘缓存 缓存生成规则:是否会影响图片内容,不影响则通用(strategy onlyRetrieveFromCache isCacheable)为通用项目
// 生成规则 加载数据原 各类参数(排除监听 排除 占位图 失败占位图)
generateResourceKey(): string{
let loadSrc = JSON.stringify(this.request.loadSrc);
let size = JSON.stringify(this.request.size);
let transformations;
for (let i = 0; i < this.request.transformtions.length; i++) {
if (i == this.request.transformtions.length - 1) {
transformations += this.request.transformtions[i].getName() + "";
} else {
transformations += this.request.transformtions[i].getName() + ",";
}
}
let dontAnimateFlag = JSON.stringify(this.request.dontAnimateFlag);
let key = "loadSrc=" + loadSrc + ";" +
"size=" + size + ";" +
"transformations=" + transformations + ";" +
"dontAnimateFlag=" + dontAnimateFlag + ";"
return key;
}
// 磁盘缓存
// 生成网络加载数据 原始数据存于磁盘的key
generateDataKey(): string{
let loadSrc = JSON.stringify(this.request.loadSrc);
let key = "loadSrc=" + loadSrc + ";"
return key;
}
updateDiskCacheKey(info: Object) {
}
}

View File

@ -0,0 +1,38 @@
/*
* 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()
}
}

View File

@ -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.
*
* <p>Note - Using {@link MessageDigest#reset()} inside of this method will result
* in undefined behavior.
* @param messageDigest
*/
updateDiskCacheKey(info: Object);
}

View File

@ -0,0 +1,407 @@
/*
* 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 {EngineKey} from "../cache/key/EngineKey"
import {EngineKeyFactories} from "../cache/key/EngineKeyFactories"
import {DiskStrategy} from "../cache/diskstrategy/DiskStrategy"
import {ResourceTypeEts} from "../glide/constants/ResourceTypeEts.ets"
import {RequestOption} from "../glide/RequestOption.ets"
import {AsyncCallback} from "../glide/interface/asynccallback.ets"
import {PlaceHolderManager} from "../glide/holder/PlaceHolderManager.ets"
import {ErrorHolderManager} from "../glide/holder/ErrorHolderManager.ets"
import {RequestManager} from "../glide/requestmanage/RequstManager.ets"
import {NONE} from "../cache/diskstrategy/enum/NONE"
import {FileTypeUtil} from '../glide/utils/FileTypeUtil.ets'
import {DownloadClient} from '../glide/networkmanage/DownloadClient.ets'
import {IDataFetch} from '../glide/networkmanage/IDataFetch.ets'
import {ParseResClient} from '../glide/resourcemanage/ParseResClient.ets'
import {IResourceFetch} from '../glide/resourcemanage/IResourceFetch.ets'
import {GlideData} from '../glide/GlideData.ets'
import {FileUtils} from '../cache/FileUtils.ets'
import {FileReader} from '../cache/FileReader.ets'
import {GlideOption} from '../glide/GlideOption.ets'
import image from "@ohos.multimedia.image"
import featureAbility from '@ohos.ability.featureAbility';
import {CompressBuilder} from "../glide/compress/CompressBuilder.ets"
export class Glide {
private memoryCache: LruCache<string, any>;
private diskMemoryCache: DiskLruCache;
private dataFetch: IDataFetch;
private resourceFetch: IResourceFetch;
private filesPath: string = ""; // data/data/包名/files目录
private placeholderCache: string = "placeholderCache"
private runningRequest: Array<RequestOption>;
private pendingRequest: Array<RequestOption>;
private fileTypeUtil: FileTypeUtil; // 通用文件格式辨别
private svgAndGifFolder: string = "svgAndGifFolder"; // svg和gif的文件路径地址
private svgAndGifCommitFile: string = "svgAndGifCommitFile" // svg和gif提交记录
private defaultListener:AsyncCallback<GlideData>; // 全局监听器
getMemoryCache(): LruCache<string, any>{
return this.memoryCache;
}
setMemoryCache(lrucache: LruCache<string, any>){
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<GlideData>){
this.defaultListener = newDefaultListener;
}
private constructor() {
// 构造方法传入size 为保存文件个数
this.memoryCache = new LruCache<string, any>(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('Glide 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: Glide;
public static with(): Glide{
if (!this.sInstance) {
this.sInstance = new Glide();
}
return this.sInstance;
}
public compressBuilder(): CompressBuilder{
return new CompressBuilder();
}
// 替代原来的LruCache
public replaceLruCache(size:number){
if(this.memoryCache.map.size() <= 0) {
this.memoryCache = new LruCache<string, any>(size);
}else{
let newLruCache = new LruCache<string, any>(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("Glide 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("Glide loadResources")
let factories = new EngineKeyFactories();
// 生成内存缓存key 内存 变换后磁盘
let cacheKey = factories.buildCacheKey(request);
// 生成磁盘缓存变换后数据key 变换后数据保存在磁盘
let transfromKey = factories.buildResourceKey(request);
// 生成磁盘缓存源数据key 原始数据保存在磁盘
let dataKey = factories.buildDataKey(request);
request.generateCacheKey = cacheKey;
request.generateResourceKey = transfromKey;
request.generateDataKey = dataKey;
this.loadCacheManager(request);
}
// 删除执行结束的running
removeRunning(request: RequestOption) {
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.loadNextPennding(request);
}
}
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的请求
loadNextPennding(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("Glide loadCacheManager")
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);
} else {
this.runningRequest.push(request);
// 不存在相同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("Glide parseSource")
console.log("Glide request ="+JSON.stringify(request))
if (request.loadSrc instanceof image.PixelMap) {
console.log("Glide parseSource PixelMap")
let glidedata = new GlideData();
glidedata.glideType = GlideData.PIXELMAP
glidedata.glideValue = request.loadSrc as PixelMap
request.loadComplete(glidedata);
} else
if (typeof request.loadSrc == 'string') {
// 进入三级缓存模型
console.log("Glide parseSource string")
return this.loadResources(request);
} else {
console.log("Glide parseSource Resource")
let res = request.loadSrc as Resource;
console.log("Glide 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("输入参数有问题!")
}
}
}
}

View File

@ -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 GlideData {
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';
glideType:string = '';
glideValue:PixelMap|string|Resource;
glideSourceType:string = ''
isSvg():boolean{
return GlideData.SVG == this.glideSourceType;
}
isGif():boolean{
return GlideData.GIF == this.glideSourceType;
}
isJpg():boolean{
return GlideData.JPG == this.glideSourceType;
}
isPng():boolean{
return GlideData.PNG == this.glideSourceType;
}
isBmp():boolean{
return GlideData.BMP == this.glideSourceType;
}
isWebp():boolean{
return GlideData.WEBP == this.glideSourceType;
}
isString():boolean{
return GlideData.STRING == this.glideType;
}
isPixelMap():boolean{
return GlideData.PIXELMAP == this.glideType;
}
isResource():boolean{
return GlideData.RESOURCE == this.glideType;
}
can2PixelMap(){ // 可以转换为PixelMap的数据源
return this.isPixelMap() || this.isBmp() || this.isJpg() || this.isWebp() || this.isPng();
}
}

View File

@ -0,0 +1,303 @@
/*
* 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 {GlideOption} from '../glide/GlideOption.ets'
import {RequestOption} from '../glide/RequestOption.ets'
import {GlideData} from '../glide/GlideData.ets'
import {PixelMapPack} from '../glide/PixelMapPack.ets'
import {Base64} from '../cache/Base64.ets'
import resourceManager from '@ohos.resourceManager';
import image from '@ohos.multimedia.image';
@Component
export struct GlideImage {
@Watch('watchGlideOption') @Link glideOption: GlideOption;
@State glidePixelMapPack: PixelMapPack = new PixelMapPack();
@State glideResource: Resource = $r('app.media.icon_loading')
@State glideString: string = ''
@State normalPixelMap: boolean = true;
@State normalResource: boolean = true;
previousData: GlideData = null;
nowData: GlideData = 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.glideOption.size ? Math.min(this.glideOption.size.height, this.glideOption.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.glidePixelMapPack.pixelMap : (this.normalResource ? this.glideResource : this.glideString))
.objectFit(this.glideOption.imageFit ? this.glideOption.imageFit : ImageFit.Fill)
.visibility(this.imageVisible)
.width(this.imageWidth)
.height(this.imageHeight)
}
.width(this.glideOption.size ? this.glideOption.size.width : '100%')
.height(this.glideOption.size ? this.glideOption.size.height : '100%')
.backgroundColor(this.glideOption.backgroundColor ? this.glideOption.backgroundColor : Color.White)
.margin(this.glideOption.margin ? this.glideOption.margin : { left: 0, top: 0, right: 0, bottom: 0 })
}
watchGlideOption() {
this.glideExecute();
}
retryClick(){
this.hasRetry = true;
this.glideExecute();
}
aboutToAppear() {
console.log('glideImage aboutToAppear happened!')
this.glideExecute();
}
configNecessary(request: RequestOption){
// 为了测试重试加载 串讲完成后删除
if(this.glideOption.loadSrc == 'https://hbimg.huabanimg.com/testRetryxxxx' && this.hasRetry){
request.load('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp')
.addListener((err, data) => {
this.glideChangeSource(data)
this.animateTo('image');
return false;
})
}else {
request.load(this.glideOption.loadSrc)
.addListener((err, data) => {
this.glideChangeSource(data)
this.animateTo('image');
return false;
})
}
if (this.glideOption.size) {
request.setImageViewSize(this.glideOption.size)
}
}
configCacheStrategy(request: RequestOption){
if (this.glideOption.onlyRetrieveFromCache) {
request.retrieveDataFromCache(this.glideOption.onlyRetrieveFromCache)
}
if (this.glideOption.isCacheable) {
request.skipMemoryCache(!this.glideOption.isCacheable)
}
if (this.glideOption.strategy) {
request.diskCacheStrategy(this.glideOption.strategy)
}
if (this.glideOption.allCacheInfoCallback) {
request.addAllCacheInfoCallback(this.glideOption.allCacheInfoCallback)
}
}
configDisplay(request: RequestOption){
if(this.glideOption.animateDuration >= 0){
request.animateDuraction = this.glideOption.animateDuration;
}
if (this.glideOption.placeholderSrc) {
request.placeholder(this.glideOption.placeholderSrc, (data) => {
this.glideChangeSource(data)
this.animateTo('image');
})
}
if (this.glideOption.thumbSizeMultiplier) {
request.thumbnail(this.glideOption.thumbSizeMultiplier, (data) => {
this.glideChangeSource(data)
this.animateTo('image');
})
}
if (this.glideOption.errorholderSrc) {
request.errorholder(this.glideOption.errorholderSrc, (data) => {
this.glideChangeSource(data)
this.animateTo('image');
})
}
if (this.glideOption.transformtions) {
request.transforms(this.glideOption.transformtions)
}
if (this.glideOption.dontAnimateFlag) {
request.dontAnimate()
}
if (this.glideOption.displayProgress) {
request.addProgressListener((percentValue: string) => {
// 如果进度条百分比 未展示大小,展示其动画
this.percent = percentValue;
if(this.glideOption.displayProgressListener){
this.glideOption.displayProgressListener(percentValue);
}
this.animateTo('progress');
})
}
if(this.glideOption.retryLoad){
request.addRetryListener((error: any) => {
console.log("RetryListener callback!")
this.animateTo('retry');
})
}
}
// glide 第一次启动和数据刷新后重新发送请求
glideExecute() {
let request = new RequestOption();
this.configNecessary(request);
this.configCacheStrategy(request);
this.configDisplay(request);
let svgGif = Glide.getSvgAndGifFolder();
console.log("输出SVG和gif的缓存地址="+svgGif)
console.log("GlideImage Ready to 'call' method! Glide is null="+(Glide == null || Glide == undefined))
Glide.call(request);
}
glideChangeSource(data:GlideData) {
this.glideSpecialFixed(data);
}
displayPixelMap(data:GlideData){
this.normalPixelMap = true;
this.normalResource = true;
let pack = new PixelMapPack();
this.glidePixelMapPack = pack;
setTimeout(() => {
let pixelMapPack2 = new PixelMapPack();
pixelMapPack2.pixelMap = data.glideValue as PixelMap;
this.glidePixelMapPack = pixelMapPack2;
},100)
}
displayResource(data:GlideData){
this.normalPixelMap = false;
this.normalResource = true;
this.glideResource = data.glideValue as Resource;
}
displayString(data:GlideData){
this.normalPixelMap = false;
this.normalResource = false;
let firstIndex = (data.glideValue as string).indexOf(Glide.getSvgAndGifFolder());
let suffix = (data.glideValue as string).substring(firstIndex, (data.glideValue as string).length)
// let glideNeedStr = 'internal://app/' + suffix;
let glideNeedStr = 'file://' + data.glideValue;
this.glideString = glideNeedStr;
}
glideSpecialFixed(data:GlideData) {
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.glideOption.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.glideOption.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.glideOption.animateDuration, curve: Curve.Linear }, () => {
this.imageWidth = '0%';
this.imageHeight = '0%';
this.percentWidth = '0%';
this.percentHeight = '0%';
this.retryWidth = '100%';
this.retryHeight = '100%';
})
}
}
}
aboutToDisappear() {
}
onPageShow() {
}
onPageHide() {
}
onBackPress() {
}
}
var Glide;
var defaultTemp = globalThis.exports.default
if (defaultTemp != undefined) {
Glide = defaultTemp.data.glide;
}

View File

@ -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 {AUTOMATIC} from "../cache/diskstrategy/enum/AUTOMATIC.ets"
import {DiskStrategy} from "../cache/diskstrategy/DiskStrategy.ets"
import {BaseTransform} from "../glide/transform/BaseTransform.ets"
import {AllCacheInfo, IAllCacheInfoCallback} from "../glide/interface/iallcacheinfocallback.ets"
export class GlideOption {
// 主图资源
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;
// 变换相关
transformtions?: Array<BaseTransform<PixelMap>> = new Array();
// 输出缓存相关内容和信息
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() {
}
}

View File

@ -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
}

View File

@ -0,0 +1,294 @@
/*
* 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 "../glide/interface/asynccallback.ets"
import {AsyncSuccess} from "../glide/interface/AsyncSuccess.ets"
import {AllCacheInfo, IAllCacheInfoCallback} from "../glide/interface/iallcacheinfocallback.ets"
import {AUTOMATIC} from "../cache/diskstrategy/enum/AUTOMATIC"
import {BaseTransform} from "../glide/transform/BaseTransform.ets"
import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets"
import {GlideData} from "../glide/GlideData.ets"
import fileio from '@ohos.fileio';
import image from '@ohos.multimedia.image';
import {CenterCrop} from '../glide/transform/pixelmap/CenterCrop.ets'
import {CenterInside} from '../glide/transform/pixelmap/CenterInside.ets'
import {FitCenter} from '../glide/transform/pixelmap/FitCenter.ets'
export class RequestOption {
loadSrc: string | PixelMap | Resource;
strategy: DiskStrategy = new AUTOMATIC();
dontAnimateFlag = false;
placeholderSrc: PixelMap | Resource;
placeholderFunc: AsyncSuccess<GlideData>;
errorholderSrc: PixelMap | Resource;
errorholderFunc: AsyncSuccess<GlideData>;
errorholderData: GlideData;
thumbSizeMultiplier: number;
// 如果存在缩略图则主图延时3000ms加载
thumbDelayTime: number = 3000
thumbholderFunc: AsyncSuccess<GlideData>;
requestListeners: Array<AsyncCallback<GlideData>>;
// 进度条
progressFunc: AsyncSuccess<string>;
// 重试图层
retryFunc: AsyncSuccess<GlideData>
// 图层切换时长
animateDuraction: number = 500;
size: {
width: number,
height: number
} = { width: -1, height: -1 };
// 网络下载数据回调
allCacheInfoCallback: IAllCacheInfoCallback;
onlyRetrieveFromCache: boolean = false;
isCacheable: boolean = true;
// 变换相关
transformtions: Array<BaseTransform<PixelMap>> = new Array();
generateCacheKey: string = "";
generateResourceKey: string = "";
generateDataKey: string = "";
private filesPath: string = ""; // data/data/包名/files目录
private cachesPath: string = ""; // 网络下载默认存储在data/data/包名/cache/GlideNetworkFolder/目标md5.img下面
// 下载原始文件地址
downloadFilePath: string = "";
// 网络文件下载统一存放
networkCacheFolder: string = "GlideNetworkFolder"
// 主线图片 状态变化 是否加载完成
// 主图未加载成功 显示占位图 主图加载成功不展示占位图
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<GlideData>) {
this.placeholderSrc = src;
this.placeholderFunc = func;
return this;
}
errorholder(src: PixelMap | Resource, func?: AsyncSuccess<GlideData>) {
this.errorholderSrc = src;
this.errorholderFunc = func;
return this;
}
thumbnail(sizeMultiplier: number, func?: AsyncSuccess<GlideData>) {
this.thumbSizeMultiplier = sizeMultiplier;
this.thumbholderFunc = func;
return this;
}
addProgressListener(func?: AsyncSuccess<string>) {
this.progressFunc = func;
return this;
}
addRetryListener(func?: AsyncSuccess<any>) {
this.retryFunc = func;
return this;
}
addListener(func: AsyncCallback<GlideData>) {
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.transformtions.push(rotateImage);
return this;
}
centerCrop() {
this.transformtions.push(new CenterCrop());
return this;
}
centerInside() {
this.transformtions.push(new CenterInside());
return this;
}
fitCenter() {
this.transformtions.push(new FitCenter());
return this;
}
transform(transform: BaseTransform<PixelMap>) {
this.transformtions.push(transform);
return this;
}
transforms(transforms: BaseTransform<PixelMap>[]) {
this.transformtions = transforms;
return this;
}
// 占位图解析成功
placeholderOnComplete(glidedata: GlideData) {
console.log("placeholderOnComplete has called!");
console.log("Main Image is Ready:" + this.loadMainReady);
if (!this.loadMainReady && !this.loadErrorReady && !this.loadThumbnailReady) {
// 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
this.placeholderFunc(glidedata)
}
}
// 占位图解析失败
placeholderOnError(error) {
console.log("占位图解析失败 error =" + error)
}
// 缩略图解析成功
thumbholderOnComplete(glidedata: GlideData) {
if (!this.loadMainReady && !this.loadErrorReady) {
//主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
this.thumbholderFunc(glidedata)
}
}
// 缩略图解析失败
thumbholderOnError(error) {
console.log("缩略图解析失败 error =" + error)
}
// 加载失败 占位图解析成功
errorholderOnComplete(glidedata: GlideData) {
// 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用
this.errorholderData = glidedata;
if (this.loadErrorReady) {
this.errorholderFunc(glidedata)
}
}
//加载失败 占位图解析失败
errorholderOnError(error) {
console.log("失败占位图解析失败 error =" + error)
}
loadComplete(glidedata: GlideData) {
this.loadMainReady = true;
// 三级缓存数据加载成功
for (let requestListener of this.requestListeners) {
var ret = requestListener("", glidedata);
if (ret) {
break;
}
}
// 加载成功之后
Glide.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)
}
}
// 加载失败之后
Glide.removeRunning(this);
}
}
var Glide;
var defaultTemp = globalThis.exports.default
if (defaultTemp != undefined) {
Glide = defaultTemp.data.glide;
}

View File

@ -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.ets'
import {OnCompressListener} from '../compress/listener/OnCompressListener.ets'
import {CompressionPredicate} from '../compress/listener/CompressionPredicate.ets'
import fileio from '@ohos.fileio';
import {CompressAdapter} from '../compress/provider/CompressAdapter.ets'
import {DataStringPathProvider} from '../compress/provider/DataStringPathProvider.ets'
import {RecourseProvider} from '../compress/provider/RecourseProvider.ets'
import featureability from '@ohos.ability.featureAbility'
import {Engine} from '../compress/Engine.ets'
export class CompressBuilder {
private _mTargetDir: string;
private _mLeastCompressSize: number= 100; //KB
private _mRenameListener: OnRenameListener;
private _mCompressListener: OnCompressListener;
private _mCompressionPredicate: CompressionPredicate
private _mStreamProviders: Array<CompressAdapter>;
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<string | Resource>): 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<string> {
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<string> {
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));
})
}
}

View File

@ -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.ets'
import {CompressionPredicate} from '../compress/listener/CompressionPredicate.ets'
import {CompressAdapter} from "../compress/provider/CompressAdapter.ets"
import {DataStringPathProvider} from '../compress/provider/DataStringPathProvider.ets'
import {RecourseProvider} from '../compress/provider/RecourseProvider.ets'
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);
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);
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, (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);
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;
}
}

View File

@ -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: T);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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.ets"
import {CompressDataListener} from "../listener/CompressDataListener.ets"
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<ArrayBuffer>);
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
}

View File

@ -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;
}

View File

@ -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.ets'
import {CompressDataListener} from '../listener/CompressDataListener.ets'
import {FileUtils} from '../../../cache/FileUtils.ets'
export class DataStringPathProvider extends CompressAdapter {
constructor(s: string) {
super()
this.mPath = s;
}
getRecoursePath(): string{
return this.mPath;
}
openInternal(callback: CompressDataListener<ArrayBuffer>) {
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);
}
}

View File

@ -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.ets"
import resmgr from '@ohos.resourceManager'
import {CompressDataListener} from "../listener/CompressDataListener.ets"
import {FileTypeUtil} from '../../../glide/utils/FileTypeUtil.ets'
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<ArrayBuffer>) {
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<ArrayBuffer>) {
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)
}
}

View File

@ -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= "Glide_js"
}

View File

@ -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
}

View File

@ -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.ets"
import image from "@ohos.multimedia.image"
import {TransformUtils} from "../transform/TransformUtils.ets"
export namespace Crop {
export function crop(buf: ArrayBuffer, x: number, y: number, cropWidth: number, cropHeight: number, func?: AsyncTransform<PixelMap>, 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);
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<PixelMap>) {
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);
}
}

View File

@ -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.ets";
@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);
}
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,12 @@
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;
}
}

View File

@ -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 "../../glide/RequestOption.ets"
import {FileTypeUtil} from "../../glide/utils/FileTypeUtil.ets"
import {GlideData} from "../GlideData.ets"
import {ParseImageUtil} from '../utils/ParseImageUtil.ets'
import {ParseResClient} from '../resourcemanage/ParseResClient.ets'
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 (this.options.errorholderSrc instanceof image.PixelMap) {
let glidedata = new GlideData();
glidedata.glideType = GlideData.PIXELMAP
glidedata.glideValue = this.options.placeholderSrc as PixelMap
onComplete(glidedata);
} 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 glidedata = new GlideData();
glidedata.glideType = "Resource"
glidedata.glideValue = this.options.errorholderSrc as Resource
glidedata.glideSourceType = typeValue;
onComplete(glidedata);
} else {
let parseImageUtils = new ParseImageUtil();
let success = (value: PixelMap) => {
let glidedata = new GlideData();
glidedata.glideType = "PixelMap"
glidedata.glideValue = value
glidedata.glideSourceType = typeValue;
onComplete(glidedata);
}
parseImageUtils.parseImage(arraybuffer, success, onError)
}
}
resourceFetch.loadResource(res, suc, onError)
} else {
onError("ErrorHolderManager 输入参数有问题!")
}
}
}
}

View File

@ -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 "../../glide/RequestOption.ets"
import {ResourceTypeEts} from "../../glide/constants/ResourceTypeEts.ets"
import {Base64} from "../../cache/Base64.ets"
import {FileTypeUtil} from "../../glide/utils/FileTypeUtil.ets"
import {GlideData} from "../GlideData.ets"
import {ParseImageUtil} from '../utils/ParseImageUtil.ets'
import {ParseResClient} from '../resourcemanage/ParseResClient.ets'
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 (this.options.placeholderSrc instanceof image.PixelMap) {
let glidedata = new GlideData();
glidedata.glideType = GlideData.PIXELMAP
glidedata.glideValue = this.options.placeholderSrc as PixelMap
onComplete(glidedata);
} 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 glidedata = this.createGlideData("Resource", this.options.placeholderSrc as Resource, typeValue);
onComplete(glidedata);
} else {
let parseImageUtils = new ParseImageUtil();
let success = (value: PixelMap) => {
let glidedata = this.createGlideData('PixelMap', value, typeValue);
onComplete(glidedata);
}
parseImageUtils.parseImage(arraybuffer, success, onError)
}
}
resourceFetch.loadResource(res, suc, onError)
} else {
onError("PlaceHolderManager 输入参数有问题!")
}
}
}
private createGlideData(glideType:string, glideValue:PixelMap|string|Resource, glideSourceType:string):GlideData{
let glidedata = new GlideData();
glidedata.glideType = glideType;
glidedata.glideValue = glideValue;
glidedata.glideSourceType = glideSourceType;
return glidedata;
}
}

View File

@ -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<T> {
(err: string, data: T): boolean;
}

View File

@ -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<T> {
(data: T);
}

View File

@ -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<T> {
callback(data: T);
}

View File

@ -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 {GlideData} from "../../glide/glidedata.ets"
export class AllCacheInfo {
memoryCacheInfo: {
key: string,
data: GlideData
}
resourceCacheInfo: {
path: string,
key: string
}
dataCacheInfo: {
path: string,
key: string
}
}
export interface IAllCacheInfoCallback {
(cacheInfo: AllCacheInfo);
}

View File

@ -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);
}

View File

@ -0,0 +1,68 @@
/*
* 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.ets"
import {RequestOption} from "../RequestOption.ets"
import {Md5} from "../../cache/Md5.ets"
import{FileUtils} from "../../cache/FileUtils.ets"
import httpRequest 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 allpath = request.networkCacheFolder + "/" + filename + ".img";
var downloadConfig = {
url: (request.loadSrc as string),
filePath: allpath
};
httpRequest.download(downloadConfig)
.then((downloadTask) => {
downloadTask.query((err, data) => {
if (err) {
onErrorFunction(err)
return;
}
downloadTask.on('progress', (uploadedSize, totalSize)=>{
let percent = Math.round(((uploadedSize*1.0)/(totalSize*1.0))*100)+"%"
if(request.progressFunc) {
request.progressFunc(percent);
}
});
downloadTask.on('complete', () => {
let downloadPath = request.getCachesPath() + "/" + allpath;
request.downloadFilePath = downloadPath;
let arraybuffer = FileUtils.getInstance()
.readFilePic(downloadPath)
onCompleteFunction(arraybuffer);
FileUtils.getInstance()
.deleteFile(downloadPath);
})
downloadTask.on('fail', (err) => {
onErrorFunction("DownloadClient Download task fail. err =" + err)
})
})
})
.catch((err) => {
onErrorFunction(err)
})
} else {
onErrorFunction("DownloadClient 暂不支持除http之外的uri加载")
}
}
}

View File

@ -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.ets"
// 网络接口
export interface IDataFetch {
loadData(request: RequestOption, onCompleteFunction, onErrorFunction);
}

View File

@ -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 {IDataFetch} from "../networkmanage/IDataFetch.ets"
import {RequestOption} from "../RequestOption.ets"
import {Md5} from "../../cache/Md5.ets"
import {FileUtils} from "../../cache/FileUtils.ets"
import {ParseResClient} from "../../glide/resourcemanage/ParseResClient"
import resourceManager from '@ohos.resourceManager';
export class SimulatedDownloadClient implements IDataFetch {
loadData(request: RequestOption, onCompleteFunction, onErrorFunction) {
console.log("SimulatedDownloadClient loadData");
let requestUrl = request.loadSrc as string;
let resource;
//jpg
if('https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB' == requestUrl){
console.log("SimulatedDownloadClient jpg");
resource = $r('app.media.jpgNet')
}
//png
else if('https://img-blog.csdnimg.cn/20191215043500229.png' == requestUrl){
console.log("SimulatedDownloadClient png");
resource = $r('app.media.pngNet')
}
//bmp
else if('https://img-blog.csdn.net/20140514114029140' == requestUrl){
console.log("SimulatedDownloadClient bmp");
resource = $r('app.media.bmpNet')
}
//webp
else if('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp' == requestUrl){
console.log("SimulatedDownloadClient webp");
resource = $r('app.media.webpNet')
}
//svg
else if('http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/30df266a-485e-411e-b178-b9fb1d8e0748.svg' == requestUrl){
console.log("SimulatedDownloadClient svg");
resource = $r('app.media.svgNet')
}
//gif
else if('https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700'== requestUrl){
console.log("SimulatedDownloadClient gif");
resource = $r('app.media.gifNet')
}else{
new Error("SimulatedDownloadClient not support otherUrl")
}
let resClient = new ParseResClient();
resClient.loadResource(resource,(arraybuffer)=>{
console.log("SimulatedDownloadClient loadResource callback! ok")
if(request.progressFunc) {
request.progressFunc("100%")
}
onCompleteFunction(arraybuffer)
},onErrorFunction)
}
}

View File

@ -0,0 +1,18 @@
import {Closeable} from "/glide/pngj/io/Closeable.ets"
import {ImageInfo} from "/glide/pngj/entry/ImageInfo.ets"
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 {
}
}

View File

@ -0,0 +1,47 @@
import {UPNG} from '../pngj/UPNG.js';
import image from '@ohos.multimedia.image';
import resourceManager from '@ohos.resourceManager';
import featureability from '@ohos.ability.featureAbility'
export class Pngj {
readPngImageInfo(arraybuffer: ArrayBuffer, callback) {
let imageSource = image.createImageSource(arraybuffer);
imageSource.getImageInfo((err, value) => {
if (err) {
return;
}
callback(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) {
var png = UPNG.decode(pngBuffer);
callback(png)
}
writePngWithString(addInfo:string, pngBuffer: ArrayBuffer,callback) {
var pngDecode = UPNG.decode(pngBuffer);
var newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
callback(newPng);
}
writePng(pngBuffer: ArrayBuffer,callback) {
var pngDecode = UPNG.decode(pngBuffer);
var newPng = UPNG.encode(UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
callback(newPng);
}
}

View File

@ -0,0 +1,5 @@
export class PngjException extends Error {
constructor(s: string) {
super(s)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
import {PngjException} from "../PngjException.ets"
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;
}
}

View File

@ -0,0 +1,5 @@
export interface IBytesConsumer {
isDone(): boolean;
consume(buf: ArrayBuffer, offset: number, len: number): number;
}

View File

@ -0,0 +1,3 @@
export interface Closeable {
close(): void;
}

View File

@ -0,0 +1,7 @@
export class Sandbox {
public static convert(origFileName: string, destFileName: string) {
}
}

View File

@ -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.ets"
import {DiskLruCache} from "../../cache/DiskLruCache.ets"
export class DiskCacheProxy implements ICache<string, ArrayBuffer> {
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();
}
}

View File

@ -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<K, V> {
// 缓存类型
getName(): string
getValue(key: K): V;
putValue(key: K, value: V);
removeValue(key: K): V;
clear();
}

View File

@ -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.ets"
import {LruCache} from "../../cache/LruCache"
export class MemoryCacheProxy <K, V> implements ICache<K, V> {
private mLruCache: LruCache<K, V>;
constructor(lruCache: LruCache<K, V>) {
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;
}
}

View File

@ -0,0 +1,582 @@
/*
* 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 "../../glide/RequestOption.ets"
import {DiskLruCache} from "../../cache/DiskLruCache.ets"
import {LruCache} from "../../cache/LruCache"
import {FileUtils} from "../../cache/FileUtils.ets"
import {Md5} from "../../cache/Md5.ets"
import{MemoryCacheProxy} from "../requestmanage/MemoryCacheProxy.ets"
import{DiskCacheProxy} from "../requestmanage/DiskCacheProxy.ets"
import{FileTypeUtil} from "../utils/FileTypeUtil.ets"
import{IDataFetch} from "../../glide/networkmanage/IDataFetch.ets"
import{IResourceFetch} from "../../glide/resourcemanage/IResourceFetch.ets"
import{GlideData} from "../GlideData.ets"
import {AllCacheInfo, IAllCacheInfoCallback} from "../../glide/interface/iallcacheinfocallback.ets"
import{ParseImageUtil} from '../utils/ParseImageUtil'
import{IParseImage} from '../interface/IParseImage.ets'
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<string, any>;
private mDiskCacheProxy: DiskCacheProxy;
private mIDataFetch: IDataFetch;
private mIResourceFetch: IResourceFetch;
private mParseImageUtil: IParseImage;
constructor(option: RequestOption, memoryCache1: LruCache<string, any>, 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<string, any>, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) {
console.log("RequestManager execute")
let manager = new RequestManager(option, memoryCache1, diskMemoryCache1, dataFetch, resourceFetch);
return new Promise<PixelMap>(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 ((GlideData.GIF == typeValue && !request.dontAnimateFlag) || GlideData.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 glidedata = this.createGlideData(GlideData.STRING, filePath, typeValue);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
})
.catch((err) => {
onError(err)
})
}
else {
if (request.transformtions[0]) {
request.transformtions[0].transform(arrayBuffer, request, (error, pixelMap: PixelMap) => {
// 输出给Image
if (pixelMap) {
let glidedata = this.createGlideData(GlideData.PIXELMAP, pixelMap, typeValue);
this.mMemoryCacheProxy.putValue(request.generateCacheKey, glidedata);
onComplete(glidedata);
} else {
onError(error);
}
})
}
else {
let success = (value: PixelMap) => {
let glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue);
this.mMemoryCacheProxy.putValue(request.generateCacheKey, glidedata);
onComplete(glidedata);
}
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 (request.loadSrc instanceof image.PixelMap) {
// 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 (((GlideData.GIF == typeValue && !request.dontAnimateFlag) || GlideData.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 glidedata = this.createGlideData(GlideData.STRING, filePath, typeValue)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
})
.catch((err) => {
onError(err)
})
} else {
if (this.options.transformtions[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.transformtions[0].transform(source, thumbOption, (error, pixelMap: PixelMap) => {
if (pixelMap) {
let glidedata = this.createGlideData(GlideData.PIXELMAP, pixelMap, typeValue);
thumbCallback(glidedata);
} else {
thumbError(error);
}
})
setTimeout(()=>{
this.options.transformtions[0].transform(source, request, (error, pixelMap: PixelMap) => {
if (pixelMap) {
// 保存一份变换后的图片PixelMap到MemoryCache
let glidedata = this.createGlideData(GlideData.PIXELMAP, pixelMap, typeValue);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
} else {
onError(error);
}
})
},this.options.thumbDelayTime);
}
else {
this.options.transformtions[0].transform(source, request, (error, pixelMap: PixelMap) => {
if (pixelMap) {
// 保存一份变换后的图片PixelMap到MemoryCache
let glidedata = this.createGlideData(GlideData.PIXELMAP, pixelMap, typeValue);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
} 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 glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue);
thumbCallback(glidedata);
}
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(()=>{
let success = (value: PixelMap) => {
let glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
}
this.mParseImageUtil.parseImage(source, success, onError)
},this.options.thumbDelayTime)
}
else {
let success = (value: PixelMap) => {
let glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
}
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 glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue);
thumbCallback(glidedata);
}
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(()=>{
let success = (value: PixelMap) => {
let glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
}
this.mParseImageUtil.parseImage(source, success, onError)
},this.options.thumbDelayTime)
}else{
let success = (value: PixelMap) => {
let glidedata = this.createGlideData(GlideData.PIXELMAP, value, typeValue)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
}
this.mParseImageUtil.parseImage(source, success, onError)
}
}
private downloadSuccess(source: ArrayBuffer, onComplete, onError) {
console.info('Download task completed.');
// 下载成功之后 去data/data/包名/唯一路径/文件名 读取数据
// 步骤一文件转为pixelMap 然后变换 给Image组件
// 步骤二: 文件名保存一份全局
// 步骤三:查看文件是否支持 非支持类型直接返回
let fileTypeUtil = new FileTypeUtil();
let filetype = fileTypeUtil.getFileType(source);
if (!fileTypeUtil.isImage(source)) {
onError("暂不支持 下载文件类型!类型=" + filetype);
return;
}
if ((GlideData.GIF == filetype && !this.options.dontAnimateFlag) || GlideData.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 glidedata = this.createGlideData(GlideData.STRING, filePath, filetype);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
onComplete(glidedata);
})
.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.transformtions[0]) {
// thumbnail 缩略图部分
if (this.options.thumbSizeMultiplier) {
this.thumbnailProcess(source, filetype, onComplete, onError);
} else {
this.options.transformtions[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 glidedata = this.createGlideData(GlideData.PIXELMAP, value, filetype);
thumbCallback(glidedata);
}
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)
}
}
}
}
createGlideData(glideType:string, glideValue:PixelMap|string|Resource, glideSourceType:string):GlideData{
let glidedata = new GlideData();
glidedata.glideType = glideType;
glidedata.glideValue = glideValue;
glidedata.glideSourceType = glideSourceType;
return glidedata;
}
private saveCacheAndDisk(value: PixelMap, filetype:string, onComplete, source:ArrayBuffer){
let glidedata = this.createGlideData(GlideData.PIXELMAP, value, filetype);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, glidedata);
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(glidedata);
}
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.transformtions[0].transform(source, thumbOption, (error, pixelMap: PixelMap) => {
if (pixelMap) {
let glidedata = this.createGlideData(GlideData.PIXELMAP, pixelMap, filetype);
thumbCallback(glidedata);
} else {
thumbError(error);
}
})
setTimeout(() => {
this.options.transformtions[0].transform(source, this.options, (error, pixelMap: PixelMap) => {
if (pixelMap) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source);
} else {
onError(error);
}
})
}, this.options.thumbDelayTime)
}
}

View File

@ -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.ets"
// 本地资源解析抽象接口
export interface IResourceFetch {
loadResource(res: Resource, onCompleteFunction, onErrorFunction);
}

View File

@ -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.ets'
import {ResourceTypeEts} from '../../glide/constants/ResourceTypeEts.ets'
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)
}
}

View File

@ -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.ets'
import {ResourceTypeEts} from '../../glide/constants/ResourceTypeEts.ets'
import {Base64} from '../../cache/Base64.ets'
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无法解析出错')
}
}
}

View File

@ -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<T> {
(err, data: T)
}

View File

@ -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.ets"
import {RequestOption} from "../../glide/RequestOption.ets"
export interface BaseTransform<T> {
//实现类 返回作为key生成的一部分
getName(): string;
transform(value: ArrayBuffer, request: RequestOption, func: AsyncTransform<T>);
}

View File

@ -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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
import {fastBlur} from "../utils/FastBlur"
export class BlurTransformation implements BaseTransform<PixelMap> {
private _mRadius: number;
constructor(radius: number) {
this._mRadius = radius;
}
getName() {
return "BlurTransformation _mRadius:" + this._mRadius;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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);
})
})
}
}

View File

@ -0,0 +1,140 @@
/*
* 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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.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<PixelMap> {
private _mBrightness: number= 0.0;
constructor(brightness: number) {
this._mBrightness = brightness;
}
getName() {
return "BrightnessFilterTransformation:" + this._mBrightness;
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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 readPromise;
let writePromise;
for (let w = 0;w <= targetWidth; w++) {
for (let h = 0;h <= targetHeight; h++) {
var buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
data.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
writePromise = new Promise<void>((resolve, reject) => {
var bytes = new Uint8Array(buffer);
var buffer1B = new ArrayBuffer(5);
var bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
bytes1B[0] = bytes[0];
bytes1B[1] = this.checkVisAble(bytes[1] * this._mBrightness + bytes[1]);
bytes1B[2] = this.checkVisAble(bytes[2] * this._mBrightness + bytes[2]);
bytes1B[3] = this.checkVisAble(bytes[3] * this._mBrightness + bytes[3]);
bytes1B[4] = bytes[4];
data.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
func("", data);
}
private checkVisAble(input: number) {
if (input > 255) {
input = 255;
}
if (input <= 0) {
input = 0;
}
return input;
}
}

View File

@ -0,0 +1,152 @@
/*
* 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 "../../glide/RequestOption.ets"
import image from "@ohos.multimedia.image"
/**
* 以24位色图像为例子每种色彩都可以用0-255
* 一共256种深度来表示。如果我们把它画在一个二维坐标上
* 正好是一条直线。比如我们将像素的色深作为横坐标,输出色深作为纵坐标的画,正好是一条经过原点(00)的45度斜线
* 那么很容易就可以写出它的直线方程Out = In * 1 系数1就是对比度的概念.如果把条直线加上一个偏移量变成B那么它的直线方程就成为
* Out = In * 1 + (ab)偏移量(ab)就是亮度的增量。
*只要有初中的代数知识就很容易看出它满足一条直线方程Y= A * X + B。但是我们这里要处理的情况稍微有些不同在图像处理中对比度和亮度要分别对待。不能因为改变而改变亮度因为我们习惯上把灰色(127127)这一点作为中心点。
*
*直线公式修改成Y=( X - 127 ) * A + B。A表示对比度B表示亮度增量。
* 只要亮度增量 B0无论怎么改变对比度 A该直线始终通过中心点(127,127),也就是说改变对比度的同时,亮度没有改变
*
*_mContrast value ranges from 0.0 to 4.0, with 1.0 as the normal level
*
*
*/
export class ContrastFilterTransformation implements BaseTransform<PixelMap> {
private _mContrast: number;
constructor(contrast: number) {
this._mContrast = contrast;
}
getName() {
return "ContrastFilterTransformation:" + this._mContrast;
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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 readPromise;
let writePromise;
for (let w = 0;w <= targetWidth; w++) {
for (let h = 0;h <= targetHeight; h++) {
var buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
data.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
writePromise = new Promise<void>((resolve, reject) => {
var bytes = new Uint8Array(buffer);
var buffer1B = new ArrayBuffer(5);
var bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
let brightness = 0; //亮度的偏移量可以默认0
bytes1B[0] = bytes[0];
bytes1B[1] = this.checkVisAble((bytes[1] - 127) * this._mContrast + brightness + 127);
bytes1B[2] = this.checkVisAble((bytes[2] - 127) * this._mContrast + brightness + 127);
bytes1B[3] = this.checkVisAble((bytes[3] - 127) * this._mContrast + brightness + 127);
bytes1B[4] = bytes[4];
data.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
func("", data);
}
private checkVisAble(input: number) {
if (input > 255) {
input = 255;
}
if (input <= 0) {
input = 0;
}
return input;
}
}

View File

@ -0,0 +1,152 @@
/*
* 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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
export class CropCircleTransformation implements BaseTransform<PixelMap> {
private static TAG: string= "CropCircleTransformation";
private mCenterX: number= 0;
private mCenterY: number= 0;
private mRadius: number= 0;
private mTransform_pixelMap: any;
getName() {
return CropCircleTransformation.TAG + ";mCenterX:" + this.mCenterX
+ ";mCenterY:" + this.mCenterY
+ ";mRadius:" + this.mRadius;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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<PixelMap>) {
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(p: PixelMap, func?: AsyncTransform<PixelMap>) {
this.mTransform_pixelMap = p;
let imageInfo = await this.mTransform_pixelMap.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 writePromise;
for (var h = 0;h <= height; h++) {
for (var w = 0;w <= width; w++) {
if (this.isContainsCircle(w, h)) {
continue;
}
writePromise = new Promise<void>((resolve, reject) => {
var buffer1 = new ArrayBuffer(5);
var bytes1 = new Uint8Array(buffer1);
var writePositionRenB = {
pixels: buffer1,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
for (let j = 0;j < 5; j++) {
bytes1[j] = 0;
}
this.mTransform_pixelMap.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
if (func) {
func("", this.mTransform_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;
}
}

View File

@ -0,0 +1,220 @@
/*
* 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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
export class CropCircleWithBorderTransformation implements BaseTransform<PixelMap> {
private static TAG: string= "CropCircleTransformation";
private mTransform_pixelMap: any;
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<PixelMap>) {
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);
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<PixelMap>) {
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: PixelMap, width: number, height: number, func?: AsyncTransform<PixelMap>) {
this.mTransform_pixelMap = pixelMap;
this.mRadius = 0;
if (width > height) {
this.mRadius = height / 2;
} else {
this.mRadius = width / 2;
}
this.mCenterX = width / 2;
this.mCenterY = height / 2;
let readPromise;
let writePromise;
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;
}
if (!isBigCircle) {
//设置透明
writePromise = new Promise<void>((resolve, reject) => {
var buffer1B = new ArrayBuffer(5);
var bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
for (let j = 0;j < 5; j++) {
bytes1B[j] = 0;
}
this.mTransform_pixelMap.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
} else {
//设置broke
var buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
this.mTransform_pixelMap.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
writePromise = new Promise<void>((resolve, reject) => {
var bytes = new Uint8Array(buffer);
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: w,
y: h
}
}
for (let j = 0;j < 5; j++) {
if (j == 1 && this.mBColor > 0) {
bytes1[j] = this.mBColor;
} else if (j == 2 && this.mGColor > 0) {
bytes1[j] = this.mGColor;
} else if (j == 3 && this.mRColor > 0) {
bytes1[j] = this.mRColor;
} else {
bytes1[j] = bytes[j];
}
}
this.mTransform_pixelMap.writePixels(writePositionRen, () => {
resolve();
});
})
await writePromise;
}
}
}
if (func) {
func("", this.mTransform_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);
}
}

View File

@ -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 "../../glide/RequestOption.ets"
import image from "@ohos.multimedia.image"
export class CropSquareTransformation implements BaseTransform<PixelMap> {
private static TAG: string= "CropSquareTransformation";
getName() {
return CropSquareTransformation.TAG + ";CropSquareTransformation:" + this;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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<PixelMap>) {
var imageSource = image.createImageSource(buf);
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);
}
})
}
}

View File

@ -0,0 +1,109 @@
/*
* 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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
export class CropTransformation implements BaseTransform<PixelMap> {
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<PixelMap>) {
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);
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 xx = (this.mWidth - scaledWidth) / 2;
var yy = Math.abs(this.getTop(pixelMapHeight));
var options = {
editable: true,
desiredRegion: { size: { width: this.mWidth, height: this.mHeight },
x: xx,
y: yy,
},
}
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
}

View File

@ -0,0 +1,123 @@
/*
* 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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
export class GrayscaleTransformation implements BaseTransform<PixelMap> {
getName() {
return "GrayscaleTransformation:" + this;
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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 readPromise;
let writePromise;
for (let w = 0;w <= targetWidth; w++) {
for (let h = 0;h <= targetHeight; h++) {
var buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
data.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
writePromise = new Promise<void>((resolve, reject) => {
var bytes = new Uint8Array(buffer);
var buffer1B = new ArrayBuffer(5);
var bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
bytes1B[0] = bytes[0];
bytes1B[1] = this.grayscale(bytes[3], bytes[2], bytes[1]);
bytes1B[2] = this.grayscale(bytes[3], bytes[2], bytes[1]);
bytes1B[3] = this.grayscale(bytes[3], bytes[2], bytes[1]);
bytes1B[4] = bytes[4];
data.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
func('',data);
}
/**
* 将读取的像素点的rgb值全部灰度化得到灰度图片黑白图片加权平均法
*/
private grayscale(r: number, g: number, b: number): number{
return (r * 28 + g * 151 + b * 77) >> 8;
}
}

View File

@ -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 {BaseTransform} from "../transform/BaseTransform.ets"
import {AsyncTransform} from "../transform/AsyncTransform.ets"
import {Constants} from "../constants/Constants.ets"
import {RequestOption} from "../../glide/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<PixelMap> {
getName() {
return "InvertFilterTransformation";
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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 readPromise;
let writePromise;
for (let w = 0;w <= targetWidth; w++) {
for (let h = 0;h <= targetHeight; h++) {
var buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
data.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
writePromise = new Promise<void>((resolve, reject) => {
var bytes = new Uint8Array(buffer);
var buffer1B = new ArrayBuffer(5);
var bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
bytes1B[0] = bytes[0];
bytes1B[1] = this.checkVisAble(255 - bytes[1]);
bytes1B[2] = this.checkVisAble(255 - bytes[2]);
bytes1B[3] = this.checkVisAble(255 - bytes[3]);
bytes1B[4] = bytes[4];
data.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
func("", data);
}
private checkVisAble(input: number) {
if (input > 255) {
input = 255;
}
if (input <= 0) {
input = 0;
}
return input;
}
}

View File

@ -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 "../../glide/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<PixelMap> {
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<PixelMap>) {
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);
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);
})
})
}
}

View File

@ -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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
export class RotateImageTransformation implements BaseTransform<PixelMap> {
private mDegreesToRotate: number;
constructor(degreesToRotate: number) {
this.mDegreesToRotate = degreesToRotate;
}
getName() {
return "RotateImageTransformation" + ";degreesToRotate:" + this.mDegreesToRotate;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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);
})
})
}
}

View File

@ -0,0 +1,223 @@
/*
* 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 "../../glide/RequestOption.ets"
import {TransformUtils} from "../transform/TransformUtils.ets"
import image from "@ohos.multimedia.image"
export class RoundedCornersTransformation implements BaseTransform<PixelMap> {
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<PixelMap>) {
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);
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<PixelMap>) {
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<ArcPoint>();
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<ArcPoint>();
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<ArcPoint>();
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<ArcPoint>();
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);
}
}
}
}

View File

@ -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 {BaseTransform} from "../transform/BaseTransform.ets"
import {AsyncTransform} from "../transform/AsyncTransform.ets"
import {Constants} from "../constants/Constants.ets"
import {RequestOption} from "../../glide/RequestOption.ets"
import image from "@ohos.multimedia.image"
/**
* Applies a simple sepia effect.
* <p>
* The intensity with a default of 1.0.
*/
export class SepiaFilterTransformation implements BaseTransform<PixelMap> {
getName() {
return "SepiaFilterTransformation";
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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 readPromise;
let writePromise;
for (let w = 0;w <= targetWidth; w++) {
for (let h = 0;h <= targetHeight; h++) {
var buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
data.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
writePromise = new Promise<void>((resolve, reject) => {
var bytes = new Uint8Array(buffer);
var buffer1B = new ArrayBuffer(5);
var bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
bytes1B[0] = bytes[0];
bytes1B[1] = this.checkVisAble(this.colorBlend(this.noise()
, (bytes[3] * 0.272) + (bytes[2] * 0.534) + (bytes[1] * 0.131)
, bytes[1]));
bytes1B[2] = this.checkVisAble(this.colorBlend(this.noise()
, (bytes[3] * 0.349) + (bytes[2] * 0.686) + (bytes[1] * 0.168)
, bytes[2]));
bytes1B[3] = this.checkVisAble(this.colorBlend(this.noise()
, (bytes[3] * 0.393) + (bytes[2] * 0.769) + (bytes[1] * 0.189)
, bytes[3]));
bytes1B[4] = bytes[4];
data.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
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;
}
}

View File

@ -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 '../../glide/RequestOption.ets'
import {TransformUtils} from '../transform/TransformUtils.ets'
import image from '@ohos.multimedia.image'
import {CalculatePixelUtils} from '../utils/CalculatePixelUtils'
export class SketchFilterTransformation implements BaseTransform<PixelMap> {
getName() {
return 'SketchFilterTransformation';
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
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);
})
})
}
}

View File

@ -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.ets'
import image from '@ohos.multimedia.image'
export class TransformUtils {
static centerCrop(buf: ArrayBuffer, outWidth: number, outHeihgt: number,
callback?: AsyncTransform<Promise<PixelMap>>) {
var imageSource = image.createImageSource(buf);
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<PixelMap>{
var imageSource = image.createImageSource(buf);
var options = {
editable: true,
rotate: degreesToRotate
}
return imageSource.createPixelMap(options);
}
static centerInside(buf: ArrayBuffer, outWidth: number, outHeihgt: number,
callback?: AsyncTransform<Promise<PixelMap>>) {
var imageSource = image.createImageSource(buf);
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<Promise<PixelMap>>) {
var imageSource = image.createImageSource(buf);
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 });
})
}
}

View File

@ -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.ets'
import {AsyncTransform} from '../AsyncTransform.ets'
import {Constants} from '../../constants/Constants.ets'
import {TransformUtils} from '../TransformUtils.ets'
import {RequestOption} from '../../../glide/RequestOption.ets'
export class CenterCrop implements BaseTransform<PixelMap> {
getName() {
return 'CenterCrop:' + this;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
})
})
}
}

View File

@ -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.ets'
import {AsyncTransform} from '../AsyncTransform.ets'
import {Constants} from '../../constants/Constants.ets'
import {TransformUtils} from '../TransformUtils.ets'
import {RequestOption} from '../../../glide/RequestOption.ets'
export class CenterInside implements BaseTransform<PixelMap> {
getName() {
return 'CenterInside:' + this;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
})
})
}
}

View File

@ -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.ets'
import {AsyncTransform} from '../AsyncTransform.ets'
import {Constants} from '../../constants/Constants.ets'
import {TransformUtils} from '../TransformUtils.ets'
import {RequestOption} from '../../../glide/RequestOption.ets'
export class FitCenter implements BaseTransform<PixelMap> {
getName() {
return 'FitCenter:' + this;
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
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);
})
})
}
}

View File

@ -0,0 +1,310 @@
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<PixelMap>) {
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<PixelEntry> = new Array()
var pixSrc: Array<number> = new Array()
var pixNvt: Array<number> = new Array()
let readPromise;
let writePromise;
for (let h = 0; h < height; h++) {
for (let w = 0; w < width; w++) {
let buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: w,
y: h
}
}
p.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
let bytes = new Uint8Array(buffer);
let entry = new PixelEntry();
entry.a = bytes[0];
entry.b = bytes[1];
entry.g = bytes[2];
entry.r = bytes[3];
entry.f = bytes[4];
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);
}
}
for (let m = 0;m < height; m++) { //y
for (let n = 0;n < width; n++) { //x
writePromise = new Promise<void>((resolve, reject) => {
let buffer1B = new ArrayBuffer(5);
let bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: n,
y: m
}
}
let index = m * width + n;
bytes1B[0] = pixEntry[m * width + n].a;
bytes1B[1] = ColorUtils.blue(pixSrc[index]);
bytes1B[2] = ColorUtils.green(pixSrc[index]);
bytes1B[3] = ColorUtils.red(pixSrc[index]);
bytes1B[4] = pixEntry[m * width + n].f;
p.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
func("success", p);
}
function gaussGray(psrc: Array<number>, 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<number>;
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<number>, n_m: Array<number>, d_p: Array<number>,
d_m: Array<number>, bd_p: Array<number>
, bd_m: Array<number>, 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<number>, src2: Array<number>,
dest: Array<number>, 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<number> {
let array = new Array<number>();
for (var index = 0; index < len; index++) {
array.push(0);
}
return array;
}
export function createInt2DArray(first_len: number, second_len: number): Array<Array<number>> {
let array = new Array<Array<number>>();
for (let f = 0; f < first_len; f++) {
let s1 = new Array<number>();
for (let s = 0; s < second_len; s++) {
s1.push(0);
}
array.push(s1);
}
return array;
}
}

View File

@ -0,0 +1,48 @@
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<string>) {
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;
}
}

View File

@ -0,0 +1,320 @@
/*
* 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 image from "@ohos.multimedia.image"
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<PixelMap>) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// 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 <mario@quasimondo.com>
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<PixelEntry> = new Array()
var pix: Array<number> = new Array()
let readPromise;
let writePromise;
for (let ph = 0; ph < h; ph++) {
for (let pw = 0; pw < w; pw++) {
let buffer = new ArrayBuffer(5);
readPromise = new Promise<void>((resolve, reject) => {
var positionRen = {
pixels: buffer,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: pw,
y: ph
}
}
bitmap.readPixels(positionRen, () => {
resolve();
});
});
await readPromise;
let bytes = new Uint8Array(buffer);
let entry = new PixelEntry();
entry.a = bytes[0];
entry.b = bytes[1];
entry.g = bytes[2];
entry.r = bytes[3];
entry.f = bytes[4];
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<number>;
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;
}
}
for (let m = 0;m < h; m++) { //y
for (let n = 0;n < w; n++) { //x
writePromise = new Promise<void>((resolve, reject) => {
let buffer1B = new ArrayBuffer(5);
let bytes1B = new Uint8Array(buffer1B);
var writePositionRenB = {
pixels: buffer1B,
offset: 1,
stride: 1024,
region: { size: { width: 1, height: 1 },
x: n,
y: m
}
}
let index = m * w + n;
bytes1B[0] = pixEntry[m * w + n].a;
bytes1B[1] = ColorUtils.blue(pix[index]);
bytes1B[2] = ColorUtils.green(pix[index]);
bytes1B[3] = ColorUtils.red(pix[index]);
bytes1B[4] = pixEntry[m * w + n].f;
bitmap.writePixels(writePositionRenB, () => {
resolve();
});
})
await writePromise;
}
}
func("success", bitmap);
}
}

Some files were not shown because too many files have changed in this diff Show More