diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e3c661c --- /dev/null +++ b/.gitignore @@ -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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 640fd29..0000000 --- a/README.en.md +++ /dev/null @@ -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/) diff --git a/README.md b/README.md index 249174d..459d1ba 100644 --- a/README.md +++ b/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) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置占位图,其中func为数据回调函数 | +| errorholder(src: PixelMap \| Resource, func?: AsyncSuccess) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置加载失败占位图,其中func为数据回调函数 | +| addListener(func: AsyncCallback) | func: AsyncCallback | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 | +| thumbnail(sizeMultiplier:number, func?: AsyncSuccess) | sizeMultiplier:number, func?: AsyncSuccess | 设置缩略图比例,缩略图返回后,加载并展示缩略图 | +| addProgressListener(func?: AsyncSuccess){ this.progressFunc = func; return this; } | func?: AsyncSuccess | 设置网络下载百分比监听,返回数据加载百分比数值 | +| addRetryListener(func?: AsyncSuccess){ this.retryFunc = func; return this; } | func?: AsyncSuccess | 设置重试监听 | +| addAllCacheInfoCallback(func: IAllCacheInfoCallback) | func: IAllCacheInfoCallback | 设置获取所有缓存信息监听 | +| skipMemoryCache(skip: boolean) | skip: boolean | 配置是否跳过内存缓存 | +| retrieveDataFromCache(flag: boolean) | flag: boolean | 配置仅从缓存中加载数据 | +| transform(transform: BaseTransform) | transform: BaseTransform | 配置自定义变换类型 | +| centerCrop(fd: number, out_width: number, out_height: number, callback?: AsyncTransform>) | fd: number, out_width: number, out_height: number, callback?: AsyncTransform> | 静态方法可以根据图片文件,目标显示大小,进行对应centerCrop | +| rotateImage(fd: number, degreesToRotate: number) | fd: number, degreesToRotate: number | 静态方法可以根据图片文件,和旋转角度,进行对应rotateImaroge | +| centerInside(fd: number, out_width: number, out_height: number, callback?: AsyncTransform>) | fd: number, out_width: number, out_height: number, callback?: AsyncTransform> | 静态方法可以根据图片文件,目标显示大小,进行对应centerInside | +| fitCenter(fd: number, out_width: number, out_height: number , callback?: AsyncTransform>) | fd: number, out_width: number, out_height: number , callback?: AsyncTransform> | 静态方法可以根据图片文件,目标显示大小,进行对应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实现 + +## 演示 + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..17664f5 --- /dev/null +++ b/build.gradle @@ -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/' + } + } +} diff --git a/entry/.gitignore b/entry/.gitignore new file mode 100644 index 0000000..7d5b7a9 --- /dev/null +++ b/entry/.gitignore @@ -0,0 +1,2 @@ +/build +/node_modules diff --git a/entry/build.gradle b/entry/build.gradle new file mode 100644 index 0000000..05a33cd --- /dev/null +++ b/entry/build.gradle @@ -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' +} diff --git a/entry/proguard-rules.pro b/entry/proguard-rules.pro new file mode 100644 index 0000000..f7666e4 --- /dev/null +++ b/entry/proguard-rules.pro @@ -0,0 +1 @@ +# config module specific ProGuard rules here. \ No newline at end of file diff --git a/entry/src/main/config.json b/entry/src/main/config.json new file mode 100644 index 0000000..a0f0190 --- /dev/null +++ b/entry/src/main/config.json @@ -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 + } + } + ] + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/app.ets b/entry/src/main/ets/MainAbility/app.ets new file mode 100644 index 0000000..2f3c856 --- /dev/null +++ b/entry/src/main/ets/MainAbility/app.ets @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import 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() { + + }, +} diff --git a/entry/src/main/ets/MainAbility/cache/Base64.ets b/entry/src/main/ets/MainAbility/cache/Base64.ets new file mode 100644 index 0000000..e219975 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/Base64.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class Base64 { + lookup: Uint8Array = new Uint8Array(256) + chars: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + private static sInstance: Base64; + + public static getInstance(): Base64{ + if (!this.sInstance) { + this.sInstance = new Base64(); + } + return this.sInstance; + } + + private constructor() { + console.log("Base64 - constructor init!") + for (var index = 0; index < this.chars.length; index++) { + this.lookup[this.chars.charCodeAt(index)] = index; + } + } + + encode(arraybuffer: ArrayBuffer): string { + let bytes = new Uint8Array(arraybuffer), + i, + len = bytes.length, + base64 = ''; + for (i = 0; i < len; i += 3) { + base64 += this.chars[bytes[i] >> 2]; + base64 += this.chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; + base64 += this.chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; + base64 += this.chars[bytes[i + 2] & 63]; + } + if (len % 3 === 2) { + base64 = base64.substring(0, base64.length - 1) + '='; + } else if (len % 3 === 1) { + base64 = base64.substring(0, base64.length - 2) + '=='; + } + return base64; + } + + decode(base64: string): ArrayBuffer{ + let bufferLength = base64.length * 0.75, + len = base64.length, + i, + p = 0, + encoded1, + encoded2, + encoded3, + encoded4; + + if (base64[base64.length - 1] === '=') { + bufferLength--; + if (base64[base64.length - 2] === '=') { + bufferLength--; + } + } + + const arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i += 4) { + encoded1 = this.lookup[base64.charCodeAt(i)]; + encoded2 = this.lookup[base64.charCodeAt(i + 1)]; + encoded3 = this.lookup[base64.charCodeAt(i + 2)]; + encoded4 = this.lookup[base64.charCodeAt(i + 3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + } + + return arraybuffer; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/CustomMap.ets b/entry/src/main/ets/MainAbility/cache/CustomMap.ets new file mode 100644 index 0000000..7190d6b --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/CustomMap.ets @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http:// www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class CustomMap { + map: Map = new Map() + + // 获取键对应的值 + get(key: K): V | undefined{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + return this.map.get(key) + } + + /** + * 是否含有key的缓存 + */ + hasKey(key: K) { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + return this.map.has(key) + } + + // 添加键值对 + put(key: K, value: V): V | undefined{ + if (key == null || value == null) { + throw new Error('key or value is invalid,checking the parameter'); + } + var pre = this.map.get(key) + if (this.hasKey(key)) { + this.map.delete(key) + } + this.map.set(key, value); + return pre + } + + // 去除键值,(去除键数据中的键名及对应的值) + remove(key: K): boolean { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + return this.map.delete(key) + } + + /** + * 获取最先存储的数据的key + */ + getFirstKey(): K{ // keys()可以遍历后需要优化put()方法,暂时仅获取index=0的key + return this.map.keys().next().value + } + + // 判断键值元素是否为空 + isEmpty(): boolean{ + return this.map.size == 0; + } + // 获取键值元素大小 + size(): number{ + return this.map.size; + } + // 遍历Map,执行处理函数. 回调函数 function(key,value,index){..} + each(fn) { + this.map.forEach(fn) + } + // 清除键值对 + clear() { + this.map.clear() + } + // 遍历key + keys(): IterableIterator{ + return this.map.keys() + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/DiskCacheEntry.ets b/entry/src/main/ets/MainAbility/cache/DiskCacheEntry.ets new file mode 100644 index 0000000..ece37d8 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/DiskCacheEntry.ets @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class DiskCacheEntry { + + // 缓存的key + key: string= '' + + // 缓存文件大小 + length: number= 0 + + constructor(key: string, length?: number) { + this.key = key + this.length = length + } + + setKey(key: string) { + this.key = key + } + + getkey(): string{ + return this.key + } + + setLength(length: number) { + this.length = length + } + + getLength(): number{ + return this.length + } + + toString(): string{ + return this.key + ' - ' + this.length + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/DiskLruCache.ets b/entry/src/main/ets/MainAbility/cache/DiskLruCache.ets new file mode 100644 index 0000000..5c18a30 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/DiskLruCache.ets @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {CustomMap} from './CustomMap' +import {FileUtils} from './FileUtils' +import {FileReader} from './FileReader' +import {DiskCacheEntry} from './DiskCacheEntry' +import fileio from '@ohos.fileio'; +import featureability from '@ohos.ability.featureAbility' +import {Md5} from './Md5.ets' + +export class DiskLruCache { + + // 缓存数据集合 + cacheMap: CustomMap = new CustomMap() + 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) + } + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/FileReader.ets b/entry/src/main/ets/MainAbility/cache/FileReader.ets new file mode 100644 index 0000000..10969e0 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/FileReader.ets @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import fileio from '@ohos.fileio'; + +export class FileReader { + + // 文件大小 + fileLength: number = 0 + + // 读取的长度 + length: number = 0 + + // 读写stream + stream: any = null + // 缓存buf + buf: ArrayBuffer = new ArrayBuffer(1) + + constructor(path: string) { + if (!path || Object.keys(path).length == 0) { + return + } + try { + this.stream = fileio.createStreamSync(path, 'r+'); + var stat = fileio.statSync(path) + this.fileLength = stat.size + } catch (e) { + } + } + + /** + * 循环读取文件数据 + */ + readLine(): string{ + var line = '' + while (this.length <= this.fileLength) { + this.stream.readSync(this.buf, { position: this.length }) + this.length++ + var temp = String.fromCharCode.apply(null, new Uint8Array(this.buf)); + line = line + temp + if (temp == '\n' || temp == '\r') { + return line + } + } + return line + } + + /** + * 判断文件是否结束 + */ + isEnd() { + return this.fileLength <= 0 || this.length == this.fileLength + } + + /** + * 关闭stream + */ + close() { + this.stream.closeSync() + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/FileUtils.ets b/entry/src/main/ets/MainAbility/cache/FileUtils.ets new file mode 100644 index 0000000..7430bcb --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/FileUtils.ets @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import resmgr from '@ohos.resourceManager' +import fileio from '@ohos.fileio'; + +export class FileUtils { + base64Str: string= '' + + private static sInstance: FileUtils; + + public static getInstance(): FileUtils{ + if (!this.sInstance) { + this.sInstance = new FileUtils(); + } + return this.sInstance; + } + + private constructor() { + console.error("FileUtils - FileUtils constructor") + } + + /** + * 新建文件 + * @param path 文件绝对路径及文件名 + * @return number 文件句柄id + */ + createFile(path: string): number{ + return fileio.openSync(path, 0o100, 0o666) + } + + /** + * 删除文件 + * @param path 文件绝对路径及文件名 + */ + deleteFile(path: string):void { + fileio.unlinkSync(path); + } + + /** + * 同步删除文件目录 必须保证文件夹里面没有文件 + * @param path 待删除目录的绝对路径 + */ + deleteFolderSync(path: string):void { + if (this.existFolder(path)) { + fileio.rmdirSync(path); + } + } + + /** + * 异步删除文件目录 必须保证文件夹里面没有文件 + * @param path 待删除目录的绝对路径 + */ + deleteFolderAsync(path: string, deleteComplete, deleteError) { + if (this.existFolder(path)) { + fileio.rmdir(path) + .then(deleteComplete).catch(deleteError); + } + } + + /** + * 拷贝文件 + * @param path 文件绝对路径及文件名 + */ + copyFile(oriPath: string, newPath: string) { + fileio.copyFileSync(oriPath, newPath); + } + + /** + * 清空已有文件数据 + */ + clearFile(path: string):number { + return fileio.openSync(path, 0o1000) + } + + /** + * 向path写入content数据,覆盖旧数据 + */ + writeFile(path: string, content: ArrayBuffer | string) { + try { + let fd = fileio.openSync(path, 0o102, 0o666) + fileio.ftruncateSync(fd) + fileio.writeSync(fd, content) + fileio.fsyncSync(fd) + fileio.closeSync(fd) + } catch (e) { + console.log("FileUtils - Failed to writeFile for " + e) + } + } + + /** + * 向path写入数据 + */ + writeData(path: string, content: ArrayBuffer | string) { + try { + console.info("FileUtils - writeData size 1= " + path) + let fd = fileio.openSync(path, 0o102, 0o666) + console.info("FileUtils - writeData size 2= ") + let stat = fileio.statSync(path) + console.info("FileUtils - writeData size = " + stat.size) + fileio.writeSync(fd, content, { position: stat.size }) + let length = 0 + if (content instanceof ArrayBuffer) { + length = content.byteLength + } else { + length = content.length + } + fileio.closeSync(fd) + } catch (e) { + console.log("FileUtils - Failed to writeData for " + e) + } + } + + /** + * 判断path文件是否存在 + */ + exist(path: string): boolean{ + try { + let stat = fileio.statSync(path) + return stat.isFile() + } catch (e) { + console.debug("FileUtils - fileutils exsit e" + e) + console.log("path=>" + path) + return false + } + } + + /** + * 向path写入数据 + */ + writePic(path: string, picData: ArrayBuffer) { + console.info("FileUtils - writepic 1") + this.createFile(path) + this.writeFile(path, picData) + console.info("FileUtils - writepic 3") + } + + /** + * 获取path的文件大小 + */ + getFileSize(path: string): number{ + try { + let stat = fileio.statSync(path) + return stat.size + } catch (e) { + console.error("FileUtils - FileUtils getFileSize e " + e) + return -1 + } + } + + /** + * 读取路径path的文件 + */ + readFilePic(path: string): ArrayBuffer { + try { + let stat = fileio.statSync(path) + console.info("FileUtils - readFilePic 1") + let fd = fileio.openSync(path, 0o2); + let length = fileio.statSync(path).size + console.info("FileUtils - readFilePic 2 length = " + length) + let buf = new ArrayBuffer(length); + console.info("FileUtils - readFilePic 3") + fileio.readSync(fd, buf) + return buf + } catch (e) { + console.log("FileUtils - readFilePic " + e) + return new ArrayBuffer(0) + } + } + + /** + * 读取media的资源文件 + */ + readMediaPic() { + resmgr.getResourceManager() + .then(result => { + result.getMediaBase64($r('app.media.icon') + .id) + .then(data => { + console.error("FileUtils - readPic data = " + data) + data = data.replace("data:image/png;base64,", "") + console.error("FileUtils - readPic this.data = " + data) + this.base64Str = data + console.error("FileUtils - readPic this.base64Str = " + this.base64Str) + }) + .catch(err => { + console.log("FileUtils - readPic err" + JSON.stringify(err)); + }) + }) + } + + /** + * stream式读取 + */ + readStream(path: string): string { + try { + let stat = fileio.statSync(path) + let length = stat.size + let buf = new ArrayBuffer(length); + let ss = fileio.createStreamSync(path, "r+"); + ss.readSync(buf) + ss.closeSync(); + return String.fromCharCode.apply(null, new Uint8Array(buf)) + } catch (e) { + console.log("FileUtils - readFilePic " + e) + return "" + } + } + + /** + * stream式写入 + */ + writeStream(path: string, tempArray: ArrayBuffer) { + try { + console.error("FileUtils - writeStream =1 ") + this.createFile(path) + console.error("FileUtils - writeStream 2 ") + let ss = fileio.createStreamSync(path, "r+"); + console.error("FileUtils - writeStream 3 " + tempArray.byteLength) + let num = ss.writeSync(tempArray, { + encoding: 'utf-8' + }); + console.error("FileUtils - write num = " + num) + ss.flushSync(); + ss.closeSync(); + } catch (e) { + console.log("FileUtils - Failed to writeStream for " + e) + } + } + + /** + * 创建文件夹 + * @param 文件夹绝对路径 + */ + createFolder(path: string) { + //创建文件夹 + if (!this.existFolder(path)) { + fileio.mkdirSync(path) + } + } + + /** + * 判断文件夹是否存在 + * @param 文件夹绝对路径 + */ + existFolder(path: string): boolean{ + try { + let stat = fileio.statSync(path) + return stat.isDirectory() + } catch (e) { + console.debug("fileutils folder exsit error=" + e) + return false + } + } + + /** + * 如果文件夹不存在则创建一个文件夹 然后在其中创建文件 并且将数据写入进文件 + * @param folder 文件夹绝对路径 + * @param file 文件绝对路径 + * @param content 文件内容数据 + */ + createFileProcess(folder: string, file: string, content: ArrayBuffer | string) { + //创建文件夹 + this.createFolder(folder); + //创建文件 + this.createFile(file); + //写入数据 + this.writeFile(file, content) + } + + /** + * string 转 Uint8Array + * @param str 输入String + */ + stringToUint8Array(str): Uint8Array{ + var arr = []; + for (var i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + var tmpUint8Array = new Uint8Array(arr); + return tmpUint8Array + } + + /** + * int 转 byte[] + * @param n 输入int + */ + intTobytes2(n) { + var bytes = []; + for (var i = 0; i < 2; i++) { + bytes[i] = n >> (8 - i * 8); + } + return bytes; + } + + + uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } + +} + +export interface AsyncCallback { + (err: string, data: T): void; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/LruCache.ets b/entry/src/main/ets/MainAbility/cache/LruCache.ets new file mode 100644 index 0000000..3e8d14d --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/LruCache.ets @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http:// www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {CustomMap} from './CustomMap' + +export class LruCache { + maxsize: number = 0 + size: number = 0; + map: CustomMap = new CustomMap(); + + constructor(maxsize: number) { + this.trimToSize(-1) + this.maxsize = maxsize + this.size = 0; + } + + // 添加缓存键值对 + put(key: K, value: V) { + if (key == null || value == null) { + throw new Error('key or value is invalid '); + } + var pre = this.map.get(key) + if (pre == null) { + this.size++ + } + this.entryRemoved(key, pre, value) + this.trimToSize(this.maxsize) + } + + // 移除键为key的缓存 + remove(key: K): V | undefined{ + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + var preValue = this.map.get(key) + if (this.map.remove(key)) { + this.size-- + } + return preValue + } + + // 获取键为key的value + get(key: K): V { + if (key == null) { + throw new Error('key is null,checking the parameter'); + } + var preValue = this.map.get(key) + if (preValue != null) { + this.entryRemoved(key, preValue, preValue) + } + return preValue + } + + /* + * 替换或删除对应key键的数据 + * evicted:是否删除 + * key:对应的键值key + * preValue 对应key键的旧value值 + * value 对应key键的新value值 + */ + entryRemoved(key: K, preValue: V, value: V) { + if (preValue != null) { + this.map.remove(key) + } + if (value != null) { + this.map.put(key, value) + } + } + + // 移除较少使用的缓存数据 + trimToSize(tempsize: number) { + while (true) { + if (tempsize < 0) { + this.map.clear() + this.size = 0 + break + } + if (this.size <= tempsize || this.map.isEmpty()) { + break + } + var delkey = this.map.getFirstKey() + this.map.remove(delkey) + this.size-- + } + } + + // 缓存数据数量 + sizeLength(): number{ + return this.size + } + + // 缓存数据最大值 + maxSize(): number{ + return this.maxsize + } + + // 设置缓存数据量最大值 + resize(maxsize: number) { + if (maxsize < 0) { + throw new Error('maxsize <0 & maxsize invalid'); + } + this.maxsize = maxsize + this.trimToSize(maxsize) + } + + // 清除缓存 + evicAll() { + this.trimToSize(-1) + } + + print():string { + let printResult = ''; + if (this.map.isEmpty()) { + return printResult; + } + + + this.map.each(function (value, key, index) { + printResult +='LruCache:key=' + key + 'value= ' + value; + }) + return printResult; + } + + foreachLruCache(fn){ + this.map.each(fn); + } + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/Md5.ets b/entry/src/main/ets/MainAbility/cache/Md5.ets new file mode 100644 index 0000000..bbfb601 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/Md5.ets @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class Md5 { + + // One time hashing functions + public static hashStr(str: string, raw?: false): string + + public static hashStr(str: string, raw: true): Int32Array + + public static hashStr(str: string, raw: boolean = false) { + return this.onePassHasher + .start() + .appendStr(str) + .end(raw); + } + + public static hashAsciiStr(str: string, raw?: false): string + + public static hashAsciiStr(str: string, raw: true): Int32Array + + public static hashAsciiStr(str: string, raw: boolean = false) { + return this.onePassHasher + .start() + .appendAsciiStr(str) + .end(raw); + } + + // Private Static Variables + private static stateIdentity = new Int32Array([1732584193, -271733879, -1732584194, 271733878]); + private static buffer32Identity = new Int32Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + private static hexChars = '0123456789abcdef'; + private static hexOut: string[] = []; + + // Permanent instance is to use for one-call hashing + private static onePassHasher = new Md5(); + + private static _hex(x: any): string { + const hc = Md5.hexChars; + const ho = Md5.hexOut; + let n; + let offset; + let j; + let i; + + for (i = 0; i < 4; i += 1) { + offset = i * 8; + n = x[i]; + for (j = 0; j < 8; j += 2) { + ho[offset + 1 + j] = hc.charAt(n & 0x0F); + n >>>= 4; + ho[offset + 0 + j] = hc.charAt(n & 0x0F); + n >>>= 4; + } + } + return ho.join(''); + } + + private static _md5cycle(x: Int32Array | Uint32Array, k: Int32Array | Uint32Array) { + let a = x[0]; + let b = x[1]; + let c = x[2]; + let d = x[3]; + // ff() + a += (b & c | ~b & d) + k[0] - 680876936 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[1] - 389564586 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[2] + 606105819 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[3] - 1044525330 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[4] - 176418897 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[5] + 1200080426 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[6] - 1473231341 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[7] - 45705983 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[8] + 1770035416 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[9] - 1958414417 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[10] - 42063 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[11] - 1990404162 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[12] + 1804603682 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[13] - 40341101 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[14] - 1502002290 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[15] + 1236535329 | 0; + b = (b << 22 | b >>> 10) + c | 0; + // gg() + a += (b & d | c & ~d) + k[1] - 165796510 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[6] - 1069501632 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[11] + 643717713 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[0] - 373897302 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[5] - 701558691 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[10] + 38016083 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[15] - 660478335 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[4] - 405537848 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[9] + 568446438 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[14] - 1019803690 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[3] - 187363961 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[8] + 1163531501 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[13] - 1444681467 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[2] - 51403784 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[7] + 1735328473 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[12] - 1926607734 | 0; + b = (b << 20 | b >>> 12) + c | 0; + // hh() + a += (b ^ c ^ d) + k[5] - 378558 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[8] - 2022574463 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[11] + 1839030562 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[14] - 35309556 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[1] - 1530992060 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[4] + 1272893353 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[7] - 155497632 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[10] - 1094730640 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[13] + 681279174 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[0] - 358537222 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[3] - 722521979 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[6] + 76029189 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[9] - 640364487 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[12] - 421815835 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[15] + 530742520 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[2] - 995338651 | 0; + b = (b << 23 | b >>> 9) + c | 0; + // ii() + a += (c ^ (b | ~d)) + k[0] - 198630844 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[5] - 57434055 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[10] - 1051523 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[15] - 30611744 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[4] - 145523070 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[2] + 718787259 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[9] - 343485551 | 0; + b = (b << 21 | b >>> 11) + c | 0; + + x[0] = a + x[0] | 0; + x[1] = b + x[1] | 0; + x[2] = c + x[2] | 0; + x[3] = d + x[3] | 0; + } + + private _dataLength: number; + private _bufferLength: number; + private _state: Int32Array = new Int32Array(4); + private _buffer: ArrayBuffer = new ArrayBuffer(68); + private _buffer8: Uint8Array; + private _buffer32: Uint32Array; + + constructor() { + this._buffer8 = new Uint8Array(this._buffer, 0, 68); + this._buffer32 = new Uint32Array(this._buffer, 0, 17); + this.start(); + } + + public start() { + this._dataLength = 0; + this._bufferLength = 0; + this._state.set(Md5.stateIdentity); + return this; + } + + // Char to code point to to array conversion: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt + // #Example.3A_Fixing_charCodeAt_to_handle_non-Basic-Multilingual-Plane_characters_if_their_presence_earlier_in_the_string_is_unknown + public appendStr(str: string) { + const buf8 = this._buffer8; + const buf32 = this._buffer32; + let bufLen = this._bufferLength; + let code; + let i; + + for (i = 0; i < str.length; i += 1) { + code = str.charCodeAt(i); + if (code < 128) { + buf8[bufLen++] = code; + } else if (code < 0x800) { + buf8[bufLen++] = (code >>> 6) + 0xC0; + buf8[bufLen++] = code & 0x3F | 0x80; + } else if (code < 0xD800 || code > 0xDBFF) { + buf8[bufLen++] = (code >>> 12) + 0xE0; + buf8[bufLen++] = (code >>> 6 & 0x3F) | 0x80; + buf8[bufLen++] = (code & 0x3F) | 0x80; + } else { + code = ((code - 0xD800) * 0x400) + (str.charCodeAt(++i) - 0xDC00) + 0x10000; + if (code > 0x10FFFF) { + throw new Error('Unicode standard supports code points up to U+10FFFF'); + } + buf8[bufLen++] = (code >>> 18) + 0xF0; + buf8[bufLen++] = (code >>> 12 & 0x3F) | 0x80; + buf8[bufLen++] = (code >>> 6 & 0x3F) | 0x80; + buf8[bufLen++] = (code & 0x3F) | 0x80; + } + if (bufLen >= 64) { + this._dataLength += 64; + Md5._md5cycle(this._state, buf32); + bufLen -= 64; + buf32[0] = buf32[16]; + } + } + this._bufferLength = bufLen; + return this; + } + + public appendAsciiStr(str: string) { + const buf8 = this._buffer8; + const buf32 = this._buffer32; + let bufLen = this._bufferLength; + let i; + let j = 0; + + for (;; ) { + i = Math.min(str.length - j, 64 - bufLen); + while (i--) { + buf8[bufLen++] = str.charCodeAt(j++); + } + if (bufLen < 64) { + break; + } + this._dataLength += 64; + Md5._md5cycle(this._state, buf32); + bufLen = 0; + } + this._bufferLength = bufLen; + return this; + } + + public appendByteArray(input: Uint8Array) { + const buf8 = this._buffer8; + const buf32 = this._buffer32; + let bufLen = this._bufferLength; + let i; + let j = 0; + + for (;; ) { + i = Math.min(input.length - j, 64 - bufLen); + while (i--) { + buf8[bufLen++] = input[j++]; + } + if (bufLen < 64) { + break; + } + this._dataLength += 64; + Md5._md5cycle(this._state, buf32); + bufLen = 0; + } + this._bufferLength = bufLen; + return this; + } + + public getState() { + const self = this; + const s = self._state; + + return { + buffer: String.fromCharCode.apply(null, self._buffer8), + buflen: self._bufferLength, + length: self._dataLength, + state: [s[0], s[1], s[2], s[3]] + }; + } + + public setState(state: any) { + const buf = state.buffer; + const x = state.state; + const s = this._state; + let i; + + this._dataLength = state.length; + this._bufferLength = state.buflen; + s[0] = x[0]; + s[1] = x[1]; + s[2] = x[2]; + s[3] = x[3]; + + for (i = 0; i < buf.length; i += 1) { + this._buffer8[i] = buf.charCodeAt(i); + } + } + + public end(raw: boolean = false) { + const bufLen = this._bufferLength; + const buf8 = this._buffer8; + const buf32 = this._buffer32; + const i = (bufLen >> 2) + 1; + let dataBitsLen; + + this._dataLength += bufLen; + + buf8[bufLen] = 0x80; + buf8[bufLen + 1] = buf8[bufLen + 2] = buf8[bufLen + 3] = 0; + buf32.set(Md5.buffer32Identity.subarray(i), i); + + if (bufLen > 55) { + Md5._md5cycle(this._state, buf32); + buf32.set(Md5.buffer32Identity); + } + + // Do the final computation based on the tail and length + // Beware that the final length may not fit in 32 bits so we take care of that + dataBitsLen = this._dataLength * 8; + if (dataBitsLen <= 0xFFFFFFFF) { + buf32[14] = dataBitsLen; + } else { + const matches = dataBitsLen.toString(16).match(/(.*?)(.{0,8})$/); + if (matches === null) { + return; + } + + const lo = parseInt(matches[2], 16); + const hi = parseInt(matches[1], 16) || 0; + + buf32[14] = lo; + buf32[15] = hi; + } + + Md5._md5cycle(this._state, buf32); + + return raw ? this._state : Md5._hex(this._state); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/DataSrc.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/DataSrc.ets new file mode 100644 index 0000000..60ad54b --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/DataSrc.ets @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** Indicates the origin of some retrieved data. */ + +export enum DataSrc { + + /** + * Indicates data was probably retrieved locally from the device, although it may have been + * obtained through a content provider that may have obtained the data from a remote source. + */ + + LOCAL, + + /** Indicates data was retrieved from a remote source other than the device. */ + + REMOTE, + + /** Indicates data was retrieved unmodified from the on device cache. */ + + DATA_DISK_CACHE, + + /** Indicates data was retrieved from modified content in the on device cache. */ + + RESOURCE_DISK_CACHE, + + /** Indicates data was retrieved from the in memory cache. */ + + MEMORY_CACHE, +} diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/DiskStrategy.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/DiskStrategy.ets new file mode 100644 index 0000000..932f078 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/DiskStrategy.ets @@ -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; +} + + diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/EncodeStrategy.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/EncodeStrategy.ets new file mode 100644 index 0000000..780c9ec --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/EncodeStrategy.ets @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +export enum EncodeStrategy { + + /** + * Writes the original unmodified data for the resource to disk, not include downsampling or + * transformations. + */ + + SOURCE, + + /** Writes the decoded, downsampled and transformed data for the resource to disk. */ + + TRANSFORMED, + + /** Will write no data. */ + + NONE, +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/ALL.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/ALL.ets new file mode 100644 index 0000000..8086159 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/ALL.ets @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class ALL implements DiskStrategy { + getName(): string{ + return 'ALL'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return dataSource == DataSrc.REMOTE; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return ((isFromAlternateCacheKey && dataSource == DataSrc.DATA_DISK_CACHE) + || dataSource == DataSrc.LOCAL) + && encodeStrategy == EncodeStrategy.TRANSFORMED; + } + + decodeCachedResource(): boolean { + return true; + } + + decodeCachedData(): boolean{ + return true; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/AUTOMATIC.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/AUTOMATIC.ets new file mode 100644 index 0000000..a1c4305 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/AUTOMATIC.ets @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class AUTOMATIC implements DiskStrategy { + getName(): string{ + return 'AUTOMATIC'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return dataSource == DataSrc.REMOTE; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return ((isFromAlternateCacheKey && dataSource == DataSrc.DATA_DISK_CACHE) + || dataSource == DataSrc.LOCAL) + && encodeStrategy == EncodeStrategy.TRANSFORMED; + } + + decodeCachedResource(): boolean { + return true; + } + + decodeCachedData(): boolean{ + return true; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/DATA.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/DATA.ets new file mode 100644 index 0000000..9e86616 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/DATA.ets @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class DATA implements DiskStrategy { + getName(): string{ + return 'DATA'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return dataSource != DataSrc.DATA_DISK_CACHE && dataSource != DataSrc.MEMORY_CACHE; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return false; + } + + decodeCachedResource(): boolean { + return false; + } + + decodeCachedData(): boolean{ + return true; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/NONE.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/NONE.ets new file mode 100644 index 0000000..25e6757 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/NONE.ets @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class NONE implements DiskStrategy { + getName(): string{ + return 'NONE'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return false; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return false; + } + + decodeCachedResource(): boolean { + return false; + } + + decodeCachedData(): boolean{ + return false; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/RESOURCE.ets b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/RESOURCE.ets new file mode 100644 index 0000000..928a029 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/diskstrategy/enum/RESOURCE.ets @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import{DiskStrategy} from '../../diskstrategy/DiskStrategy' +import{DataSrc} from '../../diskstrategy/DataSrc' +import{EncodeStrategy} from '../../diskstrategy/EncodeStrategy' + +export class RESOURCE implements DiskStrategy { + getName(): string{ + return 'RESOURCE'; + } + + isDataCacheable(dataSource: DataSrc): boolean { + return false; + } + + isResourceCacheable( + isFromAlternateCacheKey: boolean, dataSource: DataSrc, encodeStrategy: EncodeStrategy): boolean { + return dataSource != DataSrc.RESOURCE_DISK_CACHE + && dataSource != DataSrc.MEMORY_CACHE; + } + + decodeCachedResource(): boolean { + return true; + } + + decodeCachedData(): boolean{ + return false; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/cache/key/EngineKey.ets b/entry/src/main/ets/MainAbility/cache/key/EngineKey.ets new file mode 100644 index 0000000..c6bc708 --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/key/EngineKey.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {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) { + + } +} diff --git a/entry/src/main/ets/MainAbility/cache/key/EngineKeyFactories.ets b/entry/src/main/ets/MainAbility/cache/key/EngineKeyFactories.ets new file mode 100644 index 0000000..23ec9ac --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/key/EngineKeyFactories.ets @@ -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() + } +} + + + diff --git a/entry/src/main/ets/MainAbility/cache/key/Key.ets b/entry/src/main/ets/MainAbility/cache/key/Key.ets new file mode 100644 index 0000000..5f17ffb --- /dev/null +++ b/entry/src/main/ets/MainAbility/cache/key/Key.ets @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export interface Key { + + /** + * Adds all uniquely identifying information to the given digest. + * + *

Note - Using {@link MessageDigest#reset()} inside of this method will result + * in undefined behavior. + * @param messageDigest + */ + updateDiskCacheKey(info: Object); + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/Glide.ets b/entry/src/main/ets/MainAbility/glide/Glide.ets new file mode 100644 index 0000000..48291b4 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/Glide.ets @@ -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; + private diskMemoryCache: DiskLruCache; + private dataFetch: IDataFetch; + private resourceFetch: IResourceFetch; + private filesPath: string = ""; // data/data/包名/files目录 + + + private placeholderCache: string = "placeholderCache" + private runningRequest: Array; + private pendingRequest: Array; + private fileTypeUtil: FileTypeUtil; // 通用文件格式辨别 + private svgAndGifFolder: string = "svgAndGifFolder"; // svg和gif的文件路径地址 + private svgAndGifCommitFile: string = "svgAndGifCommitFile" // svg和gif提交记录 + + private defaultListener:AsyncCallback; // 全局监听器 + + getMemoryCache(): LruCache{ + return this.memoryCache; + } + + setMemoryCache(lrucache: LruCache){ + this.memoryCache = lrucache; + } + + getDiskMemoryCache(): DiskLruCache{ + return this.diskMemoryCache; + }; + + setDiskMemoryCache(diskLruCache: DiskLruCache) { + this.diskMemoryCache = diskLruCache; + }; + + getFileTypeUtil(): FileTypeUtil{ + return this.fileTypeUtil; + } + + + + getSvgAndGifFolder(): string{ + return this.svgAndGifFolder; + } + + setSvgAndGifFolder(folderPath: string){ + this.svgAndGifFolder = folderPath; + } + + getDefaultListener(){ + return this.defaultListener; + } + + setDefaultListener(newDefaultListener:AsyncCallback){ + this.defaultListener = newDefaultListener; + } + + private constructor() { + + // 构造方法传入size 为保存文件个数 + this.memoryCache = new LruCache(100); + + // 创建disk缓存 传入的size 为多少比特 比如20KB 传入20*1024 + this.diskMemoryCache = new DiskLruCache(30 * 1024 * 1024); + + // 创建网络下载能力 + this.dataFetch = new DownloadClient(); + + // 创建本地数据解析能力 + this.resourceFetch = new ParseResClient(); + + // 初始化本地 文件保存 + featureAbility.getContext() + .getFilesDir() + .then((data) => { + this.filesPath = data + this.initSvgAndGifEnvironment(); + }) + .catch((error) => { + console.error('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(size); + }else{ + let newLruCache = new LruCache(size); + this.memoryCache.foreachLruCache(function (value, key, map) { + newLruCache.put(key, value); + }) + this.memoryCache = newLruCache; + } + } + + public replaceDataFetch(fetch:IDataFetch){ + this.dataFetch = fetch; + } + + // 替代原来的DiskLruCache + public replaceDiskLruCache(size:number){ + this.diskMemoryCache = new DiskLruCache(size); + + if(this.diskMemoryCache.cacheMap.size() <= 0) { + this.diskMemoryCache = new DiskLruCache(size); + }else{ + let newDiskLruCache = new DiskLruCache(size); + this.diskMemoryCache.foreachDiskLruCache(function (value, key, map) { + newDiskLruCache.putCacheData(key, value, null); + }) + this.diskMemoryCache = newDiskLruCache; + } + } + + // 预加载 resource资源一级缓存,string资源实现二级缓存 + preload(request: RequestOption) { + // 每个request 公共信息补充 + request.setFilesPath(this.filesPath); + // svg特殊处理 + request._svgAndGifFolder = this.svgAndGifFolder; + request._svgAndGifCommitFile = this.svgAndGifCommitFile; + return this.parseSource(request); + } + + // 正常加载 + call(request: RequestOption) { + console.log("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("输入参数有问题!") + } + } + } +} + + + diff --git a/entry/src/main/ets/MainAbility/glide/GlideData.ets b/entry/src/main/ets/MainAbility/glide/GlideData.ets new file mode 100644 index 0000000..73cb56c --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/GlideData.ets @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class 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(); + } + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/GlideImage.ets b/entry/src/main/ets/MainAbility/glide/GlideImage.ets new file mode 100644 index 0000000..b142c97 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/GlideImage.ets @@ -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; +} diff --git a/entry/src/main/ets/MainAbility/glide/GlideOption.ets b/entry/src/main/ets/MainAbility/glide/GlideOption.ets new file mode 100644 index 0000000..39bc1de --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/GlideOption.ets @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {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> = 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() { + + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/PixelMapPack.ets b/entry/src/main/ets/MainAbility/glide/PixelMapPack.ets new file mode 100644 index 0000000..c8b8dbc --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/PixelMapPack.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class PixelMapPack { + pixelMap:PixelMap +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/RequestOption.ets b/entry/src/main/ets/MainAbility/glide/RequestOption.ets new file mode 100644 index 0000000..ec8c455 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/RequestOption.ets @@ -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; + errorholderSrc: PixelMap | Resource; + errorholderFunc: AsyncSuccess; + errorholderData: GlideData; + thumbSizeMultiplier: number; + + // 如果存在缩略图,则主图延时3000ms加载 + thumbDelayTime: number = 3000 + thumbholderFunc: AsyncSuccess; + requestListeners: Array>; + + // 进度条 + progressFunc: AsyncSuccess; + + // 重试图层 + retryFunc: AsyncSuccess + + // 图层切换时长 + animateDuraction: number = 500; + size: { + width: number, + height: number + } = { width: -1, height: -1 }; + + // 网络下载数据回调 + allCacheInfoCallback: IAllCacheInfoCallback; + onlyRetrieveFromCache: boolean = false; + isCacheable: boolean = true; + + // 变换相关 + transformtions: Array> = 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) { + this.placeholderSrc = src; + this.placeholderFunc = func; + return this; + } + + errorholder(src: PixelMap | Resource, func?: AsyncSuccess) { + this.errorholderSrc = src; + this.errorholderFunc = func; + return this; + } + + thumbnail(sizeMultiplier: number, func?: AsyncSuccess) { + this.thumbSizeMultiplier = sizeMultiplier; + this.thumbholderFunc = func; + return this; + } + + addProgressListener(func?: AsyncSuccess) { + this.progressFunc = func; + return this; + } + + addRetryListener(func?: AsyncSuccess) { + this.retryFunc = func; + return this; + } + + addListener(func: AsyncCallback) { + this.requestListeners.push(func); + return this; + } + + addAllCacheInfoCallback(func: IAllCacheInfoCallback) { + this.allCacheInfoCallback = func; + return this; + } + + skipMemoryCache(skip: boolean) { + this.isCacheable = !skip; + return this; + } + + retrieveDataFromCache(flag: boolean) { + this.onlyRetrieveFromCache = flag; + } + + rotateImage(degreesToRotate: number) { + let rotateImage = new RotateImageTransformation(degreesToRotate); + this.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) { + this.transformtions.push(transform); + return this; + } + + transforms(transforms: BaseTransform[]) { + 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; +} diff --git a/entry/src/main/ets/MainAbility/glide/compress/CompressBuilder.ets b/entry/src/main/ets/MainAbility/glide/compress/CompressBuilder.ets new file mode 100644 index 0000000..7fbda9d --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/CompressBuilder.ets @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {OnRenameListener} from '../compress/listener/OnRenameListener.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; + private _mFocusAlpha: boolean; + private _outFilePath: string; + constructor() { + this._mStreamProviders = new Array(); + } + + public setRenameListener(listener: OnRenameListener): CompressBuilder { + this._mRenameListener = listener; + return this; + } + + public setCompressListener(listener: OnCompressListener): CompressBuilder { + this._mCompressListener = listener; + return this; + } + + public filter(compressionPredicate: CompressionPredicate): CompressBuilder { + this._mCompressionPredicate = compressionPredicate; + return this; + } + + public setTargetDir(targetDir: string): CompressBuilder { + this._mTargetDir = targetDir; + if (this._mTargetDir) { + var timestamp = (new Date()).valueOf(); + this._outFilePath = this._mTargetDir + "/" + timestamp + (Math.random() * 100).toFixed(0) + ".jpg"; + } + return this; + } + + public load(list: Array): CompressBuilder { + for (var i = 0; i < list.length; i++) { + let element = list[i]; + if (typeof element === "string") { + this.loadString(element); + } else { + this.loadRecourse(element) + } + } + return this; + } + + /** + * load string file path; + */ + private loadString(path: string) { + this._mStreamProviders.push(new DataStringPathProvider(path)); + } + + /** + * load resource; + */ + private loadRecourse(data: Resource) { + this._mStreamProviders.push(new RecourseProvider(data)); + } + + public setFocusAlpha(focusAlpha: boolean): CompressBuilder { + this._mFocusAlpha = focusAlpha; + return this; + } + + public ignoreBy(size: number): CompressBuilder { + this._mLeastCompressSize = size; + return this; + } + + public launch() { + if (!this._mTargetDir) { + this.getImageCacheFile(); + } else { + this.startCompress(); + } + } + + public async get():Promise { + if (!this._mTargetDir) { + let path = await featureability.getContext().getFilesDir(); + var timestamp = (new Date()).valueOf(); + this._outFilePath = path + "/compress/" + timestamp + (Math.random() * 100).toFixed(0) + ".jpg"; + let result =await this.startAsyncCompress(); + return result; + } else { + let result =await this.startAsyncCompress(); + return result; + } + } + + private async startAsyncCompress():Promise { + let compressPromise = new Promise((resolve, reject) => { + + let compressListener: OnCompressListener = { + start() { + }, + onScuccess(p: PixelMap, path: string) { + resolve(path); + }, + onError(s: string) { + } + } + + compressListener.start(); + + if (this._mStreamProviders == null || this._mStreamProviders.length == 0) { + compressListener.onError("this compress path is empty"); + return; + } + + for (var i = 0; i < this._mStreamProviders.length; i++) { + let element = this._mStreamProviders[i]; + let isOpenfilter = false; + if (this._mCompressionPredicate) { + isOpenfilter = this._mCompressionPredicate.apply(element.getRecoursePath()); + } + + + if (!isOpenfilter) { + new Engine(element, this._outFilePath, this._mFocusAlpha, this._mLeastCompressSize, + compressListener, this._mCompressionPredicate).compress(); + } else { + resolve(element.getRecoursePath()); + } + } + + }) + let result = await compressPromise + return (result as string) + } + + + /** + * start compress + */ + private startCompress() { + if (this._mStreamProviders == null || this._mStreamProviders.length == 0) { + if (this._mCompressListener) { + this._mCompressListener.onError("this compress path is empty"); + } + return; + } + if (this._mRenameListener) { + var name = this._mRenameListener.reName(); + if (this._outFilePath && name) { + var start = this._outFilePath.lastIndexOf("/") + 1 + var end = this._outFilePath.length; + var replaceStr = this._outFilePath.substring(start, end); + this._outFilePath = this._outFilePath.replace(replaceStr, name); + } + } + if (this._mCompressListener) { + this._mCompressListener.start(); + } + + for (var i = 0; i < this._mStreamProviders.length; i++) { + let element = this._mStreamProviders[i]; + let isOpenfilter = false; + if (this._mCompressionPredicate) { + isOpenfilter = this._mCompressionPredicate.apply(element.getRecoursePath()); + } + if (!isOpenfilter) { + new Engine(element, this._outFilePath, this._mFocusAlpha, this._mLeastCompressSize, + this._mCompressListener, this._mCompressionPredicate).compress(); + } else { + if (this._mCompressListener) { + this._mCompressListener.onScuccess(null, element.getRecoursePath()); + } + } + } + } + + private getImageCacheFile() { + featureability.getContext() + .getFilesDir() + .then(path => { + var timestamp = (new Date()).valueOf(); + this._outFilePath = path + "/compress/" + timestamp + (Math.random() * 100).toFixed(0) + ".jpg"; + this.startCompress(); + }) + .catch(error => { + throw new Error("getImageCacheFile happened error:" + JSON.stringify(error)); + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/Engine.ets b/entry/src/main/ets/MainAbility/glide/compress/Engine.ets new file mode 100644 index 0000000..e0ccfbf --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/Engine.ets @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {OnCompressListener} from '../compress/listener/OnCompressListener.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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/listener/CompressDataListener.ets b/entry/src/main/ets/MainAbility/glide/compress/listener/CompressDataListener.ets new file mode 100644 index 0000000..fc072f7 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/listener/CompressDataListener.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface CompressDataListener { + (t: T); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/listener/CompressionPredicate.ets b/entry/src/main/ets/MainAbility/glide/compress/listener/CompressionPredicate.ets new file mode 100644 index 0000000..79bec3c --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/listener/CompressionPredicate.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * filter out unsupported + */ +export interface CompressionPredicate { + apply(path: string): boolean; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/listener/OnCompressListener.ets b/entry/src/main/ets/MainAbility/glide/compress/listener/OnCompressListener.ets new file mode 100644 index 0000000..87b40d7 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/listener/OnCompressListener.ets @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * compress listener + */ +export interface OnCompressListener { + /** + * compress start + */ + start(); + /** + * compress success + */ + onScuccess(p: PixelMap, path: string); + /** + * compress fail + */ + onError(s: string); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/listener/OnRenameListener.ets b/entry/src/main/ets/MainAbility/glide/compress/listener/OnRenameListener.ets new file mode 100644 index 0000000..5be73d7 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/listener/OnRenameListener.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * rename listener + */ +export interface OnRenameListener { + reName():string; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/provider/CompressAdapter.ets b/entry/src/main/ets/MainAbility/glide/compress/provider/CompressAdapter.ets new file mode 100644 index 0000000..3c481bc --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/provider/CompressAdapter.ets @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {CompressProvider} from "../provider/CompressProvider.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); + + abstract getRecoursePath(): string; + + abstract getPixelMapFormat(): PixelMapFormat; + + getFormat(s: string): PixelMapFormat{ + if (!s) { + return undefined; + } + if (s == "jpg" || s == "JPG") { + return PixelMapFormat.JPG; + } else if (s == "png" || s == "PNG") { + return PixelMapFormat.PNG; + } else if (s == "jpeg" || s == "JPEG") { + return PixelMapFormat.JPEG; + } else if (s == "gif" || s == "GIF") { + return PixelMapFormat.GIF; + } else if (s == "webp" || s == "WEBP" || s == "WebP") { + return PixelMapFormat.WEBP; + } else if (s == "bmg" || s == "BMG") { + return PixelMapFormat.BMG; + } else { + return PixelMapFormat.NONE; + } + } +} + +export enum PixelMapFormat { + JPG, + PNG, + JPEG, + WEBP, + BMG, + GIF, + NONE +} + diff --git a/entry/src/main/ets/MainAbility/glide/compress/provider/CompressProvider.ets b/entry/src/main/ets/MainAbility/glide/compress/provider/CompressProvider.ets new file mode 100644 index 0000000..6b74795 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/provider/CompressProvider.ets @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface CompressProvider { + close(); + + openData():ArrayBuffer; + + getPath(): string; + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/provider/DataStringPathProvider.ets b/entry/src/main/ets/MainAbility/glide/compress/provider/DataStringPathProvider.ets new file mode 100644 index 0000000..e40b67a --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/provider/DataStringPathProvider.ets @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {CompressAdapter, PixelMapFormat} from '../provider/CompressAdapter.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) { + if (!this.mPath) { + throw new Error('DataStringPathProvider error path is empty'); + } + var buffer = FileUtils.getInstance().readFilePic(this.mPath); + this.mData = buffer; + if (callback) { + callback(buffer); + } + } + + getPixelMapFormat(): PixelMapFormat{ + if (!this.mPath) { + return PixelMapFormat.NONE; + } + let lastIndex = this.mPath.lastIndexOf('/') + let s = this.mPath.substring(lastIndex + 1, this.mPath.length); + return this.getFormat(s); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/compress/provider/RecourseProvider.ets b/entry/src/main/ets/MainAbility/glide/compress/provider/RecourseProvider.ets new file mode 100644 index 0000000..ff5f6aa --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/compress/provider/RecourseProvider.ets @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {CompressAdapter, PixelMapFormat} from "../provider/CompressAdapter.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) { + console.info("asasd compress openInternal _mData"); + if (!this._mResourceData) { + throw Error("compress resource is empty"); + } + resmgr.getResourceManager() + .then(result => { + result.getMedia(this._mResourceData + .id) + .then(data => { + let buffer = this.uint8ArrayToBuffer(data); + let fileTypeUtil = new FileTypeUtil() + this._mPixelMapHeader = fileTypeUtil.getFileType(buffer); + callback(buffer); + }) + .catch(err => { + console.log("RecourseProvider openInternal err" + JSON.stringify(err)); + }) + }) + } + + getPixelMapFormat(): PixelMapFormat{ + if (!this._mPixelMapHeader) { + return PixelMapFormat.NONE; + } + return this.getFormat(this._mPixelMapHeader); + } + /** + * data decode + */ + decode(base64: string, callback: CompressDataListener) { + let bufferLength = base64.length, + len = base64.length, + i, + p = 0, + encoded1, + encoded2, + encoded3, + encoded4; + + if (base64[base64.length - 1] === '=') { + bufferLength--; + if (base64[base64.length - 2] === '=') { + bufferLength--; + } + } + + const arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i += 4) { + encoded1 = this._mLookup[base64.charCodeAt(i)]; + encoded2 = this._mLookup[base64.charCodeAt(i + 1)]; + encoded3 = this._mLookup[base64.charCodeAt(i + 2)]; + encoded4 = this._mLookup[base64.charCodeAt(i + 3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + + } + this.mData = arraybuffer; + if (callback) { + callback(arraybuffer); + } + } + + uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/constants/Constants.ets b/entry/src/main/ets/MainAbility/glide/constants/Constants.ets new file mode 100644 index 0000000..15c575f --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/constants/Constants.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class Constants { + public static PROJECT_TAG: string= "Glide_js" +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/constants/ResourceTypeEts.ets b/entry/src/main/ets/MainAbility/glide/constants/ResourceTypeEts.ets new file mode 100644 index 0000000..5c3fdee --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/constants/ResourceTypeEts.ets @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export enum ResourceTypeEts { + COLOR = 10001, + FLOAT, + STRING, + PLURAL, + BOOLEAN, + INTARRAY, + INTEGER, + PATTERN, + STRARRAY, + MEDIA = 20000, + RAWFILE = 30000 +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/crop/Crop.ets b/entry/src/main/ets/MainAbility/glide/crop/Crop.ets new file mode 100644 index 0000000..b6e3114 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/crop/Crop.ets @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {AsyncTransform} from "../transform/AsyncTransform.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, 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) { + if (!data) { + func("colorRatio pixelMap is null", null); + return; + } + if (colorRatio > 1) { + throw new Error("the colorRatio must be <= 1"); + } + var buffer = new ArrayBuffer(width * height * 5); + var bytes = new Uint8Array(buffer); + var buffer1B = new ArrayBuffer(width * height * 5); + var bytes1B = new Uint8Array(buffer1B); + + let readPromise = data.readPixelsToBuffer(buffer) + await readPromise; + for (let i = 0;i < bytes.length; i++) { + bytes1B[i] = bytes[i] * colorRatio; + } + let writePromise = data.writeBufferToPixels(buffer1B) + await writePromise; + func("", data); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/crop/CropImage.ets b/entry/src/main/ets/MainAbility/glide/crop/CropImage.ets new file mode 100644 index 0000000..502676c --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/crop/CropImage.ets @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {CropOptions} from "../crop/CropOptions.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); + } +} diff --git a/entry/src/main/ets/MainAbility/glide/crop/CropOptions.ets b/entry/src/main/ets/MainAbility/glide/crop/CropOptions.ets new file mode 100644 index 0000000..37e0214 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/crop/CropOptions.ets @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class CropOptions { + src: string | PixelMap | Resource; + size: { + width: number, + height: number; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/entry/ArcPoint.ets b/entry/src/main/ets/MainAbility/glide/entry/ArcPoint.ets new file mode 100644 index 0000000..1754f7f --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/entry/ArcPoint.ets @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class ArcPoint { + private x: number; + private y: number; + + constructor(x: number, y: number) { + this.y = y; + this.x = x; + } + + getX(): number{ + return this.x; + } + + getY(): number{ + return this.y + } +} diff --git a/entry/src/main/ets/MainAbility/glide/entry/PixelEntry.ets b/entry/src/main/ets/MainAbility/glide/entry/PixelEntry.ets new file mode 100644 index 0000000..72dd1c9 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/entry/PixelEntry.ets @@ -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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/holder/ErrorHolderManager.ets b/entry/src/main/ets/MainAbility/glide/holder/ErrorHolderManager.ets new file mode 100644 index 0000000..db630a6 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/holder/ErrorHolderManager.ets @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {RequestOption} from "../../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 输入参数有问题!") + } + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/holder/PlaceHolderManager.ets b/entry/src/main/ets/MainAbility/glide/holder/PlaceHolderManager.ets new file mode 100644 index 0000000..680ad77 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/holder/PlaceHolderManager.ets @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {RequestOption} from "../../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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/interface/AsyncCallback.ets b/entry/src/main/ets/MainAbility/glide/interface/AsyncCallback.ets new file mode 100644 index 0000000..0097fc0 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/interface/AsyncCallback.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface AsyncCallback { + (err: string, data: T): boolean; +} diff --git a/entry/src/main/ets/MainAbility/glide/interface/AsyncSuccess.ets b/entry/src/main/ets/MainAbility/glide/interface/AsyncSuccess.ets new file mode 100644 index 0000000..816e3d4 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/interface/AsyncSuccess.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface AsyncSuccess { + (data: T); +} diff --git a/entry/src/main/ets/MainAbility/glide/interface/DataCallBack.ets b/entry/src/main/ets/MainAbility/glide/interface/DataCallBack.ets new file mode 100644 index 0000000..0ccd3ba --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/interface/DataCallBack.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface DataCallBack { + callback(data: T); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/interface/IAllCacheInfoCallback.ets b/entry/src/main/ets/MainAbility/glide/interface/IAllCacheInfoCallback.ets new file mode 100644 index 0000000..d50ddbf --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/interface/IAllCacheInfoCallback.ets @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {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); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/interface/IParseImage.ets b/entry/src/main/ets/MainAbility/glide/interface/IParseImage.ets new file mode 100644 index 0000000..96024a4 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/interface/IParseImage.ets @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface IParseImage { + parseImage(imageinfo:ArrayBuffer, onCompleteFunction, onErrorFunction); + parseImageThumbnail(scale:number, imageinfo:ArrayBuffer, onCompleteFunction, onErrorFunction); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/networkmanage/DownloadClient.ets b/entry/src/main/ets/MainAbility/glide/networkmanage/DownloadClient.ets new file mode 100644 index 0000000..4bccd1f --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/networkmanage/DownloadClient.ets @@ -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加载") + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/networkmanage/IDataFetch.ets b/entry/src/main/ets/MainAbility/glide/networkmanage/IDataFetch.ets new file mode 100644 index 0000000..1900c36 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/networkmanage/IDataFetch.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {RequestOption} from "../RequestOption.ets" + +// 网络接口 +export interface IDataFetch { + loadData(request: RequestOption, onCompleteFunction, onErrorFunction); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/networkmanage/SimulatedDownloadClient.ets b/entry/src/main/ets/MainAbility/glide/networkmanage/SimulatedDownloadClient.ets new file mode 100644 index 0000000..c652cdf --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/networkmanage/SimulatedDownloadClient.ets @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {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) + + + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/PngReader.ets b/entry/src/main/ets/MainAbility/glide/pngj/PngReader.ets new file mode 100644 index 0000000..4ffb053 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/PngReader.ets @@ -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 { + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/Pngj.ets b/entry/src/main/ets/MainAbility/glide/pngj/Pngj.ets new file mode 100644 index 0000000..47e6203 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/Pngj.ets @@ -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); + } + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/PngjException.ets b/entry/src/main/ets/MainAbility/glide/pngj/PngjException.ets new file mode 100644 index 0000000..36b37a1 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/PngjException.ets @@ -0,0 +1,5 @@ +export class PngjException extends Error { + constructor(s: string) { + super(s) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/UPNG.js b/entry/src/main/ets/MainAbility/glide/pngj/UPNG.js new file mode 100644 index 0000000..b6468ed --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/UPNG.js @@ -0,0 +1,1907 @@ +/** +* MIT License +* +*Copyright (c) 2017 Photopea +* +*Permission is hereby granted, free of charge, to any person obtaining a copy +*of this software and associated documentation files (the 'Software'), to deal +*in the Software without restriction, including without limitation the rights +*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +*copies of the Software, and to permit persons to whom the Software is +*furnished to do so, subject to the following conditions: +* +*The above copyright notice and this permission notice shall be included in all +*copies or substantial portions of the Software. +* +*THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +*SOFTWARE.*/ +const pako = require('pako'); +const UZIP = null; + +export { + UPNG +} + +var UPNG = {}; + + +UPNG.toRGBA8 = function (out) { + var w = out.width, h = out.height; + if (out.tabs.acTL == null) return [UPNG.toRGBA8.decodeImage(out.data, w, h, out).buffer]; + + var frms = []; + if (out.frames[0].data == null) out.frames[0].data = out.data; + + var len = w * h * 4, img = new Uint8Array(len), empty = new Uint8Array(len), prev = new Uint8Array(len); + for (var i = 0; i < out.frames.length; i++) { + var frm = out.frames[i]; + var fx = frm.rect.x, fy = frm.rect.y, fw = frm.rect.width, fh = frm.rect.height; + var fdata = UPNG.toRGBA8.decodeImage(frm.data, fw, fh, out); + + if (i != 0) for (var j = 0; j < len; j++) prev[j] = img[j]; + + if (frm.blend == 0) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 0); + else if (frm.blend == 1) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 1); + + frms.push(img.buffer.slice(0)); + + if (frm.dispose == 0) { + } + else if (frm.dispose == 1) UPNG._copyTile(empty, fw, fh, img, w, h, fx, fy, 0); + else if (frm.dispose == 2) for (var j = 0; j < len; j++) img[j] = prev[j]; + } + return frms; +} +UPNG.toRGBA8.decodeImage = function (data, w, h, out) { + var area = w * h, bpp = UPNG.decode._getBPP(out); + var bpl = Math.ceil(w * bpp / 8); // bytes per line + + var bf = new Uint8Array(area * 4), bf32 = new Uint32Array(bf.buffer); + var ctype = out.ctype, depth = out.depth; + var rs = UPNG._bin.readUshort; + + var time = Date.now(); + + if (ctype == 6) { // RGB + alpha + var qarea = area << 2; + if (depth == 8) for (var i = 0; i < qarea; i += 4) { + bf[i] = data[i]; + bf[i+1] = data[i+1]; + bf[i+2] = data[i+2]; + bf[i+3] = data[i+3]; + } + if (depth == 16) for (var i = 0; i < qarea; i++) { + bf[i] = data[i<<1]; + } + } + else if (ctype == 2) { // RGB + var ts = out.tabs['tRNS']; + if (ts == null) { + if (depth == 8) for (var i = 0; i < area; i++) { + var ti = i * 3; + bf32[i] = (255 << 24) | (data[ti+2] << 16) | (data[ti+1] << 8) | data[ti]; + } + if (depth == 16) for (var i = 0; i < area; i++) { + var ti = i * 6; + bf32[i] = (255 << 24) | (data[ti+4] << 16) | (data[ti+2] << 8) | data[ti]; + } + } + else { + var tr = ts[0], tg = ts[1], tb = ts[2]; + if (depth == 8) for (var i = 0; i < area; i++) { + var qi = i << 2, ti = i * 3; + bf32[i] = (255 << 24) | (data[ti+2] << 16) | (data[ti+1] << 8) | data[ti]; + if (data[ti] == tr && data[ti+1] == tg && data[ti+2] == tb) bf[qi+3] = 0; + } + if (depth == 16) for (var i = 0; i < area; i++) { + var qi = i << 2, ti = i * 6; + bf32[i] = (255 << 24) | (data[ti+4] << 16) | (data[ti+2] << 8) | data[ti]; + if (rs(data, ti) == tr && rs(data, ti + 2) == tg && rs(data, ti + 4) == tb) bf[qi+3] = 0; + } + } + } + else if (ctype == 3) { // palette + var p = out.tabs['PLTE'], ap = out.tabs['tRNS'], tl = ap ? ap.length : 0; + if (depth == 1) for (var y = 0; y < h; y++) { + var s0 = y * bpl, t0 = y * w; + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, j = ((data[s0+(i >> 3)] >> (7 - ((i & 7) << 0))) & 1), cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + if (depth == 2) for (var y = 0; y < h; y++) { + var s0 = y * bpl, t0 = y * w; + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, j = ((data[s0+(i >> 2)] >> (6 - ((i & 3) << 1))) & 3), cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + if (depth == 4) for (var y = 0; y < h; y++) { + var s0 = y * bpl, t0 = y * w; + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, j = ((data[s0+(i >> 1)] >> (4 - ((i & 1) << 2))) & 15), cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + if (depth == 8) for (var i = 0; i < area; i++) { + var qi = i << 2, j = data[i], cj = 3 * j; + bf[qi] = p[cj]; + bf[qi+1] = p[cj+1]; + bf[qi+2] = p[cj+2]; + bf[qi+3] = (j < tl) ? ap[j] : 255; + } + } + else if (ctype == 4) { // gray + alpha + if (depth == 8) for (var i = 0; i < area; i++) { + var qi = i << 2, di = i << 1, gr = data[di]; + bf[qi] = gr; + bf[qi+1] = gr; + bf[qi+2] = gr; + bf[qi+3] = data[di+1]; + } + if (depth == 16) for (var i = 0; i < area; i++) { + var qi = i << 2, di = i << 2, gr = data[di]; + bf[qi] = gr; + bf[qi+1] = gr; + bf[qi+2] = gr; + bf[qi+3] = data[di+2]; + } + } + else if (ctype == 0) { // gray + var tr = out.tabs['tRNS'] ? out.tabs['tRNS'] : -1; + for (var y = 0; y < h; y++) { + var off = y * bpl, to = y * w; + if (depth == 1) for (var x = 0; x < w; x++) { + var gr = 255 * ((data[off+(x >>> 3)] >>> (7 - ((x & 7)))) & 1), al = (gr == tr * 255) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 2) for (var x = 0; x < w; x++) { + var gr = 85 * ((data[off+(x >>> 2)] >>> (6 - ((x & 3) << 1))) & 3), al = (gr == tr * 85) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 4) for (var x = 0; x < w; x++) { + var gr = 17 * ((data[off+(x >>> 1)] >>> (4 - ((x & 1) << 2))) & 15), al = (gr == tr * 17) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 8) for (var x = 0; x < w; x++) { + var gr = data[off+ x], al = (gr == tr) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + else if (depth == 16) for (var x = 0; x < w; x++) { + var gr = data[off+(x << 1)], al = (rs(data, off + (x << 1)) == tr) ? 0 : 255; + bf32[to+x] = (al << 24) | (gr << 16) | (gr << 8) | gr; + } + } + } + + return bf; +} + + +UPNG.decode = function (buff) { + var data = new Uint8Array(buff), offset = 8, bin = UPNG._bin, rUs = bin.readUshort, rUi = bin.readUint; + var out = { tabs: {}, frames: [] }; + var dd = new Uint8Array(data.length), doff = 0; // put all IDAT data into it + var fd, foff = 0; // frames + + var mgck = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; + for (var i = 0; i < 8; i++) if (data[i] != mgck[i]) throw 'The input is not a PNG file!'; + + while (offset < data.length) { + var len = bin.readUint(data, offset); + offset += 4; + var type = bin.readASCII(data, offset, 4); + offset += 4; + + + if (type == 'IHDR') { + UPNG.decode._IHDR(data, offset, out); + } + else if (type == 'CgBI') { + out.tabs[type] = data.slice(offset, offset + 4); + } + else if (type == 'IDAT') { + for (var i = 0; i < len; i++) dd[doff+i] = data[offset+i]; + doff += len; + } + else if (type == 'acTL') { + out.tabs[type] = { num_frames: rUi(data, offset), num_plays: rUi(data, offset + 4) }; + fd = new Uint8Array(data.length); + } + else if (type == 'fcTL') { + if (foff != 0) { + var fr = out.frames[out.frames.length-1]; + fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height); + foff = 0; + } + var rct = { + x: rUi(data, offset + 12), + y: rUi(data, offset + 16), + width: rUi(data, offset + 4), + height: rUi(data, offset + 8) + }; + var del = rUs(data, offset + 22); + del = rUs(data, offset + 20) / (del == 0 ? 100 : del); + var frm = { rect: rct, delay: Math.round(del * 1000), dispose: data[offset+24], blend: data[offset+25] }; + + out.frames.push(frm); + } + else if (type == 'fdAT') { + for (var i = 0; i < len - 4; i++) fd[foff+i] = data[offset + i+4]; + foff += len - 4; + } + else if (type == 'pHYs') { + out.tabs[type] = [bin.readUint(data, offset), bin.readUint(data, offset + 4), data[offset+8]]; + } + else if (type == 'cHRM') { + out.tabs[type] = []; + for (var i = 0; i < 8; i++) out.tabs[type].push(bin.readUint(data, offset + i * 4)); + } + else if (type == 'tEXt' || type == 'zTXt') { + if (out.tabs[type] == null) out.tabs[type] = {}; + var nz = bin.nextZero(data, offset); + var keyw = bin.readASCII(data, offset, nz - offset); + var text, tl = offset + len - nz - 1; + if (type == 'tEXt') text = bin.readASCII(data, nz + 1, tl); + else { + var bfr = UPNG.decode._inflate(data.slice(nz + 2, nz + 2 + tl)); + text = bin.readUTF8(bfr, 0, bfr.length); + } + out.tabs[type][keyw] = text; + } + else if (type == 'iTXt') { + if (out.tabs[type] == null) out.tabs[type] = {}; + var nz = 0, off = offset; + nz = bin.nextZero(data, off); + var keyw = bin.readASCII(data, off, nz - off); + off = nz + 1; + var cflag = data[off], cmeth = data[off+1]; + off += 2; + nz = bin.nextZero(data, off); + var ltag = bin.readASCII(data, off, nz - off); + off = nz + 1; + nz = bin.nextZero(data, off); + var tkeyw = bin.readUTF8(data, off, nz - off); + off = nz + 1; + var text, tl = len - (off - offset); + if (cflag == 0) text = bin.readUTF8(data, off, tl); + else { + var bfr = UPNG.decode._inflate(data.slice(off, off + tl)); + text = bin.readUTF8(bfr, 0, bfr.length); + } + out.tabs[type][keyw] = text; + } + else if (type == 'PLTE') { + out.tabs[type] = bin.readBytes(data, offset, len); + } + else if (type == 'hIST') { + var pl = out.tabs['PLTE'].length / 3; + out.tabs[type] = []; + for (var i = 0; i < pl; i++) out.tabs[type].push(rUs(data, offset + i * 2)); + } + else if (type == 'tRNS') { + if (out.ctype == 3) out.tabs[type] = bin.readBytes(data, offset, len); + else if (out.ctype == 0) out.tabs[type] = rUs(data, offset); + else if (out.ctype == 2) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)]; + + } + else if (type == 'gAMA') out.tabs[type] = bin.readUint(data, offset) / 100000; + else if (type == 'sRGB') out.tabs[type] = data[offset]; + else if (type == 'bKGD') { + if (out.ctype == 0 || out.ctype == 4) out.tabs[type] = [rUs(data, offset)]; + else if (out.ctype == 2 || out.ctype == 6) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)]; + else if (out.ctype == 3) out.tabs[type] = data[offset]; + } + else if (type == 'IEND') { + break; + } + + offset += len; + var crc = bin.readUint(data, offset); + offset += 4; + } + if (foff != 0) { + var fr = out.frames[out.frames.length-1]; + fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height); + } + out.data = UPNG.decode._decompress(out, dd, out.width, out.height); + + delete out.compress; + delete out.interlace; + delete out.filter; + return out; +} + +UPNG.decode._decompress = function (out, dd, w, h) { + var time = Date.now(); + var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w * bpp / 8), + buff = new Uint8Array((bpl + 1 + out.interlace) * h); + if (out.tabs['CgBI']) dd = UPNG.inflateRaw(dd, buff); + else dd = UPNG.decode._inflate(dd, buff); + + + var time = Date.now(); + if (out.interlace == 0) dd = UPNG.decode._filterZero(dd, out, 0, w, h); + else if (out.interlace == 1) dd = UPNG.decode._readInterlace(dd, out); + + return dd; +} + +UPNG.decode._inflate = function (data, buff) { + var out = UPNG['inflateRaw'](new Uint8Array(data.buffer, 2, data.length - 6), buff); + return out; +} +UPNG.inflateRaw = function(){ + var H = {}; + H.H = {}; + H.H.N = function (N, W) { + var R = Uint8Array, i = 0, m = 0, J = 0, h = 0, Q = 0, X = 0, u = 0, w = 0, d = 0, v, C; + if (N[0] == 3 && N[1] == 0)return W ? W : new R(0); + var V = H.H, n = V.b, A = V.e, l = V.R, M = V.n, I = V.A, e = V.Z, b = V.m, Z = W == null; + if (Z)W = new R(N.length >>> 2 << 5); + while (i == 0) { + i = n(N, d, 1); + m = n(N, d + 1, 2); + d += 3; + if (m == 0) { + if ((d & 7) != 0)d += 8 - (d & 7); + var D = (d >>> 3) + 4, q = N[D-4] | N[D-3] << 8; + if (Z)W = H.H.W(W, w + q); + W.set(new R(N.buffer, N.byteOffset + D, q), w); + d = D + q << 3; + w += q; + continue + } + if (Z)W = H.H.W(W, w + (1 << 17)); + if (m == 1) { + v = b.J; + C = b.h; + X = (1 << 9) - 1; + u = (1 << 5) - 1 + } + if (m == 2) { + J = A(N, d, 5) + 257; + h = A(N, d + 5, 5) + 1; + Q = A(N, d + 10, 4) + 4; + d += 14; + var E = d, j = 1; + for (var c = 0;c < 38; c += 2) { + b.Q[c] = 0; + b.Q[c+1] = 0 + } + for (var c = 0; c < Q; c++) { + var K = A(N, d + c * 3, 3); + b.Q[(b.X[c] << 1)+1] = K; + if (K > j)j = K + } + d += 3 * Q; + M(b.Q, j); + I(b.Q, j, b.u); + v = b.w; + C = b.d; + d = l(b.u, (1 << j) - 1, J + h, N, d, b.v); + var r = V.V(b.v, 0, J, b.C); + X = (1 << r) - 1; + var S = V.V(b.v, J, h, b.D); + u = (1 << S) - 1; + M(b.C, r); + I(b.C, r, v); + M(b.D, S); + I(b.D, S, C) + } + while (!0) { + var T = v[e(N, d)&X]; + d += T & 15; + var p = T >>> 4; + if (p >>> 8 == 0) { + W[w++] = p + } else if (p == 256) { + break + } else { + var z = w + p - 254; + if (p > 264) { + var _ = b.q[p-257]; + z = w + (_ >>> 3) + A(N, d, _ & 7); + d += _ & 7 + } + var $ = C[e(N, d)&u]; + d += $ & 15; + var s = $ >>> 4, Y = b.c[s], a = (Y >>> 4) + n(N, d, Y & 15); + d += Y & 15; + while (w < z) { + W[w] = W[w++-a]; + W[w] = W[w++-a]; + W[w] = W[w++-a]; + W[w] = W[w++-a] + } + w = z + } + } + } + return W.length == w ? W : W.slice(0, w) + }; + H.H.W = function (N, W) { + var R = N.length; + if (W <= R)return N; + var V = new Uint8Array(R << 1); + V.set(N, 0); + return V + }; + H.H.R = function (N, W, R, V, n, A) { + var l = H.H.e, M = H.H.Z, I = 0; + while (I < R) { + var e = N[M(V, n)&W]; + n += e & 15; + var b = e >>> 4; + if (b <= 15) { + A[I] = b; + I++ + } else { + var Z = 0, m = 0; + if (b == 16) { + m = 3 + l(V, n, 2); + n += 2; + Z = A[I-1] + } else if (b == 17) { + m = 3 + l(V, n, 3); + n += 3 + } else if (b == 18) { + m = 11 + l(V, n, 7); + n += 7 + } + var J = I + m; + while (I < J) { + A[I] = Z; + I++ + } + } + } + return n + }; + H.H.V = function (N, W, R, V) { + var n = 0, A = 0, l = V.length >>> 1; + while (A < R) { + var M = N[A+W]; + V[A<<1] = 0; + V[(A << 1)+1] = M; + if (M > n)n = M; + A++ + } + while (A < l) { + V[A<<1] = 0; + V[(A << 1)+1] = 0; + A++ + } + return n + }; + H.H.n = function (N, W) { + var R = H.H.m, V = N.length, n, A, l, M, I, e = R.j; + for (var M = 0;M <= W; M++)e[M] = 0; + for (M = 1; M < V; M += 2)e[N[M]]++; + var b = R.K; + n = 0; + e[0] = 0; + for (A = 1; A <= W; A++) { + n = n + e[A-1] << 1; + b[A] = n + } + for (l = 0; l < V; l += 2) { + I = N[l+1]; + if (I != 0) { + N[l] = b[I]; + b[I]++ + } + } + }; + H.H.A = function (N, W, R) { + var V = N.length, n = H.H.m, A = n.r; + for (var l = 0;l < V; l += 2)if (N[l+1] != 0) { + var M = l >> 1, I = N[l+1], e = M << 4 | I, b = W - I, Z = N[l] << b, m = Z + (1 << b); + while (Z != m) { + var J = A[Z] >>> 15 - W; + R[J] = e; + Z++ + } + } + }; + H.H.l = function (N, W) { + var R = H.H.m.r, V = 15 - W; + for (var n = 0;n < N.length; + n += 2) { + var A = N[n] << W - N[n+1]; + N[n] = R[A] >>> V + } + }; + H.H.M = function (N, W, R) { + R = R << (W & 7); + var V = W >>> 3; + N[V] |= R; + N[V+1] |= R >>> 8 + }; + H.H.I = function (N, W, R) { + R = R << (W & 7); + var V = W >>> 3; + N[V] |= R; + N[V+1] |= R >>> 8; + N[V+2] |= R >>> 16 + }; + H.H.e = function (N, W, R) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8) >>> (W & 7) & (1 << R) - 1 + }; + H.H.b = function (N, W, R) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8 | N[(W >>> 3)+2] << 16) >>> (W & 7) & (1 << R) - 1 + }; + H.H.Z = function (N, W) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8 | N[(W >>> 3)+2] << 16) >>> (W & 7) + }; + H.H.i = function (N, W) { + return (N[W>>>3] | N[(W >>> 3)+1] << 8 | N[(W >>> 3)+2] << 16 | N[(W >>> 3)+3] << 24) >>> (W & 7) + }; + H.H.m = function(){ + var N = Uint16Array, W = Uint32Array; + return { + K: new N(16), + j: new N(16), + X: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], + S: [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 999, 999, 999], + T: [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0], + q: new N(32), + p: [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 65535, 65535], + z: [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0], + c: new W(32), + J: new N(512), + _: [], + h: new N(32), + $: [], + w: new N(32768), + C: [], + v: [], + d: new N(32768), + D: [], + u: new N(512), + Q: [], + r: new N(1 << 15), + s: new W(286), + Y: new W(30), + a: new W(19), + t: new W(15e3), + k: new N(1 << 16), + g: new N(1 << 15) + } + }(); + (function(){ + var N = H.H.m, W = 1 << 15; + for (var R = 0;R < W; R++) { + var V = R; + V = (V & 2863311530) >>> 1 | (V & 1431655765) << 1; + V = (V & 3435973836) >>> 2 | (V & 858993459) << 2; + V = (V & 4042322160) >>> 4 | (V & 252645135) << 4; + V = (V & 4278255360) >>> 8 | (V & 16711935) << 8; + N.r[R] = (V >>> 16 | V << 16) >>> 17 + } + + function n(A, l, M) { + while (l-- != 0)A.push(0, M) + } + + for (var R = 0;R < 32; R++) { + N.q[R] = N.S[R] << 3 | N.T[R]; + N.c[R] = N.p[R] << 4 | N.z[R] + } + n(N._, 144, 8); + n(N._, 255 - 143, 9); + n(N._, 279 - 255, 7); + n(N._, 287 - 279, 8); + H.H.n(N._, 9); + H.H.A(N._, 9, N.J); + H.H.l(N._, 9); + n(N.$, 32, 5); + H.H.n(N.$, 5); + H.H.A(N.$, 5, N.h); + H.H.l(N.$, 5); + n(N.Q, 19, 0); + n(N.C, 286, 0); + n(N.D, 30, 0); + n(N.v, 320, 0) + }()); + return H.H.N +}() + + +UPNG.decode._readInterlace = function (data, out) { + var w = out.width, h = out.height; + var bpp = UPNG.decode._getBPP(out), cbpp = bpp >> 3, bpl = Math.ceil(w * bpp / 8); + var img = new Uint8Array(h * bpl); + var di = 0; + + var starting_row = [0, 0, 4, 0, 2, 0, 1]; + var starting_col = [0, 4, 0, 2, 0, 1, 0]; + var row_increment = [8, 8, 8, 4, 4, 2, 2]; + var col_increment = [8, 8, 4, 4, 2, 2, 1]; + + var pass = 0; + while (pass < 7) { + var ri = row_increment[pass], ci = col_increment[pass]; + var sw = 0, sh = 0; + var cr = starting_row[pass]; + while (cr < h) { + cr += ri; + sh++; + } + var cc = starting_col[pass]; + while (cc < w) { + cc += ci; + sw++; + } + var bpll = Math.ceil(sw * bpp / 8); + UPNG.decode._filterZero(data, out, di, sw, sh); + + var y = 0, row = starting_row[pass]; + while (row < h) { + var col = starting_col[pass]; + var cdi = (di + y * bpll) << 3; + + while (col < w) { + if (bpp == 1) { + var val = data[cdi>>3]; + val = (val >> (7 - (cdi & 7))) & 1; + img[row * bpl + (col >> 3)] |= (val << (7 - ((col & 7) << 0))); + } + if (bpp == 2) { + var val = data[cdi>>3]; + val = (val >> (6 - (cdi & 7))) & 3; + img[row * bpl + (col >> 2)] |= (val << (6 - ((col & 3) << 1))); + } + if (bpp == 4) { + var val = data[cdi>>3]; + val = (val >> (4 - (cdi & 7))) & 15; + img[row * bpl + (col >> 1)] |= (val << (4 - ((col & 1) << 2))); + } + if (bpp >= 8) { + var ii = row * bpl + col * cbpp; + for (var j = 0; j < cbpp; j++) img[ii+j] = data[(cdi >> 3)+j]; + } + cdi += bpp; + col += ci; + } + y++; + row += ri; + } + if (sw * sh != 0) di += sh * (1 + bpll); + pass = pass + 1; + } + return img; +} + +UPNG.decode._getBPP = function (out) { + var noc = [1, null, 3, 1, 2, null, 4][out.ctype]; + return noc * out.depth; +} + +UPNG.decode._filterZero = function (data, out, off, w, h) { + var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w * bpp / 8), paeth = UPNG.decode._paeth; + bpp = Math.ceil(bpp / 8); + + var i, di, type = data[off], x = 0; + + if (type > 1) data[off] = [0, 0, 1][type-2]; + if (type == 3) for (x = bpp; x < bpl; x++) data[x+1] = (data[x+1] + (data[x + 1-bpp] >>> 1)) & 255; + + for (var y = 0; y < h; y++) { + i = off + y * bpl; + di = i + y + 1; + type = data[di-1]; + x = 0; + + if (type == 0) for (; x < bpl; x++) data[i+x] = data[di+x]; + else if (type == 1) { + for (; x < bpp; x++) data[i+x] = data[di+x]; + for (; x < bpl; x++) data[i+x] = (data[di+x] + data[i + x-bpp]); + } + else if (type == 2) { + for (; x < bpl; x++) data[i+x] = (data[di+x] + data[i + x-bpl]); + } + else if (type == 3) { + for (; x < bpp; x++) data[i+x] = (data[di+x] + (data[i + x-bpl] >>> 1)); + for (; x < bpl; x++) data[i+x] = (data[di+x] + ((data[i + x-bpl] + data[i + x-bpp]) >>> 1)); + } + else { + for (; x < bpp; x++) data[i+x] = (data[di+x] + paeth(0, data[i + x-bpl], 0)); + for (; x < bpl; x++) data[i+x] = (data[di+x] + paeth(data[i + x-bpp], data[i + x-bpl], data[i + x - bpp-bpl])); + } + } + return data; +} + +UPNG.decode._paeth = function (a, b, c) { + var p = a + b - c, pa = (p - a), pb = (p - b), pc = (p - c); + if (pa * pa <= pb * pb && pa * pa <= pc * pc) return a; + else if (pb * pb <= pc * pc) return b; + return c; +} + +UPNG.decode._IHDR = function (data, offset, out) { + var bin = UPNG._bin; + out.width = bin.readUint(data, offset); + offset += 4; + out.height = bin.readUint(data, offset); + offset += 4; + out.depth = data[offset]; + offset++; + out.ctype = data[offset]; + offset++; + out.compress = data[offset]; + offset++; + out.filter = data[offset]; + offset++; + out.interlace = data[offset]; + offset++; +} + +UPNG._bin = { + nextZero: function (data, p) { + while (data[p] != 0) p++; + return p; + }, + readUshort: function (buff, p) { + return (buff[p] << 8) | buff[p+1]; + }, + writeUshort: function (buff, p, n) { + buff[p] = (n >> 8) & 255; + buff[p+1] = n & 255; + }, + readUint: function (buff, p) { + return (buff[p] * (256 * 256 * 256)) + ((buff[p+1] << 16) | (buff[p+2] << 8) | buff[p+3]); + }, + writeUint: function (buff, p, n) { + buff[p] = (n >> 24) & 255; + buff[p+1] = (n >> 16) & 255; + buff[p+2] = (n >> 8) & 255; + buff[p+3] = n & 255; + }, + readASCII: function (buff, p, l) { + var s = ''; + for (var i = 0; i < l; i++) s += String.fromCharCode(buff[p+i]); + return s; + }, + writeASCII: function (data, p, s) { + for (var i = 0; i < s.length; i++) data[p+i] = s.charCodeAt(i); + }, + readBytes: function (buff, p, l) { + var arr = []; + for (var i = 0; i < l; i++) arr.push(buff[p+i]); + return arr; + }, + pad: function (n) { + return n.length < 2 ? '0' + n : n; + }, + readUTF8: function (buff, p, l) { + var s = '', ns; + for (var i = 0; i < l; i++) s += '%' + UPNG._bin.pad(buff[p+i].toString(16)); + try { + ns = decodeURIComponent(s); + } + catch (e) { + return UPNG._bin.readASCII(buff, p, l); + } + return ns; + } +} +UPNG._copyTile = function (sb, sw, sh, tb, tw, th, xoff, yoff, mode) { + var w = Math.min(sw, tw), h = Math.min(sh, th); + var si = 0, ti = 0; + for (var y = 0; y < h; y++) + for (var x = 0; x < w; x++) { + if (xoff >= 0 && yoff >= 0) { + si = (y * sw + x) << 2; + ti = ((yoff + y) * tw + xoff + x) << 2; + } + else { + si = ((-yoff + y) * sw - xoff + x) << 2; + ti = (y * tw + x) << 2; + } + + if (mode == 0) { + tb[ti] = sb[si]; + tb[ti+1] = sb[si+1]; + tb[ti+2] = sb[si+2]; + tb[ti+3] = sb[si+3]; + } + else if (mode == 1) { + var fa = sb[si+3] * (1 / 255), fr = sb[si] * fa, fg = sb[si+1] * fa, fb = sb[si+2] * fa; + var ba = tb[ti+3] * (1 / 255), br = tb[ti] * ba, bg = tb[ti+1] * ba, bb = tb[ti+2] * ba; + + var ifa = 1 - fa, oa = fa + ba * ifa, ioa = (oa == 0 ? 0 : 1 / oa); + tb[ti+3] = 255 * oa; + tb[ti+0] = (fr + br * ifa) * ioa; + tb[ti+1] = (fg + bg * ifa) * ioa; + tb[ti+2] = (fb + bb * ifa) * ioa; + } + else if (mode == 2) { // copy only differences, otherwise zero + var fa = sb[si+3], fr = sb[si], fg = sb[si+1], fb = sb[si+2]; + var ba = tb[ti+3], br = tb[ti], bg = tb[ti+1], bb = tb[ti+2]; + if (fa == ba && fr == br && fg == bg && fb == bb) { + tb[ti] = 0; + tb[ti+1] = 0; + tb[ti+2] = 0; + tb[ti+3] = 0; + } + else { + tb[ti] = fr; + tb[ti+1] = fg; + tb[ti+2] = fb; + tb[ti+3] = fa; + } + } + else if (mode == 3) { // check if can be blended + var fa = sb[si+3], fr = sb[si], fg = sb[si+1], fb = sb[si+2]; + var ba = tb[ti+3], br = tb[ti], bg = tb[ti+1], bb = tb[ti+2]; + if (fa == ba && fr == br && fg == bg && fb == bb) continue; + + if (fa < 220 && ba > 20) return false; + } + } + return true; + } + + +UPNG.encode = function (bufs, w, h, ps, dels, tabs, forbidPlte) { + if (ps == null) ps = 0; + if (forbidPlte == null) forbidPlte = false; + + var nimg = UPNG.encode.compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte, false]); + UPNG.encode.compressPNG(nimg, -1); + + return UPNG.encode._main(nimg, w, h, dels, tabs); +} +UPNG.encodeWithString = function (writeString, bufs, w, h, ps, dels, tabs, forbidPlte) { + if (ps == null) ps = 0; + if (forbidPlte == null) forbidPlte = false; + + var nimg = UPNG.encode.compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte, false]); + UPNG.encode.compressPNG(nimg, -1); + + return UPNG.encode._mainWithString(writeString, nimg, w, h, dels, tabs); +} + +UPNG.encodeLL = function (bufs, w, h, cc, ac, depth, dels, tabs) { + var nimg = { ctype: 0 + (cc == 1 ? 0 : 2) + (ac == 0 ? 0 : 4), depth: depth, frames: [] }; + + var time = Date.now(); + var bipp = (cc + ac) * depth, bipl = bipp * w; + for (var i = 0; i < bufs.length; i++) + nimg.frames.push({ + rect: { x: 0, y: 0, width: w, height: h }, + img: new Uint8Array(bufs[i]), + blend: 0, + dispose: 1, + bpp: Math.ceil(bipp / 8), + bpl: Math.ceil(bipl / 8) + }); + + UPNG.encode.compressPNG(nimg, 0, true); + + var out = UPNG.encode._main(nimg, w, h, dels, tabs); + return out; +} + +UPNG.encode._main = function (nimg, w, h, dels, tabs) { + try { + if (tabs == null) tabs = {}; + var crc = UPNG.crc.crc, wUi = UPNG._bin.writeUint, wUs = UPNG._bin.writeUshort, wAs = UPNG._bin.writeASCII; + var offset = 8, anim = nimg.frames.length > 1, pltAlpha = false; + + var leng = 8 + (16 + 5 + 4) /*+ (9+4)*/ + + (anim ? 20 : 0); + if (tabs['sRGB'] != null) leng += 8 + 1 + 4; + if (tabs['pHYs'] != null) leng += 8 + 9 + 4; + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + for (var i = 0; i < dl; i++) if ((nimg.plte[i] >>> 24) != 255) pltAlpha = true; + leng += (8 + dl * 3 + 4) + (pltAlpha ? (8 + dl * 1 + 4) : 0); + } + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) leng += 38; + leng += fr.cimg.length + 12; + if (j != 0) leng += 4; + } + leng += 12; + + var data = new Uint8Array(leng); + var wr = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; + for (var i = 0; i < 8; i++) data[i] = wr[i]; + + wUi(data, offset, 13); + offset += 4; + wAs(data, offset, 'IHDR'); + offset += 4; + wUi(data, offset, w); + offset += 4; + wUi(data, offset, h); + offset += 4; + data[offset] = nimg.depth; + offset++; // depth + data[offset] = nimg.ctype; + offset++; // ctype + data[offset] = 0; + offset++; // compress + data[offset] = 0; + offset++; // filter + data[offset] = 0; + offset++; // interlace + wUi(data, offset, crc(data, offset - 17, 17)); + offset += 4; // crc + + // 13 bytes to say, that it is sRGB + if (tabs['sRGB'] != null) { + wUi(data, offset, 1); + offset += 4; + wAs(data, offset, 'sRGB'); + offset += 4; + data[offset] = tabs['sRGB']; + offset++; + wUi(data, offset, crc(data, offset - 5, 5)); + offset += 4; // crc + } + if (tabs['pHYs'] != null) { + wUi(data, offset, 9); + offset += 4; + wAs(data, offset, 'pHYs'); + offset += 4; + wUi(data, offset, tabs['pHYs'][0]); + offset += 4; + wUi(data, offset, tabs['pHYs'][1]); + offset += 4; + data[offset] = tabs['pHYs'][2]; + offset++; + wUi(data, offset, crc(data, offset - 13, 13)); + offset += 4; // crc + } + + if (anim) { + wUi(data, offset, 8); + offset += 4; + wAs(data, offset, 'acTL'); + offset += 4; + wUi(data, offset, nimg.frames.length); + offset += 4; + wUi(data, offset, tabs['loop'] != null ? tabs['loop'] : 0); + offset += 4; + wUi(data, offset, crc(data, offset - 12, 12)); + offset += 4; // crc + } + + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + wUi(data, offset, dl * 3); + offset += 4; + wAs(data, offset, 'PLTE'); + offset += 4; + for (var i = 0; i < dl; i++) { + var ti = i * 3, c = nimg.plte[i], r = (c) & 255, g = (c >>> 8) & 255, b = (c >>> 16) & 255; + data[offset + ti+0] = r; + data[offset + ti+1] = g; + data[offset + ti+2] = b; + } + offset += dl * 3; + wUi(data, offset, crc(data, offset - dl * 3 - 4, dl * 3 + 4)); + offset += 4; // crc + + if (pltAlpha) { + wUi(data, offset, dl); + offset += 4; + wAs(data, offset, 'tRNS'); + offset += 4; + for (var i = 0; i < dl; i++) data[offset+i] = (nimg.plte[i] >>> 24) & 255; + offset += dl; + wUi(data, offset, crc(data, offset - dl - 4, dl + 4)); + offset += 4; // crc + } + } + + var fi = 0; + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) { + wUi(data, offset, 26); + offset += 4; + wAs(data, offset, 'fcTL'); + offset += 4; + wUi(data, offset, fi++); + offset += 4; + wUi(data, offset, fr.rect.width); + offset += 4; + wUi(data, offset, fr.rect.height); + offset += 4; + wUi(data, offset, fr.rect.x); + offset += 4; + wUi(data, offset, fr.rect.y); + offset += 4; + wUs(data, offset, dels[j]); + offset += 2; + wUs(data, offset, 1000); + offset += 2; + data[offset] = fr.dispose; + offset++; // dispose + data[offset] = fr.blend; + offset++; // blend + wUi(data, offset, crc(data, offset - 30, 30)); + offset += 4; // crc + } + + var imgd = fr.cimg, dl = imgd.length; + wUi(data, offset, dl + (j == 0 ? 0 : 4)); + offset += 4; + var ioff = offset; + wAs(data, offset, (j == 0) ? 'IDAT' : 'fdAT'); + offset += 4; + if (j != 0) { + wUi(data, offset, fi++); + offset += 4; + } + data.set(imgd, offset); + offset += dl; + wUi(data, offset, crc(data, ioff, offset - ioff)); + offset += 4; // crc + } + + wUi(data, offset, 0); + offset += 4; + wAs(data, offset, 'IEND'); + offset += 4; + wUi(data, offset, crc(data, offset - 4, 4)); + offset += 4; // crc + return data.buffer; + } + catch (err) { + } +} +UPNG.encode._mainWithString = function (writeString, nimg, w, h, dels, tabs) { + if (tabs == null) tabs = {}; + var crc = UPNG.crc.crc, wUi = UPNG._bin.writeUint, wUs = UPNG._bin.writeUshort, wAs = UPNG._bin.writeASCII; + var offset = 8, anim = nimg.frames.length > 1, pltAlpha = false; + + var leng = 8 + (16 + 5 + 4) /*+ (9+4)*/ + + (anim ? 20 : 0); + if (tabs['sRGB'] != null) leng += 8 + 1 + 4; + if (tabs['pHYs'] != null) leng += 8 + 9 + 4; + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + for (var i = 0; i < dl; i++) if ((nimg.plte[i] >>> 24) != 255) pltAlpha = true; + leng += (8 + dl * 3 + 4) + (pltAlpha ? (8 + dl * 1 + 4) : 0); + } + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) leng += 38; + leng += fr.cimg.length + 12; + if (j != 0) leng += 4; + } + + // 由于IEND数据块永远是 00 00 00 00 49 45 4E 44 AE 42 60 82 + // 其中 IEND 是 49 45 4E 44 因此CRC码也总是 AE 42 60 82 + + let writeUint8 = UPNG.encode._strToUint8Array(writeString); + + leng += 12 + writeUint8.byteLength; + + + var data = new Uint8Array(leng); + var wr = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; + for (var i = 0; i < 8; i++) data[i] = wr[i]; + + wUi(data, offset, 13); + offset += 4; + wAs(data, offset, 'IHDR'); + offset += 4; + wUi(data, offset, w); + offset += 4; + wUi(data, offset, h); + offset += 4; + data[offset] = nimg.depth; + offset++; // depth + data[offset] = nimg.ctype; + offset++; // ctype + data[offset] = 0; + offset++; // compress + data[offset] = 0; + offset++; // filter + data[offset] = 0; + offset++; // interlace + wUi(data, offset, crc(data, offset - 17, 17)); + offset += 4; // crc + + // 13 bytes to say, that it is sRGB + if (tabs['sRGB'] != null) { + wUi(data, offset, 1); + offset += 4; + wAs(data, offset, 'sRGB'); + offset += 4; + data[offset] = tabs['sRGB']; + offset++; + wUi(data, offset, crc(data, offset - 5, 5)); + offset += 4; // crc + } + if (tabs['pHYs'] != null) { + wUi(data, offset, 9); + offset += 4; + wAs(data, offset, 'pHYs'); + offset += 4; + wUi(data, offset, tabs['pHYs'][0]); + offset += 4; + wUi(data, offset, tabs['pHYs'][1]); + offset += 4; + data[offset] = tabs['pHYs'][2]; + offset++; + wUi(data, offset, crc(data, offset - 13, 13)); + offset += 4; // crc + } + + if (anim) { + wUi(data, offset, 8); + offset += 4; + wAs(data, offset, 'acTL'); + offset += 4; + wUi(data, offset, nimg.frames.length); + offset += 4; + wUi(data, offset, tabs['loop'] != null ? tabs['loop'] : 0); + offset += 4; + wUi(data, offset, crc(data, offset - 12, 12)); + offset += 4; // crc + } + + if (nimg.ctype == 3) { + var dl = nimg.plte.length; + wUi(data, offset, dl * 3); + offset += 4; + wAs(data, offset, 'PLTE'); + offset += 4; + for (var i = 0; i < dl; i++) { + var ti = i * 3, c = nimg.plte[i], r = (c) & 255, g = (c >>> 8) & 255, b = (c >>> 16) & 255; + data[offset + ti+0] = r; + data[offset + ti+1] = g; + data[offset + ti+2] = b; + } + offset += dl * 3; + wUi(data, offset, crc(data, offset - dl * 3 - 4, dl * 3 + 4)); + offset += 4; // crc + + if (pltAlpha) { + wUi(data, offset, dl); + offset += 4; + wAs(data, offset, 'tRNS'); + offset += 4; + for (var i = 0; i < dl; i++) data[offset+i] = (nimg.plte[i] >>> 24) & 255; + offset += dl; + wUi(data, offset, crc(data, offset - dl - 4, dl + 4)); + offset += 4; // crc + } + } + + var fi = 0; + for (var j = 0; j < nimg.frames.length; j++) { + var fr = nimg.frames[j]; + if (anim) { + wUi(data, offset, 26); + offset += 4; + wAs(data, offset, 'fcTL'); + offset += 4; + wUi(data, offset, fi++); + offset += 4; + wUi(data, offset, fr.rect.width); + offset += 4; + wUi(data, offset, fr.rect.height); + offset += 4; + wUi(data, offset, fr.rect.x); + offset += 4; + wUi(data, offset, fr.rect.y); + offset += 4; + wUs(data, offset, dels[j]); + offset += 2; + wUs(data, offset, 1000); + offset += 2; + data[offset] = fr.dispose; + offset++; // dispose + data[offset] = fr.blend; + offset++; // blend + wUi(data, offset, crc(data, offset - 30, 30)); + offset += 4; // crc + } + + var imgd = fr.cimg, dl = imgd.length; + wUi(data, offset, dl + (j == 0 ? 0 : 4)); + offset += 4; + var ioff = offset; + wAs(data, offset, (j == 0) ? 'IDAT' : 'fdAT'); + offset += 4; + if (j != 0) { + wUi(data, offset, fi++); + offset += 4; + } + data.set(imgd, offset); + offset += dl; + wUi(data, offset, crc(data, ioff, offset - ioff)); + offset += 4; // crc + } + + wUi(data, offset, 0); + offset += 4; + + wAs(data, offset, 'IEND'); + offset += 4; + wUi(data, offset, crc(data, offset - (4), 4)); + offset += 4; // crc + wAs(data, offset, writeString); + offset += writeUint8.byteLength; + return data.buffer; +} + +UPNG.encode.compressPNG = function (out, filter, levelZero) { + try { + for (var i = 0; i < out.frames.length; i++) { + var frm = out.frames[i], nw = frm.rect.width, nh = frm.rect.height; + var fdata = new Uint8Array(nh * frm.bpl + nh); + frm.cimg = UPNG.encode._filterZero(frm.img, nh, frm.bpp, frm.bpl, fdata, filter, levelZero); + } + } catch (err) { + } +} + + +UPNG.encode.compress = function (bufs, w, h, ps, prms) // prms: onlyBlend, minBits, forbidPlte +{ + try { + + var onlyBlend = prms[0], evenCrd = prms[1], forbidPrev = prms[2], minBits = prms[3], forbidPlte = prms[4], + dither = prms[5]; + + var ctype = 6, depth = 8, alphaAnd = 255 + + for (var j = 0; j < bufs.length; j++) { // when not quantized, other frames can contain colors, that are not in an initial frame + var img = new Uint8Array(bufs[j]), ilen = img.length; + for (var i = 0; i < ilen; i += 4) alphaAnd &= img[i+3]; + } + var gotAlpha = (alphaAnd != 255); + + var frms = UPNG.encode.framize(bufs, w, h, onlyBlend, evenCrd, forbidPrev); + + var cmap = {}, plte = [], inds = []; + + if (ps != 0) { + var nbufs = []; + for (var i = 0; i < frms.length; i++) nbufs.push(frms[i].img.buffer); + + var abuf = UPNG.encode.concatRGBA(nbufs), qres = UPNG.quantize(abuf, ps); + + for (var i = 0; i < qres.plte.length; i++) plte.push(qres.plte[i].est.rgba); + + var cof = 0; + for (var i = 0; i < frms.length; i++) { + var frm = frms[i], bln = frm.img.length, ind = new Uint8Array(qres.inds.buffer, cof >> 2, bln >> 2); + inds.push(ind); + var bb = new Uint8Array(qres.abuf, cof, bln); + + if (dither) UPNG.encode.dither(frm.img, frm.rect.width, frm.rect.height, plte, bb, ind); + + frm.img.set(bb); + cof += bln; + } + } + else { + // what if ps==0, but there are <=256 colors? we still need to detect, if the palette could be used + for (var j = 0; j < frms.length; j++) { // when not quantized, other frames can contain colors, that are not in an initial frame + var frm = frms[j], img32 = new Uint32Array(frm.img.buffer), nw = frm.rect.width, ilen = img32.length; + var ind = new Uint8Array(ilen); + inds.push(ind); + for (var i = 0; i < ilen; i++) { + var c = img32[i]; + if (i != 0 && c == img32[i- 1]) ind[i] = ind[i-1]; + else if (i > nw && c == img32[i-nw]) ind[i] = ind[i-nw]; + else { + var cmc = cmap[c]; + if (cmc == null) { + cmap[c] = cmc = plte.length; + plte.push(c); + if (plte.length >= 300) break; + } + ind[i] = cmc; + } + } + } + } + + var cc = plte.length; + if (cc <= 256 && forbidPlte == false) { + if (cc <= 2) depth = 1; else if (cc <= 4) depth = 2; else if (cc <= 16) depth = 4; else depth = 8; + depth = Math.max(depth, minBits); + } + + for (var j = 0; j < frms.length; j++) { + var frm = frms[j], nx = frm.rect.x, ny = frm.rect.y, nw = frm.rect.width, nh = frm.rect.height; + var cimg = frm.img, cimg32 = new Uint32Array(cimg.buffer); + var bpl = 4 * nw, bpp = 4; + if (cc <= 256 && forbidPlte == false) { + bpl = Math.ceil(depth * nw / 8); + var nimg = new Uint8Array(bpl * nh); + var inj = inds[j]; + for (var y = 0; y < nh; y++) { + var i = y * bpl, ii = y * nw; + if (depth == 8) for (var x = 0; x < nw; x++) nimg[i+(x)] = (inj[ii+x]); + else if (depth == 4) for (var x = 0; x < nw; x++) nimg[i+(x >> 1)] |= (inj[ii+x] << (4 - (x & 1) * 4)); + else if (depth == 2) for (var x = 0; x < nw; x++) nimg[i+(x >> 2)] |= (inj[ii+x] << (6 - (x & 3) * 2)); + else if (depth == 1) for (var x = 0; x < nw; x++) nimg[i+(x >> 3)] |= (inj[ii+x] << (7 - (x & 7) * 1)); + } + cimg = nimg; + ctype = 3; + bpp = 1; + } + else if (gotAlpha == false && frms.length == 1) { // some next 'reduced' frames may contain alpha for blending + var nimg = new Uint8Array(nw * nh * 3), area = nw * nh; + for (var i = 0; i < area; i++) { + var ti = i * 3, qi = i * 4; + nimg[ti] = cimg[qi]; + nimg[ti+1] = cimg[qi+1]; + nimg[ti+2] = cimg[qi+2]; + } + cimg = nimg; + ctype = 2; + bpp = 3; + bpl = 3 * nw; + } + frm.img = cimg; + frm.bpl = bpl; + frm.bpp = bpp; + } + return { ctype: ctype, depth: depth, plte: plte, frames: frms }; + } catch (err) { + } +} +UPNG.encode.framize = function (bufs, w, h, alwaysBlend, evenCrd, forbidPrev) { + + try { + var frms = []; + for (var j = 0; j < bufs.length; j++) { + var cimg = new Uint8Array(bufs[j]), cimg32 = new Uint32Array(cimg.buffer); + var nimg; + + var nx = 0, ny = 0, nw = w, nh = h, blend = alwaysBlend ? 1 : 0; + if (j != 0) { + var tlim = (forbidPrev || alwaysBlend || j == 1 || frms[j-2].dispose != 0) ? 1 : 2, tstp = 0, + tarea = 1e9; + for (var it = 0; it < tlim; it++) { + var pimg = new Uint8Array(bufs[j - 1-it]), p32 = new Uint32Array(bufs[j - 1-it]); + var mix = w, miy = h, max = -1, may = -1; + for (var y = 0; y < h; y++) for (var x = 0; x < w; x++) { + var i = y * w + x; + if (cimg32[i] != p32[i]) { + if (x < mix) mix = x; + if (x > max) max = x; + if (y < miy) miy = y; + if (y > may) may = y; + } + } + if (max == -1) mix = miy = max = may = 0; + if (evenCrd) { + if ((mix & 1) == 1)mix--; + if ((miy & 1) == 1)miy--; + } + var sarea = (max - mix + 1) * (may - miy + 1); + if (sarea < tarea) { + tarea = sarea; + tstp = it; + nx = mix; + ny = miy; + nw = max - mix + 1; + nh = may - miy + 1; + } + } + + // alwaysBlend: pokud zjistím, že blendit nelze, nastavím předchozímu snímku dispose=1. Zajistím, aby obsahoval můj obdélník. + var pimg = new Uint8Array(bufs[j - 1-tstp]); + if (tstp == 1) frms[j-1].dispose = 2; + + nimg = new Uint8Array(nw * nh * 4); + UPNG._copyTile(pimg, w, h, nimg, nw, nh, -nx, -ny, 0); + + blend = UPNG._copyTile(cimg, w, h, nimg, nw, nh, -nx, -ny, 3) ? 1 : 0; + if (blend == 1) UPNG.encode._prepareDiff(cimg, w, h, nimg, { x: nx, y: ny, width: nw, height: nh }); + else UPNG._copyTile(cimg, w, h, nimg, nw, nh, -nx, -ny, 0); + } + else nimg = cimg.slice(0); // img may be rewritten further ... don't rewrite input + + frms.push({ rect: { x: nx, y: ny, width: nw, height: nh }, img: nimg, blend: blend, dispose: 0 }); + } + + if (alwaysBlend) for (var j = 0; j < frms.length; j++) { + var frm = frms[j]; + if (frm.blend == 1) continue; + var r0 = frm.rect, r1 = frms[j-1].rect + var miX = Math.min(r0.x, r1.x), miY = Math.min(r0.y, r1.y); + var maX = Math.max(r0.x + r0.width, r1.x + r1.width), maY = Math.max(r0.y + r0.height, r1.y + r1.height); + var r = { x: miX, y: miY, width: maX - miX, height: maY - miY }; + + frms[j-1].dispose = 1; + if (j - 1 != 0) + UPNG.encode._updateFrame(bufs, w, h, frms, j - 1, r, evenCrd); + UPNG.encode._updateFrame(bufs, w, h, frms, j, r, evenCrd); + } + var area = 0; + if (bufs.length != 1) for (var i = 0; i < frms.length; i++) { + var frm = frms[i]; + area += frm.rect.width * frm.rect.height; + } + return frms; + } catch (err) { + } +} +UPNG.encode._updateFrame = function (bufs, w, h, frms, i, r, evenCrd) { + var U8 = Uint8Array, U32 = Uint32Array; + var pimg = new U8(bufs[i-1]), pimg32 = new U32(bufs[i-1]), nimg = i + 1 < bufs.length ? new U8(bufs[i+1]) : null; + var cimg = new U8(bufs[i]), cimg32 = new U32(cimg.buffer); + + var mix = w, miy = h, max = -1, may = -1; + for (var y = 0; y < r.height; y++) for (var x = 0; x < r.width; x++) { + var cx = r.x + x, cy = r.y + y; + var j = cy * w + cx, cc = cimg32[j]; + // no need to draw transparency, or to dispose it. Or, if writing the same color and the next one does not need transparency. + if (cc == 0 || (frms[i-1].dispose == 0 && pimg32[j] == cc && (nimg == null || nimg[j * 4+3] != 0)) /**/ + ) { + } + else { + if (cx < mix) mix = cx; + if (cx > max) max = cx; + if (cy < miy) miy = cy; + if (cy > may) may = cy; + } + } + if (max == -1) mix = miy = max = may = 0; + if (evenCrd) { + if ((mix & 1) == 1)mix--; + if ((miy & 1) == 1)miy--; + } + r = { x: mix, y: miy, width: max - mix + 1, height: may - miy + 1 }; + + var fr = frms[i]; + fr.rect = r; + fr.blend = 1; + fr.img = new Uint8Array(r.width * r.height * 4); + if (frms[i-1].dispose == 0) { + UPNG._copyTile(pimg, w, h, fr.img, r.width, r.height, -r.x, -r.y, 0); + UPNG.encode._prepareDiff(cimg, w, h, fr.img, r); + } + else + UPNG._copyTile(cimg, w, h, fr.img, r.width, r.height, -r.x, -r.y, 0); +} +UPNG.encode._prepareDiff = function (cimg, w, h, nimg, rec) { + UPNG._copyTile(cimg, w, h, nimg, rec.width, rec.height, -rec.x, -rec.y, 2); +} + +UPNG.encode._filterZero = function (img, h, bpp, bpl, data, filter, levelZero) { + var fls = [], ftry = [0, 1, 2, 3, 4]; + if (filter != -1) ftry = [filter]; + else if (h * bpl > 500000 || bpp == 1) ftry = [0]; + var opts; + if (levelZero) opts = { level: 0 }; + + + var CMPR = (data.length > 10e6 && UZIP != null) ? UZIP : pako; + + + var time = Date.now(); + for (var i = 0; i < ftry.length; i++) { + for (var y = 0; y < h; y++) UPNG.encode._filterLine(data, img, y, bpl, bpp, ftry[i]); + fls.push(CMPR['deflate'](data, opts)); + } + + var ti, tsize = 1e9; + for (var i = 0; i < fls.length; i++) if (fls[i].length < tsize) { + ti = i; + tsize = fls[i].length; + } + return fls[ti]; +} +UPNG.encode._filterLine = function (data, img, y, bpl, bpp, type) { + var i = y * bpl, di = i + y, paeth = UPNG.decode._paeth + data[di] = type; + di++; + + if (type == 0) { + if (bpl < 500) for (var x = 0; x < bpl; x++) data[di+x] = img[i+x]; + else data.set(new Uint8Array(img.buffer, i, bpl), di); + } + else if (type == 1) { + for (var x = 0; x < bpp; x++) data[di+x] = img[i+x]; + for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] - img[i + x-bpp] + 256) & 255; + } + else if (y == 0) { + for (var x = 0; x < bpp; x++) data[di+x] = img[i+x]; + + if (type == 2) for (var x = bpp; x < bpl; x++) data[di+x] = img[i+x]; + if (type == 3) for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] - (img[i + x-bpp] >> 1) + 256) & 255; + if (type == 4) for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] - paeth(img[i + x-bpp], 0, 0) + 256) & 255; + } + else { + if (type == 2) { + for (var x = 0; x < bpl; x++) data[di+x] = (img[i+x] + 256 - img[i + x-bpl]) & 255; + } + if (type == 3) { + for (var x = 0; x < bpp; x++) data[di+x] = (img[i+x] + 256 - (img[i + x-bpl] >> 1)) & 255; + for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] + 256 - ((img[i + x-bpl] + img[i + x-bpp]) >> 1)) & 255; + } + if (type == 4) { + for (var x = 0; x < bpp; x++) data[di+x] = (img[i+x] + 256 - paeth(0, img[i + x-bpl], 0)) & 255; + for (var x = bpp; x < bpl; x++) data[di+x] = (img[i+x] + 256 - paeth(img[i + x-bpp], img[i + x-bpl], img[i + x - bpp-bpl])) & 255; + } + } +} + +UPNG.crc = { + table: (function () { + var tab = new Uint32Array(256); + for (var n = 0; n < 256; n++) { + var c = n; + for (var k = 0; k < 8; k++) { + if (c & 1) c = 0xedb88320 ^ (c >>> 1); + else c = c >>> 1; + } + tab[n] = c; + } + return tab; + })(), + update: function (c, buf, off, len) { + for (var i = 0; i < len; i++) c = UPNG.crc.table[(c ^ buf[off+i]) & 0xff] ^ (c >>> 8); + return c; + }, + crc: function (b, o, l) { + return UPNG.crc.update(0xffffffff, b, o, l) ^ 0xffffffff; + } +} + + +UPNG.quantize = function (abuf, ps) { + var sb = new Uint8Array(abuf), tb = sb.slice(0), tb32 = new Uint32Array(tb.buffer); + + var KD = UPNG.quantize.getKDtree(tb, ps); + var root = KD[0], leafs = KD[1]; + + var planeDst = UPNG.quantize.planeDst; + var len = sb.length; + + var inds = new Uint8Array(len >> 2), nd; + if (sb.length < 20e6) // precise, but slow :( + for (var i = 0; i < len; i += 4) { + var r = sb[i] * (1 / 255), g = sb[i+1] * (1 / 255), b = sb[i+2] * (1 / 255), a = sb[i+3] * (1 / 255); + + nd = UPNG.quantize.getNearest(root, r, g, b, a); + inds[i>>2] = nd.ind; + tb32[i>>2] = nd.est.rgba; + } + else + for (var i = 0; i < len; i += 4) { + var r = sb[i] * (1 / 255), g = sb[i+1] * (1 / 255), b = sb[i+2] * (1 / 255), a = sb[i+3] * (1 / 255); + + nd = root; + while (nd.left) nd = (planeDst(nd.est, r, g, b, a) <= 0) ? nd.left : nd.right; + inds[i>>2] = nd.ind; + tb32[i>>2] = nd.est.rgba; + } + return { abuf: tb.buffer, inds: inds, plte: leafs }; +} + +UPNG.quantize.getKDtree = function (nimg, ps, err) { + if (err == null) err = 0.0001; + var nimg32 = new Uint32Array(nimg.buffer); + + var root = { + i0: 0, + i1: nimg.length, + bst: null, + est: null, + tdst: 0, + left: null, + right: null + }; // basic statistic, extra statistic + root.bst = UPNG.quantize.stats(nimg, root.i0, root.i1); + root.est = UPNG.quantize.estats(root.bst); + var leafs = [root]; + + while (leafs.length < ps) { + var maxL = 0, mi = 0; + for (var i = 0; i < leafs.length; i++) if (leafs[i].est.L > maxL) { + maxL = leafs[i].est.L; + mi = i; + } + if (maxL < err) break; + var node = leafs[mi]; + + var s0 = UPNG.quantize.splitPixels(nimg, nimg32, node.i0, node.i1, node.est.e, node.est.eMq255); + var s0wrong = (node.i0 >= s0 || node.i1 <= s0); + if (s0wrong) { + node.est.L = 0; + continue; + } + + var ln = { + i0: node.i0, + i1: s0, + bst: null, + est: null, + tdst: 0, + left: null, + right: null + }; + ln.bst = UPNG.quantize.stats(nimg, ln.i0, ln.i1); + ln.est = UPNG.quantize.estats(ln.bst); + var rn = { + i0: s0, + i1: node.i1, + bst: null, + est: null, + tdst: 0, + left: null, + right: null + }; + rn.bst = { R: [], m: [], N: node.bst.N - ln.bst.N }; + for (var i = 0; i < 16; i++) rn.bst.R[i] = node.bst.R[i] - ln.bst.R[i]; + for (var i = 0; i < 4; i++) rn.bst.m[i] = node.bst.m[i] - ln.bst.m[i]; + rn.est = UPNG.quantize.estats(rn.bst); + + node.left = ln; + node.right = rn; + leafs[mi] = ln; + leafs.push(rn); + } + leafs.sort(function (a, b) { + return b.bst.N - a.bst.N; + }); + for (var i = 0; i < leafs.length; i++) leafs[i].ind = i; + return [root, leafs]; +} + +UPNG.quantize.getNearest = function (nd, r, g, b, a) { + if (nd.left == null) { + nd.tdst = UPNG.quantize.dist(nd.est.q, r, g, b, a); + return nd; + } + var planeDst = UPNG.quantize.planeDst(nd.est, r, g, b, a); + + var node0 = nd.left, node1 = nd.right; + if (planeDst > 0) { + node0 = nd.right; + node1 = nd.left; + } + + var ln = UPNG.quantize.getNearest(node0, r, g, b, a); + if (ln.tdst <= planeDst * planeDst) return ln; + var rn = UPNG.quantize.getNearest(node1, r, g, b, a); + return rn.tdst < ln.tdst ? rn : ln; +} +UPNG.quantize.planeDst = function (est, r, g, b, a) { + var e = est.e; + return e[0] * r + e[1] * g + e[2] * b + e[3] * a - est.eMq; +} +UPNG.quantize.dist = function (q, r, g, b, a) { + var d0 = r - q[0], d1 = g - q[1], d2 = b - q[2], d3 = a - q[3]; + return d0 * d0 + d1 * d1 + d2 * d2 + d3 * d3; +} + +UPNG.quantize.splitPixels = function (nimg, nimg32, i0, i1, e, eMq) { + var vecDot = UPNG.quantize.vecDot; + i1 -= 4; + var shfs = 0; + while (i0 < i1) { + while (vecDot(nimg, i0, e) <= eMq) i0 += 4; + while (vecDot(nimg, i1, e) > eMq) i1 -= 4; + if (i0 >= i1) break; + + var t = nimg32[i0>>2]; + nimg32[i0>>2] = nimg32[i1>>2]; + nimg32[i1>>2] = t; + + i0 += 4; + i1 -= 4; + } + while (vecDot(nimg, i0, e) > eMq) i0 -= 4; + return i0 + 4; +} +UPNG.quantize.vecDot = function (nimg, i, e) { + return nimg[i] * e[0] + nimg[i+1] * e[1] + nimg[i+2] * e[2] + nimg[i+3] * e[3]; +} +UPNG.quantize.stats = function (nimg, i0, i1) { + var R = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var m = [0, 0, 0, 0]; + var N = (i1 - i0) >> 2; + for (var i = i0; i < i1; i += 4) { + var r = nimg[i] * (1 / 255), g = nimg[i+1] * (1 / 255), b = nimg[i+2] * (1 / 255), a = nimg[i+3] * (1 / 255); + m[0] += r; + m[1] += g; + m[2] += b; + m[3] += a; + + R[0] += r * r; + R[1] += r * g; + R[2] += r * b; + R[3] += r * a; + R[5] += g * g; + R[6] += g * b; + R[7] += g * a; + R[10] += b * b; + R[11] += b * a; + R[15] += a * a; + } + R[4] = R[1]; + R[8] = R[2]; + R[9] = R[6]; + R[12] = R[3]; + R[13] = R[7]; + R[14] = R[11]; + + return { R: R, m: m, N: N }; +} +UPNG.quantize.estats = function (stats) { + var R = stats.R, m = stats.m, N = stats.N; + + // when all samples are equal, but N is large (millions), the Rj can be non-zero ( 0.0003.... - precission error) + var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], iN = (N == 0 ? 0 : 1 / N); + var Rj = [ + R[0] - m0 * m0 * iN, R[1] - m0 * m1 * iN, R[2] - m0 * m2 * iN, R[3] - m0 * m3 * iN, + R[4] - m1 * m0 * iN, R[5] - m1 * m1 * iN, R[6] - m1 * m2 * iN, R[7] - m1 * m3 * iN, + R[8] - m2 * m0 * iN, R[9] - m2 * m1 * iN, R[10] - m2 * m2 * iN, R[11] - m2 * m3 * iN, + R[12] - m3 * m0 * iN, R[13] - m3 * m1 * iN, R[14] - m3 * m2 * iN, R[15] - m3 * m3 * iN + ]; + + var A = Rj, M = UPNG.M4; + var b = [Math.random(), Math.random(), Math.random(), Math.random()], mi = 0, tmi = 0; + + if (N != 0) + for (var i = 0; i < 16; i++) { + b = M.multVec(A, b); + tmi = Math.sqrt(M.dot(b, b)); + b = M.sml(1 / tmi, b); + if (i != 0 && Math.abs(tmi - mi) < 1e-9) break; + mi = tmi; + } + //b = [0,0,1,0]; mi=N; + var q = [m0 * iN, m1 * iN, m2 * iN, m3 * iN]; + var eMq255 = M.dot(M.sml(255, q), b); + + return { + Cov: Rj, + q: q, + e: b, + L: mi, + eMq255: eMq255, + eMq: M.dot(b, q), + rgba: (((Math.round(255 * q[3]) << 24) | (Math.round(255 * q[2]) << 16) | (Math.round(255 * q[1]) << 8) | (Math.round(255 * q[0]) << 0)) >>> 0) + }; +} +UPNG.M4 = { + multVec: function (m, v) { + return [ + m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * v[3], + m[4] * v[0] + m[5] * v[1] + m[6] * v[2] + m[7] * v[3], + m[8] * v[0] + m[9] * v[1] + m[10] * v[2] + m[11] * v[3], + m[12] * v[0] + m[13] * v[1] + m[14] * v[2] + m[15] * v[3] + ]; + }, + dot: function (x, y) { + return x[0] * y[0] + x[1] * y[1] + x[2] * y[2] + x[3] * y[3]; + }, + sml: function (a, y) { + return [a * y[0], a * y[1], a * y[2], a * y[3]]; + } +} + +UPNG.encode.concatRGBA = function (bufs) { + var tlen = 0; + for (var i = 0; i < bufs.length; i++) tlen += bufs[i].byteLength; + var nimg = new Uint8Array(tlen), noff = 0; + for (var i = 0; i < bufs.length; i++) { + var img = new Uint8Array(bufs[i]), il = img.length; + for (var j = 0; j < il; j += 4) { + var r = img[j], g = img[j+1], b = img[j+2], a = img[j+3]; + if (a == 0) r = g = b = 0; + nimg[noff+j] = r; + nimg[noff + j+1] = g; + nimg[noff + j+2] = b; + nimg[noff + j+3] = a; + } + noff += il; + } + return nimg.buffer; +} + +UPNG.encode.dither = function (sb, w, h, plte, tb, oind) { + + function addErr(er, tg, ti, f) { + tg[ti] += (er[0] * f) >> 4; + tg[ti+1] += (er[1] * f) >> 4; + tg[ti+2] += (er[2] * f) >> 4; + tg[ti+3] += (er[3] * f) >> 4; + } + + function N(x) { + return Math.max(0, Math.min(255, x)); + } + + function D(a, b) { + var dr = a[0] - b[0], dg = a[1] - b[1], db = a[2] - b[2], da = a[3] - b[3]; + return (dr * dr + dg * dg + db * db + da * da); + } + + + var pc = plte.length, nplt = [], rads = []; + for (var i = 0; i < pc; i++) { + var c = plte[i]; + nplt.push([((c >>> 0) & 255), ((c >>> 8) & 255), ((c >>> 16) & 255), ((c >>> 24) & 255)]); + } + for (var i = 0; i < pc; i++) { + var ne = 0xffffffff, ni = 0; + for (var j = 0; j < pc; j++) { + var ce = D(nplt[i], nplt[j]); + if (j != i && ce < ne) { + ne = ce; + ni = j; + } + } + var hd = Math.sqrt(ne) / 2; + rads[i] = ~~(hd * hd); + } + + var tb32 = new Uint32Array(tb.buffer); + var err = new Int16Array(w * h * 4); + + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + var i = (y * w + x) * 4; + + var cc = [N(sb[i] + err[i]), N(sb[i+1] + err[i+1]), N(sb[i+2] + err[i+2]), N(sb[i+3] + err[i+3])]; + + var ni = 0, nd = 0xffffff; + for (var j = 0; j < pc; j++) { + var cd = D(cc, nplt[j]); + if (cd < nd) { + nd = cd; + ni = j; + } + } + + var nc = nplt[ni]; + var er = [cc[0] - nc[0], cc[1] - nc[1], cc[2] - nc[2], cc[3] - nc[3]]; + + if (x != w - 1) addErr(er, err, i + 4, 7); + if (y != h - 1) { + if (x != 0) addErr(er, err, i + 4 * w - 4, 3); + addErr(er, err, i + 4 * w, 5); + if (x != w - 1) addErr(er, err, i + 4 * w + 4, 1); //*/ + } + + oind[i>>2] = ni; + tb32[i>>2] = plte[ni]; + } + } +} + +UPNG.encode._strToUint8Array = function (str) { + + var arr = []; + for (var i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + var tmpUint8Array = new Uint8Array(arr); + return tmpUint8Array +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/entry/ImageInfo.ets b/entry/src/main/ets/MainAbility/glide/pngj/entry/ImageInfo.ets new file mode 100644 index 0000000..fdf7a38 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/entry/ImageInfo.ets @@ -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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/interface/IBytesConsumer.ets b/entry/src/main/ets/MainAbility/glide/pngj/interface/IBytesConsumer.ets new file mode 100644 index 0000000..b9cb4ef --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/interface/IBytesConsumer.ets @@ -0,0 +1,5 @@ +export interface IBytesConsumer { + isDone(): boolean; + + consume(buf: ArrayBuffer, offset: number, len: number): number; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/io/Closeable.ets b/entry/src/main/ets/MainAbility/glide/pngj/io/Closeable.ets new file mode 100644 index 0000000..2accfe7 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/io/Closeable.ets @@ -0,0 +1,3 @@ +export interface Closeable { + close(): void; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/pngj/misc/Sandbox.ets b/entry/src/main/ets/MainAbility/glide/pngj/misc/Sandbox.ets new file mode 100644 index 0000000..a5c2b7c --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/pngj/misc/Sandbox.ets @@ -0,0 +1,7 @@ +export class Sandbox { + + + public static convert(origFileName: string, destFileName: string) { + + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/requestmanage/DiskCacheProxy.ets b/entry/src/main/ets/MainAbility/glide/requestmanage/DiskCacheProxy.ets new file mode 100644 index 0000000..3234bf1 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/requestmanage/DiskCacheProxy.ets @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {ICache} from "../requestmanage/ICache.ets" +import {DiskLruCache} from "../../cache/DiskLruCache.ets" + +export class DiskCacheProxy implements ICache { + private mDiskLruCache: DiskLruCache; + + constructor(diskLruCache: DiskLruCache) { + this.mDiskLruCache = diskLruCache; + } + + // 缓存类型 + getName(): string{ + return "Level2DiskCache"; + } + + getCachePath():string{ + let folderPath = this.mDiskLruCache.dirPath + if (folderPath.endsWith('/')) { + return folderPath; + } else { + return folderPath + '/' + } + } + + getValue(key: string): ArrayBuffer{ + return this.mDiskLruCache.getCacheDataByKey(key); + } + + putValue(key: string, value: ArrayBuffer) { + this.mDiskLruCache.putCacheData(key, value, null) + } + + removeValue(key: string): ArrayBuffer{ + // Disk暂无实现 + return; + } + + clear() { + this.mDiskLruCache.cleanCacheData(); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/requestmanage/ICache.ets b/entry/src/main/ets/MainAbility/glide/requestmanage/ICache.ets new file mode 100644 index 0000000..a108f84 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/requestmanage/ICache.ets @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ICache { + + // 缓存类型 + getName(): string + + getValue(key: K): V; + + putValue(key: K, value: V); + + removeValue(key: K): V; + + clear(); + + +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/requestmanage/MemoryCacheProxy.ets b/entry/src/main/ets/MainAbility/glide/requestmanage/MemoryCacheProxy.ets new file mode 100644 index 0000000..18996b4 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/requestmanage/MemoryCacheProxy.ets @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {ICache} from "../requestmanage/ICache.ets" +import {LruCache} from "../../cache/LruCache" + +export class MemoryCacheProxy implements ICache { + private mLruCache: LruCache; + + constructor(lruCache: LruCache) { + this.mLruCache = lruCache; + } + + // 缓存类型 + getName() { + return "Level1MemoryCache" + } + + getValue(key: K): V{ + console.log("Level1MemoryCache getValue come in!"); + return this.mLruCache.get(key); + } + + putValue(key: K, value: V) { + this.mLruCache.put(key, value); + } + + removeValue(key: K): V{ + return this.mLruCache.remove(key); + } + + clear() { + this.mLruCache.evicAll(); + } + + + // 外界调用 + loadMemoryCache(key: K, isMemoryCacheable: boolean): V{ + // 是否开启内存缓存 + if (!isMemoryCacheable) { + return null; + } + let cached = this.getValue(key) + if (cached != null) { + return cached; + } + return null; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/requestmanage/RequstManager.ets b/entry/src/main/ets/MainAbility/glide/requestmanage/RequstManager.ets new file mode 100644 index 0000000..9da4eaa --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/requestmanage/RequstManager.ets @@ -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; + private mDiskCacheProxy: DiskCacheProxy; + private mIDataFetch: IDataFetch; + private mIResourceFetch: IResourceFetch; + private mParseImageUtil: IParseImage; + + constructor(option: RequestOption, memoryCache1: LruCache, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) { + this.options = option; + + // 缓存部分 + this.mMemoryCacheProxy = new MemoryCacheProxy(memoryCache1); + this.mDiskCacheProxy = new DiskCacheProxy(diskMemoryCache1); + + // 网络下载能力 + this.mIDataFetch = dataFetch; + + // 本地数据解析能力 + this.mIResourceFetch = resourceFetch; + + // 解析image能力 + this.mParseImageUtil = new ParseImageUtil(); + } + + static execute(option: RequestOption, memoryCache1: LruCache, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) { + console.log("RequestManager execute") + let manager = new RequestManager(option, memoryCache1, diskMemoryCache1, dataFetch, resourceFetch); + return new Promise(manager.process.bind(manager)) + .then(option.loadComplete.bind(option)) + .then(manager.loadCompleteAfter.bind(manager)) + .catch(option.loadError.bind(option)); + } + + loadCompleteAfter() { + try { // 内部消化问题 + console.log("loadCompleteAfter!") + if (this.options.allCacheInfoCallback) { + console.log("RequestOption =" + JSON.stringify(this.options)); + + // 内存缓存 + let allCacheInfo = new AllCacheInfo(); + let memoryCache = this.mMemoryCacheProxy.getValue(this.options.generateCacheKey); + allCacheInfo.memoryCacheInfo = { + key: this.options.generateCacheKey, + data: memoryCache + } + + // 变换后缓存 + allCacheInfo.resourceCacheInfo = { + key: Md5.hashStr(this.options.generateResourceKey), + path: (this.mDiskCacheProxy.getCachePath() + Md5.hashStr(this.options.generateResourceKey)) + }; + + // 原图缓存 + allCacheInfo.dataCacheInfo = { + key: Md5.hashStr(this.options.generateDataKey), + path: this.mDiskCacheProxy.getCachePath() + Md5.hashStr(this.options.generateDataKey) + } + this.options.allCacheInfoCallback(allCacheInfo) + } + } catch (err) { + console.log("after err =" + err) + } + } + + + // DecodeJob work + private mStage: Stage = Stage.INITIALIZE; + private mRunReason: RunReason = RunReason.INITIALIZE; + + process(onComplete, onError) { + console.log("RequestManager process !"); + this.loadLeve1MemoryCache(onComplete, onError) + } + + private runWrapped(request: RequestOption, runReason: RunReason, onComplete, onError) { + console.log("RequestManager runWrapped") + if (runReason == RunReason.INITIALIZE) { + this.mStage = this.getNextStage(request, this.mStage); + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); + } else { + throw new Error("Unrecognized run reason: " + runReason) + } + } + + private getNextStage(request: RequestOption, current: Stage): Stage{ + if (current == Stage.INITIALIZE) { + return request.strategy.decodeCachedResource() + ? Stage.RESOURCE_CACHE + : this.getNextStage(request, Stage.RESOURCE_CACHE); + } else if (current == Stage.RESOURCE_CACHE) { + return request.strategy.decodeCachedData() + ? Stage.DATA_CACHE + : this.getNextStage(request, Stage.DATA_CACHE); + } else if (current == Stage.DATA_CACHE) { + return request.onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; + } else if (current == Stage.SOURCE) { + return Stage.FINISHED; + } else if (current == Stage.FINISHED) { + return Stage.FINISHED; + } else { + throw new Error("Unrecognized stage: " + current); + } + } + + //究竟从哪里加载数据 + private searchLoadFrom(request: RequestOption, current: Stage, onComplete, onError) { + console.log("RequestManager searchLoadFrom") + if (current == Stage.RESOURCE_CACHE) { + this.loadDiskFromTransform(request, onComplete, onError); + } else if (current == Stage.DATA_CACHE) { + this.loadDiskFromSource(request, onComplete, onError); + } else if (current == Stage.SOURCE) { + this.parseSource(request, onComplete, onError) + } else if (current == Stage.FINISHED) { + onError("在仅从缓存获取数据中,未获取到数据!") + } else { + throw new Error("Unrecognized stage: " + current); + } + } + + // 加载网络资源 + private loadSourceFromNetwork(request: RequestOption, onComplete, onError) { + let success = (arraybuffer) => { + this.downloadSuccess(arraybuffer, onComplete, onError) + } + this.mIDataFetch.loadData(request, success, onError); + } + + // 加载本地资源 + private loadSourceFormNative(request: RequestOption, onComplete, onError) { + console.log("RequestManager loadSourceFormNative") + // 本地解析后进行一级缓存 + let success = (arrayBuffer) => { + // 使用媒体子系统 ImageSource解析文件 获取PixelMap + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arrayBuffer) + console.log("RequstManager - 文件类型为= " + typeValue) + if ((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) + } + +} + + diff --git a/entry/src/main/ets/MainAbility/glide/resourcemanage/IResourceFetch.ets b/entry/src/main/ets/MainAbility/glide/resourcemanage/IResourceFetch.ets new file mode 100644 index 0000000..872cc53 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/resourcemanage/IResourceFetch.ets @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {RequestOption} from "../RequestOption.ets" + +// 本地资源解析抽象接口 +export interface IResourceFetch { + loadResource(res: Resource, onCompleteFunction, onErrorFunction); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/resourcemanage/ParseResClient.ets b/entry/src/main/ets/MainAbility/glide/resourcemanage/ParseResClient.ets new file mode 100644 index 0000000..eab8aa4 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/resourcemanage/ParseResClient.ets @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {IResourceFetch} from '../resourcemanage/IResourceFetch.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) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/resourcemanage/ParseResClientBase64.ets b/entry/src/main/ets/MainAbility/glide/resourcemanage/ParseResClientBase64.ets new file mode 100644 index 0000000..40342cc --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/resourcemanage/ParseResClientBase64.ets @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {IResourceFetch} from '../resourcemanage/IResourceFetch.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无法解析出错') + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/AsyncTransform.ets b/entry/src/main/ets/MainAbility/glide/transform/AsyncTransform.ets new file mode 100644 index 0000000..80bfd74 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/AsyncTransform.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface AsyncTransform { + (err, data: T) +} diff --git a/entry/src/main/ets/MainAbility/glide/transform/BaseTransform.ets b/entry/src/main/ets/MainAbility/glide/transform/BaseTransform.ets new file mode 100644 index 0000000..626c755 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/BaseTransform.ets @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {RequestOption} from "../../glide/RequestOption.ets" + +export interface BaseTransform { + //实现类 返回作为key生成的一部分 + getName(): string; + + transform(value: ArrayBuffer, request: RequestOption, func: AsyncTransform); +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/BlurTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/BlurTransformation.ets new file mode 100644 index 0000000..6216064 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/BlurTransformation.ets @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../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 { + private _mRadius: number; + + constructor(radius: number) { + this._mRadius = radius; + } + + getName() { + return "BlurTransformation _mRadius:" + this._mRadius; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";BlurTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";BlurTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + fastBlur.blur(data, this._mRadius, true, func); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/BrightnessFilterTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/BrightnessFilterTransformation.ets new file mode 100644 index 0000000..f2001c1 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/BrightnessFilterTransformation.ets @@ -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 { + private _mBrightness: number= 0.0; + + constructor(brightness: number) { + this._mBrightness = brightness; + } + + getName() { + return "BrightnessFilterTransformation:" + this._mBrightness; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + + 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((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((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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/ContrastFilterTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/ContrastFilterTransformation.ets new file mode 100644 index 0000000..29711b7 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/ContrastFilterTransformation.ets @@ -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 { + private _mContrast: number; + + constructor(contrast: number) { + this._mContrast = contrast; + } + + getName() { + return "ContrastFilterTransformation:" + this._mContrast; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";ContrastFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";ContrastFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + + 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((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((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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/CropCircleTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/CropCircleTransformation.ets new file mode 100644 index 0000000..e5a4f2d --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/CropCircleTransformation.ets @@ -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 { + 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) { + 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) { + 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) { + 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((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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/CropCircleWithBorderTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/CropCircleWithBorderTransformation.ets new file mode 100644 index 0000000..40fefcc --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/CropCircleWithBorderTransformation.ets @@ -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 { + 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) { + 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) { + 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) { + 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((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((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((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); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/CropSquareTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/CropSquareTransformation.ets new file mode 100644 index 0000000..30aa686 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/CropSquareTransformation.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../glide/RequestOption.ets" + +import image from "@ohos.multimedia.image" + +export class CropSquareTransformation implements BaseTransform { + private static TAG: string= "CropSquareTransformation"; + + getName() { + return CropSquareTransformation.TAG + ";CropSquareTransformation:" + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";CropSquareTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";CropSquareTransformation buf is empty", null); + } + return; + } + this.squareCrop(buf, request, func); + } + + squareCrop(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + var imageSource = image.createImageSource(buf); + imageSource.getImageInfo() + .then((p) => { + var pw = p.size.width; + var ph = p.size.height; + var outWidth = request.size.width; + var outHeight = request.size.height; + if (pw < outWidth) { + outWidth = pw; + } + if (ph < outHeight) { + outHeight = ph; + } + var targetSize = outWidth > outHeight ? outHeight : outWidth; + var options = { + editable: true, + rotate: 0, + desiredSize: { + width: outWidth, + height: outHeight + }, + desiredRegion: { size: { width: targetSize, height: targetSize }, + x: pw / 2 - targetSize / 2, + y: ph / 2 - targetSize / 2, + }, + } + imageSource.createPixelMap(options) + .then(data => { + if (func) { + func("", data); + } + }) + .catch(e => { + if (func) { + func(Constants.PROJECT_TAG + ";CropSquareTransformation e:" + e, null); + } + }) + }) + .catch((error) => { + if (func) { + func(Constants.PROJECT_TAG + ";CropSquareTransformation error:" + error, null); + } + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/CropTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/CropTransformation.ets new file mode 100644 index 0000000..5e23729 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/CropTransformation.ets @@ -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 { + private static TAG: string= "CropCircleTransformation"; + private mWidth: number; + private mHeight: number; + private mCropType: CropType= CropType.CENTER; + + constructor(width: number, height: number, cropType?: CropType) { + this.mWidth = width; + this.mHeight = height; + this.mCropType = cropType; + } + + getName() { + return CropTransformation.TAG + ";mWidth:" + this.mWidth + + ";mHeight:" + this.mHeight + + ";mCropType:" + this.mCropType; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";CropTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";CropTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + 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 +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/GrayscaleTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/GrayscaleTransformation.ets new file mode 100644 index 0000000..8a536bc --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/GrayscaleTransformation.ets @@ -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 { + getName() { + return "GrayscaleTransformation:" + this; + } + + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + + 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((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((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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/InvertFilterTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/InvertFilterTransformation.ets new file mode 100644 index 0000000..159b8bb --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/InvertFilterTransformation.ets @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {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 { + getName() { + return "InvertFilterTransformation"; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";InvertFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";InvertFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + + 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((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((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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/PixelationFilterTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/PixelationFilterTransformation.ets new file mode 100644 index 0000000..976a26a --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/PixelationFilterTransformation.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../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 { + private _mPixel: number= 10.0; + + constructor(pixel?: number) { + if (pixel) { + this._mPixel = pixel; + } + } + + getName() { + return "PixelationFilterTransformation" + this._mPixel; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";PixelationFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";PixelationFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + pixelUtils.pixel(data, this._mPixel, func); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/RotateImageTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/RotateImageTransformation.ets new file mode 100644 index 0000000..7d80646 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/RotateImageTransformation.ets @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {BaseTransform} from "../transform/BaseTransform.ets" +import {AsyncTransform} from "../transform/AsyncTransform.ets" +import {Constants} from "../constants/Constants.ets" +import {RequestOption} from "../../glide/RequestOption.ets" +import {TransformUtils} from "../transform/TransformUtils.ets" + +import image from "@ohos.multimedia.image" + +export class RotateImageTransformation implements BaseTransform { + private mDegreesToRotate: number; + + constructor(degreesToRotate: number) { + this.mDegreesToRotate = degreesToRotate; + } + + getName() { + return "RotateImageTransformation" + ";degreesToRotate:" + this.mDegreesToRotate; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";RotateImageTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";RotateImageTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + rotate: this.mDegreesToRotate%360, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + func("", data); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/RoundedCornersTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/RoundedCornersTransformation.ets new file mode 100644 index 0000000..17ba708 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/RoundedCornersTransformation.ets @@ -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 { + 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) { + 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) { + var options = { + editable: true, + desiredSize: { + width: outWith, + height: outHeight + } + } + imageSource.createPixelMap(options) + .then((pixelMap) => { + this.mTransform_pixelMap = pixelMap; + this.mTransform_pixelMap.getImageInfo() + .then((data) => { + let width = data.size.width; + let height = data.size.height; + if (this.mTop_left > 0) { + this.top_left_corners(); + } + if (this.mTop_right > 0) { + this.top_right_corners(width); + } + if (this.mBottom_left > 0) { + this.bottom_left_corners(width, height); + } + if (this.mBottom_right > 0) { + this.bottom_right_corners(width, height); + } + if (func) { + func("", this.mTransform_pixelMap); + } + }) + .catch((error) => { + console.log(Constants.PROJECT_TAG + "RoundedCornersTransformation error:" + error); + }); + }) + .catch((e) => { + console.log(Constants.PROJECT_TAG + ";error:" + e); + if (func) { + func(e, null); + } + }) + + } + + private top_left_corners() { + this.mPoint = new Array(); + for (var time = 180; time < 270; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = this.mTop_left + Math.sin(hudu) * this.mTop_left; + var y = this.mTop_left + Math.cos(hudu) * this.mTop_left; + this.mPoint.push(new ArcPoint(x, y)); + } + this.hand_pixel_point(this.mPoint); + } + + private top_right_corners(width: number) { + this.mPoint = new Array(); + for (var time = 0; time < 90; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = (width - this.mTop_right) + Math.cos(hudu) * this.mTop_right; + var y = this.mTop_right - Math.sin(hudu) * this.mTop_right; + this.mPoint.push(new ArcPoint(x, y)); + } + + this.hand_right_pixel_point(this.mPoint, width); + } + + private bottom_left_corners(width: number, height: number) { + this.mPoint = new Array(); + for (var time = 90; time < 180; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = this.mBottom_left + Math.cos(hudu) * this.mBottom_left; + var y = height - this.mBottom_left + Math.sin(hudu) * this.mBottom_left; + this.mPoint.push(new ArcPoint(x, y)); + } + this.hand_pixel_point(this.mPoint); + } + + private bottom_right_corners(width: number, height: number) { + this.mPoint = new Array(); + for (var time = 0; time < 90; time++) { + var hudu = (2 * Math.PI / 360) * time; + var x = width - this.mBottom_right + Math.cos(hudu) * this.mBottom_right; + var y = height - this.mBottom_right + Math.sin(hudu) * this.mBottom_right; + this.mPoint.push(new ArcPoint(x, y)); + } + this.hand_right_pixel_point(this.mPoint, width); + } + + private hand_pixel_point(points: ArcPoint[]) { + for (var index = 0; index < points.length; index++) { + const element = points[index]; + let x = element.getX(); + let y = element.getY(); + + for (var i = 0; i <= x; i++) { + var buffer1 = new ArrayBuffer(5); + var bytes1 = new Uint8Array(buffer1); + var writePositionRen = { + pixels: buffer1, + offset: 1, + stride: 1024, + region: { size: { width: 1, height: 1 }, + x: i, + y: y + } + } + for (let j = 0;j < 5; j++) { + bytes1[j] = 0; + } + this.mTransform_pixelMap.writePixels(writePositionRen); + } + } + } + + private hand_right_pixel_point(points: ArcPoint[], width: number) { + for (var index = 0; index < points.length; index++) { + const element = points[index]; + let x = element.getX(); + let y = element.getY(); + + for (var i = x; i <= width; i++) { + var buffer1 = new ArrayBuffer(5); + var bytes1 = new Uint8Array(buffer1); + var writePositionRen = { + pixels: buffer1, + offset: 0, + stride: 4, + region: { size: { width: 1, height: 1 }, + x: i, + y: y + } + } + for (let j = 0;j < 5; j++) { + bytes1[j] = 0; + } + this.mTransform_pixelMap.writePixels(writePositionRen); + } + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/SepiaFilterTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/SepiaFilterTransformation.ets new file mode 100644 index 0000000..d47e703 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/SepiaFilterTransformation.ets @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {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. + *

+ * The intensity with a default of 1.0. + */ +export class SepiaFilterTransformation implements BaseTransform { + getName() { + return "SepiaFilterTransformation"; + } + + async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + console.log(Constants.PROJECT_TAG + ";SepiaFilterTransformation buf is empty"); + if (func) { + func(Constants.PROJECT_TAG + ";SepiaFilterTransformation buf is empty", null); + } + return; + } + var imageSource = image.createImageSource(buf); + + 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((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((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; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/SketchFilterTransformation.ets b/entry/src/main/ets/MainAbility/glide/transform/SketchFilterTransformation.ets new file mode 100644 index 0000000..fa15e4d --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/SketchFilterTransformation.ets @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from '../transform/BaseTransform.ets' +import {AsyncTransform} from '../transform/AsyncTransform.ets' +import {Constants} from '../constants/Constants.ets' +import {RequestOption} from '../../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 { + getName() { + return 'SketchFilterTransformation'; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';SketchFilterTransformation buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';SketchFilterTransformation buf is empty', null); + } + return; + } + var imageSource = image.createImageSource(buf); + TransformUtils.getPixelMapSize(imageSource, (error, size: { + width: number, + height: number + }) => { + if (!size) { + func(error, null) + return; + } + var pixelMapWidth = size.width; + var pixelMapHeight = size.height; + var targetWidth = request.size.width; + var targetHeight = request.size.height; + if (pixelMapWidth < targetWidth) { + targetWidth = pixelMapWidth; + } + if (pixelMapHeight < targetHeight) { + targetHeight = pixelMapHeight; + } + + var options = { + editable: true, + desiredSize: { + width: targetWidth, + height: targetHeight + } + } + imageSource.createPixelMap(options) + .then((data) => { + CalculatePixelUtils.sketch(data, func); + }) + .catch((e) => { + func(e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/TransformUtils.ets b/entry/src/main/ets/MainAbility/glide/transform/TransformUtils.ets new file mode 100644 index 0000000..3cd80a1 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/TransformUtils.ets @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {AsyncTransform} from '../transform/AsyncTransform.ets' +import image from '@ohos.multimedia.image' + +export class TransformUtils { + static centerCrop(buf: ArrayBuffer, outWidth: number, outHeihgt: number, + callback?: AsyncTransform>) { + 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{ + 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>) { + 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>) { + 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 }); + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/pixelmap/CenterCrop.ets b/entry/src/main/ets/MainAbility/glide/transform/pixelmap/CenterCrop.ets new file mode 100644 index 0000000..45012bb --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/pixelmap/CenterCrop.ets @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from '../BaseTransform.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 { + getName() { + return 'CenterCrop:' + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';CenterCrop buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';CenterCrop buf is empty', null); + } + return; + } + TransformUtils.centerCrop(buf, request.size.width, request.size.height, (error, data) => { + data.then(p => { + func('', p); + }).catch(e => { + func(Constants.PROJECT_TAG + ';CenterCrop error:' + e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/pixelmap/CenterInside.ets b/entry/src/main/ets/MainAbility/glide/transform/pixelmap/CenterInside.ets new file mode 100644 index 0000000..292a84b --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/pixelmap/CenterInside.ets @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from '../BaseTransform.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 { + getName() { + return 'CenterInside:' + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';CenterInside buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';CenterInside buf is empty', null); + } + return; + } + TransformUtils.centerInside(buf, request.size.width, request.size.height, (error, data) => { + data.then(p => { + func('', p); + }).catch(e => { + func(Constants.PROJECT_TAG + ';CenterInside error:' + e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/transform/pixelmap/FitCenter.ets b/entry/src/main/ets/MainAbility/glide/transform/pixelmap/FitCenter.ets new file mode 100644 index 0000000..0e8c0b8 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/transform/pixelmap/FitCenter.ets @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {BaseTransform} from '../BaseTransform.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 { + getName() { + return 'FitCenter:' + this; + } + + transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform) { + if (!buf || buf.byteLength <= 0) { + throw new Error(Constants.PROJECT_TAG + ';FitCenter buf is empty'); + if (func) { + func(Constants.PROJECT_TAG + ';FitCenter buf is empty', null); + } + return; + } + TransformUtils.fitCenter(buf, request.size.width, request.size.height, (error, data) => { + data.then(p => { + func('', p); + }).catch(e => { + func(Constants.PROJECT_TAG + ';FitCenter error:' + e, null); + }) + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/utils/CalculatePixelUtils.ets b/entry/src/main/ets/MainAbility/glide/utils/CalculatePixelUtils.ets new file mode 100644 index 0000000..2ee2de2 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/CalculatePixelUtils.ets @@ -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) { + let imageInfo = await p.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + func(new Error("sketch The image size does not exist."), null) + return; + } + + let pos, row, col, clr: number; + let width = size.width; + let height = size.height; + var pixEntry: Array = new Array() + var pixSrc: Array = new Array() + var pixNvt: Array = new Array() + let 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((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((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, horz: number, vert: number, + width: number, height: number): number { + let dst, src, n_p, n_m, d_p, d_m, bd_p, bd_m, val_p, val_m, initial_p, initial_m: Array; + let i, j, t, k, row, col, terms, std_dev, sp_p_idx, sp_m_idx, vp_idx, vm_idx: number; + let row_stride = width; + let max_len = Math.max(width, height); + val_p = createIntArray(max_len); + val_m = createIntArray(max_len); + n_p = createIntArray(5); + n_m = createIntArray(5); + d_p = createIntArray(5); + d_m = createIntArray(5); + bd_p = createIntArray(5); + bd_m = createIntArray(5); + src = createIntArray(max_len); + dst = createIntArray(max_len); + initial_p = createIntArray(4); + initial_m = createIntArray(4); + // 垂直方向 + if (vert > 0.0) { + vert = Math.abs(vert) + 1.0; + std_dev = Math.sqrt(-(vert * vert) / (2 * Math.log(1.0 / 255.0))); + // 初试化常量 + findConstants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + for (col = 0; col < width; col++) { + for (k = 0; k < max_len; k++) { + val_m[k] = val_p[k] = 0; + } + for (t = 0; t < height; t++) { + src[t] = psrc[t * row_stride + col]; + } + sp_p_idx = 0; + sp_m_idx = height - 1; + vp_idx = 0; + vm_idx = height - 1; + initial_p[0] = src[0]; + initial_m[0] = src[height - 1]; + for (row = 0; row < height; row++) { + terms = (row < 4) ? row : 4; + for (i = 0; i <= terms; i++) { + val_p[vp_idx] += n_p[i] * src[sp_p_idx - i] - d_p[i] + * val_p[vp_idx - i]; + val_m[vm_idx] += n_m[i] * src[sp_m_idx + i] - d_m[i] + * val_m[vm_idx + i]; + } + for (j = i; j <= 4; j++) { + val_p[vp_idx] += (n_p[j] - bd_p[j]) * initial_p[0]; + val_m[vm_idx] += (n_m[j] - bd_m[j]) * initial_m[0]; + } + sp_p_idx++; + sp_m_idx--; + vp_idx++; + vm_idx--; + } + transferGaussPixels(val_p, val_m, dst, 1, height); + for (t = 0; t < height; t++) { + psrc[t * row_stride + col] = dst[t]; + } + } + } + // 水平方向 + if (horz > 0.0) { + horz = Math.abs(horz) + 1.0; + if (horz != vert) { + std_dev = Math.sqrt(-(horz * horz) + / (2 * Math.log(1.0 / 255.0))); + // 初试化常量 + findConstants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + } + for (row = 0; row < height; row++) { + for (k = 0; k < max_len; k++) { + val_m[k] = val_p[k] = 0; + } + for (t = 0; t < width; t++) { + src[t] = psrc[row * row_stride + t]; + } + sp_p_idx = 0; + sp_m_idx = width - 1; + vp_idx = 0; + vm_idx = width - 1; + initial_p[0] = src[0]; + initial_m[0] = src[width - 1]; + for (col = 0; col < width; col++) { + terms = (col < 4) ? col : 4; + for (i = 0; i <= terms; i++) { + val_p[vp_idx] += n_p[i] * src[sp_p_idx - i] - d_p[i] + * val_p[vp_idx - i]; + val_m[vm_idx] += n_m[i] * src[sp_m_idx + i] - d_m[i] + * val_m[vm_idx + i]; + } + for (j = i; j <= 4; j++) { + val_p[vp_idx] += (n_p[j] - bd_p[j]) * initial_p[0]; + val_m[vm_idx] += (n_m[j] - bd_m[j]) * initial_m[0]; + } + sp_p_idx++; + sp_m_idx--; + vp_idx++; + vm_idx--; + } + transferGaussPixels(val_p, val_m, dst, 1, width); + for (t = 0; t < width; t++) { + psrc[row * row_stride + t] = dst[t]; + } + } + } + return 0; + } + + function findConstants(n_p: Array, n_m: Array, d_p: Array, + d_m: Array, bd_p: Array + , bd_m: Array, std_dev: number) { + let div = Math.sqrt(2 * 3.141593) * std_dev; + let x0 = -1.783 / std_dev; + let x1 = -1.723 / std_dev; + let x2 = 0.6318 / std_dev; + let x3 = 1.997 / std_dev; + let x4 = 1.6803 / div; + let x5 = 3.735 / div; + let x6 = -0.6803 / div; + let x7 = -0.2598 / div; + let i; + n_p[0] = x4 + x6; + n_p[1] = (Math.exp(x1) + * (x7 * Math.sin(x3) - (x6 + 2 * x4) * Math.cos(x3)) + Math + .exp(x0) * (x5 * Math.sin(x2) - (2 * x6 + x4) * Math.cos(x2))); + n_p[2] = (2 + * Math.exp(x0 + x1) + * ((x4 + x6) * Math.cos(x3) * Math.cos(x2) - x5 * Math.cos(x3) + * Math.sin(x2) - x7 * Math.cos(x2) * Math.sin(x3)) + x6 + * Math.exp(2 * x0) + x4 * Math.exp(2 * x1)); + n_p[3] = (Math.exp(x1 + 2 * x0) + * (x7 * Math.sin(x3) - x6 * Math.cos(x3)) + Math.exp(x0 + 2 + * x1) + * (x5 * Math.sin(x2) - x4 * Math.cos(x2))); + n_p[4] = 0.0; + d_p[0] = 0.0; + d_p[1] = -2 * Math.exp(x1) * Math.cos(x3) - 2 * Math.exp(x0) + * Math.cos(x2); + d_p[2] = 4 * Math.cos(x3) * Math.cos(x2) * Math.exp(x0 + x1) + + Math.exp(2 * x1) + Math.exp(2 * x0); + d_p[3] = -2 * Math.cos(x2) * Math.exp(x0 + 2 * x1) - 2 * Math.cos(x3) + * Math.exp(x1 + 2 * x0); + d_p[4] = Math.exp(2 * x0 + 2 * x1); + for (i = 0; i <= 4; i++) { + d_m[i] = d_p[i]; + } + n_m[0] = 0.0; + for (i = 1; i <= 4; i++) { + n_m[i] = n_p[i] - d_p[i] * n_p[0]; + } + let sum_n_p, sum_n_m, sum_d, a, b: number; + sum_n_p = 0.0; + sum_n_m = 0.0; + sum_d = 0.0; + for (i = 0; i <= 4; i++) { + sum_n_p += n_p[i]; + sum_n_m += n_m[i]; + sum_d += d_p[i]; + } + a = sum_n_p / (1.0 + sum_d); + b = sum_n_m / (1.0 + sum_d); + for (i = 0; i <= 4; i++) { + bd_p[i] = d_p[i] * a; + bd_m[i] = d_m[i] * b; + } + } + + function transferGaussPixels(src1: Array, src2: Array, + dest: Array, bytes: number, width: number) { + let i, j, k, b, sum: number; + let bend = bytes * width; + i = j = k = 0; + for (b = 0; b < bend; b++) { + sum = src1[i++] + src2[j++]; + if (sum > 255) + sum = 255; + else if (sum < 0) + sum = 0; + dest[k++] = sum; + } + } + + export function createIntArray(len: number): Array { + let array = new Array(); + for (var index = 0; index < len; index++) { + array.push(0); + } + return array; + } + + export function createInt2DArray(first_len: number, second_len: number): Array> { + let array = new Array>(); + for (let f = 0; f < first_len; f++) { + let s1 = new Array(); + for (let s = 0; s < second_len; s++) { + s1.push(0); + } + array.push(s1); + } + return array; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/utils/ColorUtils.ets b/entry/src/main/ets/MainAbility/glide/utils/ColorUtils.ets new file mode 100644 index 0000000..a14bcf7 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/ColorUtils.ets @@ -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) { + resmgr.getResourceManager() + .then(result => { + var reColor = 'sys.color.' + c; + result.getString($r(reColor) + .id, (err, color) => { + if (!err) { + var cos = JSON.stringify(color); + callback.callback(cos) + } else { + callback.callback(err.message) + } + }); + }) + .catch((error) => { + callback.callback(error.message) + }) + } + + export function red(color: number): number { + return (color >> 16) & 0xFF; + } + + export function green(color: number): number { + return (color >> 8) & 0xFF; + } + + export function blue(color: number): number { + return color & 0xFF; + } + + export function alpha(color: number): number { + return color >>> 24; + } + + export function rgb(red: number, green: number, blue: number): number { + return 0xff000000 | (red << 16) | (green << 8) | blue; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/utils/FastBlur.ets b/entry/src/main/ets/MainAbility/glide/utils/FastBlur.ets new file mode 100644 index 0000000..d690091 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/FastBlur.ets @@ -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) { + + // Stack Blur v1.0 from + // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + // + // Java Author: Mario Klingemann + // http://incubator.quasimondo.com + // created Feburary 29, 2004 + // Android port : Yahel Bouaziz + // http://www.kayenko.com + // ported april 5th, 2012 + + // This is a compromise between Gaussian Blur and Box blur + // It creates much better looking blurs than Box Blur, but is + // 7x faster than my Gaussian Blur implementation. + // + // I called it Stack Blur because this describes best how this + // filter works internally: it creates a kind of moving stack + // of colors whilst scanning through the image. Thereby it + // just has to add one new block of color to the right side + // of the stack and remove the leftmost color. The remaining + // colors on the topmost layer of the stack are either added on + // or reduced by one, depending on if they are on the right or + // on the left side of the stack. + // + // If you are using this algorithm in your code please add + // the following line: + // + // Stack Blur Algorithm by Mario Klingemann + if (radius < 1) { + func("error,radius must be greater than 1 ", null); + return; + } + + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + + if (!size) { + func(new Error("fastBlur The image size does not exist."), null) + return; + } + + let w = size.width; + let h = size.height; + var pixEntry: Array = new Array() + var pix: Array = new Array() + + let 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((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; + 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((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); + } +} diff --git a/entry/src/main/ets/MainAbility/glide/utils/FileTypeUtil.ets b/entry/src/main/ets/MainAbility/glide/utils/FileTypeUtil.ets new file mode 100644 index 0000000..7462063 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/FileTypeUtil.ets @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class FileTypeUtil { + private map = new Map(); + + constructor() { + this.initImageType(); + this.initMediaType(); + this.initOtherType(); + } + + private initImageType(){ + this.map.set("FFD8FF", "JPG") + this.map.set("89504E47", "PNG") + this.map.set("47494638", "GIF") + this.map.set("49492A00", "TIF") + this.map.set("52494646", "RIFF") + this.map.set("57454250", "WEBP") + this.map.set("3C3F786D6C", "SVG") + this.map.set("424D", "BMP") + this.map.set("424D228C010000000000", "BMP") // 16色位图(bmp) + this.map.set("424D8240090000000000", "BMP") // 24位位图(bmp) + this.map.set("424D8E1B030000000000", "BMP") // 256色位图(bmp) + } + + private initMediaType(){ + this.map.set("57415645", "WAV") + this.map.set("41564920", "AVI") + this.map.set("00000020667479706D70", "MP4") + this.map.set("49443303000000002176", "MP3") + this.map.set("464C5601050000000900", "FLV") + } + + private initOtherType(){ + this.map.set("41433130", "DWG") + this.map.set("38425053", "PSD") + this.map.set("7B5C727466", "RTF") + /** XML */ + // this.map.set("3C3F786D6C", "XML") + this.map.set("68746D6C3E", "HTML") + this.map.set("44656C69766572792D646174653A", "EML") + this.map.set("CFAD12FEC5FD746F", "DBX") + this.map.set("2142444E", "PST") + this.map.set("0xD0CF11E0A1B11AE1", "OLE2") + /** Microsoft Word/Excel 注意:word 和 excel的文件头一样 */ + this.map.set("D0CF11E0", "XLS") + + // this.map.set("DOC", "D0CF11E0") + + // this.map.set("504B0304", "DOCX") + + this.map.set("504B0304", "XLSX") + this.map.set("5374616E64617264204A", "MDB") + this.map.set("FF575043", "WPB") + this.map.set("252150532D41646F6265", "EPS") + this.map.set("252150532D41646F6265", "PS") + this.map.set("255044462D312E", "PDF") + this.map.set("AC9EBD8F", "qdf") + this.map.set("458600000600", "qbb") + this.map.set("E3828596", "PWL") + this.map.set("504B0304", "ZIP") + this.map.set("52617221", "ARAR") + this.map.set("2E7261FD", "RAM") + this.map.set("2E524D46", "RM") + this.map.set("2E524D46000000120001", "RMVB") + this.map.set("000001BA", "MPG") + this.map.set("6D6F6F76", "MOV") + this.map.set("3026B2758E66CF11", "ASF") + this.map.set("60EA", "ARJ") + this.map.set("4D546864", "MID") + + this.map.set("1F8B08", "GZ") + this.map.set("48544D4C207B0D0A0942", "CSS") + this.map.set("696B2E71623D696B2E71", "JS") + this.map.set("d0cf11e0a1b11ae10000", "VSD") + this.map.set("d0cf11e0a1b11ae10000", "WPS") + this.map.set("6431303A637265617465", "TORRENT") + this.map.set("3C2540207061676520", "JSP") + this.map.set("7061636B61676520", "JAVA") + this.map.set("CAFEBABE0000002E00", "CLASS") + this.map.set("504B03040A000000", "JAR") + this.map.set("4D616E69666573742D56", "MF") + this.map.set("4D5A9000030000000400", "EXE") + this.map.set("7F454C4601010100", "ELF") + this.map.set("2000604060", "WK1") + this.map.set("00001A0000100400", "WK3") + this.map.set("00001A0002100400", "WK4") + this.map.set("576F726450726F", "LWP") + this.map.set("53520100", "SLY") + } + + + getMaxKeyLength() { + let length = 0; + this.map.forEach((value, key, map) => { + let keyName = key; + length = Math.max(keyName.length, length); + }) + return length; + } + + isImage(arraybuffer: ArrayBuffer) { + + let value = this.getFileType(arraybuffer) + if ( + value == "jpg" || + value == "png" || + value == "riff" || + value == "webp" || + value == "bmp" || + value == "gif" || + value == "svg" + ) { + return true; + } + + return false; + } + + isPixelMapType(arraybuffer: ArrayBuffer) { + + let value = this.getFileType(arraybuffer) + if ( + value == "jpg" || + value == "png" || + value == "riff" || + value == "webp" || + value == "bmp" + ) { + return true; + } + + return false; + } + + isGif(arraybuffer: ArrayBuffer) { + let value = this.getFileType(arraybuffer) + if ( + value == "gif" + ) { + return true; + } + return false; + } + + isSvg(arraybuffer: ArrayBuffer) { + let value = this.getFileType(arraybuffer) + if ( + value == "svg" + ) { + return true; + } + return false; + } + + getFileType(arraybuffer: ArrayBuffer) { + let maxlen = this.getMaxKeyLength() / 2; + let dataView = new DataView(arraybuffer); + let searchKey = ""; + for (let i = 0; i < maxlen; i++) { + searchKey = searchKey + this.dec2Hex(dataView.getUint8(i)); + let value = this.map.get(searchKey); + if (value != undefined) { + return (value as string).toLowerCase(); + } + } + } + + dec2Hex(uint8: number) { + let hex = uint8.toString(16); + if (hex.length <= 1) { + hex = "0" + hex; + } + return hex.toUpperCase(); + } +} diff --git a/entry/src/main/ets/MainAbility/glide/utils/K2DArray.ets b/entry/src/main/ets/MainAbility/glide/utils/K2DArray.ets new file mode 100644 index 0000000..60977ba --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/K2DArray.ets @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * 定义一个二维数组 + */ +export class K2DArray { + private _2dArray: Array> = new Array>(); + private rows: number; + private columns: number; + + public constructor(r: number, c: number, value: number) { + this.rows = r; + this.columns = c; + this.initRows(r); + this.initColumns(c, value); + } + + private initRows(row: number) { + if (row < 1) { + return; + } + for (var i = 0; i < row; i++) { + this._2dArray.push(new Array()) + } + } + + private initColumns(c: number, value: number) { + if (c < 1) { + return; + } + for (var i = 0; i < this._2dArray.length; i++) { + for (var j = 0; j < c; j++) { + this._2dArray[i].push(value); + } + } + } + + /** + * 获取数组 + */ + public getArray(): Array>{ + return this._2dArray; + } + + /** + * 获取数组 + */ + public getColumnsArray(r: number): Array{ + if (r < 0 || r >= this.rows) { + return null; + } + return this._2dArray[r]; + } + + /** + * 获取值 + */ + public getValue(r: number, c: number): number { + if (r < 0 || c < 0 || r >= this.rows || c >= this.columns) { + return; + } + return this._2dArray[r][c]; + } + + /** + * 设置值 + */ + public setValye(r: number, c: number, value: number) { + if (r < 0 || c < 0 || r >= this.rows || c >= this.columns) { + return; + } + this._2dArray[r][c] = value; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/utils/ParseImageUtil.ets b/entry/src/main/ets/MainAbility/glide/utils/ParseImageUtil.ets new file mode 100644 index 0000000..670cec2 --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/ParseImageUtil.ets @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import{IParseImage} from '../interface/IParseImage.ets' +import image from '@ohos.multimedia.image'; + +export class ParseImageUtil implements IParseImage { + parseImage(imageinfo: ArrayBuffer, onCompleteFunction, onErrorFunction) { + this.parseImageThumbnail(1, imageinfo, onCompleteFunction, onErrorFunction) + } + + // scale(0,1) + parseImageThumbnail(scale: number, imageinfo: ArrayBuffer, onCompleteFunction, onErrorFunction) { + let imageSource = image.createImageSource(imageinfo); // 步骤一:文件转为pixelMap 然后变换 给Image组件 + imageSource.getImageInfo((err, value) => { + if (err) { + onErrorFunction(err); + return; + } + let hValue = Math.round(value.size.height * scale); + let wValue = Math.round(value.size.width * scale); + let defaultSize = { + 'height': hValue, + 'width': wValue + }; + + let opts = { + editable: true, + size: defaultSize + }; + + + imageSource.createPixelMap(opts, (err, pixelmap) => { + if (err) { + onErrorFunction(err); + } else { + onCompleteFunction(pixelmap); + } + }) + + }) + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/glide/utils/PixelUtils.ets b/entry/src/main/ets/MainAbility/glide/utils/PixelUtils.ets new file mode 100644 index 0000000..0cc14de --- /dev/null +++ b/entry/src/main/ets/MainAbility/glide/utils/PixelUtils.ets @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {CalculatePixelUtils} from "./CalculatePixelUtils" +import {PixelEntry} from "../entry/PixelEntry" +import {AsyncTransform} from "../transform/AsyncTransform" +import {ColorUtils} from "./ColorUtils" + +export namespace pixelUtils { + + export async function pixel(bitmap: any, pixel: number, func: AsyncTransform) { + + let imageInfo = await bitmap.getImageInfo(); + let size = { + width: imageInfo.size.width, + height: imageInfo.size.height + } + if (!size) { + func(new Error("GrayscaleTransformation The image size does not exist."), null) + return; + } + let targetWidth = size.width; + let targetHeight = size.height; + + var pixEntry: Array = new Array() + let inPixels: Array> = CalculatePixelUtils.createInt2DArray(targetHeight, targetWidth); + let readPromise; + let writePromise; + //读取 + for (let ph = 0; ph < targetHeight; ph++) { + for (let pw = 0; pw < targetWidth; pw++) { + let buffer = new ArrayBuffer(5); + readPromise = new Promise((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); + inPixels[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b); + } + } + var realPixel_W = pixel > targetWidth ? targetWidth : pixel; + var realPixel_H = pixel > targetHeight ? targetHeight : pixel; + + //横排的正方形个数 + var x_index = Math.floor(targetWidth / realPixel_W); + //纵排的正方形个数 + var y_index = Math.floor(targetHeight / realPixel_H); + + for (let ch = 0; ch < y_index; ch++) { + for (let cw = 0; cw < x_index; cw++) { + + let max_x = (cw + 1) * realPixel_W > targetWidth ? targetWidth : (cw + 1) * realPixel_W; + let max_y = (ch + 1) * realPixel_H > targetHeight ? targetHeight : (ch + 1) * realPixel_H; + + + let min_x = cw * realPixel_W; + let min_y = ch * realPixel_H; + + //取左上角的像素值 + let center_p = inPixels[min_y+1][min_x+1]; + //设置该正方形里的像素统一 + for (let zh = min_y; zh < max_y; zh++) { + for (let zw = min_x; zw < max_x; zw++) { + inPixels[zh][zw] = center_p; + } + } + } + } + + + for (let m = 0;m < targetHeight; m++) { //y + for (let n = 0;n < targetWidth; n++) { //x + writePromise = new Promise((resolve, reject) => { + let buffer1B = new ArrayBuffer(5); + let bytes1B = new Uint8Array(buffer1B); + let writePositionRenB = { + pixels: buffer1B, + offset: 1, + stride: 1024, + region: { size: { width: 1, height: 1 }, + x: n, + y: m + } + } + let index = m * targetWidth + n; + let pxix1 = inPixels[m][n]; + let p_b = ColorUtils.blue(pxix1); + let p_g = ColorUtils.green(pxix1); + let p_r = ColorUtils.red(pxix1); + + bytes1B[0] = pixEntry[index].a; + bytes1B[1] = p_b; + bytes1B[2] = p_g; + bytes1B[3] = p_r; + bytes1B[4] = pixEntry[index].f; + bitmap.writePixels(writePositionRenB, () => { + resolve(); + }); + }) + await writePromise; + } + } + func("success", bitmap); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/CompressPage.ets b/entry/src/main/ets/MainAbility/pages/CompressPage.ets new file mode 100644 index 0000000..fda4304 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/CompressPage.ets @@ -0,0 +1,135 @@ +import {Glide} from '../glide/Glide.ets' +import {PixelMapPack} from '../glide/PixelMapPack.ets' +import {OnRenameListener} from '../glide/compress/listener/OnRenameListener.ets' +import {OnCompressListener} from '../glide/compress/listener/OnCompressListener.ets' + +@Entry +@Component +struct CompressPage { + @State mRPixelMap: PixelMapPack = new PixelMapPack(); + @State mFPixelMap: PixelMapPack = new PixelMapPack(); + @State mResultText: string= "压缩回调结果" + @State mResultPath: string= "压缩路径:" + @State mAsyncPath: string= "" + @State mAsyncPathHint: string= "" + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { + + Column() { + Column() { + Text("Resource image compress").fontColor(Color.Gray).fontSize(16); + Button() { + Text("同步压缩").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.compressAsyncRecource(); + }); + Scroll(){ + Text(this.mAsyncPathHint).fontSize(13) + } + .height(55) + .width(350) + + + Image(this.mAsyncPath) + .width(200) + .height(200) + .margin({ top: 10 }) + .backgroundColor(Color.Pink) + + Button() { + Text($r("app.string.resource_image_compress")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.cropressRecource(); + }); + Image(this.mRPixelMap.pixelMap) + .objectFit(ImageFit.None) + .width(200) + .height(200) + .margin({ top: 10 }) + Text(this.mResultText).fontColor(Color.Gray).fontSize(16); + Text(this.mResultPath).fontColor(Color.Gray).fontSize(16); + }.margin({ top: 10 }); + + Column() { + Text("file image compress").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.file_image_compress")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + }); + Image(this.mFPixelMap.pixelMap) + .objectFit(ImageFit.None) + .width(200) + .height(200) + .margin({ top: 10 }); + }.margin({ top: 10 }).visibility(Visibility.Hidden); + }.margin({ bottom: 30 }); + }.width('100%').height('100%'); + } + private compressAsyncRecource() { + var data = new Array(); + data.push($r('app.media.jpgSample')) + + console.info("asasd start compress") + Glide.with() + .compressBuilder() + .load(data) + .ignoreBy(100) + .get() + .then((path)=>{ + this.mAsyncPathHint = path; + this.mAsyncPath='file://' + path; + }) + ; + console.info("asasd start compress end") + } + private cropressRecource() { + var data = new Array(); + data.push($r('app.media.photo5')) + var rename: OnRenameListener = { + reName() { + return "test_1.jpg"; + } + } + var that = this; + var listener: OnCompressListener = { + start() { + that.mResultText = "start" + console.info("asasd start") + }, + onScuccess(p: PixelMap, path: string) { + let pack = new PixelMapPack(); + pack.pixelMap = p; + that.mRPixelMap = pack; + console.info("asasd success path:" + this.mRPixelMap) + that.mResultText = "success"; + that.mResultPath = path; + }, + onError(s: string) { + console.info("asasd onError:" + s) + that.mResultText = "fail"; + } + } + console.info("asasd start compress") + Glide.with() + .compressBuilder() + .load(data) + .ignoreBy(100) + .setRenameListener(rename) + .setCompressListener(listener) + .launch(); + console.info("asasd start compress end") + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/CropImagePage.ets b/entry/src/main/ets/MainAbility/pages/CropImagePage.ets new file mode 100644 index 0000000..ae83e2d --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/CropImagePage.ets @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {CropImage} from '../glide/crop/CropImage.ets' +import {CropOptions} from '../glide/crop/CropOptions.ets' +import {Crop} from '../glide/crop/Crop.ets' +import {RecourseProvider} from '../glide/compress/provider/RecourseProvider.ets' +import {PixelMapPack} from "../glide/PixelMapPack.ets"; + + +@Component +@Entry +export struct CropImagePage { + private _resource: Resource= $r('app.media.demo_org'); + @State x: number = 0; + @State y: number = 0; + @State crop_size: number = 100; + @State colorRotate: number = 100; + @State _mCropPixelMap: PixelMapPack= new PixelMapPack(); + @State _mCropOptions: CropOptions= { + src: this._mCropPixelMap.pixelMap, + size: { + width: 200, + height: 200 + } + } + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text('原图').fontSize(20) + Image(this._resource).width(300).height(300).margin(10).objectFit(ImageFit.Contain); + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + TextInput({ text: '', placeholder: '裁X坐标' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.x = parseInt(value); + }) + .height(60) + .width(130) + .margin(2) + TextInput({ text: '', placeholder: '裁Y坐标' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.y = parseInt(value); + }) + .height(60) + .width(130) + .margin(2) + + TextInput({ text: '', placeholder: '裁剪长度' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.crop_size = parseInt(value); + }) + .height(60) + .width(130) + .margin(2) + + TextInput({ text: '', placeholder: '颜色比<1' }) + .type(InputType.Number) + .placeholderColor(Color.Gray) + .placeholderFont({ size: 20 }) + .onChange((value: string) => { + this.colorRotate = parseFloat(value); + }) + .height(60) + .width(130) + .margin(2) + + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Button() { + Text('Crop').fontSize(15).fontColor(Color.White) + } + .height(35) + .width(150) + .onClick(() => { + var provider = new RecourseProvider(this._resource); + provider.openInternal((buffer) => { + Crop.crop(buffer, this.x, this.y, this.crop_size, this.crop_size, (error, data) => { + let result = new CropOptions(); + result.src=null; + this._mCropOptions=result; + setTimeout(() => { + this._mCropOptions = { + src: data, + size: { + width: 200, + height: 200 + } + } + },100) + + }, this.colorRotate); + }) + }).margin(10); + CropImage({ _mOptions: $_mCropOptions }) + }.width('100%').height('100%'); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/TransformPixelMapPage.ets b/entry/src/main/ets/MainAbility/pages/TransformPixelMapPage.ets new file mode 100644 index 0000000..88f4730 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/TransformPixelMapPage.ets @@ -0,0 +1,829 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 {CropCircleTransformation} from "../glide/transform/CropCircleTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" +import {CropCircleWithBorderTransformation} from "../glide/transform/CropCircleWithBorderTransformation.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {CropSquareTransformation} from "../glide/transform/CropSquareTransformation.ets" +import {CropTransformation} from "../glide/transform/CropTransformation.ets" +import {CropType} from "../glide/transform/CropTransformation" +import {GrayscaleTransformation} from "../glide/transform/GrayscaleTransformation" +import {BrightnessFilterTransformation} from "../glide/transform/BrightnessFilterTransformation" +import {ContrastFilterTransformation} from "../glide/transform/ContrastFilterTransformation" +import {InvertFilterTransformation} from "../glide/transform/InvertFilterTransformation" +import {SepiaFilterTransformation} from "../glide/transform/SepiaFilterTransformation" +import {SketchFilterTransformation} from "../glide/transform/SketchFilterTransformation" +import {BlurTransformation} from "../glide/transform/BlurTransformation" +import {PixelationFilterTransformation} from "../glide/transform/PixelationFilterTransformation" +import {PixelMapPack} from "../glide/PixelMapPack.ets"; + +/** + * PixelMap transform 示例 + */ +let mRotate: number = 0; +//let mUrl = "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB" +let mUrl = $r('app.media.transformBase'); + +@Entry +@Component +struct TransformPixelMapPage { + @State url: string= ""; + @State mCropPixelMap: PixelMapPack= new PixelMapPack(); + @State mRoundPixelMap: PixelMapPack= new PixelMapPack(); + @State mCirclePixelMap: PixelMapPack= new PixelMapPack(); + @State mCircleBorderPixelMap: PixelMapPack= new PixelMapPack(); + @State mRotatePixelMap: PixelMapPack= new PixelMapPack(); + @State mSquarePixelMap: PixelMapPack= new PixelMapPack(); + @State mClipTopPixelMap: PixelMapPack= new PixelMapPack(); + @State mClipCenterPixelMap: PixelMapPack= new PixelMapPack(); + @State mClipBottomPixelMap: PixelMapPack= new PixelMapPack(); + @State mGrayscalePixelMap: PixelMapPack= new PixelMapPack(); + @State mBrightnessPixelMap: PixelMapPack= new PixelMapPack(); + @State mContrastPixelMap: PixelMapPack= new PixelMapPack(); + @State mInvertPixelMap: PixelMapPack= new PixelMapPack(); + @State mSepiaPixelMap: PixelMapPack= new PixelMapPack(); + @State mSketchPixelMap: PixelMapPack= new PixelMapPack(); + @State mBlurPixelMap: PixelMapPack= new PixelMapPack(); + @State mPixelPixelMap: PixelMapPack= new PixelMapPack(); + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { + Scroll() { + Column() { + Column() { + Text("基础变换").fontColor(Color.Gray).fontSize(16); + Row({ space: 1 }) { + Button() { + Text("CenterCrop").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(100) + .onClick(() => { + this.centerCrop(); + }); + Button() { + Text("CenterInside").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(100) + .onClick(() => { + this.centerInside(); + }); + Button() { + Text("fitCenter").fontSize(13).fontColor(Color.White) + } + .height(35) + .width(100) + .onClick(() => { + this.fitCenter(); + }); + }.margin({ top: 10 }) + + Image(this.mCropPixelMap.pixelMap) + .objectFit(ImageFit.None) + .width(100) + .height(100) + .backgroundColor("#23d1de") + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("RoundedCornersTransformation").fontColor(Color.Gray).fontSize(16); + Row({ space: 1 }) { + Button() { + Text($r("app.string.left_top_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(10, 0, 0, 0); + }); + Button() { + Text($r("app.string.r_top_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(0, 0, 10, 0); + }); + Button() { + Text($r("app.string.left_bottom_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(0, 10, 0, 0); + }); + Button() { + Text($r("app.string.r_bottom_corner")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(0, 0, 0, 10); + }); + Button("All") + .fontSize(13) + .height(35) + .width(72) + .onClick(() => { + this.roundedCornersTransformation(10, 10, 10, 10); + }); + }.margin({ top: 10 }) + + Image(this.mRoundPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropCircleTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_circle")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.circleTransformation(); + }); + Image(this.mCirclePixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropCircleWithBorderTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_circle_border")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.circleBorderTransformation(5); + }); + Image(this.mCircleBorderPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("RotateImageTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_rotate")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + mRotate += 45; + if (mRotate > 360) { + mRotate = 0; + } + this.transformRotate(mRotate); + }); + Image(this.mRotatePixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropSquareTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.trans_square")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.transformSquare(); + }); + Image(this.mSquarePixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("CropTransformation").fontColor(Color.Gray).fontSize(16); + Row({ space: 1 }) { + Button() { + Text($r("app.string.trans_clip_top")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.clipPixelMap(25,25, CropType.TOP); + }); + Button() { + Text($r("app.string.trans_clip_center")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.clipPixelMap(25,25, CropType.CENTER); + }); + Button() { + Text($r("app.string.trans_clip_bottom")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(72) + .onClick(() => { + this.clipPixelMap(25,25, CropType.BOTTOM); + }); + }.margin({ top: 10 }) + + Row({ space: 1 }) { + Image(this.mClipTopPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + Image(this.mClipCenterPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + Image(this.mClipBottomPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + } + }.margin({ top: 10 }); + + Column() { + Text("GrayscaleTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_grayscale")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.grayscalePixelMap(); + }); + Image(this.mGrayscalePixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("BrightnessFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Brightness")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.brightnessPixelMap(0.8); + }); + Image(this.mBrightnessPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("ContrastFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Contrast")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.contrastPixelMap(4); + }); + Image(this.mContrastPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("InvertFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Invert")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.invertPixelMap(); + }); + Image(this.mInvertPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("SepiaFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Sepia")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.sepiaPixelMap(); + }); + Image(this.mSepiaPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + Column() { + Text("SketchFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_Sketch")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.sketchPixelMap(); + }); + Image(this.mSketchPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + Column() { + Text("BlurTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_blur")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.blurHandlePixelMap(20); + }); + Image(this.mBlurPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + + Column() { + Text("PixelationFilterTransformation").fontColor(Color.Gray).fontSize(16); + Button() { + Text($r("app.string.image_pixel")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onClick(() => { + this.pixelHandlePixelMap(20); + }); + Image(this.mPixelPixelMap.pixelMap) + .objectFit(ImageFit.Fill) + .width(100) + .height(100) + .margin({ top: 10 }) + + }.margin({ top: 10 }); + + }.margin({ bottom: 30 }); + + } + }.width('100%').height('100%'); + } + + aboutToAppear() { + + } + + /** + * centerCrop + */ + centerCrop() { + var glideOption = new RequestOption(); + glideOption.load($r('app.media.photo5')) + // glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mCropPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.glideValue as PixelMap; + this.mCropPixelMap = result2; + },100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .centerCrop(); + Glide.call(glideOption); + } + + /** + * centerInside + */ + centerInside() { + var glideOption = new RequestOption(); + glideOption.load($r('app.media.Back')) + //glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mCropPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.glideValue as PixelMap; + this.mCropPixelMap = result2; + },100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .centerInside(); + Glide.call(glideOption); + } + + /** + * centerInside + */ + fitCenter() { + var glideOption = new RequestOption() + glideOption.load($r('app.media.Back')) + //glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mCropPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.glideValue as PixelMap; + this.mCropPixelMap = result2; + },100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .fitCenter(); + Glide.call(glideOption); + } + /** + * 圆角设置 + */ + roundedCornersTransformation(top_left: number, + bottom_left: number, top_right: number, bottom_right: number) { + + var glideOption = new RequestOption(); + + //glideOption.load($r('app.media.photo5')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + this.mRoundPixelMap = result; + setTimeout(() => { + let result2 = new PixelMapPack(); + result2.pixelMap = data.glideValue as PixelMap; + this.mRoundPixelMap = result2; + },100) + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(new RoundedCornersTransformation({ top_left: top_left, top_right: top_right + , bottom_left: bottom_left, bottom_right: bottom_right })) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + } + + /** + * 裁剪圆 + */ + circleTransformation() { + let glideOption = new RequestOption(); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mCirclePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(new CropCircleTransformation()) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + } + + /** + * 圆环裁剪 + */ + circleBorderTransformation(border: number) { + let glideOption = new RequestOption(); + var circleTransformation = new CropCircleWithBorderTransformation(border, + { r_color: 255, g_color: 204, b_color: 204 }); + //glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mCircleBorderPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(circleTransformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + } + + /** + * 旋转 + */ + transformRotate(angled: number) { + let glideOption = new RequestOption(); + var transformation = new RotateImageTransformation(angled); + //glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mRotatePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + } + + /** + * 正方形裁剪 + */ + transformSquare() { + let glideOption = new RequestOption(); + var transformation = new CropSquareTransformation(); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mSquarePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + } + + /** + * 区域裁剪 + */ + clipPixelMap(width: number, height: number, cropType: CropType) { + let glideOption = new RequestOption(); + var transformation = new CropTransformation(width, height, cropType); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + if (cropType == CropType.TOP) { + result.pixelMap=data.glideValue as PixelMap; + this.mClipTopPixelMap = result; + } else if (cropType == CropType.CENTER) { + result.pixelMap=data.glideValue as PixelMap; + this.mClipCenterPixelMap = result; + } else if (cropType == CropType.BOTTOM) { + result.pixelMap=data.glideValue as PixelMap; + this.mClipBottomPixelMap = result; + } + return false; + }) + .setImageViewSize({ width: width, height: height }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + * 灰度 + */ + grayscalePixelMap() { + let glideOption = new RequestOption(); + var transformation = new GrayscaleTransformation(); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mGrayscalePixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + *亮度b + */ + brightnessPixelMap(brightness: number) { + let glideOption = new RequestOption(); + var transformation = new BrightnessFilterTransformation(brightness); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mBrightnessPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + *对比度 + */ + contrastPixelMap(contrast: number) { + let glideOption = new RequestOption(); + var transformation = new ContrastFilterTransformation(contrast); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mContrastPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + *反转处理 + */ + invertPixelMap() { + let glideOption = new RequestOption(); + var transformation = new InvertFilterTransformation(); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mInvertPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + *照片老旧出来(黑褐色) + */ + sepiaPixelMap() { + let glideOption = new RequestOption(); + var transformation = new SepiaFilterTransformation(); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mSepiaPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + *素描 + */ + sketchPixelMap() { + let glideOption = new RequestOption(); + var transformation = new SketchFilterTransformation(); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mSketchPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + + /** + *模糊 + */ + blurHandlePixelMap(radius: number) { + let glideOption = new RequestOption(); + var transformation = new BlurTransformation(radius); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mBlurPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } + /** + *马赛克 + */ + pixelHandlePixelMap(pixel: number) { + let glideOption = new RequestOption(); + var transformation = new PixelationFilterTransformation(pixel); + // glideOption.load($r('app.media.photo6')) + glideOption.load(mUrl) + .addListener((err, data) => { + let result = new PixelMapPack(); + result.pixelMap=data.glideValue as PixelMap; + this.mPixelPixelMap = result; + return false; + }) + .setImageViewSize({ width: vp2px(100), height: vp2px(100) }) + .skipMemoryCache(true) + .transform(transformation) + // .diskCacheStrategy(new NONE()) + Glide.call(glideOption); + + } +} + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/basicTestFeatureAbilityPage.ets b/entry/src/main/ets/MainAbility/pages/basicTestFeatureAbilityPage.ets new file mode 100644 index 0000000..ab2ba4f --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestFeatureAbilityPage.ets @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import featureAbility from '@ohos.ability.featureAbility'; + +@Entry +@Component +struct BasicTestFeatureAbilityPage { + @Watch("watchPathChange") @State filePath:string= "查看featureAbility路径"; + + watchPathChange() { + console.log("watchPathChange"); + } + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.filePath).fontSize(20) + Button("featureAbility.getContext().getFilesDir()") + .margin({top:20}) + .onClick(()=>{ + featureAbility.getContext() + .getFilesDir() + .then((data) => { + console.log("Glide filesPath = " + data) + this.filePath = data + }) + .catch((error) => { + console.error('Glide Failed to obtain the filesPath directory. Cause:' + error.message); + }) + }) + Button("featureAbility.getContext().getCacheDir()") + .margin({top:20}) + .onClick(()=>{ + featureAbility.getContext().getCacheDir() + .then((data) => { + console.log("Glide cachesPath = " + data) + this.filePath = data + }) + .catch((error) => { + console.error('Glide Failed to obtain the cachesPath directory. Cause:' + error.message); + }) + }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestFileIOPage.ets b/entry/src/main/ets/MainAbility/pages/basicTestFileIOPage.ets new file mode 100644 index 0000000..3cf1995 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestFileIOPage.ets @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import featureAbility from '@ohos.ability.featureAbility'; +import {FileUtils} from '../cache/FileUtils.ets' +import resourceManager from '@ohos.resourceManager'; + +@Entry +@Component +struct BasicTestFileIOPage { + @Watch('watchPathChange') @State filePath: string= '查看featureAbility路径'; + appFilePath = ''; + appCachePath = ''; + + watchPathChange() { + console.log('watchPathChange'); + } + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.filePath).fontSize(20) + Button('featureAbility.getContext().getFilesDir()') + .margin({ top: 10 }) + .onClick(() => { + featureAbility.getContext() + .getFilesDir() + .then((data) => { + console.log('Glide filesPath = ' + data) + this.filePath = data + this.appFilePath = data; + }) + .catch((error) => { + console.error('Glide Failed to obtain the filesPath directory. Cause:' + error.message); + }) + }) + Button('featureAbility.getContext().getCacheDir()') + .margin({ top: 10 }) + .onClick(() => { + featureAbility.getContext() + .getCacheDir() + .then((data) => { + console.log('Glide cachesPath = ' + data) + this.filePath = data + this.appCachePath = data + }) + .catch((error) => { + console.error('Glide Failed to obtain the cachesPath directory. Cause:' + error.message); + }) + }) + Button('files目录创建Folder1和Folder2 验证statSync mkdirSync') + .margin({ top: 10 }) + .onClick(() => { + FileUtils.getInstance() + .createFolder(this.appFilePath + '/Folder1'); + FileUtils.getInstance() + .createFolder(this.appFilePath + '/Folder2'); + }) + Button('将media资源存入Folder1 验证writeSync mkdirSync createStreamSync') + .margin({ top: 10 }) + .onClick(() => { + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample').id, ) + .then(data => { + console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data) + let arrayBuffer = this.typedArrayToBuffer(data); + FileUtils.getInstance().writeFile(this.appFilePath + '/Folder1/jpgSample.jpg',arrayBuffer) + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + }) + Button('copy:Folder1至Folder2, 验证copyFileSync') + .margin({ top: 10 }) + .onClick(() => { + let filePath1 = this.appFilePath + '/Folder1/jpgSample.jpg'; + let filePath2 = this.appFilePath + '/Folder2/jpgSample.jpg'; + FileUtils.getInstance().createFolder(this.appFilePath + '/Folder2') + FileUtils.getInstance().copyFile(filePath1, filePath2); + }) + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestMediaImage.ets b/entry/src/main/ets/MainAbility/pages/basicTestMediaImage.ets new file mode 100644 index 0000000..d399cee --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestMediaImage.ets @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import featureAbility from '@ohos.ability.featureAbility'; +import {FileUtils} from '../cache/FileUtils.ets' +import {FileTypeUtil} from '../glide/utils/FileTypeUtil.ets' +import resourceManager from '@ohos.resourceManager'; +import {Base64} from '../cache/Base64.ets' +import {PixelMapPack} from '../glide/PixelMapPack.ets' +import {ParseImageUtil} from '../glide/utils/ParseImageUtil.ets' + +@Entry +@Component +struct BasicTestMediaImage { + @State pixelMapPack:PixelMapPack= new PixelMapPack(); + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button('本地资源jpg') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let jpgPack = new PixelMapPack(); + jpgPack.pixelMap = pxielmap; + this.pixelMapPack = jpgPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源png') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.pngSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let pngPack = new PixelMapPack(); + pngPack.pixelMap = pxielmap; + this.pixelMapPack = pngPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源bmp') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.bmpSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let bmpPack = new PixelMapPack(); + bmpPack.pixelMap = pxielmap; + this.pixelMapPack = bmpPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源webp') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.webpSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let webpPack = new PixelMapPack(); + webpPack.pixelMap = pxielmap; + this.pixelMapPack = webpPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + Button('本地资源gif') + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.gifSample').id) + .then(data => { + let arrayBuffer = this.typedArrayToBuffer(data); + let parseImageUtil = new ParseImageUtil(); + parseImageUtil.parseImage(arrayBuffer,(pxielmap)=>{ + let gifPack = new PixelMapPack(); + gifPack.pixelMap = pxielmap; + this.pixelMapPack = gifPack; + },(err)=>{}) + }) + .catch(err => { + console.log('basicTestMediaImage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + + }).margin({left:15}).backgroundColor(Color.Blue) + } + .margin({top:15}) + Image(this.pixelMapPack.pixelMap) + .width(300) + .height(300) + .backgroundColor(Color.Pink) + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/basicTestResourceManagerPage.ets b/entry/src/main/ets/MainAbility/pages/basicTestResourceManagerPage.ets new file mode 100644 index 0000000..d11e1e5 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/basicTestResourceManagerPage.ets @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import featureAbility from '@ohos.ability.featureAbility'; +import {FileUtils} from '../cache/FileUtils.ets' +import {FileTypeUtil} from '../glide/utils/FileTypeUtil.ets' +import resourceManager from '@ohos.resourceManager'; +import {Base64} from '../cache/Base64.ets' + +@Entry +@Component +struct BasicTestResourceManagerPage { + @State fileTypeStr: string = '解析后图片类型'; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.fileTypeStr).fontSize(20) + .width(300).height(200).backgroundColor(Color.Pink) + Button('getMedia解析一张jpg图片') + .margin({ top: 10 }) + .onClick(() => { + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample') + .id,) + .then(data => { + console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data) + let arrayBuffer = this.typedArrayToBuffer(data); + let filetypeUtil = new FileTypeUtil(); + let fileType = filetypeUtil.getFileType(arrayBuffer); + this.fileTypeStr = fileType; + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + }) + Button('getMediaBase64解析一张png图片') + .margin({ top: 10 }) + .onClick(() => { + resourceManager.getResourceManager() + .then(result => { + result.getMediaBase64($r('app.media.pngSample') + .id) + .then(data => { + console.log('ParseResClientBase64 - 本地加载资源 解析后数据data = ' + data) + let matchReg = ';base64,'; + var firstIndex = data.indexOf(matchReg); + data = data.substring(firstIndex + matchReg.length, data.length) + console.log('ParseResClientBase64 - 本地加载资源 解析后数据剔除非必要数据后data= ' + data) + let arrayBuffer = Base64.getInstance() + .decode(data); + let filetypeUtil = new FileTypeUtil(); + let fileType = filetypeUtil.getFileType(arrayBuffer); + this.fileTypeStr = fileType; + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + }) + }) + + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} diff --git a/entry/src/main/ets/MainAbility/pages/frescoImageTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/frescoImageTestCasePage.ets new file mode 100644 index 0000000..3375324 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/frescoImageTestCasePage.ets @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" + +@Entry +@Component +struct FrescoImageTestCasePage { + + @State progresshint:string = "输出加载百分比回调信息" + + + @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'), + displayProgress: true + }; + @State glideOption2: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true + }; + @State glideOption3: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true + }; + @State glideOption4: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + displayProgressListener:(value)=>{ + console.log("百分比value:"+value) + this.progresshint+="\n"+value; + + } + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { +// GlideImage({ glideOption: $glideOption1 }) +// GlideImage({ glideOption: $glideOption2 }) +// GlideImage({ glideOption: $glideOption3 }) + GlideImage({ glideOption: $glideOption4 }) + Scroll() { + Text(this.progresshint).fontSize(15) + }.width(300).height(200) + + + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/frescoLayerTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/frescoLayerTestCasePage.ets new file mode 100644 index 0000000..9569cfe --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/frescoLayerTestCasePage.ets @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import router from '@system.router'; + +@Entry +@Component +struct FrescoLayerTestCasePage { + + @Watch("watchV1") @State v1:Visibility = Visibility.Visible + @Watch("watchV2") @State v2:Visibility = Visibility.Visible + @Watch("watchV3") @State v3:Visibility = Visibility.Visible + + @State v1Width:string = "100%"; + @State v1Height:string = "100%"; + @State v2Width:string = "100%"; + @State v2Height:string = "100%"; + @State v3Width:string = "100%"; + @State v3Height:string = "100%"; + + + + + watchV1(){ + console.log("watchV1") + } + watchV2(){ + console.log("watchV2") + } + watchV3(){ + console.log("watchV3") + } + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Stack() { + Text('1%') + .fontSize(100) + .fontWeight(FontWeight.Bold) + .visibility(this.v1) + .width(this.v1Width) + .height(this.v1Height) + Image($r('app.media.icon_failed')) + .visibility(this.v2) + .width(this.v2Width) + .height(this.v2Height) + Image($r('app.media.jpgSample')) + .visibility(this.v3) + .width(this.v3Width) + .height(this.v3Height) + } + .width(200) + .height(200) + + Button("显示第一个组件") + .onClick(()=>{ + this.v1 = Visibility.Visible; + this.v2 = Visibility.Hidden; + this.v3 = Visibility.Hidden; + + animateTo({duration:500,curve:Curve.Linear},()=>{ + this.v1Width = "100%"; + this.v1Height = "100%"; + + this.v2Width = "0%"; + this.v2Height = "0%"; + + this.v3Width = "0%"; + this.v3Height = "0%"; + }) + + + }) + Button("显示第二个组件") + .onClick(()=>{ + this.v2 = Visibility.Visible; + this.v1 = Visibility.Hidden; + this.v3 = Visibility.Hidden; + + animateTo({duration:500,curve:Curve.Linear},()=>{ + this.v2Width = "100%"; + this.v2Height = "100%"; + + this.v1Width = "0%"; + this.v1Height = "0%"; + + this.v3Width = "0%"; + this.v3Height = "0%"; + }) + }) + Button("显示第三个组件") + .onClick(()=>{ + this.v3 = Visibility.Visible; + this.v2 = Visibility.Hidden; + this.v1 = Visibility.Hidden; + + animateTo({duration:500,curve:Curve.Linear},()=>{ + this.v3Width = "100%"; + this.v3Height = "100%"; + + this.v2Width = "0%"; + this.v2Height = "0%"; + + this.v1Width = "0%"; + this.v1Height = "0%"; + }) + }) + + } + } + .width('100%') + .height('100%') + } + + + + +} + diff --git a/entry/src/main/ets/MainAbility/pages/frescoRetryTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/frescoRetryTestCasePage.ets new file mode 100644 index 0000000..6291cfa --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/frescoRetryTestCasePage.ets @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" + +@Entry +@Component +struct FrescoImageTestCasePage { + @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'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + @State glideOption2: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + @State glideOption3: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + @State glideOption4: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/testRetryxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + animateDuration: 300, + retryLoad:true + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { +// GlideImage({ glideOption: $glideOption1 }) +// GlideImage({ glideOption: $glideOption2 }) +// GlideImage({ glideOption: $glideOption3 }) + GlideImage({ glideOption: $glideOption4 }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/index.ets b/entry/src/main/ets/MainAbility/pages/index.ets new file mode 100644 index 0000000..76cf4d2 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/index.ets @@ -0,0 +1,188 @@ +/* + * Copyright (C) 1521 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import router from '@system.router'; +import {Pngj} from '../glide/pngj/Pngj' +import {SimulatedDownloadClient} from '../glide/networkmanage/SimulatedDownloadClient' + +@Entry +@Component +struct Index { + @State hint1:string = '启用网络模拟加载替换网络加载' + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button(this.hint1).fontSize(15) + .onClick(()=>{ + let simulatedDownloadClient = new SimulatedDownloadClient(); + Glide.replaceDataFetch(simulatedDownloadClient) + this.hint1 = '已启用网络模拟加载替换网络加载' + }) + Text("OHOS基础接口测试列表").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试元能力") + .onClick(() => { + console.log("测试元能力子系统") + router.push({ uri: "pages/basicTestFeatureAbilityPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试文件") + .onClick(() => { + console.log("测试文件子系统") + router.push({ uri: "pages/basicTestFileIOPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试全球化") + .onClick(() => { + console.log("测试全球化子系统") + router.push({ uri: "pages/basicTestResourceManagerPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试媒体") + .onClick(() => { + console.log("测试媒体子系统") + router.push({ uri: "pages/basicTestMediaImage" }); + }).margin({ top: 5, left: 3 }) + + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试图片切换功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试本地加载") + .onClick(() => { + console.log("测试bmp,webp,jpg,png本地加载 页面跳转") + router.push({ uri: "pages/loadResourceTestCasePage" }); + }).margin({ top: 5, left: 3 }) + Button("测试图片切换") + .onClick(() => { + console.log("测试GlideImage所有图片切换") + router.push({ uri: "pages/testGlideOptionChangedPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试thumbnail") + .onClick(() => { + console.log("测试GlideImage thumbnail") + router.push({ uri: "pages/testGlideOptionChangedPage2" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试存储(1级 2级缓存)功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试一级内存缓存") + .onClick(() => { + console.log("测试一级内存缓存") + router.push({ uri: "pages/storageTestLruCache" }); + }).margin({ top: 5, left: 3 }) + Button("测试二级内存缓存") + .onClick(() => { + console.log("测试二级内存缓存") + router.push({ uri: "pages/storageTestDiskLruCache" }); + }).margin({ top: 5, left: 3 }) + Button("测试JPEG") + .onClick(() => { + console.log("测试JPEG") + router.push({ uri: "pages/JpegProgressTestCasePage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试占位图 失败占位图 功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试占位图") + .onClick(() => { + console.log("测试占位图") + router.push({ uri: "pages/loadNetworkTestCasePage" }); + }).margin({ top: 5, left: 3 }) + Button("测试失败占位图") + .onClick(() => { + console.log("测试失败占位图") + router.push({ uri: "pages/showErrorholderTestCasePage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试预加载 gif静态动态切换功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试预加载") + .onClick(() => { + console.log("测试预加载") + router.push({ uri: "pages/testPreloadPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试gif静态动态切换") + .onClick(() => { + console.log("测试gif静态动态切换") + router.push({ uri: "pages/testGifDontAnimatePage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text("测试图片变换 图片压缩 功能点").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试图片变换") + .onClick(() => { + console.log("测试图片变换") + router.push({ uri: "pages/TransformPixelMapPage" }); + }).margin({ top: 5, left: 3 }) + Button("测试图片压缩") + .onClick(() => { + console.log("测试图片压缩") + router.push({ uri: "pages/CompressPage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + + Button("测试所有缓存信息输出") + .onClick(() => { + console.log("pages/testAllCacheInfoPage 页面跳转") + router.push({ uri: "pages/testAllCacheInfoPage" }); + }).margin({ top: 15 }) + + Button("测试fresco部分AR") + .onClick(() => { + console.log("pages/indexFresco 页面跳转") + router.push({ uri: "pages/indexFresco" }); + }).margin({ top: 15 }) + Button("测试pngj") + .onClick(() => { + console.log("pages/pngjTestCasePage 页面跳转") + router.push({ uri: "pages/pngjTestCasePage" }); + }).margin({ top: 15 }) + Button("测试图片的裁剪") + .onClick(() => { + console.log("pages/CropImagePage 页面跳转") + router.push({ uri: "pages/CropImagePage" }); + }).margin({ top: 15 }) + Button("测试网络") + .onClick(() => { + console.log("pages/networkTestCasePage 页面跳转") + router.push({ uri: "pages/networkTestCasePage" }); + }).margin({ top: 15 }) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + } + + onBackPress() { + let cache = Glide.getMemoryCache(); + cache.print() + } +} +var Glide; +var defaultTemp = globalThis.exports.default +if (defaultTemp != undefined) { + Glide = defaultTemp.data.glide; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/indexFresco.ets b/entry/src/main/ets/MainAbility/pages/indexFresco.ets new file mode 100644 index 0000000..b130c16 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/indexFresco.ets @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import router from '@system.router'; + +@Entry +@Component +struct IndexFresco { + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("测试控件隐藏与展示和动画") + .onClick(() => { + router.push({ uri: "pages/frescoLayerTestCasePage" }); + }).margin({ top: 15 }) + Button("测试自定义控件FrescoImage的加载百分比") + .onClick(() => { + router.push({ uri: "pages/frescoImageTestCasePage" }); + }).margin({ top: 15 }) + Button("测试自定义控件FrescoImage重试Retry") + .onClick(() => { + router.push({ uri: "pages/frescoRetryTestCasePage" }); + }).margin({ top: 15 }) + + + + } + } + .width('100%') + .height('100%') + } + + + + +} + diff --git a/entry/src/main/ets/MainAbility/pages/jpegProgressTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/jpegProgressTestCasePage.ets new file mode 100644 index 0000000..59cb872 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/jpegProgressTestCasePage.ets @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {FileUtils} from "../cache/FileUtils.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" +import resourceManager from '@ohos.resourceManager'; +import image from "@ohos.multimedia.image" +@Entry +@Component +struct JpegProgressTestCasePage { + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('点击调用渐进式解码') + .onClick(()=> { + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample').id) + .then(data => { + let arrayBuffer = FileUtils.getInstance().uint8ArrayToBuffer(data); + let imageSourceIncrementalSApi = image.createIncrementalSource(data); + let array = [1,2,3,4,5,6,7,8,9,10]; + imageSourceIncrementalSApi.updateData(array, false,(error,data) => { + console.log("data is null="+(data == null || data == undefined)) + console.log("array = "+array) + console.log("data ="+data) + + }) + }) + }) + + }) + Button('点击调用渐进式解码带上length') + .onClick(()=> { + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.jpgSample').id) + .then(data => { + let arrayBuffer = FileUtils.getInstance().uint8ArrayToBuffer(data); + let imageSourceIncrementalSApi = image.createIncrementalSource(data); + let array = [1,2,3,4,5,6,7,8,9,10]; + imageSourceIncrementalSApi.updateData(array, false, 0, 10,(error,data) => { + console.log("data is null="+(data == null || data == undefined)) + console.log("array = "+array) + console.log("data ="+data) + + }) + }) + }) + + }) + } + } + .width('100%') + .height('100%') + } +} + diff --git a/entry/src/main/ets/MainAbility/pages/loadNetworkTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/loadNetworkTestCasePage.ets new file mode 100644 index 0000000..684406a --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/loadNetworkTestCasePage.ets @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" + +@Entry +@Component +struct LoadNetworkTestCasePage { + @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'), + }; + @State glideOption2: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption3: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption4: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + GlideImage({ glideOption: $glideOption1 }) + GlideImage({ glideOption: $glideOption2 }) + GlideImage({ glideOption: $glideOption3 }) + GlideImage({ glideOption: $glideOption4 }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/loadResourceTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/loadResourceTestCasePage.ets new file mode 100644 index 0000000..73def41 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/loadResourceTestCasePage.ets @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" + +@Entry +@Component +struct LoadResourceTestCasePage { + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption2: GlideOption = + { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, +// placeholderSrc: $r('app.media.icon_loading'), +// errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption3: GlideOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, +// placeholderSrc: $r('app.media.icon_loading'), +// errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption4: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, +// placeholderSrc: $r('app.media.icon_loading'), +// errorholderSrc: $r('app.media.icon_failed'), + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + GlideImage({ glideOption: $glideOption1 }) +// GlideImage({ glideOption: $glideOption2 }) +// GlideImage({ glideOption: $glideOption3 }) +// GlideImage({ glideOption: $glideOption4 }) + } + } + .width('100%') + .height('100%') + } +} + diff --git a/entry/src/main/ets/MainAbility/pages/networkTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/networkTestCasePage.ets new file mode 100644 index 0000000..0d8853c --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/networkTestCasePage.ets @@ -0,0 +1,114 @@ +/* + * Copyright (C) 1521 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import router from '@system.router'; + +import request from '@ohos.requestability'; + +@Entry +@Component +struct NetworkTestCasePage { + @State hint1: string = '基础request' + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('网络上传下载1').fontSize(15) + .margin({ top: 30 }) + .onClick(() => { + console.log("网络上传下载1") + + let DownloadConfig = { + url: 'https://mirror.bjtu.edu.cn/kernel/linux/libs/libc5/libc5.cvs.tar.gz', // Resource address. + header: {}, // Adds an HTTP or HTTPS header to be included with the upload request. + enableMetered: true, + enableRoaming: true, // Allows download in a roaming network. + description: 'a', // Sets the description of a download session. + networkType: 1, // Sets the network type allowed for download. + filePath: '/data/abc1.txt', // Sets the path for downloads. + title: 'a', // Sets a download session title. + } + + let downloadTask; + + // 使用callback形式回调返回DownloadTask实例。 + console.log("------------------start Download_Test_0100-------------------"); + try { + console.log("Show me the log"); + request.download(DownloadConfig, (err, data) => { + console.log("Download_Test_0100: register download issue successful, result = " + data); + }); + } catch (error) { + console.log("logMessage Download_Test_0100: error = " + error); + } + console.log("------------------end Download_Test_0100-------------------"); + }) + + Button('网络上传下载2').fontSize(15) + .margin({ top: 30 }) + .onClick(() => { + console.log("网络上传下载2") + let downloadConfig = { + url: 'https://img-blog.csdn.net/20140514114029140', + header: {}, + enableMetered: true, + enableRoaming: true, + description: 'download libc from mirror site', + networkType: 1, + filePath: '/data/bmpSample.bmp', + title: 'download libc', + } + let downloadTask; + // 使用callback形式回调返回DownloadTask实例。 + console.log("------------------start Download_Test_0102-------------------"); + try { + console.log("Show me the log"); + request.download(downloadConfig, (err, data) => { + console.log("Download_Test_0102: register download issue successful, result = " + data); + data.on('complete',(err1,data1) =>{ + console.log("Download_Test_0700: , on complete result = "+data1); + }) + data.on('eventType',(err1,data1,data2) =>{ + console.log("Download_Test_0200: , on progress result data1 = "+data1); + console.log("Download_Test_0200: , on progress result data2 = "+data2); + }) + }); + } catch (error) { + console.log("logMessage Download_Test_0102: error = " + error); + } + console.log("------------------end Download_Test_0102-------------------"); + }) + + + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + } + + onBackPress() { + let cache = Glide.getMemoryCache(); + cache.print() + } +} + +var Glide; +var defaultTemp = globalThis.exports.default +if (defaultTemp != undefined) { + Glide = defaultTemp.data.glide; +} \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/pngjTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/pngjTestCasePage.ets new file mode 100644 index 0000000..fdd9c57 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/pngjTestCasePage.ets @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import router from '@system.router'; +import {Pngj} from '../glide/pngj/Pngj' +import resourceManager from '@ohos.resourceManager'; +import {FileUtils} from '../cache/FileUtils.ets' +import featureability from '@ohos.ability.featureAbility' + +@Entry +@Component +struct PngjTestCasePage { + pngSource: ArrayBuffer = new ArrayBuffer(0); + rootFolder: string = ''; + @State hint1: string = 'readPngImageInfo内容展示' + @State hint2: string = 'readPngImage内容展示' + @State hint3: string = 'writePngWithString内容展示' + @State hint4: string = 'writePngWithString内容展示' + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text('pngj接口测试列表').fontSize(20) + + Button('点击获取Png图片buffer').fontSize(20) + .onClick(() => { + + featureability.getContext() + .getFilesDir() + .then((data) => { + this.rootFolder = data; + }) + .catch((err) => { + console.log('点击获取Png图片buffer 路径获取失败 err:' + err) + }) + + + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.Tomato').id) + .then(data => { + this.pngSource = FileUtils.getInstance().uint8ArrayToBuffer(data); + }) + .catch(err => { + console.log('点击获取Png图片buffer err=' + err) + }) + }) + }) + + + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('测试readPngImageInfo') + .onClick(() => { + let pngj = new Pngj(); + pngj.readPngImageInfo(this.pngSource, (value) => { + this.hint1 = JSON.stringify(value); + }) + }).margin({ top: 5, left: 10 }) + Button('测试readPngImage') + .onClick(() => { + let pngj = new Pngj(); + pngj.readPngImage(this.pngSource, (value) => { + this.hint2 = 'img with=' + value.width + ' img height=' + value.height + + ' img depth=' + value.depth + ' img ctype=' + value.ctype + console.log('png data =' + value.data); + }) + }).margin({ top: 5, left: 10 }) + Button('测试writePngWithString') + .onClick(() => { + let pngj = new Pngj(); + pngj.writePngWithString('hello world', this.pngSource, (value) => { + + FileUtils.getInstance().createFileProcess( + this.rootFolder + '/pngj', + this.rootFolder + '/pngj/newPng.png', + value) + let png1 = new Uint8Array(value) + this.hint3 = 'png写入后长度' + png1.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng.png' + '保存后使用2进制查看数据是否新增' + }) + }).margin({ top: 5, left: 10 }) + Button('测试writePng') + .onClick(() => { + let pngj = new Pngj(); + pngj.writePng(this.pngSource, (value) => { + FileUtils.getInstance().createFileProcess( + this.rootFolder + '/pngj', + this.rootFolder + '/pngj/newPng2.png', + value) + let png2 = new Uint8Array(value) + this.hint4 = 'png2未写入长度' + png2.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng2.png' + '保存后使用2进制查看数据是否新增' + }) + }).margin({ top: 5, left: 10 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + Text(this.hint1) + .width('100%') + .height(120) + Text(this.hint2) + .width('100%') + .height(120) + Text(this.hint3) + .width('100%') + .height(120) + Text(this.hint4) + .width('100%') + .height(120) + } + } + .width('100%') + .height('100%') + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/showErrorholderTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/showErrorholderTestCasePage.ets new file mode 100644 index 0000000..342cb46 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/showErrorholderTestCasePage.ets @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" + +@Entry +@Component +struct ShowErrorholderTestCasePage { + @State glideOption1: GlideOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption2: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption3: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glideOption4: GlideOption = + { + loadSrc: "https://hbimg.huabanimg.com/xxxxx", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + GlideImage({ glideOption: $glideOption1 }) + GlideImage({ glideOption: $glideOption2 }) + GlideImage({ glideOption: $glideOption3 }) + GlideImage({ glideOption: $glideOption4 }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/storageTestDiskLruCache.ets b/entry/src/main/ets/MainAbility/pages/storageTestDiskLruCache.ets new file mode 100644 index 0000000..5568a99 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/storageTestDiskLruCache.ets @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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" + + + + +@Entry +@Component +struct StorageTestDiskLruCache { + @Watch('watchGlideOption') @State glideOption: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + @State glidePixelMapPack: PixelMapPack = new PixelMapPack(); + @State glideResource: Resource = $r('app.media.icon_loading') + @State glideString: string = "" + @State normalPixelMap: boolean = false; + @State normalResource: boolean = true; + previousData: GlideData = null; + nowData: GlideData = null; + @State logText: string = "打印日志结果"; + + + watchGlideOption() { + this.glideExecute(); + } + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("Glide测试DiskLruCache能力") + .backgroundColor(Color.Blue) + Button("替换Glide默认DiskLruCache并设置大小1M") + .onClick(() => { + diskGlide.replaceDiskLruCache(1 * 1024 * 1024) + }).margin({top:15, bottom:15}) + + Button("替换Glide默认DiskLruCache并设置大小30M") + .onClick(() => { + diskGlide.replaceDiskLruCache(30 * 1024 * 1024) + }).margin({top:15, bottom:15}) + + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("加载jpg网络图") + .onClick(() => { + this.glideOption = { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({ top: 5, left: 10 }) + Button("加载png网络图") + .onClick(() => { + this.glideOption = { + loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({ top: 5, left: 10 }) + Button("加载webp网络图") + .onClick(() => { + this.glideOption = { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({ top: 5, left: 10 }) + Button("加载bmp网络图") + .onClick(() => { + this.glideOption = { + loadSrc: "https://img-blog.csdn.net/20140514114029140", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({ top: 5, left: 10 }) + }.width('100%') + .height(60).backgroundColor(Color.Pink) + + + Image(this.normalPixelMap ? this.glidePixelMapPack.pixelMap : (this.normalResource ? this.glideResource : this.glideString)) + .width(this.glideOption.size ? this.glideOption.size.width : '100%') + .height(this.glideOption.size ? this.glideOption.size.height : '100%') + .objectFit(this.glideOption.imageFit ? this.glideOption.imageFit : ImageFit.Fill) + .backgroundColor(this.glideOption.backgroundColor ? this.glideOption.backgroundColor : Color.White) + .margin(this.glideOption.margin ? this.glideOption.margin : { left: 0, top: 0, right: 0, bottom: 0 }) + + + + Scroll() { + Text(this.logText).fontSize(15) + }.width(300).height(300).margin({top:20}).backgroundColor(Color.Pink) + + + } + } + .width('100%') + .height('100%') + } + + +// glide 第一次启动和数据刷新后重新发送请求 + glideExecute() { + let request = new RequestOption(); + request.load(this.glideOption.loadSrc) + .addListener((err, data) => { + this.glideChangeSource(data) + return false; + }) + if (this.glideOption.placeholderSrc) { + request.placeholder(this.glideOption.placeholderSrc, (data) => { + this.glideChangeSource(data) + }) + } + if (this.glideOption.errorholderSrc) { + request.errorholder(this.glideOption.errorholderSrc, (data) => { + this.glideChangeSource(data) + }) + } + if (this.glideOption.transformtions) { + request.transforms(this.glideOption.transformtions) + } + + if (this.glideOption.size) { + request.setImageViewSize(this.glideOption.size) + } + + 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.dontAnimateFlag) { + request.dontAnimate() + } + if (this.glideOption.allCacheInfoCallback) { + request.addAllCacheInfoCallback(this.glideOption.allCacheInfoCallback) + } + + diskGlide.call(request); + } + + glideChangeSource(data:GlideData) { + this.glideSpecialFixed(data); + + //查看mGlide中的DiskLruCache + let disk = diskGlide.getDiskMemoryCache(); + let showDisk = '' + disk.foreachDiskLruCache((value, key, map) => { + showDisk += "key=" + key + "&value=" + value; + }) + this.logText = "日志结果:" + showDisk; + } + + glideSpecialFixed(data:GlideData) { + if (this.nowData) { + this.previousData = this.nowData; + this.nowData = data; + if (data.isPixelMap()) { + // PixelMap + console.log("Glide占位图输出=PixelMap") + if (this.previousData.isSvg()) { + console.log("Glide占位图输出=PixelMap 上一个是SVG") + this.normalPixelMap = true; + this.normalResource = true; + + let pixelMapPack1 = new PixelMapPack(); + pixelMapPack1.pixelMap = new PixelMap(); + + this.glidePixelMapPack = pixelMapPack1; + + setTimeout(() => { + let pixelMapPack2 = new PixelMapPack(); + pixelMapPack2.pixelMap = data.glideValue as PixelMap; + this.glidePixelMapPack = pixelMapPack2; + }, 100) + } else { + this.normalPixelMap = true; + this.normalResource = true; + + let pixelMapPack3 = new PixelMapPack(); + pixelMapPack3.pixelMap = data.glideValue as PixelMap; + + this.glidePixelMapPack = pixelMapPack3; + } + } + else if (data.isString()) { + // String + console.log("glidevalue=" + JSON.stringify(data)); + console.log("Glide占位图输出=String") + if (this.previousData.isSvg()) { + + console.log("data.glideValue=" + JSON.stringify(data.glideValue)) + console.log("Glide占位图输出=String 拥有上一个图片类型 上一个是SVG") + this.normalPixelMap = false; + this.normalResource = false; + let firstIndex = (data.glideValue as string).indexOf(diskGlide.getSvgAndGifFolder()); + console.log("firstIndex=" + firstIndex); + let suffix = (data.glideValue as string).substring(firstIndex, (data.glideValue as string).length) + console.log("suffix =" + suffix); + let glideNeedStr = 'internal://app/' + suffix; + this.glideString = glideNeedStr; + } else { + console.log("data.glideValue=" + JSON.stringify(data.glideValue)) + console.log("Glide占位图输出=String 拥有上一个图片类型 上一个不是SVG") + + this.normalPixelMap = false; + this.normalResource = false; + let firstIndex = (data.glideValue as string).indexOf(diskGlide.getSvgAndGifFolder()); + console.log("firstIndex=" + firstIndex); + let suffix = (data.glideValue as string).substring(firstIndex, (data.glideValue as string).length) + console.log("suffix =" + suffix); + let glideNeedStr = 'internal://app/' + suffix; + this.glideString = glideNeedStr; + } + } else if (data.isResource()) { + console.log("Glide占位图输出=Resource") + if (this.previousData.isSvg()) { + console.log("Glide占位图输出=Resource 上一个是SVG") + this.normalPixelMap = false; + this.normalResource = true; + this.glideResource = data.glideValue as Resource; + } else { + this.normalPixelMap = false; + this.normalResource = true; + this.glideResource = data.glideValue as Resource; + } + } else { + console.log("Glide占位图输出=数据错误") + } + + } else { + this.nowData = data; + if (data.isPixelMap()) { + // PixelMap + console.log("Glide占位图输出=PixelMap") + this.normalPixelMap = true; + this.normalResource = true; + + let pixelMapPack4 = new PixelMapPack(); + pixelMapPack4.pixelMap = data.glideValue as PixelMap; + + this.glidePixelMapPack = pixelMapPack4; + } + else if (data.isString()) { + // String + console.log("data.glideValue=" + JSON.stringify(data.glideValue)) + console.log("Glide占位图输出=String 没有上一个图片类型") + this.normalPixelMap = false; + this.normalResource = false; + let firstIndex = (data.glideValue as string).indexOf(diskGlide.getSvgAndGifFolder()); + console.log("firstIndex=" + firstIndex); + let suffix = (data.glideValue as string).substring(firstIndex, (data.glideValue as string).length) + console.log("suffix =" + suffix); + let glideNeedStr = 'internal://app/' + suffix; + this.glideString = glideNeedStr; + } else if (data.isResource()) { + console.log("Glide占位图输出=Resource") + this.normalPixelMap = false; + this.normalResource = true; + this.glideResource = data.glideValue as Resource; + } else { + console.log("Glide占位图输出=数据错误") + } + + } + } + +//函数在自定义组件析构消耗之前执行。 +//不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。 + aboutToDisappear() { + + } +//当此页面显示时触发一次。包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 + onPageShow() { + } +//当此页面消失时触发一次。包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 + onPageHide() { + } + +// 当用户点击返回按钮时触发,,仅@Entry修饰的自定义组件生效。 +//返回true表示页面自己处理返回逻辑, 不进行页面路由。 +//返回false表示使用默认的返回逻辑。 +//不返回值会作为false处理。 + onBackPress() { + + } +} +var diskGlide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/storageTestLruCache.ets b/entry/src/main/ets/MainAbility/pages/storageTestLruCache.ets new file mode 100644 index 0000000..12873d6 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/storageTestLruCache.ets @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import featureAbility from '@ohos.ability.featureAbility'; +import {LruCache} from '../cache/LruCache.ets' + +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值 +} + +@Entry +@Component +struct StorageTestLruCache { + @State logText:string = "打印日志结果"; + @State nowNumText:string = "显示输入的数据"; + mLruCache:LruCache = new LruCache(5); + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("默认创建一个容量为5的LruCache") + .backgroundColor(Color.Blue) + Button("随机存入一个数字0-9") + .onClick(()=>{ + let randomNum = getRandomInt(0,10); + this.nowNumText = ''+randomNum; + this.mLruCache.put(randomNum+"",randomNum+"") + this.logText = "日志结果:"+this.mLruCache.print(); + }) .margin({top:20}) + + Button(this.nowNumText) + .margin({top:20}) + + Scroll() { + Text(this.logText).fontSize(15) + }.width(300).height(200).margin({top:20}).backgroundColor(Color.Pink) + + } + .width('100%') + .height('100%') + } + } +} diff --git a/entry/src/main/ets/MainAbility/pages/testAllCacheInfoPage.ets b/entry/src/main/ets/MainAbility/pages/testAllCacheInfoPage.ets new file mode 100644 index 0000000..834547b --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testAllCacheInfoPage.ets @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 {AllCacheInfo,IAllCacheInfoCallback} from "../glide/interface/iallcacheinfocallback.ets" +import {GlideImage} from "../glide/GlideImage.ets" +import {PixelMapPack} from "../glide/PixelMapPack.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" + +@Entry +@Component +struct TestAllCacheInfoPage { + @State nativePixelMap: PixelMapPack = new PixelMapPack(); + @State networkPixelMap: PixelMapPack = new PixelMapPack(); + allCacheInfoCallback1 =(allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback glideimage1 memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback glideimage1 resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback glideimage1 data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo3 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + } + allCacheInfoCallback2 =(allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback glideimage2 memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback glideimage2 resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback glideimage2 data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo4 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + } + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{top:15}, + transformtions: [new RotateImageTransformation(180)], + allCacheInfoCallback:this.allCacheInfoCallback1 + }; + @State glideOption2: 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'), + margin:{top:15}, + transformtions: [new RotateImageTransformation(180)], + allCacheInfoCallback:this.allCacheInfoCallback2 + }; + glideImageAngle:number = 90; + + @State cacheinfo1:string = "观察本地资源获取缓存信息输出" + @State cacheinfo2:string = "观察网络资源获取缓存信息输出" + @State cacheinfo3:string = "观察GlideImage本地缓存输出" + @State cacheinfo4:string = "观察GlideImage网络缓存输出" + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("加载本地资源获取缓存信息") + .width(300).height(25) + .onClick(() => { + this.testAllCacheInfoNative(); + }).margin({ top: 15 }) + Scroll() { + Text(this.cacheinfo1).fontSize(15) + }.width(300).height(200) + Image(this.nativePixelMap.pixelMap) + .width(300) + .height(300) + .objectFit(ImageFit.Contain) + .backgroundColor(Color.Green) + .margin({ top: 15 }) + Button("加载网络资源获取缓存信息").width(300).height(25) + .onClick(() => { + this.testAllCacheInfoNetwork(); + }).margin({ top: 15 }) + Scroll() { + Text(this.cacheinfo2).fontSize(15) + }.width(300).height(200) + Image(this.networkPixelMap.pixelMap) + .width(300) + .height(300) + .objectFit(ImageFit.Contain) + .backgroundColor(Color.Green) + .margin({ top: 15 }) + + Button("GlideImage加载本地资源获取缓存信息").width(300).height(25) + .onClick(() => { + this.glideImageAngle = this.glideImageAngle + 45; + this.glideOption1 = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { top: 15 }, + transformtions: [new RotateImageTransformation(this.glideImageAngle)], + allCacheInfoCallback:this.allCacheInfoCallback1 + }; + }).margin({ top: 15 }) + Scroll() { + Text(this.cacheinfo3).fontSize(15) + }.width(300).height(200) + GlideImage({ glideOption: $glideOption1 }) + + Button("GlideImage加载网络资源获取缓存信息").width(300).height(25) + .onClick(() => { + this.glideImageAngle = this.glideImageAngle + 45; + this.glideOption2 = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { top: 15 }, + transformtions: [new RotateImageTransformation(this.glideImageAngle)], + allCacheInfoCallback:this.allCacheInfoCallback2 + }; + }) + Scroll() { + Text(this.cacheinfo4).fontSize(15) + }.width(300).height(200) + GlideImage({ glideOption: $glideOption2 }) + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + + } + + private testAllCacheInfoNative() { + let glideOption = new RequestOption(); + glideOption.load($r('app.media.pngSample')) + .setImageViewSize({width:300,height:300}) + .addListener((err, data) => { + let pack = new PixelMapPack(); + pack.pixelMap = data.glideValue as PixelMap;; + this.nativePixelMap = pack; + return false; + }).addAllCacheInfoCallback((allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo1 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + }) + Glide.call(glideOption); + } + + private testAllCacheInfoNetwork() { + let glideOption2 = new RequestOption(); + glideOption2.load("https://hbimg.huabanimg.com/0ef60041445edcfd6b38d20e19024b2cd9281dcc3525a4-Vy8fYO_fw658/format/webp") + .addListener((err, data) => { + let pack = new PixelMapPack(); + pack.pixelMap = data.glideValue as PixelMap; + this.networkPixelMap = pack; + console.log("glide2 图片2 赋值!") + return false; + }).addAllCacheInfoCallback((allCacheInfo)=>{ + let info = allCacheInfo as AllCacheInfo; + console.log("AllCacheInfoCallback memory ="+JSON.stringify(info.memoryCacheInfo)) + console.log("AllCacheInfoCallback resource ="+JSON.stringify(info.resourceCacheInfo)) + console.log("AllCacheInfoCallback data ="+JSON.stringify(info.dataCacheInfo)) + this.cacheinfo2 = "memory="+JSON.stringify(info.memoryCacheInfo)+ + "\n resource ="+JSON.stringify(info.resourceCacheInfo)+ + "\n data ="+JSON.stringify(info.dataCacheInfo) + }) + .setImageViewSize({width:300,height:300}) + .rotateImage(180) + Glide.call(glideOption2); + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testAllTypeGlideImagePage.ets b/entry/src/main/ets/MainAbility/pages/testAllTypeGlideImagePage.ets new file mode 100644 index 0000000..191c4c2 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testAllTypeGlideImagePage.ets @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" + +@Entry +@Component +struct TestAllTypeGlideImagePage { + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + @State glideOption2: GlideOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + @State glideOption3: GlideOption = + { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + @State glideOption4: GlideOption = + { + loadSrc: $r('app.media.svgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + @State glideOption5: GlideOption = + { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + GlideImage({ glideOption: $glideOption1 }) + GlideImage({ glideOption: $glideOption2 }) + GlideImage({ glideOption: $glideOption3 }) + GlideImage({ glideOption: $glideOption4 }) + GlideImage({ glideOption: $glideOption5 }) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testAllTypeNativeImagePage.ets b/entry/src/main/ets/MainAbility/pages/testAllTypeNativeImagePage.ets new file mode 100644 index 0000000..c3f4633 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testAllTypeNativeImagePage.ets @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" + +@Entry +@Component +struct TestAllTypeNativeImagePage { + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Image($r('app.media.jpgSample')) + .width(300) + .height(300) + Image($r('app.media.pngSample')) + .width(300) + .height(300) + Image($r('app.media.webpSample')) + .width(300) + .height(300) + Image($r('app.media.svgSample')) + .width(300) + .height(300) + Image($r('app.media.bmpSample')) + .width(300) + .height(300) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testGifDontAnimatePage.ets b/entry/src/main/ets/MainAbility/pages/testGifDontAnimatePage.ets new file mode 100644 index 0000000..17184d0 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testGifDontAnimatePage.ets @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from '../glide/GlideImage.ets' +import {GlideOption} from '../glide/GlideOption.ets' +import {RotateImageTransformation} from '../glide/transform/RotateImageTransformation.ets' + +@Entry +@Component +struct TestGifDontAnimatePage { + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15} + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button('本地资源gif') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15} + } + + }).margin({left:15}).backgroundColor(Color.Grey) + Button('本地资源gif静态') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15}, + dontAnimateFlag:true + } + + }).margin({left:15}).backgroundColor(Color.Grey) + } + .margin({top:15}) + Flex({direction:FlexDirection.Row}){ + Button('网络资源gif') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15} + }; + }).margin({left:15}).backgroundColor(Color.Grey) + Button('网络资源gif静态') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:15,top:15,right:15,bottom:15}, + dontAnimateFlag:true + }; + }).margin({left:15}).backgroundColor(Color.Grey) + } + .margin({top:15}) + GlideImage({ glideOption: $glideOption1 }) + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log('aboutToAppear()') + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testGlideOptionChangedPage.ets b/entry/src/main/ets/MainAbility/pages/testGlideOptionChangedPage.ets new file mode 100644 index 0000000..022bae3 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testGlideOptionChangedPage.ets @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT 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 {GlideImage} from '../glide/GlideImage.ets' +import {GlideOption} from '../glide/GlideOption.ets' +import {RotateImageTransformation} from '../glide/transform/RotateImageTransformation.ets' + +@Entry +@Component +struct TestGlideOptionChangedPage { + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button('本地资源jpg') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源png') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源bmp') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源webp') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源svg') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.svgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + + }).margin({left:5}).backgroundColor(Color.Blue) + Button('本地资源gif') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + };; + + }).margin({left:5}).backgroundColor(Color.Blue) + } + .margin({top:15}) + Flex({direction:FlexDirection.Row}){ + Button('网络资源jpg') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源png') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://img-blog.csdnimg.cn/20191215043500229.png', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源bmp') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://img-blog.csdn.net/20140514114029140', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源webp') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源svg') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/30df266a-485e-411e-b178-b9fb1d8e0748.svg', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button('网络资源gif') + .onClick(()=>{ + this.glideOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5} + }; + }).margin({left:5}).backgroundColor(Color.Blue) + } + .margin({top:15}) + + Text('下面为展示图片区域').margin({top:5}) + Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ + GlideImage({ glideOption: $glideOption1 }) + }.width(400).height(400).margin({top:10}).backgroundColor(Color.Pink) + + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log('aboutToAppear()') + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testGlideOptionChangedPage2.ets b/entry/src/main/ets/MainAbility/pages/testGlideOptionChangedPage2.ets new file mode 100644 index 0000000..f27ec72 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testGlideOptionChangedPage2.ets @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" + +@Entry +@Component +struct TestGlideOptionChangedPage2 { + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button("网络资源jpg") + .onClick(()=>{ + this.glideOption1 = { + loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button("网络资源png") + .onClick(()=>{ + this.glideOption1 = { + loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button("网络资源bmp") + .onClick(()=>{ + this.glideOption1 = { + loadSrc: "https://img-blog.csdn.net/20140514114029140", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + Button("网络资源webp") + .onClick(()=>{ + this.glideOption1 = { + loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin:{left:5,top:5,right:5,bottom:5}, + thumbSizeMultiplier:0.1 + }; + }).margin({left:5}).backgroundColor(Color.Blue) + } + .margin({top:15}) + + Text("下面为展示图片区域").margin({top:5}) + Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ + GlideImage({ glideOption: $glideOption1 }) + }.width(400).height(400).margin({top:10}).backgroundColor(Color.Pink) + + + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testMemoryCachePage.ets b/entry/src/main/ets/MainAbility/pages/testMemoryCachePage.ets new file mode 100644 index 0000000..ae2fe84 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testMemoryCachePage.ets @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import resourceManager from '@ohos.resourceManager'; +import util from '@ohos.util'; +import {RequestOption} from "../glide/RequestOption.ets" +//import {Glide} from '../glide/Glide' +import{ALL} from "../cache/diskstrategy/enum/ALL" +import{NONE} from "../cache/diskstrategy/enum/NONE" +import {AsyncCallback} from "../glide/interface/asynccallback.ets" +import {AsyncSuccess} from "../glide/interface/AsyncSuccess.ets" + + +@Entry +@Component +struct TestMemoryCachePage { + @State tomatoPixelMap: PixelMap = new PixelMap(); + @State tomatoPixelMap2: PixelMap = new PixelMap(); + @State iceCreamPixelMap: PixelMap = new PixelMap(); + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Image(this.tomatoPixelMap) + .width(200) + .height(200) + .objectFit(ImageFit.Contain) + .backgroundColor(Color.Green) + .onClick(() => { + }) + Image(this.iceCreamPixelMap) + .backgroundColor(Color.Grey) + .objectFit(ImageFit.Contain) + .width(200) + .height(200) + Image(this.tomatoPixelMap2) + .objectFit(ImageFit.Contain) + .backgroundColor(Color.Orange) + .width(200) + .height(200) + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + this.testAllResourceLoading(); + } + + private testAllResourceLoading() { + + let glideOption = new RequestOption(); + glideOption.load($r('app.media.Tomato')) + .addListener((err, data) => { + console.log("glide1 图片1 赋值!") + this.tomatoPixelMap = data.glideValue as PixelMap; + return false; + }) + + Glide.call(glideOption); + + + let glideOption2 = new RequestOption(); + glideOption2.load($r('app.media.IceCream')) + .addListener((err, data) => { + this.iceCreamPixelMap = data.glideValue as PixelMap; + console.log("glide2 图片2 赋值!") + return false; + }) + + Glide.call(glideOption2); + + + let glideOption3 = new RequestOption(); + glideOption3.load($r('app.media.Tomato')) + .addListener((err, data) => { + this.tomatoPixelMap2 = data.glideValue as PixelMap; + console.log("glide3 图片1 赋值!") + return false; + }) + + Glide.call(glideOption3); + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testMultiThreadWorkerPage2.ets b/entry/src/main/ets/MainAbility/pages/testMultiThreadWorkerPage2.ets new file mode 100644 index 0000000..c0a93c2 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testMultiThreadWorkerPage2.ets @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import ArkWorker from '@ohos.worker' + +@Entry +@Component +struct TestMultiThreadWorkerPage2 { + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("创建Worker向子线程发送携带Arraybuffer数据") + .margin({ top: 20 }) + .onClick(() => { + let worker = new ArkWorker.Worker("workers/worker1.js", { type: "classic", name: "zhangsan" }) + worker.onerror = function (data) { + console.info("worker:: receive onerror " + data.lineno + ", msg = " + data.message + ", filename = " + data.filename + ", colno = " + data.colno); + } + + worker.onmessageerror = function (e) { + console.log("worker:: receive onmessageerror "); + } + + worker.onexit = function () { + console.log("worker:: receive onexit"); + } + + worker.onmessage = function (e) { + var data = e.data; + switch (data.type) { + case "normal": + console.log("worker:: onmessage " + data.data); + break; + case "buffer": + console.log("worker:: receive buffer length is " + data.data.byteLength); + break; + default: + console.log("worker:: worker.js receive unknow type"); + break + } + worker.terminate(); + } + + console.log("worker:: start post buffer"); + + let uint8array = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]) + let buffer = uint8array.buffer.slice(uint8array.byteOffset, uint8array.byteLength + uint8array.byteOffset) + + var obj = { type: "buffer", data: buffer }; + console.log("worker:: before post, buffer length is " + obj.data.byteLength); + worker.postMessage(obj, [buffer]); + console.log("worker:: after post, buffer length is " + obj.data.byteLength); + console.info("end post buffer"); + + + }); + + } + } + .width('100%') + .height('100%') + } +} diff --git a/entry/src/main/ets/MainAbility/pages/testPreloadPage.ets b/entry/src/main/ets/MainAbility/pages/testPreloadPage.ets new file mode 100644 index 0000000..e65c134 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testPreloadPage.ets @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from '../glide/GlideImage.ets' +import {GlideOption} from '../glide/GlideOption.ets' +import {RequestOption} from '../glide/RequestOption.ets' +import {RotateImageTransformation} from '../glide/transform/RotateImageTransformation.ets' + +@Entry +@Component +struct TestPreloadPage { + @State glideOption1: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State glideOption2: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State glideOption3: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + + @State glideOption4: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State glideOption5: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + @State glideOption6: GlideOption = + { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源gif') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.gifSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源gif 出现错误! err=' + err) + } else { + console.log('预加载本地资源gif成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源gif') + .onClick(() => { + this.glideOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('预加载本地资源gif静态') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.gifSample')) + .setImageViewSize({ width: 300, height: 300 }) + .dontAnimate() + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源gif静态 出现错误! err=' + err) + } else { + console.log('预加载本地资源gif静态成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('本地资源gif静态') + .onClick(() => { + this.glideOption1 = { + loadSrc: $r('app.media.gifSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 }, + dontAnimateFlag: true + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源gif') + .onClick(() => { + let request = new RequestOption(); + request.load('https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源gif 出现错误! err=' + err) + } else { + console.log('预加载网络资源gif成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源gif') + .onClick(() => { + this.glideOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('预加载网络资源gif静态') + .onClick(() => { + let request = new RequestOption(); + request.load('https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700') + .setImageViewSize({ width: 300, height: 300 }) + .dontAnimate() + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源gif静态 出现错误! err=' + err) + } else { + console.log('预加载网络资源gif静态成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源gif静态') + .onClick(() => { + this.glideOption1 = { + loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 }, + dontAnimateFlag: true + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + GlideImage({ glideOption: $glideOption1 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源svg') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.svgSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源svg 出现错误! err=' + err) + } else { + console.log('预加载本地资源svg成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源svg') + .onClick(() => { + this.glideOption2 = { + loadSrc: $r('app.media.svgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源svg') + .onClick(() => { + let request = new RequestOption(); + request.load('http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/4dc8463e-8ac6-4eb4-862c-783bf486a242.svg') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源gif 出现错误! err=' + err) + } else { + console.log('预加载网络资源gif成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源svg') + .onClick(() => { + this.glideOption2 = { + loadSrc: 'http://design-svc.fat.lunz.cn/StaticFiles/BP9999999772/BV9999999422/SA9999998420/4dc8463e-8ac6-4eb4-862c-783bf486a242.svg', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + GlideImage({ glideOption: $glideOption2 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源webp') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.webpSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源webp 出现错误! err=' + err) + } else { + console.log('预加载本地资源webp成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源webp') + .onClick(() => { + this.glideOption3 = { + loadSrc: $r('app.media.webpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源webp') + .onClick(() => { + let request = new RequestOption(); + request.load('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源webp 出现错误! err=' + err) + } else { + console.log('预加载网络资源webp成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源webp') + .onClick(() => { + this.glideOption3 = { + loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + GlideImage({ glideOption: $glideOption3 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源bmp') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.bmpSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源bmp 出现错误! err=' + err) + } else { + console.log('预加载本地资源bmp成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源bmp') + .onClick(() => { + this.glideOption4 = { + loadSrc: $r('app.media.bmpSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源bmp') + .onClick(() => { + let request = new RequestOption(); + request.load('https://img-blog.csdn.net/20140514114029140') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源bmp 出现错误! err=' + err) + } else { + console.log('预加载网络资源bmp成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源bmp') + .onClick(() => { + this.glideOption4 = { + loadSrc: 'https://img-blog.csdn.net/20140514114029140', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + GlideImage({ glideOption: $glideOption4 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源png') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.pngSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源png 出现错误! err=' + err) + } else { + console.log('预加载本地资源png成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源png') + .onClick(() => { + this.glideOption5 = { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源png') + .onClick(() => { + let request = new RequestOption(); + request.load('https://img-blog.csdnimg.cn/20191215043500229.png') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源bmp 出现错误! err=' + err) + } else { + console.log('预加载网络资源bmp成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源png') + .onClick(() => { + this.glideOption5 = { + loadSrc: 'https://img-blog.csdnimg.cn/20191215043500229.png', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + GlideImage({ glideOption: $glideOption5 }) + + } + + Flex({ direction: FlexDirection.Column }) { + Flex({ direction: FlexDirection.Row }) { + Button('预加载本地资源jpg') + .onClick(() => { + let request = new RequestOption(); + request.load($r('app.media.jpgSample')) + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载本地资源jpg 出现错误! err=' + err) + } else { + console.log('预加载本地资源jpg成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + Button('本地资源jpg') + .onClick(() => { + this.glideOption6 = { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + } + + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + + } + .margin({ top: 15 }) + + Flex({ direction: FlexDirection.Row }) { + + Button('预加载网络资源jpg') + .onClick(() => { + let request = new RequestOption(); + request.load('https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB') + .setImageViewSize({ width: 300, height: 300 }) + .addListener((err, data) => { + if (err && err.length > 0) { + console.log('预加载网络资源jpg 出现错误! err=' + err) + } else { + console.log('预加载网络资源jpg成功! glidedata=' + JSON.stringify(data)) + } + return false; + }) + Glide.preload(request); + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + + Button('网络资源jpg') + .onClick(() => { + this.glideOption6 = { + loadSrc: 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB', + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + margin: { left: 15, top: 15, right: 15, bottom: 15 } + }; + }) + .margin({ left: 15 }) + .backgroundColor(Color.Grey) + } + .margin({ top: 15 }) + + GlideImage({ glideOption: $glideOption6 }) + + } + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log('aboutToAppear()') + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/testResourceManagerPage.ets b/entry/src/main/ets/MainAbility/pages/testResourceManagerPage.ets new file mode 100644 index 0000000..bcc42c0 --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/testResourceManagerPage.ets @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {RequestOption} from "../glide/RequestOption.ets" +import{NONE} from "../cache/diskstrategy/enum/NONE" +import {Base64} from "../cache/Base64.ets" +import {FileTypeUtil} from "../glide/utils/FileTypeUtil.ets" +import {GlideData} from "../glide/GlideData.ets" + +import resourceManager from '@ohos.resourceManager'; +@Entry +@Component +struct TestResourceManagerPage { + + @State glideData: GlideData = new GlideData(); + + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.glideData.glideType) + .fontSize(20) + .backgroundColor(Color.Pink) + .width(300) + .height(300) + Button("点击执行ResourceManager的Base64") + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMediaBase64($r('app.media.jpgSample').id) + .then(data => { + console.log("jpgSample data=" + data) + let matchUseLess = ";base64,"; + var matchUseLessIndex = data.indexOf(matchUseLess) + data = data.substring(matchUseLessIndex + matchUseLess.length, data.length) + console.log("jpgSample prepare save data=" + data) + let arrayBuffer = Base64.getInstance().decode(data); + console.log("arrayBuffer data=" + arrayBuffer) + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arrayBuffer); + console.log("typeValue data=" + typeValue) + let newGlideData = new GlideData(); + newGlideData.glideType = typeValue + + this.glideData = newGlideData; + }) + + }) + }) + Button("点击执行ResourceManager的非Base64") + .margin({top:25}) + .onClick(()=>{ + resourceManager.getResourceManager() + .then(result => { + result.getMedia($r('app.media.pngSample').id) + .then(data => { + console.log("arrayBuffer data=" + data) + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(this.typedArrayToBuffer(data)); + console.log("typeValue data=" + typeValue) + let newGlideData = new GlideData(); + newGlideData.glideType = typeValue + this.glideData = newGlideData; + }) + + }) + }) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } + + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } + +} + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/pages/transformTestCasePage.ets b/entry/src/main/ets/MainAbility/pages/transformTestCasePage.ets new file mode 100644 index 0000000..150deae --- /dev/null +++ b/entry/src/main/ets/MainAbility/pages/transformTestCasePage.ets @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is dibistributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {GlideImage} from "../glide/GlideImage.ets" +import {GlideOption} from "../glide/GlideOption.ets" +import {RotateImageTransformation} from "../glide/transform/RotateImageTransformation.ets" +import {RoundedCornersTransformation} from "../glide/transform/RoundedCornersTransformation.ets" + +@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.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + @State glideOption2: GlideOption = + { + loadSrc: "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83ericA1Mv66TwicuYOtbDMBcUhv1aa9RJBeAn9uURfcZD0AUGrJebAn1g2AjN0vb2E1XTET7fTuLBNmA/132", + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RoundedCornersTransformation({ + top_left: 30, + top_right: 30, + bottom_left: 30, + bottom_right: 30 + })] + }; + @State glideOption3: GlideOption = + { + loadSrc: $r('app.media.pngSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RotateImageTransformation(180)] + }; + @State glideOption4: GlideOption = + { + loadSrc: $r('app.media.jpgSample'), + size: { width: 300, height: 300 }, + placeholderSrc: $r('app.media.Tomato'), + errorholderSrc: $r('app.media.picture1'), + transformtions: [new RoundedCornersTransformation({ + top_left: 130, + top_right: 130, + bottom_left: 130, + bottom_right: 130 + })] + }; + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + GlideImage({ glideOption: $glideOption1 }) + GlideImage({ glideOption: $glideOption2 }) + GlideImage({ glideOption: $glideOption3 }) + GlideImage({ glideOption: $glideOption4 }) + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } +} + + +var Glide = globalThis.exports.default.data.glide \ No newline at end of file diff --git a/entry/src/main/ets/MainAbility/workers/worker1.js b/entry/src/main/ets/MainAbility/workers/worker1.js new file mode 100644 index 0000000..8acdf98 --- /dev/null +++ b/entry/src/main/ets/MainAbility/workers/worker1.js @@ -0,0 +1,27 @@ +import arkWorker from '@ohos.worker'; + +function foo(x) { + return x +} + +arkWorker.parentPort.onmessage = function (e) { + var data = e.data; + switch (data.type) { + case 'normal': + arkWorker.parentPort.postMessage(data); + break; + case 'error': + throw new Error('123'); + break; + case 'buffer': + let uint8Array = new Uint8Array(data.data); + arkWorker.parentPort.postMessage(data, [data.data]); + + break; + default: + + break + } +} + + diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000..6146fec --- /dev/null +++ b/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "test_color", + "value": "#3d2564" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000..012fb52 --- /dev/null +++ b/entry/src/main/resources/base/element/string.json @@ -0,0 +1,104 @@ +{ + "string": [ + { + "name": "GlideJS_OHOS", + "value": "GlideJS_OHOS" + }, + { + "name": "mainability_description", + "value": "ETS_Empty Ability" + }, + { + "name": "left_top_corner", + "value": "左上角" + }, + { + "name": "r_top_corner", + "value": "右上角" + }, + { + "name": "left_bottom_corner", + "value": "左下角" + }, + { + "name": "r_bottom_corner", + "value": "右下角" + }, + { + "name": "trans_circle", + "value": "裁剪-圆" + }, + { + "name": "trans_circle_border", + "value": "裁剪-圆环" + }, + { + "name": "trans_rotate", + "value": "旋转" + }, + { + "name": "trans_square", + "value": "正方形裁剪" + }, + { + "name": "trans_clip_top", + "value": "上方裁剪" + }, + { + "name": "trans_clip_center", + "value": "中间裁剪" + }, + { + "name": "trans_clip_bottom", + "value": "底下裁剪" + }, + { + "name": "resource_image_compress", + "value": "资源图片压缩" + }, + { + "name": "file_image_compress", + "value": "本地文件图片压缩" + }, + { + "name": "image_transform", + "value": "图片变换" + }, + { + "name": "image_compress", + "value": "图片压缩" + }, + { + "name": "image_grayscale", + "value": "灰度处理" + }, + { + "name": "image_Brightness", + "value": "亮度处理" + }, + { + "name": "image_Contrast", + "value": "对比度处理" + }, + { + "name": "image_Invert", + "value": "反转处理" + }, + { + "name": "image_Sepia", + "value": "黑褐色处理" + }, + { + "name": "image_Sketch", + "value": "素描处理" + }, + { + "name": "image_blur", + "value": "模糊处理" + }, + { + "name": "image_pixel", + "value": "马赛克处理" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/Avocado.png b/entry/src/main/resources/base/media/Avocado.png new file mode 100644 index 0000000..33dfdd7 Binary files /dev/null and b/entry/src/main/resources/base/media/Avocado.png differ diff --git a/entry/src/main/resources/base/media/Back.png b/entry/src/main/resources/base/media/Back.png new file mode 100644 index 0000000..2b0806c Binary files /dev/null and b/entry/src/main/resources/base/media/Back.png differ diff --git a/entry/src/main/resources/base/media/Blueberry.png b/entry/src/main/resources/base/media/Blueberry.png new file mode 100644 index 0000000..a07421e Binary files /dev/null and b/entry/src/main/resources/base/media/Blueberry.png differ diff --git a/entry/src/main/resources/base/media/Crab.png b/entry/src/main/resources/base/media/Crab.png new file mode 100644 index 0000000..b71a627 Binary files /dev/null and b/entry/src/main/resources/base/media/Crab.png differ diff --git a/entry/src/main/resources/base/media/Cucumber.png b/entry/src/main/resources/base/media/Cucumber.png new file mode 100644 index 0000000..6dd7477 Binary files /dev/null and b/entry/src/main/resources/base/media/Cucumber.png differ diff --git a/entry/src/main/resources/base/media/IceCream.png b/entry/src/main/resources/base/media/IceCream.png new file mode 100644 index 0000000..13a8674 Binary files /dev/null and b/entry/src/main/resources/base/media/IceCream.png differ diff --git a/entry/src/main/resources/base/media/Index.png b/entry/src/main/resources/base/media/Index.png new file mode 100644 index 0000000..5c57223 Binary files /dev/null and b/entry/src/main/resources/base/media/Index.png differ diff --git a/entry/src/main/resources/base/media/IndexGray.png b/entry/src/main/resources/base/media/IndexGray.png new file mode 100644 index 0000000..942eceb Binary files /dev/null and b/entry/src/main/resources/base/media/IndexGray.png differ diff --git a/entry/src/main/resources/base/media/Kiwi.png b/entry/src/main/resources/base/media/Kiwi.png new file mode 100644 index 0000000..0b4b6ed Binary files /dev/null and b/entry/src/main/resources/base/media/Kiwi.png differ diff --git a/entry/src/main/resources/base/media/Mushroom.png b/entry/src/main/resources/base/media/Mushroom.png new file mode 100644 index 0000000..3e984ee Binary files /dev/null and b/entry/src/main/resources/base/media/Mushroom.png differ diff --git a/entry/src/main/resources/base/media/NoRecord.png b/entry/src/main/resources/base/media/NoRecord.png new file mode 100644 index 0000000..724b2e1 Binary files /dev/null and b/entry/src/main/resources/base/media/NoRecord.png differ diff --git a/entry/src/main/resources/base/media/Onion.png b/entry/src/main/resources/base/media/Onion.png new file mode 100644 index 0000000..9c1c5a8 Binary files /dev/null and b/entry/src/main/resources/base/media/Onion.png differ diff --git a/entry/src/main/resources/base/media/Pitaya.png b/entry/src/main/resources/base/media/Pitaya.png new file mode 100644 index 0000000..2770b34 Binary files /dev/null and b/entry/src/main/resources/base/media/Pitaya.png differ diff --git a/entry/src/main/resources/base/media/Statistics.png b/entry/src/main/resources/base/media/Statistics.png new file mode 100644 index 0000000..28099ad Binary files /dev/null and b/entry/src/main/resources/base/media/Statistics.png differ diff --git a/entry/src/main/resources/base/media/StatisticsGray.png b/entry/src/main/resources/base/media/StatisticsGray.png new file mode 100644 index 0000000..018f9c3 Binary files /dev/null and b/entry/src/main/resources/base/media/StatisticsGray.png differ diff --git a/entry/src/main/resources/base/media/Strawberry.png b/entry/src/main/resources/base/media/Strawberry.png new file mode 100644 index 0000000..a8d2394 Binary files /dev/null and b/entry/src/main/resources/base/media/Strawberry.png differ diff --git a/entry/src/main/resources/base/media/Switch.png b/entry/src/main/resources/base/media/Switch.png new file mode 100644 index 0000000..51aa0fc Binary files /dev/null and b/entry/src/main/resources/base/media/Switch.png differ diff --git a/entry/src/main/resources/base/media/Tomato.png b/entry/src/main/resources/base/media/Tomato.png new file mode 100644 index 0000000..93ad983 Binary files /dev/null and b/entry/src/main/resources/base/media/Tomato.png differ diff --git a/entry/src/main/resources/base/media/Walnut.png b/entry/src/main/resources/base/media/Walnut.png new file mode 100644 index 0000000..8187a42 Binary files /dev/null and b/entry/src/main/resources/base/media/Walnut.png differ diff --git a/entry/src/main/resources/base/media/abc.PNG b/entry/src/main/resources/base/media/abc.PNG new file mode 100644 index 0000000..3e7f10f Binary files /dev/null and b/entry/src/main/resources/base/media/abc.PNG differ diff --git a/entry/src/main/resources/base/media/baidu.png b/entry/src/main/resources/base/media/baidu.png new file mode 100644 index 0000000..510f111 Binary files /dev/null and b/entry/src/main/resources/base/media/baidu.png differ diff --git a/entry/src/main/resources/base/media/bmpNet.bmp b/entry/src/main/resources/base/media/bmpNet.bmp new file mode 100644 index 0000000..a343af9 Binary files /dev/null and b/entry/src/main/resources/base/media/bmpNet.bmp differ diff --git a/entry/src/main/resources/base/media/bmpSample.bmp b/entry/src/main/resources/base/media/bmpSample.bmp new file mode 100644 index 0000000..94b0a91 Binary files /dev/null and b/entry/src/main/resources/base/media/bmpSample.bmp differ diff --git a/entry/src/main/resources/base/media/check_big.png b/entry/src/main/resources/base/media/check_big.png new file mode 100644 index 0000000..3262131 Binary files /dev/null and b/entry/src/main/resources/base/media/check_big.png differ diff --git a/entry/src/main/resources/base/media/check_big_test.png b/entry/src/main/resources/base/media/check_big_test.png new file mode 100644 index 0000000..64059ab Binary files /dev/null and b/entry/src/main/resources/base/media/check_big_test.png differ diff --git a/entry/src/main/resources/base/media/delete.png b/entry/src/main/resources/base/media/delete.png new file mode 100644 index 0000000..f3c3705 Binary files /dev/null and b/entry/src/main/resources/base/media/delete.png differ diff --git a/entry/src/main/resources/base/media/deletebackground.png b/entry/src/main/resources/base/media/deletebackground.png new file mode 100644 index 0000000..59490bd Binary files /dev/null and b/entry/src/main/resources/base/media/deletebackground.png differ diff --git a/entry/src/main/resources/base/media/demo_org.jpg b/entry/src/main/resources/base/media/demo_org.jpg new file mode 100644 index 0000000..8374680 Binary files /dev/null and b/entry/src/main/resources/base/media/demo_org.jpg differ diff --git a/entry/src/main/resources/base/media/gifNet.gif b/entry/src/main/resources/base/media/gifNet.gif new file mode 100644 index 0000000..511f667 Binary files /dev/null and b/entry/src/main/resources/base/media/gifNet.gif differ diff --git a/entry/src/main/resources/base/media/gifSample.gif b/entry/src/main/resources/base/media/gifSample.gif new file mode 100644 index 0000000..6dab2d1 Binary files /dev/null and b/entry/src/main/resources/base/media/gifSample.gif differ diff --git a/entry/src/main/resources/base/media/icon.png b/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000..ce307a8 Binary files /dev/null and b/entry/src/main/resources/base/media/icon.png differ diff --git a/entry/src/main/resources/base/media/icon_failed.png b/entry/src/main/resources/base/media/icon_failed.png new file mode 100644 index 0000000..6eadcfd Binary files /dev/null and b/entry/src/main/resources/base/media/icon_failed.png differ diff --git a/entry/src/main/resources/base/media/icon_loading.png b/entry/src/main/resources/base/media/icon_loading.png new file mode 100644 index 0000000..6eb4e9a Binary files /dev/null and b/entry/src/main/resources/base/media/icon_loading.png differ diff --git a/entry/src/main/resources/base/media/icon_retry.jpg b/entry/src/main/resources/base/media/icon_retry.jpg new file mode 100644 index 0000000..19911b6 Binary files /dev/null and b/entry/src/main/resources/base/media/icon_retry.jpg differ diff --git a/entry/src/main/resources/base/media/jpgNet.jpg b/entry/src/main/resources/base/media/jpgNet.jpg new file mode 100644 index 0000000..f430168 Binary files /dev/null and b/entry/src/main/resources/base/media/jpgNet.jpg differ diff --git a/entry/src/main/resources/base/media/jpgSample.jpg b/entry/src/main/resources/base/media/jpgSample.jpg new file mode 100644 index 0000000..dad4caa Binary files /dev/null and b/entry/src/main/resources/base/media/jpgSample.jpg differ diff --git a/entry/src/main/resources/base/media/photo5.jpg b/entry/src/main/resources/base/media/photo5.jpg new file mode 100644 index 0000000..ccf589d Binary files /dev/null and b/entry/src/main/resources/base/media/photo5.jpg differ diff --git a/entry/src/main/resources/base/media/photo6.jpg b/entry/src/main/resources/base/media/photo6.jpg new file mode 100644 index 0000000..aed456f Binary files /dev/null and b/entry/src/main/resources/base/media/photo6.jpg differ diff --git a/entry/src/main/resources/base/media/picture1.jpg b/entry/src/main/resources/base/media/picture1.jpg new file mode 100644 index 0000000..8374680 Binary files /dev/null and b/entry/src/main/resources/base/media/picture1.jpg differ diff --git a/entry/src/main/resources/base/media/pngNet.png b/entry/src/main/resources/base/media/pngNet.png new file mode 100644 index 0000000..cba0bad Binary files /dev/null and b/entry/src/main/resources/base/media/pngNet.png differ diff --git a/entry/src/main/resources/base/media/pngSample.png b/entry/src/main/resources/base/media/pngSample.png new file mode 100644 index 0000000..bda2612 Binary files /dev/null and b/entry/src/main/resources/base/media/pngSample.png differ diff --git a/entry/src/main/resources/base/media/svgNet.svg b/entry/src/main/resources/base/media/svgNet.svg new file mode 100644 index 0000000..cee5c31 --- /dev/null +++ b/entry/src/main/resources/base/media/svgNet.svg @@ -0,0 +1,17 @@ + + + 蒙版 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/svgSample.svg b/entry/src/main/resources/base/media/svgSample.svg new file mode 100644 index 0000000..063bd30 --- /dev/null +++ b/entry/src/main/resources/base/media/svgSample.svg @@ -0,0 +1,26 @@ + + + 蒙版 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/svgSample2.svg b/entry/src/main/resources/base/media/svgSample2.svg new file mode 100644 index 0000000..cee5c31 --- /dev/null +++ b/entry/src/main/resources/base/media/svgSample2.svg @@ -0,0 +1,17 @@ + + + 蒙版 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/tiger.jpg b/entry/src/main/resources/base/media/tiger.jpg new file mode 100644 index 0000000..bf4f798 Binary files /dev/null and b/entry/src/main/resources/base/media/tiger.jpg differ diff --git a/entry/src/main/resources/base/media/transformBase.bmp b/entry/src/main/resources/base/media/transformBase.bmp new file mode 100644 index 0000000..cee0930 Binary files /dev/null and b/entry/src/main/resources/base/media/transformBase.bmp differ diff --git a/entry/src/main/resources/base/media/user.txt b/entry/src/main/resources/base/media/user.txt new file mode 100644 index 0000000..710e1c6 --- /dev/null +++ b/entry/src/main/resources/base/media/user.txt @@ -0,0 +1,9 @@ +syntax = "proto3"; +package User; + +message UserLoginResponse{ + string sessionId = 1; + string userPrivilege = 2; + int64 servTimesTemp = 3; + string formatTimestamp = 4; +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/webpNet.webp b/entry/src/main/resources/base/media/webpNet.webp new file mode 100644 index 0000000..bcf109c Binary files /dev/null and b/entry/src/main/resources/base/media/webpNet.webp differ diff --git a/entry/src/main/resources/base/media/webpSample.webp b/entry/src/main/resources/base/media/webpSample.webp new file mode 100644 index 0000000..bcf109c Binary files /dev/null and b/entry/src/main/resources/base/media/webpSample.webp differ diff --git a/entry/src/ohosTest/ets/MainAbility/app.ets b/entry/src/ohosTest/ets/MainAbility/app.ets new file mode 100644 index 0000000..8658c07 --- /dev/null +++ b/entry/src/ohosTest/ets/MainAbility/app.ets @@ -0,0 +1,11 @@ +export default { + onCreate() { + console.info('Application onCreate') + }, + onShow() { + console.info('Application onShow') + }, + onDestroy() { + console.info('Application onDestroy') + }, +} diff --git a/entry/src/ohosTest/ets/MainAbility/i18n/en-US.json b/entry/src/ohosTest/ets/MainAbility/i18n/en-US.json new file mode 100644 index 0000000..55561b8 --- /dev/null +++ b/entry/src/ohosTest/ets/MainAbility/i18n/en-US.json @@ -0,0 +1,8 @@ +{ + "strings": { + "hello": "Hello", + "world": "World" + }, + "Files": { + } +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/MainAbility/i18n/zh-CN.json b/entry/src/ohosTest/ets/MainAbility/i18n/zh-CN.json new file mode 100644 index 0000000..cce1af0 --- /dev/null +++ b/entry/src/ohosTest/ets/MainAbility/i18n/zh-CN.json @@ -0,0 +1,8 @@ +{ + "strings": { + "hello": "您好", + "world": "世界" + }, + "Files": { + } +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/MainAbility/pages/index/index.ets b/entry/src/ohosTest/ets/MainAbility/pages/index/index.ets new file mode 100644 index 0000000..dc65e41 --- /dev/null +++ b/entry/src/ohosTest/ets/MainAbility/pages/index/index.ets @@ -0,0 +1,51 @@ +import {Core, ExpectExtend, InstrumentLog} from "deccjsunit/index" +import testsuite from "../../../test/List.test.ets" +import app from '@system.app' +import featureAbility from "@ohos.ability.featureAbility" + +@Entry +@Component +struct MyComponent { + aboutToAppear() { + console.info("start run testcase!!!!") + featureAbility.getWant() + .then((Want) => { + const core = Core.getInstance() + const instrumentLog = new InstrumentLog({ + 'id': 'report', 'unity': 'true' + }) + const expectExtend = new ExpectExtend({ + 'id': 'extend' + }) + core.addService('expect', expectExtend) + core.addService('report', instrumentLog) + core.init() + core.subscribeEvent('spec', instrumentLog) + core.subscribeEvent('suite', instrumentLog) + core.subscribeEvent('task', instrumentLog) + const configService = core.getDefaultService('config') + configService.setConfig(Want.parameters) + testsuite() + core.execute() + console.info('Operation successful. Data: ' + JSON.stringify(Want)); + }) + .catch((error) => { + console.error('Operation failed. Cause: ' + JSON.stringify(error)); + }) + } + + build() { + Flex({ + direction: FlexDirection.Column, + alignItems: ItemAlign.Center, + justifyContent: FlexAlign.Center + }) { + Text('Hello World') + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + .height('100%') + } +} + diff --git a/entry/src/ohosTest/ets/test/ExampleJsunit.test.ets b/entry/src/ohosTest/ets/test/ExampleJsunit.test.ets new file mode 100644 index 0000000..2438a8a --- /dev/null +++ b/entry/src/ohosTest/ets/test/ExampleJsunit.test.ets @@ -0,0 +1,14 @@ +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from "deccjsunit/index" +import app from '@system.app' + +export default function exampleJsunit() { + describe('appInfoTest', function () { + it('app_info_test_001', 0, function () { + var info = app.getInfo() + expect("1.0") + .assertEqual('1.0') + expect(info.versionCode) + .assertEqual('3') + }) + }) +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/test/GlideJSTest.test.ets b/entry/src/ohosTest/ets/test/GlideJSTest.test.ets new file mode 100644 index 0000000..80a8be3 --- /dev/null +++ b/entry/src/ohosTest/ets/test/GlideJSTest.test.ets @@ -0,0 +1,229 @@ +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from "deccjsunit/index" +import featureability from '@ohos.ability.featureAbility' +import {Glide} from '../../../main/ets/default/glide/Glide.ets' +import {GlideData} from '../../../main/ets/default/glide/GlideData.ets' +import {LruCache} from '../../../main/ets/default/cache/LruCache' +import {DiskLruCache} from '../../../main/ets/default/cache/DiskLruCache' +import {AsyncCallback} from "../../../main/ets/default/glide/interface/asynccallback.ets" +import dataStorage from '@ohos.data.storage'; +import {FileUtils} from '../../../main/ets/default/cache/FileUtils' +import {TransformUtils} from '../../../main/ets/default/glide/transform/TransformUtils.ets' +import resmgr from '@ohos.resourceManager' +import {ColorUtils} from "../../../main/ets/default/glide/utils/ColorUtils.ets"; +import {DataCallBack} from "../../../main/ets/default/glide/interface/DataCallBack.ets"; + + +export default function glidejsRootJsunit() { + + describe('GlideJSTest', function () { + let filePath = '/data/data/com.huawei.mydemoall/files' + let cachePath = '/data/data/com.huawei.mydemoall/cache' + + let GlideSingleton; + beforeAll(function () { + GlideSingleton = Glide.with(); + }); + + it('glidejs_test_001', 0, function () { + expect(GlideSingleton != null && GlideSingleton != undefined).assertEqual(true) + }) + + // 替换MemoryCache + it('glidejs_glide_test_001', 0, function () { + expect(GlideSingleton.getMemoryCache() + .maxsize).assertEqual(100) + GlideSingleton.setMemoryCache(new LruCache(200)) + expect(GlideSingleton.getMemoryCache() + .maxsize).assertEqual(200) + }) + + // 替换DiskLruCache + it('glidejs_glide_test_002', 0, function () { + expect(GlideSingleton.getDiskMemoryCache() + .maxsize).assertEqual(30 * 1024 * 1024) + GlideSingleton.setDiskMemoryCache(new DiskLruCache(40 * 1024 * 1024)) + expect(GlideSingleton.getDiskMemoryCache() + .maxsize).assertEqual(40 * 1024 * 1024) + }) + + // 替换svgAndGifFolder + it('glidejs_glide_test_003', 0, function () { + expect(GlideSingleton.getSvgAndGifFolder()).assertEqual("svgAndGifFolder") + GlideSingleton.setSvgAndGifFolder("renameFolder") + expect(GlideSingleton.getSvgAndGifFolder()).assertEqual("renameFolder") + }) + + // 替换defaultListener + it('glidejs_glide_test_004', 0, function () { + expect(GlideSingleton.getDefaultListener() != null && GlideSingleton.getDefaultListener() != undefined) + .assertEqual(false) + GlideSingleton.setDefaultListener((err, glideData: GlideData) => { + // watch callback + }) + expect(GlideSingleton.getDefaultListener() != null && GlideSingleton.getDefaultListener() != undefined) + .assertEqual(true) + }) + + // fileutils createFile + it('glidejs_file_utils_test_001', 0, function () { + let fd = FileUtils.getInstance().createFile(this.filePath + "temp1.txt") + expect(fd > 0).assertEqual(true) + }) + + // fileutils clearFile + it('glidejs_file_utils_test_002', 0, function () { + let fd = FileUtils.getInstance().clearFile(this.filePath + "temp1.txt") + expect(fd > 0).assertEqual(true) + }) + + // fileutils exist + it('glidejs_file_utils_test_003', 0, function () { + let result = FileUtils.getInstance().exist(this.filePath + "temp1.txt") + expect(result).assertEqual(true) + }) + + // fileutils getFileSize + it('glidejs_file_utils_test_004', 0, function () { + let size = FileUtils.getInstance().getFileSize(this.filePath + "temp1.txt") + expect(size).assertEqual(0) + }) + + // fileutils existFolder + it('glidejs_file_utils_test_005', 0, function () { + let result = FileUtils.getInstance().existFolder(this.filePath) + expect(result).assertEqual(true) + }) + + // fileutils stringToUint8Array + it('glidejs_file_utils_test_006', 0, function () { + let result = FileUtils.getInstance().stringToUint8Array("A") + expect(result[0]).assertEqual(65) + }) + + // fileutils stringToUint8Array + it('glidejs_file_utils_test_007', 0, function () { + let uint8array = FileUtils.getInstance().stringToUint8Array("A") + let result = FileUtils.getInstance().uint8ArrayToBuffer(uint8array) + expect(result[0]).assertEqual(65) + }) + + // LruCache get + it('glidejs_lrucache_test_001', 0, function () { + let lruCache = new LruCache(5) + lruCache.put("1", 1); + lruCache.put("2", 2); + lruCache.put("3", 3); + lruCache.put("4", 4); + lruCache.put("5", 5); + expect(lruCache.get("1")).assertEqual(1) + }) + + // LruCache resize maxsize trimToSize + it('glidejs_lrucache_test_002', 0, function () { + let lruCache = new LruCache(5) + lruCache.put("1", 1); + lruCache.put("2", 2); + lruCache.put("3", 3); + lruCache.put("4", 4); + lruCache.put("5", 5); + lruCache.get("1") + lruCache.resize(4) + expect(lruCache.maxSize()).assertEqual(4) + expect(lruCache.get("2") == undefined).assertEqual(true) + }) + + // DiskLruCache putCacheData getCacheDataByKey + it('glidejs_disklrucache_test_001', 0, function () { + let diskLruCache = new DiskLruCache(40 * 1024 * 1024) + let uint8Array = new Uint8Array([1,2,3,4]) + let arraybuffer = FileUtils.getInstance().uint8ArrayToBuffer(uint8Array); + diskLruCache.putCacheData("1",arraybuffer,null) + let getValue = diskLruCache.getCacheDataByKey("1") + + let uint8GetValue = new Uint8Array(getValue); + expect(uint8Array[0]).assertEqual(1) + expect(uint8Array[1]).assertEqual(2) + expect(uint8Array[2]).assertEqual(3) + expect(uint8Array[3]).assertEqual(4) + }) + + // DiskLruCache cleanCacheData + it('glidejs_disklrucache_test_002', 0, function () { + let diskLruCache = new DiskLruCache(40 * 1024 * 1024) + let uint8Array = new Uint8Array([1,2,3,4]) + let arraybuffer = FileUtils.getInstance().uint8ArrayToBuffer(uint8Array); + diskLruCache.putCacheData("1",arraybuffer,null) + diskLruCache.cleanCacheData(); + let getValue = diskLruCache.getCacheDataByKey("1") + expect(getValue==null).assertEqual(true) + }) + + // DiskLruCache getCacheFileByKey + it('glidejs_disklrucache_test_003', 0, function () { + let diskLruCache = new DiskLruCache(40 * 1024 * 1024) + let uint8Array = new Uint8Array([1,2,3,4]) + let arraybuffer = FileUtils.getInstance().uint8ArrayToBuffer(uint8Array); + diskLruCache.putCacheData("1",arraybuffer,null) + let path = diskLruCache.getCacheFileByKey("1"); + expect(path!=null).assertEqual(true) + }) + + // DiskLruCache setMaxSize + it('glidejs_disklrucache_test_004', 0, function () { + let diskLruCache = new DiskLruCache(40 * 1024 * 1024) + diskLruCache.setMaxSize(20 * 1024 * 1024) + expect(diskLruCache.maxSize==(20 * 1024 * 1024)).assertEqual(true) + }) + + + // DiskLruCache deleteCacheDataBykey + it('glidejs_disklrucache_test_005', 0, function () { + let diskLruCache = new DiskLruCache(40 * 1024 * 1024) + let uint8Array = new Uint8Array([1,2,3,4]) + let arraybuffer = FileUtils.getInstance().uint8ArrayToBuffer(uint8Array); + diskLruCache.putCacheData("1",arraybuffer,null) + diskLruCache.deleteCacheDataBykey("1"); + let value = diskLruCache.getCacheDataByKey("1") + expect(value == null).assertEqual(true) + }) + + //pngj + it('glidejs_pngj_test_001', 0, function () { + let pngj = new Pngj(); + let uint8Array = new Uint8Array([1,2,3,4]) + let inputArray = FileUtils.getInstance().uint8ArrayToBuffer(uint8Array); + pngj.writePng(inputArray,(buffer1)=>{ + let uint8array1 = new Uint8Array(buffer1); + let pngj1length = uint8array1.byteLength; + pngj.writePngWithString("hello",inputArray,(buffer2)=>{ + let uint8array2 = new Uint8Array(buffer2); + let pngj2length = uint8array2.byteLength; + expect(pngj2length > pngj1length).assertEqual(true) + }); + }); + }) + + + it('glidejs_color_test_01', 0, function () { + let call: DataCallBack = { + callback(data: string) { + expect(data != null).assertEqual(true) + } + } + ColorUtils.parseColor("test_color", call); + }) + + it('glidejs_color_test_02', 0, function () { + expect(ColorUtils.red(1325455) == ((1325455 >> 16) & 0xFF)).assertEqual(true); + }) + it('glidejs_color_test_03', 0, function () { + expect(ColorUtils.blue(1325455) == (1325455 & 0xFF)).assertEqual(true); + }) + it('glidejs_color_test_04', 0, function () { + expect(ColorUtils.green(1325455) == ((1325455 >> 8) & 0xFF)).assertEqual(true); + }) + it('glidejs_color_test_05', 0, function () { + expect(ColorUtils.rgb(25, 123, 150) == (0xff000000 | (25 << 16) | (123 << 8) | 150)).assertEqual(true); + }) + }) +} \ No newline at end of file diff --git a/entry/src/ohosTest/ets/test/List.test.ets b/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000..00198c5 --- /dev/null +++ b/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import exampleJsunit from "../test/ExampleJsunit.test.ets" +import GlideJSTest from '../test/GlideJSTest.test.ets' +export default function testsuite() { + GlideJSTest() +} \ No newline at end of file diff --git a/entry/src/ohosTest/resources/base/element/string.json b/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000..1c1522b --- /dev/null +++ b/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,12 @@ +{ + "string": [ + { + "name": "app_name", + "value": "GlideJSCache" + }, + { + "name": "mainability_description", + "value": "hap sample empty page" + } + ] +} diff --git a/entry/src/ohosTest/resources/base/media/icon.png b/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000..ce307a8 Binary files /dev/null and b/entry/src/ohosTest/resources/base/media/icon.png differ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..be49249 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,13 @@ +# Project-wide Gradle settings. +# IDE (e.g. DevEco Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# If the Chinese output is garbled, please configure the following parameter. +# This function is enabled by default when the DevEco Studio builds the hap/app,if you need disable gradle parallel,you should set org.gradle.parallel false. +# more information see https://docs.gradle.org/current/userguide/performance.html +# org.gradle.parallel=false +# org.gradle.jvmargs=-Dfile.encoding=GBK \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..490fda8 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..63c817f --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://repo.huaweicloud.com/gradle/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..2fe81a7 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..62bd9b9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..74bc244 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,11 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "pako": { + "version": "1.0.11", + "resolved": "http://mirrors.tools.huawei.com/npm/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a0c761f --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "pako": "^1.0.5" + } +} diff --git a/screenshot/g1.gif b/screenshot/g1.gif new file mode 100644 index 0000000..2c322db Binary files /dev/null and b/screenshot/g1.gif differ diff --git a/screenshot/g2.gif b/screenshot/g2.gif new file mode 100644 index 0000000..f2b6e98 Binary files /dev/null and b/screenshot/g2.gif differ diff --git a/screenshot/g3.gif b/screenshot/g3.gif new file mode 100644 index 0000000..519c261 Binary files /dev/null and b/screenshot/g3.gif differ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..4773db7 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':entry'