ImageKnife版本v1.0.0提交
Signed-off-by: zhoulisheng1 <zhoulisheng1@huawei.com>
This commit is contained in:
parent
7da838a541
commit
91d81d5210
|
@ -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
|
|
@ -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.
|
36
README.en.md
36
README.en.md
|
@ -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
306
README.md
|
@ -1,39 +1,291 @@
|
|||
# ImageKnife
|
||||
# GlideJS
|
||||
|
||||
#### 介绍
|
||||
{**以下是 Gitee 平台说明,您可以替换此简介**
|
||||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
|
||||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
|
||||
**专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单**
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
## 简介
|
||||
|
||||
- 支持内存缓存,使用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
|
||||
3. xxxx
|
||||
```
|
||||
import {Glide} from './glide/Glide.ets'
|
||||
export default {
|
||||
data: {
|
||||
glide: {} // Glide全局占位符
|
||||
},
|
||||
onCreate() {
|
||||
this.data.glide = Glide.with();// Glide占位符全局初始化赋值
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 参与贡献
|
||||
2.在页面index.ets中使用Glide
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
```
|
||||
@Entry
|
||||
@Component
|
||||
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 上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
#### 推荐使用:
|
||||
|
||||
使用GlideOption作为入参,配合自定义组件GlideImage使用。
|
||||
|
||||
```typescript
|
||||
@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%"/>
|
|
@ -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/'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/build
|
||||
/node_modules
|
|
@ -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'
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
# config module specific ProGuard rules here.
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
||||
},
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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("输入参数有问题!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 输入参数有问题!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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加载")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export class PngjException extends Error {
|
||||
constructor(s: string) {
|
||||
super(s)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export interface IBytesConsumer {
|
||||
isDone(): boolean;
|
||||
|
||||
consume(buf: ArrayBuffer, offset: number, len: number): number;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface Closeable {
|
||||
close(): void;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
export class Sandbox {
|
||||
|
||||
|
||||
public static convert(origFileName: string, destFileName: string) {
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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无法解析出错')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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>);
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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种深度来表示。如果我们把它画在一个二维坐标上,
|
||||
* 正好是一条直线。比如我们将像素的色深作为横坐标,输出色深作为纵坐标的画,正好是一条经过原点(0,0)的45度斜线
|
||||
* 那么很容易就可以写出它的直线方程:Out = In * 1 ,系数1就是对比度的概念.如果把条直线加上一个偏移量变成B,那么它的直线方程就成为:
|
||||
* Out = In * 1 + (ab)偏移量(ab)就是亮度的增量。
|
||||
*只要有初中的代数知识就很容易看出它满足一条直线方程:Y= A * X + B。但是,我们这里要处理的情况稍微有些不同,在图像处理中,对比度和亮度要分别对待。不能因为改变而改变亮度,因为我们习惯上把灰色(127,127)这一点作为中心点。
|
||||
*
|
||||
*直线公式修改成:Y=( X - 127 ) * A + B。A表示对比度,B表示亮度增量。
|
||||
* 只要亮度增量 B=0,无论怎么改变对比度 A,该直线始终通过中心点(127,127),也就是说改变对比度的同时,亮度没有改变
|
||||
*
|
||||
*_mContrast value ranges from 0.0 to 4.0, with 1.0 as the normal level
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class ContrastFilterTransformation implements BaseTransform<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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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 });
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue