diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b4530be306618bfda67fd77473d95109c872bfbe --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,113 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#import("//build/config/ohos/rules.gni") +import("//build/ohos.gni") + +#ohos_combine_jars("image_combine_java") { + # image +# deps = [ +# "adapter/frameworks/bitmapconverter/java:imagesystemadapter_java", +# "adapter/frameworks/exif:image_exifadapter_java", +# "interfaces/kits/java:image_java", +# "interfaces/kits/java:image_receiver_java", +# ] + +# if (is_double_framework && !mrt) { +# dex_path = "${target_out_dir}/image.z.jar" +# } + +# subsystem_name = "multimedia" +# part_name = "multimedia_image" +#} + +#ohos_maple_java("image_combine_maple_java") { +# deps = [ ":image_combine_java" ] + +# if (is_double_framework) { +# aosp_deps = [ "maple:framework" ] +# } + +# external_deps = [ +# "ability:abilitykit_java_maple", +# "ans:intentagent_base_java_maple", +# "appexecfwk:abilityshell_java_maple", +# "appexecfwk:appexecfwk_base_java_maple", +# "appexecfwk:appexecfwk_java_maple", +# "appexecfwk:eventhandler_java_maple", +# "bytrace:bytrace_maple_java", +# "ces:commonevent_base_java_maple", +# "ces:commoneventkit_java_maple", +# "dmsadapter:uri_java_maple", +# "graphic:agp_maple_java", +# "graphic:agpwindowkit_maple_java", +# "graphic:surfaceviewadapter_maple_java", +# "hilog:hilog_maple_java", +# "intent:intent_java_maple", +# "ipc:ipc_maple_java", +# "ivicommon:drivingsafety_innerkit_maple_java", +# "location:locationkits_maple_java", +# "multimodalinput:mmi_event_maple_java", +# "multimodalinput:mmi_eventimpl_maple_java", +# "resmgr:kits_maple_java", +# "startup:syspara_maple_java", +# "utils:utils_java", +# "utils:utils_maple_java", +# ] + +# so_name = "multimedia" + +# subsystem_name = "multimedia" +#} + +group("image_framework") { + deps = [ +# "adapter/frameworks/bitmapconverter/native:bitmapconverter", + "frameworks/innerkitsimpl/utils:image_utils", + "interfaces/innerkits:image", + #"interfaces/kits/native:multimedia_target", + ] +} + +group("plugins") { + deps = [ + "plugins/common/libs:multimediaplugin", + "plugins/manager:pluginmanager", + ] + +} + +#group("image_test_list") { +# testonly = true + + # image +# deps = [ +# "adapter/frameworks/bitmapconverter/java/test:unittest", +# "frameworks/innerkitsimpl/test:unittest", +# "interfaces/kits/java/test:unittest", +# "interfaces/kits/native/test:unittest", +# "plugins/manager/test/unittest/common:unittest", +# ] +#} +#group("image_performance_test_list") { +# testonly = true +# deps = [ "interfaces/kits/java/test/:performance" ] +#} + +config("media_config") { + defines = [] + #if (current_cpu == "arm64" || (current_cpu == "arm" && arm_use_neon)) { + if (current_cpu == "arm64" || (current_cpu == "arm")) { + defines += [ "USE_NEON" ] + } +} diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000000000000000000000000000000000000..2bb9ad240fa04c8cf706a4901c4807878e90c2dc --- /dev/null +++ b/LICENSE @@ -0,0 +1,176 @@ + 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 \ No newline at end of file diff --git a/OAT.xml b/OAT.xml new file mode 100755 index 0000000000000000000000000000000000000000..7de7b0b657a32ce36ffb9d5ae3fd50eede1bbe17 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 0781a0f05b76db30b991282c699ec17b295b624b..c33fd63fdbecac7a8d6bc1b0406777e73bcfce9d --- a/README.md +++ b/README.md @@ -1,39 +1,203 @@ -# multimedia_image_standard +# Image -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +- [Introduction](#section11660541593) +- [Directory Structure](#section161941989596) +- [Usage](#section1312121216216) + - [Available APIs](#section1551164914237) + - [Usage Guidelines](#section129654513264) -#### 软件架构 -软件架构说明 +- [Repositories Involved](#section1533973044317) +## Introduction -#### 安装教程 +The **image** repository provides easy-to-use APIs for developing image encoding and decoding features. Currently, the following image formats are supported: JPEG, PNG, BMP, WEBP, GIF, HEIF, and RAW. -1. xxxx -2. xxxx -3. xxxx +**Figure 1** Image architecture +![](figures/image-architecture.png "image-architecture") -#### 使用说明 +## Directory Structure -1. xxxx -2. xxxx -3. xxxx +The structure of the repository directory is as follows: -#### 参与贡献 +``` +/foundation/multimedia/image +├── adapter # Adaptation code +│ ├── frameworks # Framework adaptation +│ └── hals # HAL adaptation +├── frameworks # Framework code +│ ├── innerkitsimpl # Native API implementation +│ └── jni # JNI implementation +├── ohos.build # Build configuration +├── interfaces # External APIs +│ ├── innerkits # APIs of other internal subsystems +│ ├── kits # Java APIs +│ └── native # NDK APIs +├── mock # Mock implementation +├── plugins # Image plug-in implementation +│ ├── common # Common image plug-ins +│ ├── manager # Image plug-in manager +├── test # Test resources +``` -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +## Usage +### Available APIs -#### 特技 +Major methods in **ImageSource** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Method

+

Description

+

create(String pathName, SourceOptions opts)

+

Creates an ImageSource based on an image file path.

+

create(InputStream is, SourceOptions opts)

+

Creates an ImageSource based on an input stream.

+

create(byte[] data, SourceOptions opts)

+

Creates an ImageSource based on a byte array.

+

create(byte[] data, int offset, int length, SourceOptions opts)

+

Creates an ImageSource based on a byte array with specified offset and length.

+

create(File file, SourceOptions opts)

+

Creates an ImageSource based on a File object.

+

create(FileDescriptor fd, SourceOptions opts)

+

Creates an ImageSource based on a file descriptor.

+

createIncrementalSource(SourceOptions opts)

+

Creates an incremental data source based on a SourceOptions object.

+

createIncrementalSource(IncrementalSourceOptions opts)

+

Creates an incremental data source based on an IncrementalSourceOptions object.

+

createPixelmap(DecodingOptions opts)

+

Decodes source image data and creates a pixel map.

+

createPixelmap(int index, DecodingOptions opts)

+

Decodes source image data based on a specified index location in the ImageSource and creates a pixel map.

+

release()

+

Releases local resources associated with the PixelMap object.

+
+ +Major methods in **PixelMap** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Method

+

Description

+

create(InitializationOptions opts)

+

Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type).

+

create(PixelMap source, Rect srcRegion, InitializationOptions opts)

+

Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type) and the data source described by a source pixel map and the expected area on it.

+

getBytesNumberPerRow()

+

Obtains the number of bytes in each row of pixels.

+

getPixelBytesCapacity()

+

Obtains the memory capacity for storing the pixels of this pixel map.

+

readPixel(Position pos)

+

Reads the color value at the specified position. The color value is in PixelFormat.ARGB_8888 format.

+

readPixels(int[] pixels, int offset, int stride, Rect region)

+

Reads the color values of a specified region and writes them into a pixels array with the specified start offset and stride. The color values are in PixelFormat.ARGB_8888 format.

+

readPixels(Buffer dst)

+

Reads a copy of color values of this PixelMap instance and stores it to the specified buffer.

+

writePixels(int[] pixels, int offset, int stride, Rect region)

+

Writes data from the specified color data array (based on the start offset and stride) into the specified region of this PixelMap instance. The color data to write is in PixelFormat.ARGB_8888 format.

+

writePixels(Buffer src)

+

Writes the pixel data in the specified buffer into this PixelMap. The buffer data will overwrite the PixelMap data, so the color format of the source data must be compatible with this PixelMap.

+

getImageInfo()

+

Obtains basic image information.

+

release()

+

Releases local resources associated with the PixelMap object.

+
+ +### Usage Guidelines + +The following example shows how to parse a local image by calling methods in **ImageSource**: + +``` +ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); +srcOpts.formatHint = "image/png"; +String pathName = "/sdcard/image.png"; +ImageSource imageSource = ImageSource.create(pathName, srcOpts); +ImageSource imageSourceNoOptions = ImageSource.create(pathName, null); +// Common decoding with scaling, cropping, and rotation +ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); +decodingOpts.desiredSize = new Size(100, 2000); +decodingOpts.desiredRegion = new Rect(0, 0, 100, 100); +decodingOpts.rotateDegrees = 90; +PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); +// Common decoding mode +PixelMap pixelMapNoOptions = imageSource.createPixelmap(null); +``` + +## Repositories Involved + +hmf/multimedia/image -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/) diff --git a/README_zh.md b/README_zh.md new file mode 100755 index 0000000000000000000000000000000000000000..deccb87b7a516109255cdfcca461676964bd9cc6 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,203 @@ +# Image组件 + +- [简介](#section11660541593) +- [目录](#section161941989596) +- [说明](#section1312121216216) + - [接口说明](#section1551164914237) + - [使用说明](#section129654513264) + +- [相关仓](#section1533973044317) + +## 简介 + +Image组件提供了简单易用的接口用于开发图像的编解码功能,目前支持主流的如下图片格式:JPEG、PNG、BMP、WEBP、GIF、HEIF、RAW。 + +**图 1** Image组件架构图 +![](figures/Image组件架构图.png "Image组件架构图") + +## 目录 + +仓目录结构如下: + +``` +/foundation/multimedia/image # Image组件业务代码 +├── adapter # 适配层代码 +│ └── frameworks # 框架适配层 +│ └── hals # hal适配层 +├── frameworks # 框架代码 +│ ├── innerkitsimpl # 框架native层业务实现 +│ └── jni # jni层实现 +├── ohos.build # 编译配置 +├── interfaces # 外部接口层 +│ ├── innerkits # 内部其他子系统接口 +│ ├── kits # java接口层 +│ └── native # ndk接口层 +├── mock # mock实现 +├── plugins # 图像插件实现 +│ ├── common # 图像通用插件 +│ └── manager # 图像插件管理模块 +├── test # 测试资源目录 +``` + +## 说明 + +### 接口说明 + +ImageSource提供的主要接口如下: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

接口名

+

描述

+

create(String pathName, SourceOptions opts)

+

从图像文件路径创建图像数据源。

+

create(InputStream is, SourceOptions opts)

+

从输入流创建图像数据源。

+

create(byte[] data, SourceOptions opts)

+

从字节数组创建图像源。

+

create(byte[] data, int offset, int length, SourceOptions opts)

+

从字节数组指定范围创建图像源。

+

create(File file, SourceOptions opts)

+

从文件对象创建图像数据源。

+

create(FileDescriptor fd, SourceOptions opts)

+

从文件描述符创建图像数据源。

+

createIncrementalSource(SourceOptions opts)

+

创建渐进式图像数据源。

+

createIncrementalSource(IncrementalSourceOptions opts)

+

创建渐进式图像数据源,支持设置渐进式数据更新模式。

+

createPixelmap(DecodingOptions opts)

+

从图像数据源解码并创建PixelMap图像。

+

createPixelmap(int index, DecodingOptions opts)

+

从图像数据源解码并创建PixelMap图像,如果图像数据源支持多张图片的话,支持指定图像索引。

+

release()

+

释放对象关联的本地资源。

+
+ +PixelMap提供的主要接口如下: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

接口名

+

描述

+

create(InitializationOptions opts)

+

根据图像大小、像素格式、alpha类型等初始化选项创建PixelMap。

+

create(PixelMap source, Rect srcRegion, InitializationOptions opts)

+

根据图像大小、像素格式、alpha类型等初始化选项,以源PixelMap、源裁剪区域描述的数据源创建PixelMap。

+

getBytesNumberPerRow()

+

获取每行像素数据占用的字节数。

+

getPixelBytesCapacity()

+

获取存储Pixelmap像素数据的内存容量。

+

readPixel(Position pos)

+

读取指定位置像素的颜色值,返回的颜色格式为PixelFormat.ARGB_8888。

+

readPixels(int[] pixels, int offset, int stride, Rect region)

+

读取指定区域像素的颜色值,输出到以起始偏移量、行像素大小描述的像素数组,返回的颜色格式为PixelFormat.ARGB_8888。

+

readPixels(Buffer dst)

+

读取像素的颜色值到缓冲区,返回的数据是PixelMap中像素数据的原样拷贝,即返回的颜色数据格式与PixelMap中像素格式一致。

+

writePixels(int[] pixels, int offset, int stride, Rect region)

+

将像素颜色数组、起始偏移量、行像素的个数描述的源像素数据写入PixelMap的指定区域,写入颜色格式为PixelFormat.ARGB_8888。

+

writePixels(Buffer src)

+

将缓冲区描述的源像素数据写入PixelMap,写入的数据将原样覆盖PixelMap中的像素数据,即写入数据的颜色格式应与PixelMap的配置兼容。

+

getImageInfo()

+

获取图像基本信息。

+

release()

+

释放对象关联的本地资源。

+
+ +### 使用说明 + +下面提供了使用ImageSource解析本地图片的例子: + +``` +ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); +srcOpts.formatHint = "image/png"; +String pathName = "/sdcard/image.png"; +ImageSource imageSource = ImageSource.create(pathName, srcOpts); +ImageSource imageSourceNoOptions = ImageSource.create(pathName, null); +// 普通解码叠加缩放、裁剪、旋转 +ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); +decodingOpts.desiredSize = new Size(100, 2000); +decodingOpts.desiredRegion = new Rect(0, 0, 100, 100); +decodingOpts.rotateDegrees = 90; +PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); +// 普通模式解码 +PixelMap pixelMapNoOptions = imageSource.createPixelmap(null); +``` + +## 相关仓 + +hmf/multimedia/image + diff --git a/adapter/LICENSE b/adapter/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..3d9b23b82406505acfa2c506609c121e74e57711 --- /dev/null +++ b/adapter/LICENSE @@ -0,0 +1,44 @@ +Copyright (C) 2021 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************** +android permission, multimedia, it is derived from the following: +https://android.googlesource.com/platform/frameworks/base/ +version 10.0.0_r2 +*************************************************************** +Copyright 2005-2008 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************** +heif, it is derived from the following: +https://android.googlesource.com/platform/frameworks/av/ +version 10.0.0_r2 +*************************************************************** +Copyright 2005-2008 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/adapter/frameworks/bitmapconverter/java/BUILD.gn b/adapter/frameworks/bitmapconverter/java/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2a7a2306f01106a9e287dcfd59b3ecb90e9c5a1d --- /dev/null +++ b/adapter/frameworks/bitmapconverter/java/BUILD.gn @@ -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("//build/config/ohos/rules.gni") + +java_library("imagesystemadapter_java") { + java_files = [ "src/ohos/media/image/inner/ImageDoubleFwConverter.java" ] + + classpath_deps = [ + "//foundation/multimedia/image/interfaces/kits/java:image_java", + "//foundation/multimedia/utils/java:multimedia_utils_java", + ] + + external_deps = [ + "ipc:ipc_java", + "utils:utils_java", + ] + part_name = "multimedia_image" +} + +ohos_maple_java("imagesystemadapter_maple_java") { + deps = [ + ":imagesystemadapter_java", + "//foundation/multimedia/image/interfaces/kits/java:image_maple_java", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + "//utils/java:utils_java", + "//utils/java:utils_maple_java", + ] + + aosp_deps = [ "maple:framework" ] + + external_deps = [ + "hilog:hilog_maple_java", + "ipc:ipc_java", + "utils:utils_maple_java", + ] + + subsystem_name = "multimedia" +} diff --git a/adapter/frameworks/bitmapconverter/java/src/ohos/media/image/inner/ImageDoubleFwConverter.java b/adapter/frameworks/bitmapconverter/java/src/ohos/media/image/inner/ImageDoubleFwConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..5880725b2581e1ef111bf467cd8fc9c6cf78de6c --- /dev/null +++ b/adapter/frameworks/bitmapconverter/java/src/ohos/media/image/inner/ImageDoubleFwConverter.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2006 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.inner; + +import android.graphics.Bitmap; + +import ohos.utils.Parcel; +import ohos.rpc.MessageParcel; +import ohos.media.image.PixelMap; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; + +/** + * Bitmap and PixelMap Converter + * + * @since 1 + */ +public class ImageDoubleFwConverter { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageDoubleFwConverter.class); + + static { + LOGGER.debug("Begin loading image_converter_jni library"); + try { + System.loadLibrary("image_converter_jni.z"); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary image_converter_jni.z fail"); + } + } + + /** + * convert PixelMap to Bitmap + * + * @param pixelMap create form source image + * @return android Bitmap on success, otherwise return null + * @since 1 + */ + public static Bitmap createShadowBitmap(PixelMap pixelMap) { + if (pixelMap == null) { + LOGGER.error("createShadowBitmap pixelMap is null"); + return null; + } + + return nativeCreateBitmap(pixelMap); + } + + /** + * Convert Bitmap to PixelMap + * + * @param bitmap android's Bitmap object + * @return PixelMap on success, otherwise return null + * @since 1 + */ + public static PixelMap createShellPixelMap(Bitmap bitmap) { + if (bitmap == null) { + LOGGER.error("createShellPixelMap bitmap is null"); + return null; + } + + return nativeCreatePixelMap(bitmap); + } + + /** + * Write PixelMap to Parcel + * + * @param pixelMap source image + * @param parcel ohos parcel object + * @since 3 + */ + public static void writeToParcel(PixelMap pixelMap, Parcel parcel) { + if (pixelMap == null) { + LOGGER.error("writeToParcel pixelMap is null"); + return; + } + + if (parcel instanceof MessageParcel) { + nativeWriteToParcel(pixelMap, parcel); + } else { + LOGGER.error("writeToParcel not a MessageParcel"); + } + } + + private static native Bitmap nativeCreateBitmap(PixelMap pixelMap); + + private static native PixelMap nativeCreatePixelMap(Bitmap bitmap); + + private static native void nativeWriteToParcel(PixelMap pixelMap, Parcel parcel); +} diff --git a/adapter/frameworks/bitmapconverter/java/test/BUILD.gn b/adapter/frameworks/bitmapconverter/java/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..63ca42a1b049aa8f541ef9eb20512f7a25c7ab82 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/java/test/BUILD.gn @@ -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("//build/test.gni") + +module_output_path = "multimedia_image/image_standard" + +#ohos_java_unittest("test_imagesystemadapter_java_maple") { +# java_files = +# [ "unittest/src/ohos/media/image/inner/ImageDoubleFwConverterTest.java" ] +# +# deps = [ +# "//foundation/multimedia/image/adapter/frameworks/bitmapconverter/java:imagesystemadapter_maple_java", +# "//foundation/multimedia/image/interfaces/kits/java:image_maple_java", +# "//foundation/multimedia/utils/java:multimedia_utils_maple_java", +# "//utils/java:utils_java", +# "//utils/java:utils_maple_java", +# ] + +# external_deps = [ +# "ipc:ipc_java", +# "utils:utils_maple_java", +# ] + +# sub_output_dir = "$module_output_path/" +# resource_config_file = +# "//foundation/multimedia/image/test/resource/image/ohos_test.xml" +#} + +#group("unittest") { +# testonly = true +# deps = [ ":test_imagesystemadapter_java_maple" ] +#} diff --git a/adapter/frameworks/bitmapconverter/java/test/unittest/src/ohos/media/image/inner/ImageDoubleFwConverterTest.java b/adapter/frameworks/bitmapconverter/java/test/unittest/src/ohos/media/image/inner/ImageDoubleFwConverterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ea5aab6149b9167101024e13df40a90744e99b76 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/java/test/unittest/src/ohos/media/image/inner/ImageDoubleFwConverterTest.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2007 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.inner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Parcel; + +import ohos.media.image.ImageSource; +import ohos.media.image.PixelMap; +import ohos.media.image.common.AllocatorType; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.Position; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.rpc.MessageParcel; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.nio.ByteBuffer; +import java.util.Arrays; + +/** + * ImageDoubleFwConverterTest, test cases for ImageDoubleFwConverter class, + * mainly including test cases for PixelMap and Bitmap conversion. + * + * @since 1 + */ +public class ImageDoubleFwConverterTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageDoubleFwConverterTest.class); + + private static File pngFile; + + static { + try { + System.loadLibrary("ipc_core.z"); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary ipc_core.z fail"); + } + } + + private ImageSource imageSource; + + private PixelMap pixelMap; + + private ImageDoubleFwConverter converter = new ImageDoubleFwConverter(); + + /** + * Action before all test case. + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + pngFile = new File("/sdcard/multimedia/image/test.png"); + if (!pngFile.exists()) { + LOGGER.error("test file not exist."); + fail("files not exist"); + } + } + + /** + * Action after all test case. + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + /** + * Action before test case. + */ + @Before + public void setUp() throws Exception { + } + + /** + * Action after test case. + */ + @After + public void tearDown() throws Exception { + try { + if (imageSource != null) { + imageSource.release(); + imageSource = null; + } + if (pixelMap != null) { + pixelMap.release(); + pixelMap = null; + } + } catch (Throwable throwable) { + LOGGER.error("test case teardown fail, %{public}s", throwable.getMessage()); + } + } + + /** + * @tc.name: testImageDoubleFwConverter001 + * @tc.desc: convert between Bitmap and PixelMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageDoubleFwConverter001() { + /** + * @tc.steps: step1.get pixelmap from path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/png"; + String pathName = "/sdcard/multimedia/image/test.png"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2.convert pixelmap to bitmap and convert bitmap to pixelmap back. + * @tc.expected: step2.conversion ok + */ + Bitmap bitmap = ImageDoubleFwConverter.createShadowBitmap(pixelMap); + assertNotNull(bitmap); + assertNotNull(bitmap.getConfig()); + + Bitmap bitmap1 = bitmap.copy(bitmap.getConfig(), false); + assertNotNull(bitmap1); + + Bitmap bitmap2 = BitmapFactory.decodeFile(pathName); + PixelMap pixelMapNew = ImageDoubleFwConverter.createShellPixelMap(bitmap2); + assertNotNull(pixelMapNew); + + assertEquals(472, pixelMapNew.getImageInfo().size.width); + assertEquals(75, pixelMapNew.getImageInfo().size.height); + } + + /** + * @tc.name: testImageDoubleFwConverter002 + * @tc.desc: convert between Bitmap and PixelMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageDoubleFwConverter002() { + /** + * @tc.steps: step1.get pixelmap from path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/png"; + String pathName = "/sdcard/multimedia/image/test_large.webp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.decode pixelmap. + * @tc.expected: step2.decode ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step3.read pixel map by pos. + * @tc.expected: step3.read ok + */ + int zColor = pixelMap.readPixel(new Position(360, 342)); + byte[] zBytes = new byte[4]; + zBytes[3] = (byte) (zColor & 0xff); // B 87 + zBytes[2] = (byte) (zColor >> 8 & 0xff); // G 248 + zBytes[1] = (byte) (zColor >> 16 & 0xff); // R 243 + zBytes[0] = (byte) (zColor >> 24 & 0xff); // A 255 + + assertEquals(zBytes[0], (byte)-1); + assertEquals(zBytes[1], (byte)63); + assertEquals(zBytes[2], (byte)71); + assertEquals(zBytes[3], (byte)-51); + + /** + * @tc.steps: step4.convert pixelmap to bitmap and read same pos. + * @tc.expected: step4.pixelmap's color is same of bitmap's color + */ + Bitmap bitmap = ImageDoubleFwConverter.createShadowBitmap(pixelMap); + assertNotNull(bitmap); + assertNotNull(bitmap.getConfig()); + int aColor = bitmap.getPixel(360, 342); + assertEquals(zColor, aColor); + + /** + * @tc.steps: step5.convert bitmap to pixelmap and read same pos. + * @tc.expected: step5.pixelmapback's color is same of pixelmap's color + */ + PixelMap pixelMapBack = ImageDoubleFwConverter.createShellPixelMap(bitmap); + int zColorBack = pixelMapBack.readPixel(new Position(360, 342)); + assertEquals(zColor, zColorBack); + + /** + * @tc.steps: step6.copy bitmap and read same pos. + * @tc.expected: step6.bitmapcopy's color is same of pixelmap's color + */ + Bitmap bitmap1 = bitmap.copy(bitmap.getConfig(), false); + assertNotNull(bitmap1); + int colorCopy = bitmap1.getPixel(360, 342); + assertEquals(zColor, colorCopy); + assertEquals(aColor, colorCopy); + + /** + * @tc.steps: step7.decode bitmap and convert to pixelmap then read same pos. + * @tc.expected: step7.bitmap's color is same of pixelmap's color + */ + Bitmap bitmap2 = BitmapFactory.decodeFile(pathName); + PixelMap pixelMapNew = ImageDoubleFwConverter.createShellPixelMap(bitmap2); + assertNotNull(pixelMapNew); + int aColor2 = bitmap2.getPixel(360, 342); + int zColor2 = pixelMapNew.readPixel(new Position(360, 342)); + assertEquals(aColor2, zColor2); + } + + /** + * @tc.name: testImageDoubleFwConverter003 + * @tc.desc: PixelMap write to parcel. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageDoubleFwConverter003() { + /** + * @tc.steps: step1.get pixelmap from path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/png"; + String pathName = "/sdcard/multimedia/image/test_large.webp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixelmap and bitmap. + * @tc.expected: step2.create ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + Bitmap bitmap = ImageDoubleFwConverter.createShadowBitmap(pixelMap); + assertNotNull(bitmap); + + /** + * @tc.steps: step3.write bitmap to android parcel, pixelMap to MessageParcel, compare size. + * @tc.expected: step3.size equals + */ + android.os.Parcel aParcel = android.os.Parcel.obtain(); + bitmap.writeToParcel(aParcel, 0); + int aParcelSize = aParcel.dataSize(); + + MessageParcel zParcel = MessageParcel.obtain(); + ImageDoubleFwConverter.writeToParcel(pixelMap, zParcel); + int zParcelSize = zParcel.getSize(); + + assertEquals(zParcelSize, aParcelSize); + + aParcel.recycle(); + zParcel.reclaim(); + } + + /** + * @tc.name: testImageDoubleFwConverter004 + * @tc.desc: PixelMap write to parcel using shared memory. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageDoubleFwConverter004() { + /** + * @tc.steps: step1.get pixelmap from path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/png"; + String pathName = "/sdcard/multimedia/image/test.png"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixelmap and bitmap. + * @tc.expected: step2.create ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + decodingOpts.allocator = AllocatorType.SHARED_MEMORY; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + Bitmap bitmap = ImageDoubleFwConverter.createShadowBitmap(pixelMap); + assertNotNull(bitmap); + + assertEquals(Bitmap.Config.ARGB_8888, bitmap.getConfig()); + assertEquals(472, bitmap.getWidth()); + assertEquals(75, bitmap.getHeight()); + + int pixelMapDataSize = (int) pixelMap.getPixelBytesCapacity(); + ByteBuffer pixelMapByteBuffer = ByteBuffer.allocate(pixelMapDataSize); + pixelMap.readPixels(pixelMapByteBuffer); + + int bitMapdataSize = bitmap.getByteCount(); + ByteBuffer bitmapByteBuffer = ByteBuffer.allocate(bitMapdataSize); + bitmap.copyPixelsToBuffer(bitmapByteBuffer); + + assertEquals(0, pixelMapByteBuffer.compareTo(bitmapByteBuffer)); + } + +} diff --git a/adapter/frameworks/bitmapconverter/native/BUILD.gn b/adapter/frameworks/bitmapconverter/native/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..8fd57b81964a4315ccd2ffd9b65f3df7b8605fc4 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/BUILD.gn @@ -0,0 +1,207 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +#config("bitmapconverter_public_config") { +# visibility = [ ":*" ] +# include_dirs = [ +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/private", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/android", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/gpu", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/frameworks/base/libs/hwui/hwui", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/frameworks/native/libs/nativewindow/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/frameworks/native/libs/arect/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/system/core/libcutils/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/frameworks/native/libs/ui/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/frameworks/native/libs/nativebase/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/system/core/libsystem/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/system/core/libutils/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/hardware/libhardware/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/hardware/libhardware/include", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/system/core/liblog/include", +# ] + +# if (use_mingw_win) { +# include_dirs += [ +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/external/skia/include/config/win", +# "${asdk_dir}/shared_library/${target_os}_${target_cpu}/include/external/skia/include/config", +# ] +# } else { +# include_dirs += [ "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/android" ] +# } +#} + +ohos_shared_library("bitmapconverter") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/src/bitmap_wrapper.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/src/image_bitmap_converter.cpp", + ] + +# public_configs = [ ":bitmapconverter_public_config" ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/include/encode", + "//third_party/flutter/skia", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/src/ports", + "//third_party/flutter/skia/src/images", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/third_party/externals/freetype/include/freetype", + "//third_party/flutter/skia/include/private", + + ] + + if (use_mingw_win) { + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:static_image", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + ] + + libs = [ "//foundation/multimedia/image_standard/libskia.a" ] + } else { + include_dirs += [ + "//utils/native/base/include", +# "//sdk/aosp-arm64/communication/ipc_core/include/", + ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//utils/native/base:utils", + ] + +# aosp_deps = [ +# "shared_library:libhwui", +# "shared_library:liblog", +# ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + } + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_static_library("static_bitmapconverter") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/src/bitmap_wrapper.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/src/image_bitmap_converter.cpp", + ] + +# public_configs = [ ":bitmapconverter_public_config" ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/include/encode", + "//third_party/flutter/skia", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/src/ports", + "//third_party/flutter/skia/src/images", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/third_party/externals/freetype/include/freetype", + "//third_party/flutter/skia/include/private", + + ] + + if (use_mingw_win) { + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:static_image", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + ] + + libs = [ "//foundation/multimedia/image_standard/libskia.a" ] + } else { + include_dirs += [ + "//utils/native/base/include", +# "//sdk/aosp-arm64/communication/ipc_core/include/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//utils/native/base:utils", + ] + +# aosp_deps = [ +# "shared_library:libhwui", +# "shared_library:liblog", +# ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + } +} + +#config("image_converter_jni_config") { +# visibility = [ ":*" ] +# include_dirs = [ +# "//utils/native/base/include", +# "//utils/jni/jnikit/include", +# "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/include", +# "//foundation/multimedia/image_standard/interfaces/innerkits/include", +# "//foundation/multimedia/image_standard/plugins/manager/include", +# "//foundation/multimedia/utils/include", +# "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/include", +# ] +#} + +#group("g_image_converter_jni") { +# deps = [ ":image_converter_jni" ] +#} + +#ohos_shared_library("image_converter_jni") { +# sources = [ +# "src/image_native_interface_utils.cpp", +# "src/ohos_image_ImageDoubleFwConverter.cpp", +# ] + +# configs = [ ":image_converter_jni_config" ] + +# include_dirs = [ "//sdk/aosp-arm64/communication/ipc_core/include/" ] + +# deps = [ +# "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native:bitmapconverter", +# "//foundation/multimedia/image_standard/interfaces/innerkits:image", +# "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", +# "//utils/jni:utils_jnikit", +# "//utils/native/base:utils", +# ] + +# external_deps = [ +# "hilog:libhilog", +# "ipc:ipc_core", +# ] +# subsystem_name = "multimedia" +# part_name = "multimedia_image" +#} diff --git a/adapter/frameworks/bitmapconverter/native/include/bitmap_wrapper.h b/adapter/frameworks/bitmapconverter/native/include/bitmap_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..3b15f9c286abc0f82c93ec662b4f3561da55e6f7 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/include/bitmap_wrapper.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2015 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef BITMAP_WRAPPER_H +#define BITMAP_WRAPPER_H + +#include "Bitmap.h" +#include "SkBitmap.h" + +namespace android { +class BitmapWrapper { +public: + BitmapWrapper(android::Bitmap *bitmap) : mBitmap(bitmap) {} + ~BitmapWrapper() {} + void freePixels(); + bool valid() const; + android::Bitmap &bitmap(); + void assertValid() const; + void getSkBitmap(SkBitmap *outBitmap) const; + bool hasHardwareMipMap(); + void setHasHardwareMipMap(bool hasMipMap); + void setAlphaType(SkAlphaType alphaType); + const SkImageInfo &info(); + size_t getAllocationByteCount() const; + size_t rowBytes() const; + uint32_t getGenerationID() const; + bool isHardware(); + +private: + sk_sp mBitmap = nullptr; + SkImageInfo mInfo; + bool mHasHardwareMipMap = false; + size_t mAllocationSize = 0; + size_t mRowBytes = 0; + uint32_t mGenerationId = 0; + bool mIsHardware = false; +}; +} // namespace android +#endif // BITMAP_WRAPPER_H diff --git a/adapter/frameworks/bitmapconverter/native/include/hilog/log.h b/adapter/frameworks/bitmapconverter/native/include/hilog/log.h new file mode 100644 index 0000000000000000000000000000000000000000..5515244b1e5dee5203ca0a3a0d66b9ca6f5bcc89 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/include/hilog/log.h @@ -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. + */ + + +#ifndef HIVIEWDFX_HILOG_H +#define HIVIEWDFX_HILOG_H + +#include "hilog/log_c.h" +#include "hilog/log_cpp.h" + +#endif // HIVIEWDFX_HILOG_H \ No newline at end of file diff --git a/adapter/frameworks/bitmapconverter/native/include/hilog/log_c.h b/adapter/frameworks/bitmapconverter/native/include/hilog/log_c.h new file mode 100644 index 0000000000000000000000000000000000000000..d64551d00b4e706319c1d3bd824073a0be230c86 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/include/hilog/log_c.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef HIVIEWDFX_HILOG_C_H +#define HIVIEWDFX_HILOG_C_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Log domain +#ifndef LOG_DOMAIN +#define LOG_DOMAIN 0 +#endif + +// Log tag +#ifndef LOG_TAG +#define LOG_TAG NULL +#endif + +// Log type +typedef enum { + LOG_TYPE_MIN = 0, + // Log to kmsg, only used by init phase. + LOG_INIT = 1, + // Used by core service, framework. + LOG_CORE = 3, + LOG_TYPE_MAX +} LogType; + +// Log level +typedef enum { + LOG_LEVEL_MIN = 0, + LOG_DEBUG = 3, + LOG_INFO = 4, + LOG_WARN = 5, + LOG_ERROR = 6, + LOG_FATAL = 7, + LOG_LEVEL_MAX, +} LogLevel; + +int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) + __attribute__((__format__(os_log, 5, 6))); + +#define HILOG_DEBUG(type, ...) ((void)HiLogPrint((type), LOG_DEBUG, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_INFO(type, ...) ((void)HiLogPrint((type), LOG_INFO, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_WARN(type, ...) ((void)HiLogPrint((type), LOG_WARN, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_ERROR(type, ...) ((void)HiLogPrint((type), LOG_ERROR, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_FATAL(type, ...) ((void)HiLogPrint((type), LOG_FATAL, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +bool HiLogIsLoggable(unsigned int domain, const char *tag, LogLevel level); + +#ifdef __cplusplus +} +#endif + +#endif // HIVIEWDFX_HILOG_C_H diff --git a/adapter/frameworks/bitmapconverter/native/include/hilog/log_cpp.h b/adapter/frameworks/bitmapconverter/native/include/hilog/log_cpp.h new file mode 100644 index 0000000000000000000000000000000000000000..e27379231ddd78114695e7d4cead7535c8ce6235 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/include/hilog/log_cpp.h @@ -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. + */ + + +#ifndef HIVIEWDFX_HILOG_CPP_H +#define HIVIEWDFX_HILOG_CPP_H + +#include "hilog/log_c.h" + +#ifdef __cplusplus + +namespace OHOS { +namespace HiviewDFX { +typedef struct HiLogLabel { + LogType type; + unsigned int domain; + const char *tag; +} HiLogLabel; + +class HiLog final { +public: + static int Debug(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Info(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Warn(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Error(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Fatal(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif // __cplusplus +#endif // HIVIEWDFX_HILOG_CPP_H diff --git a/adapter/frameworks/bitmapconverter/native/include/image_bitmap_converter.h b/adapter/frameworks/bitmapconverter/native/include/image_bitmap_converter.h new file mode 100644 index 0000000000000000000000000000000000000000..6ec0fbf0b165e19298ec8407999815e9bebba877 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/include/image_bitmap_converter.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2015 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_BITMAP_CONVERTER_H +#define IMAGE_BITMAP_CONVERTER_H + +#include +#include "bitmap_wrapper.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "pixel_map.h" +#include "message_parcel.h" + +namespace OHOS { +namespace Media { +class ImageBitmapConverter { +public: + static android::BitmapWrapper *CreateShadowBitmap(PixelMap *pixelMap); + static PixelMap *CreateShellPixelMap(android::BitmapWrapper *bitmapWrapper); + static void PixelMapWriteToParcel(PixelMap *pixelMap, int density, MessageParcel *parcel); + static PixelMap *createFromAlpha(PixelMap *pixelMapSrc); + +private: + static const size_t SIZE_LIMIT = 16 * 1024; + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageBitmapConverter" + }; + static SkColorType GetColorType(PixelFormat pixelFormat); + static void FreeBitmap(void *addr, void *context); + static PixelFormat GetPixelFormat(SkColorType colorType); + static void FreePixelMapFunc(void *addr, void *context, uint32_t size); + static SkAlphaType ConvertToSkAlphaType(AlphaType alphaType); + static AlphaType ConvertToAlphaType(SkAlphaType at); + static void WriteBigData(MessageParcel *p, const void* data, size_t size, bool isMutable); + static PixelMap *CreateSkShellPixelMap(SkBitmap &skBitmap, + void *context = nullptr, + PixelFormat pixelFormat = PixelFormat::UNKNOWN, + ColorSpace colorSpace = ColorSpace::SRGB, + bool copy = false); +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_BITMAP_CONVERTER_H diff --git a/adapter/frameworks/bitmapconverter/native/src/bitmap_wrapper.cpp b/adapter/frameworks/bitmapconverter/native/src/bitmap_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b04377b45450af7000030baa326066b95562b72c --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/src/bitmap_wrapper.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2015 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "bitmap_wrapper.h" + +namespace android { +void BitmapWrapper::freePixels() +{ + if (!valid()) { + ALOGE("BitmapWrapper freePixels already done, so we do nothing"); + return; + } + ALOGE("BitmapWrapper freePixels"); +} + +bool BitmapWrapper::valid() const +{ + return mBitmap != nullptr; +} + +android::Bitmap &BitmapWrapper::bitmap() +{ + assertValid(); + return *mBitmap; +} + +void BitmapWrapper::assertValid() const +{ + LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!"); +} + +void BitmapWrapper::getSkBitmap(SkBitmap *outBitmap) const +{ + assertValid(); + mBitmap->getSkBitmap(outBitmap); +} + +bool BitmapWrapper::hasHardwareMipMap() +{ + if (mBitmap) { + return mBitmap->hasHardwareMipMap(); + } + return mHasHardwareMipMap; +} + +void BitmapWrapper::setHasHardwareMipMap(bool hasMipMap) +{ + assertValid(); + mBitmap->setHasHardwareMipMap(hasMipMap); +} + +void BitmapWrapper::setAlphaType(SkAlphaType alphaType) +{ + assertValid(); + mBitmap->setAlphaType(alphaType); +} + +const SkImageInfo &BitmapWrapper::info() +{ + if (mBitmap) { + return mBitmap->info(); + } + return mInfo; +} + +size_t BitmapWrapper::getAllocationByteCount() const +{ + if (mBitmap) { + return mBitmap->getAllocationByteCount(); + } + return mAllocationSize; +} + +size_t BitmapWrapper::rowBytes() const +{ + if (mBitmap) { + return mBitmap->rowBytes(); + } + return mRowBytes; +} + +uint32_t BitmapWrapper::getGenerationID() const +{ + if (mBitmap) { + return mBitmap->getGenerationID(); + } + return mGenerationId; +} + +bool BitmapWrapper::isHardware() +{ + if (mBitmap) { + return mBitmap->isHardware(); + } + return mIsHardware; +} +} // namespace android \ No newline at end of file diff --git a/adapter/frameworks/bitmapconverter/native/src/image_bitmap_converter.cpp b/adapter/frameworks/bitmapconverter/native/src/image_bitmap_converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b2a3b5602d308a5e97ff05f3249c5239d043465 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/src/image_bitmap_converter.cpp @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2015 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_bitmap_converter.h" +#include "SkBitmap.h" +#include "SkImageInfo.h" + +#include "media_errors.h" +#if defined(_WIN32) || defined(_APPLE) +#include +#else +#include +#include +#include "ashmem.h" +#include "securec.h" +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +static constexpr uint32_t G_MAX_COLOR_SPACE_SERIALIZED_BYTES = 80; + +enum { + RAW_INPLACE = 0, + RAW_ASHMEM_IMMUTABLE = 1, + RAW_ASHMEM_MUTABLE = 2, +}; + +SkColorType ImageBitmapConverter::GetColorType(PixelFormat pixelFormat) +{ + SkColorType colorType = kUnknown_SkColorType; + switch (pixelFormat) { + case PixelFormat::ALPHA_8: { + colorType = kAlpha_8_SkColorType; + break; + } + case PixelFormat::RGB_565: { + colorType = kRGB_565_SkColorType; + break; + } + case PixelFormat::RGBA_F16: { + colorType = kRGBA_F16_SkColorType; + break; + } + case PixelFormat::RGBA_8888: + case PixelFormat::BGRA_8888: { + colorType = kN32_SkColorType; + break; + } + default: { + HiLog::Error(LABEL, "convert from pixel format:%{public}d to color type failed.", + static_cast(pixelFormat)); + break; + } + } + + return colorType; +} + +SkAlphaType ImageBitmapConverter::ConvertToSkAlphaType(AlphaType alphaType) +{ + SkAlphaType skAlphaType = kUnknown_SkAlphaType; + switch (alphaType) { + case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE: { + skAlphaType = kOpaque_SkAlphaType; + break; + } + case AlphaType::IMAGE_ALPHA_TYPE_PREMUL: { + skAlphaType = kPremul_SkAlphaType; + break; + } + case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL: { + skAlphaType = kUnpremul_SkAlphaType; + break; + } + default: { + HiLog::Error(LABEL, "unknown alpha type:%{public}d.", static_cast(alphaType)); + break; + } + } + return skAlphaType; +} + +void ImageBitmapConverter::FreeBitmap(void *addr, void *context) +{ + // free bitmap do nothing, the bitmap malloc data will be released by pixelmap destruct function. + HiLog::Debug(LABEL, "free bitmap."); + return; +} + +android::BitmapWrapper *ImageBitmapConverter::CreateShadowBitmap(PixelMap *pixelMap) +{ + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "create shadow bitmap error, input parameter is null."); + return nullptr; + } + uint8_t *base = const_cast(pixelMap->GetPixels()); + if (base == nullptr) { + HiLog::Error(LABEL, "create shadow bitmap error, pixel addr is null."); + return nullptr; + } + int32_t width = pixelMap->GetWidth(); + int32_t height = pixelMap->GetHeight(); + int32_t rowBytes = pixelMap->GetRowBytes(); + PixelFormat pixelFormat = pixelMap->GetPixelFormat(); + SkColorType colorType = GetColorType(pixelFormat); + AlphaType alphaType = pixelMap->GetAlphaType(); + SkAlphaType skAlphaType = ConvertToSkAlphaType(alphaType); + SkImageInfo skImageInfo = SkImageInfo::Make(width, height, colorType, skAlphaType, SkColorSpace::MakeSRGB()); + sk_sp bitmap = nullptr; + AllocatorType allocType = pixelMap->GetAllocatorType(); + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { + int32_t *fd = static_cast(pixelMap->GetFd()); + if (fd == nullptr || *fd < 0) { + HiLog::Error(LABEL, "CreateShadowBitmap fd is invalid."); + return nullptr; + } + SkBitmap skBitmap; + if (!skBitmap.setInfo((skImageInfo), rowBytes)) { + HiLog::Error(LABEL, "CreateShadowBitmap, setInfo failed!"); + return nullptr; + } + size_t bitmapSize = skBitmap.computeByteSize(); + int32_t dupFd = fcntl(*fd, F_DUPFD_CLOEXEC, 0); + if (dupFd < 0) { + HiLog::Error(LABEL, "CreateShadowBitmap, dupFd < 0."); + return nullptr; + } + bitmap = android::Bitmap::createFrom(skImageInfo, rowBytes, dupFd, nullptr, bitmapSize, false); + if (bitmap == nullptr) { + HiLog::Error(LABEL, "CreateShadowBitmap malloc bitmap createFrom failed."); + ::close(dupFd); + return nullptr; + } + } else { + SkPixelRef *skPixelRef = new (std::nothrow) SkPixelRef(width, height, base, rowBytes); + if (skPixelRef == nullptr) { + HiLog::Error(LABEL, "skPixelRef is nullptr."); + return nullptr; + } + bitmap = android::Bitmap::createFrom(skImageInfo, *skPixelRef); + if (bitmap.get() == nullptr) { + HiLog::Error(LABEL, "malloc shadow bitmap error."); + delete skPixelRef; + return nullptr; + } + } + android::BitmapWrapper *bitmapWrapper = new (std::nothrow) android::BitmapWrapper(bitmap.get()); + if (bitmapWrapper == nullptr) { + HiLog::Error(LABEL, "malloc shadow bitmap wrapper error."); + return nullptr; + } + (void)bitmap.release(); + return bitmapWrapper; +} + +PixelFormat ImageBitmapConverter::GetPixelFormat(SkColorType colorType) +{ + PixelFormat pixelFormat = PixelFormat::UNKNOWN; + switch (colorType) { + case kAlpha_8_SkColorType: { + pixelFormat = PixelFormat::ALPHA_8; + break; + } + case kRGB_565_SkColorType: { + pixelFormat = PixelFormat::RGB_565; + break; + } + case kRGBA_F16_SkColorType: { + pixelFormat = PixelFormat::RGBA_F16; + break; + } + case kRGBA_8888_SkColorType: { + pixelFormat = PixelFormat::RGBA_8888; + break; + } + case kBGRA_8888_SkColorType: { + pixelFormat = PixelFormat::BGRA_8888; + break; + } + default: { + HiLog::Error(LABEL, "convert from color type:%{public}d to pixel format failed.", + static_cast(colorType)); + break; + } + } + return pixelFormat; +} + +AlphaType ImageBitmapConverter::ConvertToAlphaType(SkAlphaType at) +{ + AlphaType alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; + switch (at) { + case kOpaque_SkAlphaType: { + alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + break; + } + case kPremul_SkAlphaType: { + alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + break; + } + case kUnpremul_SkAlphaType: { + alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + break; + } + default: { + HiLog::Error(LABEL, "unknown skia alpha type:%{public}d.", static_cast(at)); + break; + } + } + return alphaType; +} + +void ImageBitmapConverter::FreePixelMapFunc(void *addr, void *context, uint32_t size) +{ + android::BitmapWrapper *bitmap = static_cast(context); + if (bitmap != nullptr) { + bitmap->freePixels(); + } +} + +PixelMap *ImageBitmapConverter::CreateShellPixelMap(android::BitmapWrapper *bitmapWrapper) +{ + if (bitmapWrapper == nullptr) { + HiLog::Error(LABEL, "create shell pixel map error, input parameter is null."); + return nullptr; + } + SkBitmap skBitmap; + bitmapWrapper->getSkBitmap(&skBitmap); + return CreateSkShellPixelMap(skBitmap, bitmapWrapper); +} + +void ImageBitmapConverter::PixelMapWriteToParcel(PixelMap *pixelMap, int density, MessageParcel *p) +{ +#ifndef _WIN32 + android::BitmapWrapper *bitmapWrapper = ImageBitmapConverter::CreateShadowBitmap(pixelMap); + SkBitmap bitmap; + bitmapWrapper->getSkBitmap(&bitmap); + + bool isMutable = pixelMap->IsEditable(); + p->WriteInt32(isMutable); + p->WriteInt32(bitmap.colorType()); + p->WriteInt32(bitmap.alphaType()); + SkColorSpace* colorSpace = bitmap.colorSpace(); + if (colorSpace != nullptr) { + sk_sp data = colorSpace->serialize(); + size_t size = data->size(); + p->WriteUint32(size); + if (size > 0) { + if (size > G_MAX_COLOR_SPACE_SERIALIZED_BYTES) { + HiLog::Error(LABEL, "Serialized SkColorSpace is larger than expected, ret:%{public}zu.", size); + } + p->WriteBuffer(data->data(), size); + } + } else { + p->WriteUint32(0); + } + p->WriteInt32(bitmap.width()); + p->WriteInt32(bitmap.height()); + p->WriteInt32(bitmap.rowBytes()); + p->WriteInt32(density); + + // Transfer the underlying ashmem region if we have one and it's immutable. + android::status_t status; + int fd = bitmapWrapper->bitmap().getAshmemFd(); + if (fd >= 0 && !isMutable) { + status = p->WriteFileDescriptor(fd); + if (status) { + HiLog::Error(LABEL, "Could not write file descriptor."); + return; + } + ::close(fd); + return; + } + + size_t size = bitmap.computeByteSize(); + const void* pSrc = bitmap.getPixels(); + if (pSrc == NULL) { + if (size == 0) { + HiLog::Error(LABEL, "malloc failed, size %{public}zu.", size); + return; + } + void* data = malloc(size); + if (data == nullptr) { + HiLog::Error(LABEL, "malloc failed, size %{public}zu.", size); + return; + } + if (memset_s(data, size, 0, size) != EOK) { + HiLog::Error(LABEL, "memset failed"); + free(data); + return; + } + WriteBigData(p, data, size, isMutable); + free(data); + } else { + WriteBigData(p, pSrc, size, isMutable); + } +#endif + return; +} + +#ifndef _WIN32 +void ImageBitmapConverter::WriteBigData(MessageParcel *p, const void* data, size_t size, bool isMutable) +{ + HiLog::Debug(LABEL, "WriteBigData size:[%{public}lld] isMutable:[%{public}d]", (long long)size, isMutable); + if (size < SIZE_LIMIT) { + p->WriteInt32(RAW_INPLACE); + p->WriteBuffer(data, size); + return; + } + int fd = AshmemCreate("Parcel RawData", size); + if (fd < 0) { + return; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return; + } + void* ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return; + } + if (isMutable) { + p->WriteInt32(RAW_ASHMEM_MUTABLE); + } else { + result = AshmemSetProt(fd, PROT_READ); + if (result < 0) { + ::munmap(ptr, size); + ::close(fd); + return; + } + p->WriteInt32(RAW_ASHMEM_IMMUTABLE); + } + if (!p->WriteFileDescriptor(fd)) { + ::munmap(ptr, size); + ::close(fd); + return; + } + if (memcpy_s(ptr, size, data, size) != EOK) { + ::munmap(ptr, size); + ::close(fd); + return; + } + ::munmap(ptr, size); + ::close(fd); + return; +} +#endif +PixelMap *ImageBitmapConverter::CreateSkShellPixelMap(SkBitmap &skBitmap, void *context, PixelFormat pixelFormat, + ColorSpace colorSpace, bool copy) +{ + void *base = skBitmap.getPixels(); + if (base == nullptr) { + HiLog::Error(LABEL, "create skbitmap shell pixel map error, bitmap addr is null."); + return nullptr; + } + int32_t width = skBitmap.width(); + int32_t height = skBitmap.height(); + SkColorType colorType = skBitmap.colorType(); + SkAlphaType skAlphaType = skBitmap.alphaType(); + size_t byteCount = skBitmap.rowBytes() * height; + PixelMap *pixelMap = new (std::nothrow) PixelMap(); + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "malloc skbitmap shell pixel map error."); + return nullptr; + } + ImageInfo info; + info.size.width = width; + info.size.height = height; + info.pixelFormat = (pixelFormat == PixelFormat::UNKNOWN ? GetPixelFormat(colorType) : pixelFormat); + info.alphaType = ConvertToAlphaType(skAlphaType); + info.colorSpace = colorSpace; + uint32_t ret = pixelMap->SetImageInfo(info); + if (ret != SUCCESS) { + delete pixelMap; + HiLog::Error(LABEL, "skbitmap pixel map set image info failed, ret:%{public}u.", ret); + return nullptr; + } + if (copy) { + void *dstPixels = malloc(byteCount); + if (dstPixels == nullptr) { + HiLog::Error(LABEL, "allocate memory byteCount %{public}zu fail", byteCount); + return nullptr; + } + if (memcpy_s(dstPixels, byteCount, base, byteCount) != EOK) { + free(dstPixels); + return nullptr; + } + skBitmap.reset(); + pixelMap->SetPixelsAddr(dstPixels, nullptr, byteCount, AllocatorType::HEAP_ALLOC, nullptr); + } else { + pixelMap->SetPixelsAddr(base, context, byteCount, AllocatorType::CUSTOM_ALLOC, FreePixelMapFunc); + } + return pixelMap; +} + +PixelMap *ImageBitmapConverter::createFromAlpha(PixelMap *pixelMapSrc) +{ + if (pixelMapSrc) { + SkBitmap src; + SkBitmap dst; + CreateShadowBitmap(pixelMapSrc)->getSkBitmap(&src); + if (!src.extractAlpha(&dst) || (dst.getPixels() == nullptr && src.getPixels() != nullptr)) { + HiLog::Error(LABEL, "failed to allocate pixels for alpha"); + return nullptr; + } + return CreateSkShellPixelMap(dst, nullptr, PixelFormat::ALPHA_8, ColorSpace::SRGB, true); + } else { + HiLog::Error(LABEL, "input PixelMap is null, unable to get alpha from a null PixelMap"); + } + return nullptr; +} +} // namespace Media +} // namespace OHOS diff --git a/adapter/frameworks/bitmapconverter/native/src/image_native_interface_utils.cpp b/adapter/frameworks/bitmapconverter/native/src/image_native_interface_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5586c78d559d8f9fa4d7b0d18f5f67d6a932056 --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/src/image_native_interface_utils.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2015 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hilog/log.h" +#include "image_bitmap_converter.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" +#include "pixel_map_manager.h" + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "Image_Native_Interface_Utils" +}; + +namespace OHOS { +namespace Media { +PixelMap *GetNativePixelMap(JNIEnv *env, jobject pixelMapObj) +{ + if (pixelMapObj == nullptr) { + HiLog::Error(LABEL, "GetNativePixelMapPtr, pixelMap object is null."); + return nullptr; + } + jclass pixelMapClazz = env->GetObjectClass(pixelMapObj); + if (pixelMapClazz == nullptr) { + HiLog::Error(LABEL, "GetNativePixelMapPtr, PixelMap class not found."); + return nullptr; + } + jfieldID pixelMapFileId = env->GetFieldID(pixelMapClazz, "nativeImagePixelMap", "J"); + env->DeleteLocalRef(pixelMapClazz); + if (pixelMapFileId == nullptr) { + HiLog::Error(LABEL, "GetNativePixelMapPtr get nativeImagePixelMap error."); + return nullptr; + } + jlong pixelMapPtr = env->GetLongField(pixelMapObj, pixelMapFileId); + PixelMapManager *pixelMapManager = reinterpret_cast(pixelMapPtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "GetNativeBitmap pixelMap is null."); + return nullptr; + } + return &(pixelMapManager->GetPixelMap()); +} + +jobject GetNativeBitmap(JNIEnv *env, jobject pixelMapObj) +{ + if (pixelMapObj == nullptr) { + HiLog::Error(LABEL, "GetNativeBitmap, pixelMap object is null."); + return nullptr; + } + PixelMap *pixelMap = GetNativePixelMap(env, pixelMapObj); + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "GetNativeBitmap pixelMap is null."); + return nullptr; + } + + jclass bitmapClazz = env->FindClass("android/graphics/Bitmap"); + if (bitmapClazz == nullptr) { + HiLog::Error(LABEL, "GetNativeBitmap: find android Bitmap class fail, bitmapClazz is null."); + return nullptr; + } + + jmethodID bitmapConstructMethodId = + env->GetMethodID(bitmapClazz, "", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V"); + if (bitmapConstructMethodId == nullptr) { + HiLog::Error(LABEL, + "GetNativeBitmap: find android Bitmap construct method fail, bitmapConstructMethodId is null."); + env->DeleteLocalRef(bitmapClazz); + return nullptr; + } + + android::BitmapWrapper *bitmapWrapper = ImageBitmapConverter::CreateShadowBitmap(pixelMap); + if (bitmapWrapper == nullptr) { + HiLog::Error(LABEL, "GetNativeBitmap bitmap is null."); + env->DeleteLocalRef(bitmapClazz); + return nullptr; + } + + bool heapAlloc = pixelMap->GetAllocatorType() == AllocatorType::HEAP_ALLOC; + jobject bitmapObj = env->NewObject(bitmapClazz, bitmapConstructMethodId, reinterpret_cast(bitmapWrapper), + bitmapWrapper->bitmap().width(), bitmapWrapper->bitmap().height(), -1, true, + nullptr, nullptr, heapAlloc); + env->DeleteLocalRef(bitmapClazz); + + return bitmapObj; +} + +jobject GetShellPixelMap(JNIEnv *env, jobject bitmapObj) +{ + if (bitmapObj == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap, pixelMap object is null."); + return nullptr; + } + jclass bitmapClazz = env->GetObjectClass(bitmapObj); + if (bitmapClazz == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap, Bitmap class not found."); + return nullptr; + } + jfieldID bitmapWrapperFileId = env->GetFieldID(bitmapClazz, "mNativePtr", "J"); + env->DeleteLocalRef(bitmapClazz); + if (bitmapWrapperFileId == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap get mNativeBitmap error."); + return nullptr; + } + jlong bitmapWrapperPtr = env->GetLongField(bitmapObj, bitmapWrapperFileId); + android::BitmapWrapper *bitmapWrapper = reinterpret_cast(bitmapWrapperPtr); + if (bitmapWrapper == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap bitmapWrapper is null."); + return nullptr; + } + + jclass pixelMapClazz = env->FindClass("ohos/media/image/PixelMap"); + if (pixelMapClazz == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap: find PixelMap class fail, pixelMapClazz is null."); + return nullptr; + } + + jmethodID pixelMapConstructMethodId = env->GetMethodID(pixelMapClazz, "", "(JJJ)V"); + if (pixelMapConstructMethodId == nullptr) { + HiLog::Error(LABEL, + "GetShellPixelMap: find PixelMap construct method fail, pixelMapConstructMethodId is null."); + env->DeleteLocalRef(pixelMapClazz); + return nullptr; + } + + PixelMap *pixelMap = ImageBitmapConverter::CreateShellPixelMap(bitmapWrapper); + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap pixelMap is null."); + env->DeleteLocalRef(pixelMapClazz); + return nullptr; + } + PixelMapManager *pixelMapManager = new (std::nothrow) PixelMapManager(pixelMap); + if (pixelMapManager == nullptr) { + HiLog::Error(LABEL, "new pixelMapManager is null."); + env->DeleteLocalRef(pixelMapClazz); + return nullptr; + } + jobject globalBitmapObj = env->NewGlobalRef(bitmapObj); + jobject pixelMapObj = + env->NewObject(pixelMapClazz, pixelMapConstructMethodId, reinterpret_cast(pixelMapManager), + static_cast(pixelMap->GetByteCount()), reinterpret_cast(globalBitmapObj)); + env->DeleteLocalRef(pixelMapClazz); + return pixelMapObj; +} + +void PixelMapWriteToParcel(JNIEnv* env, jobject pixelMapObj, jobject zParcel) +{ + if (zParcel == NULL) { + HiLog::Error(LABEL, "writeToParcel null parcel."); + return; + } + jclass zParcelClazz = env->GetObjectClass(zParcel); + if (zParcelClazz == NULL) { + HiLog::Error(LABEL, "writeToParcel null zParcelClazz."); + return; + } + jfieldID zNativeHandleField = env->GetFieldID(zParcelClazz, "nativeHandle", "J"); + env->DeleteLocalRef(zParcelClazz); + if (zNativeHandleField == nullptr) { + HiLog::Error(LABEL, "zNativeHandleField is invalid"); + return; + } + jlong zParcelNative = env->GetLongField(zParcel, zNativeHandleField); + auto parcelZ = reinterpret_cast(zParcelNative); + HiLog::Debug(LABEL, "PixelMapWriteToParcel zParcel Ptr=%p", parcelZ); + + if (parcelZ == nullptr) { + HiLog::Debug(LABEL, "Failed to get Z native Parcel"); + return; + } + if (pixelMapObj == nullptr) { + HiLog::Error(LABEL, "nativeWriteToParcel, pixelMap object is null."); + return; + } + jclass pixelMapClazz = env->FindClass("ohos/media/image/PixelMap"); + if (pixelMapClazz == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap: find PixelMap class fail, pixelMapClazz is null."); + return; + } + jmethodID pixelMapGetDensityMethodId = env->GetMethodID(pixelMapClazz, "getBaseDensity", "()I"); + if (pixelMapGetDensityMethodId == nullptr) { + HiLog::Error(LABEL, "GetShellPixelMap: pixelMapGetDensityMethodId is null."); + env->DeleteLocalRef(pixelMapClazz); + return; + } + env->DeleteLocalRef(pixelMapClazz); + jint density = env->CallIntMethod(pixelMapObj, pixelMapGetDensityMethodId); + PixelMap *pixelMap = GetNativePixelMap(env, pixelMapObj); + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "nativeWriteToParcel pixelMap is null."); + return; + } + ImageBitmapConverter::PixelMapWriteToParcel(pixelMap, density, parcelZ); +} +} // namespace Media +} // namespace OHOS diff --git a/adapter/frameworks/bitmapconverter/native/src/ohos_image_ImageDoubleFwConverter.cpp b/adapter/frameworks/bitmapconverter/native/src/ohos_image_ImageDoubleFwConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ecf4faf0c52d2f9c9aba25076b365a127ce4ccf --- /dev/null +++ b/adapter/frameworks/bitmapconverter/native/src/ohos_image_ImageDoubleFwConverter.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2015 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "hilog/log.h" +#include "image_native_interface_utils.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageDoubleFwConverter_JNI" +}; + +jobject ohos_media_image_inner_ImageDoubleFwConverter_nativeCreateBitmap(JNIEnv *env, jobject thiz, + jobject pixelMapObj) +{ + jobject bitmap = GetNativeBitmap(env, pixelMapObj); + if (bitmap == nullptr) { + HiLog::Error(LABEL, "nativeCreateBitmap GetNativeBitmap fail"); + return nullptr; + } + + return bitmap; +} + +jobject ohos_media_image_inner_ImageDoubleFwConverter_nativeCreatePixelMap(JNIEnv *env, jobject thiz, + jobject bitmapObj) +{ + jobject pixelMapObj = GetShellPixelMap(env, bitmapObj); + if (pixelMapObj == nullptr) { + HiLog::Error(LABEL, "nativeCreatePixelMap GetShellPixelMap fail"); + return nullptr; + } + + return pixelMapObj; +} + +void ohos_media_image_inner_ImageDoubleFwConverter_nativeWriteToParcel(JNIEnv *env, jobject thiz, + jobject pixelMapObj, + jobject parcel) +{ + PixelMapWriteToParcel(env, pixelMapObj, parcel); + return; +} + +static const JNINativeMethod METHODS[] = { + { "nativeCreateBitmap", "(Lohos/media/image/PixelMap;)Landroid/graphics/Bitmap;", + reinterpret_cast(ohos_media_image_inner_ImageDoubleFwConverter_nativeCreateBitmap) }, + { "nativeCreatePixelMap", "(Landroid/graphics/Bitmap;)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_inner_ImageDoubleFwConverter_nativeCreatePixelMap) }, + { "nativeWriteToParcel", "(Lohos/media/image/PixelMap;Lohos/utils/Parcel;)V", + reinterpret_cast(ohos_media_image_inner_ImageDoubleFwConverter_nativeWriteToParcel) } +}; + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + HiLog::Debug(LABEL, "JNI_OnLoad begin"); + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + HiLog::Error(LABEL, "JNI_OnLoad: GetEnv failed"); + return ERROR; + } + int ret = JkitRegisterNativeMethods(env, "ohos/media/image/inner/ImageDoubleFwConverter", METHODS, + ARRCOUNT(METHODS)); + if (ret == JNI_ERR) { + HiLog::Error(LABEL, "JkitRegisterNativeMethods failed, ret=%{public}d", ret); + return ERROR; + } + Jkit::nativeInit(vm); + HiLog::Debug(LABEL, "JNI_OnLoad end"); + return JNI_VERSION_1_4; +} diff --git a/adapter/frameworks/exif/BUILD.gn b/adapter/frameworks/exif/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9354fa78f35ca2598f0cc25fc83e1b7ab0f7479f --- /dev/null +++ b/adapter/frameworks/exif/BUILD.gn @@ -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("//build/config/ohos/rules.gni") + +java_library("image_exifadapter_java") { + java_files = [ "src/ohos/media/image/exifadapter/ExifAdapter.java" ] + + classpath_deps = + [ "//foundation/multimedia/utils/java:multimedia_utils_java" ] + + external_deps = [ "utils:utils_java" ] + part_name = "multimedia_image" +} + +ohos_maple_java("image_exifadapter_maple_java") { + deps = [ + ":image_exifadapter_java", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + ] + + aosp_deps = [ "maple:framework" ] + + external_deps = [ + "hilog:hilog_maple_java", + "utils:utils_maple_java", + ] + + subsystem_name = "multimedia" +} diff --git a/adapter/frameworks/exif/src/ohos/media/image/exifadapter/ExifAdapter.java b/adapter/frameworks/exif/src/ohos/media/image/exifadapter/ExifAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..511dac98b42e171b99e492e3aa19a84ac40f7a58 --- /dev/null +++ b/adapter/frameworks/exif/src/ohos/media/image/exifadapter/ExifAdapter.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2007 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.exifadapter; + +import android.media.ExifInterface; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; + +/** + * exif adapter for ImageSource. + * + * @since 3 + */ +public class ExifAdapter { + private final ExifInterface exifInterface; + + /** + * Instantiates a new Exif adapter. + * + * @param pathName the path name + * @throws IOException the io exception + * @since 3 + */ + public ExifAdapter(String pathName) throws IOException { + exifInterface = new ExifInterface(pathName); + } + + /** + * Instantiates a new Exif adapter. + * + * @param inputStream the input stream + * @throws IOException the io exception + * @since 3 + */ + public ExifAdapter(InputStream inputStream) throws IOException { + exifInterface = new ExifInterface(inputStream); + } + + /** + * Instantiates a new Exif adapter. + * + * @param data the data + * @param offset the offset + * @param length the length + * @throws IOException the io exception + * @since 3 + */ + public ExifAdapter(byte[] data, int offset, int length) throws IOException { + exifInterface = new ExifInterface(new ByteArrayInputStream(data, offset, length)); + } + + /** + * Instantiates a new Exif adapter. + * + * @param file the input file + * @throws IOException the io exception + * @since 3 + */ + public ExifAdapter(File file) throws IOException { + exifInterface = new ExifInterface(file); + } + + /** + * Instantiates a new Exif adapter. + * + * @param fd the input fd + * @throws IOException the io exception + * @since 3 + */ + public ExifAdapter(FileDescriptor fd) throws IOException { + exifInterface = new ExifInterface(fd); + } + + /** + * Gets image property. + * + * @param key the key + * @return the image property + * @since 3 + */ + public String getImagePropertyString(String key) { + return exifInterface.getAttribute(key); + } + + /** + * Gets image property int. + * + * @param key the key + * @param defaultValue the default value + * @return the image property int + * @since 3 + */ + public int getImagePropertyInt(String key, int defaultValue) { + return exifInterface.getAttributeInt(key, defaultValue); + } + + /** + * Get thumbnail bytes byte. + * + * @return the byte + * @since 3 + */ + public byte[] getThumbnailBytes() { + return exifInterface.getThumbnailBytes(); + } + + /** + * Get thumbnail byte. + * + * @return the byte + * @since 3 + */ + public byte[] getThumbnail() { + return exifInterface.getThumbnail(); + } + + /** + * Get thumbnail offset and length. + * + * @return two-element array, the offset in the first value, and length in the + * second, or {@code null} if no thumbnail was found or the thumbnail + * strips are not placed consecutively. + * @since 6 + */ + public long[] getThumbnailRange() { + return exifInterface.getThumbnailRange(); + } + + /** + * Gets image property double. + * + * @param key the key + * @param defaultValue the default value + * @return the image property double + */ + public double getImagePropertyDouble(String key, double defaultValue) { + return exifInterface.getAttributeDouble(key, defaultValue); + } + + /** + * set image property. + * + * @param key the property key + * @param property value + * @since 3 + */ + public void setImageProperty(String key, String value) { + exifInterface.setAttribute(key, value); + } + + /** + * Save the setImageProperty property data into the original image file + * + * @throws IOException the io exception + * @since 3 + */ + public void saveAttributes() throws IOException { + try { + exifInterface.saveAttributes(); + } catch (IOException e) { + throw new IOException("only supports JPEG format for changing and saving Exif properties"); + } + } +} diff --git a/adapter/frameworks/heifcodec/BUILD.gn_old b/adapter/frameworks/heifcodec/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..0139c0e7a6faa7f65c124968a7114b31108db3db --- /dev/null +++ b/adapter/frameworks/heifcodec/BUILD.gn_old @@ -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("//build/ohos.gni") +config("heifadapter_public_config") { + visibility = [ ":*" ] +} + +ohos_shared_library("heifadapter") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/heifcodec/src/heif_decoder_adapter.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/heifcodec/src/heif_stream_wrapper.cpp", + ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libheifplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/heifcodec/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + public_configs = [ ":heifadapter_public_config" ] + +# aosp_deps = [ "shared_library:libheif" ] + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/heifcodec/include/heif_decoder_adapter.h b/adapter/frameworks/heifcodec/include/heif_decoder_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..c014a1315578cda48f8436fedcd1e7e648b86449 --- /dev/null +++ b/adapter/frameworks/heifcodec/include/heif_decoder_adapter.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HEIF_DECODER_ADAPTER_H +#define HEIF_DECODER_ADAPTER_H + +#include +#include "abs_image_decoder.h" +#include "heif_decoder_interface.h" +#include "heif_stream_wrapper.h" +#include "image_plugin_type.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class HeifDecoderAdapter : public ImagePlugin::HeifDecoderInterface { +public: + HeifDecoderAdapter() = default; + explicit HeifDecoderAdapter(HeifDecoder *heifDecoder); + virtual ~HeifDecoderAdapter() override{}; + static std::unique_ptr MakeFromStream(ImagePlugin::InputDataStream &stream); + virtual uint32_t OnGetPixels(const ImagePlugin::PlSize &dstSize, const uint32_t dstRowBytes, + ImagePlugin::DecodeContext &context) override; + virtual void SetAllowPartial(const bool isAllowPartialImage) override; + virtual void GetHeifSize(ImagePlugin::PlSize &size) override; + virtual bool ConversionSupported(const ImagePlugin::PlPixelFormat &plPixelFormat, int32_t &bytesPerPixel) override; + uint32_t ReadRows(const uint32_t rowBytes, const uint32_t count, ImagePlugin::DecodeContext &context); + +private: + DISALLOW_COPY_AND_MOVE(HeifDecoderAdapter); + std::unique_ptr heifDecoder_ = nullptr; + bool isAllowPartialImage_ = false; + static HeifFrameInfo heifFrameInfo_; +}; +} // namespace Media +} // namespace OHOS + +#endif // HEIF_DECODER_ADAPTER_H \ No newline at end of file diff --git a/adapter/frameworks/heifcodec/include/heif_stream_wrapper.h b/adapter/frameworks/heifcodec/include/heif_stream_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..b9fb7455ead83da397825112a7630cc7a7760fbd --- /dev/null +++ b/adapter/frameworks/heifcodec/include/heif_stream_wrapper.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2017 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HEIF_STREAM_WRAPPER_H +#define HEIF_STREAM_WRAPPER_H + +#include "HeifDecoderAPI.h" +#include "input_data_stream.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class HeifStreamWrapper : public HeifStream { +public: + HeifStreamWrapper() = default; + explicit HeifStreamWrapper(ImagePlugin::InputDataStream *stream); + virtual ~HeifStreamWrapper() override{}; + virtual size_t read(void *buffer, size_t size) override; + virtual bool rewind() override; + virtual bool seek(size_t position) override; + virtual bool hasLength() const override; + virtual size_t getLength() const override; + +private: + DISALLOW_COPY_AND_MOVE(HeifStreamWrapper); + ImagePlugin::InputDataStream *inputData_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // HEIF_STREAM_WRAPPER_H \ No newline at end of file diff --git a/adapter/frameworks/heifcodec/src/heif_decoder_adapter.cpp b/adapter/frameworks/heifcodec/src/heif_decoder_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99e2a1af89b732e14d37c9da103aafd8a75448a5 --- /dev/null +++ b/adapter/frameworks/heifcodec/src/heif_decoder_adapter.cpp @@ -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. + */ + +#include "heif_decoder_adapter.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "media_errors.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace ImagePlugin; + +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "HeifDecodeAdapter" }; + +constexpr int32_t PER_BYTES_RGB565 = 2; +constexpr int32_t PER_BYTES_RGBA = 4; +constexpr int32_t PER_BYTES_BGRA = 4; + +HeifFrameInfo HeifDecoderAdapter::heifFrameInfo_; +HeifDecoderAdapter::HeifDecoderAdapter(HeifDecoder *heifDecoder) : heifDecoder_(heifDecoder) +{} + +std::unique_ptr HeifDecoderAdapter::MakeFromStream(InputDataStream &stream) +{ + std::unique_ptr heifDecoder(createHeifDecoder()); + if (heifDecoder.get() == nullptr) { + HiLog::Error(LABEL, "heif decoder object is null."); + return nullptr; + } + + HeifStreamWrapper *heifStreamWrapper = new (std::nothrow) HeifStreamWrapper(&stream); + if (heifStreamWrapper == nullptr) { + HiLog::Error(LABEL, "create heif stream wrapper object failed."); + return nullptr; + } + + if (!heifDecoder->init(heifStreamWrapper, &heifFrameInfo_)) { + HiLog::Error(LABEL, "init heif decoder failed."); + delete heifStreamWrapper; + return nullptr; + } + + HeifDecoderAdapter *heifDecoderAdapter = new (std::nothrow) HeifDecoderAdapter(heifDecoder.release()); + if (heifDecoderAdapter == nullptr) { + HiLog::Error(LABEL, "create heif decoder adapter object failed."); + delete heifStreamWrapper; + return nullptr; + } + return std::unique_ptr(heifDecoderAdapter); +} + +uint32_t HeifDecoderAdapter::ReadRows(const uint32_t rowBytes, const uint32_t count, DecodeContext &context) +{ + uint8_t *decodeDst = static_cast(context.pixelsBuffer.buffer); + for (uint32_t i = 0; i < count; i++) { + if (!heifDecoder_->getScanline(decodeDst)) { + HiLog::Error(LABEL, "scan line failed, current rows:%{public}u.", i); + return i; + } + decodeDst = (decodeDst + rowBytes); + if (decodeDst == nullptr) { + HiLog::Error(LABEL, "decodeDst is null, current rows:%{public}u.", i); + return i; + } + } + return count; +} + +uint32_t HeifDecoderAdapter::OnGetPixels(const PlSize &dstSize, const uint32_t dstRowBytes, DecodeContext &context) +{ + if (context.pixelsBuffer.buffer == nullptr) { + HiLog::Error(LABEL, "buffer is null."); + return ERR_IMAGE_DECODE_FAILED; + } + + HeifFrameInfo heifInfo; + bool success = heifDecoder_->decode(&heifInfo); + if (!success) { + HiLog::Error(LABEL, "heif decode failed."); + return ERR_IMAGE_DECODE_FAILED; + } + + uint32_t rows = this->ReadRows(dstRowBytes, dstSize.height, context); + if (rows < dstSize.height && !isAllowPartialImage_) { + HiLog::Error(LABEL, "current rows:%{public}u less than desire height:%{public}u.", rows, dstSize.height); + return ERR_IMAGE_DECODE_FAILED; + } + + return SUCCESS; +} + +void HeifDecoderAdapter::GetHeifSize(PlSize &size) +{ + size.width = heifFrameInfo_.mWidth; + size.height = heifFrameInfo_.mHeight; +} + +void HeifDecoderAdapter::SetAllowPartial(const bool isAllowPartialImage) +{ + HiLog::Debug(LABEL, "allow image display partial."); + isAllowPartialImage_ = isAllowPartialImage; +} + +bool HeifDecoderAdapter::ConversionSupported(const PlPixelFormat &format, int32_t &bytesPerPixel) +{ + bool isSetOK = true; + switch (format) { + case PlPixelFormat::RGBA_8888: + isSetOK = heifDecoder_->setOutputColor(kHeifColorFormat_RGBA_8888); + bytesPerPixel = PER_BYTES_RGBA; + break; + case PlPixelFormat::BGRA_8888: + isSetOK = heifDecoder_->setOutputColor(kHeifColorFormat_BGRA_8888); + bytesPerPixel = PER_BYTES_BGRA; + break; + case PlPixelFormat::RGB_565: + isSetOK = heifDecoder_->setOutputColor(kHeifColorFormat_RGB565); + bytesPerPixel = PER_BYTES_RGB565; + break; + default: + isSetOK = heifDecoder_->setOutputColor(kHeifColorFormat_RGBA_8888); + bytesPerPixel = PER_BYTES_RGBA; + break; + } + return isSetOK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/adapter/frameworks/heifcodec/src/heif_stream_wrapper.cpp b/adapter/frameworks/heifcodec/src/heif_stream_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1be8aad2fc955ceb822dbfb5630154b90b08a92 --- /dev/null +++ b/adapter/frameworks/heifcodec/src/heif_stream_wrapper.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "heif_stream_wrapper.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "HeifStreamWrapper" }; + +HeifStreamWrapper::HeifStreamWrapper(ImagePlugin::InputDataStream *stream) : inputData_(stream){}; +size_t HeifStreamWrapper::read(void *buffer, size_t size) +{ + if (buffer == nullptr) { + HiLog::Error(LABEL, "input buffer is null."); + return size; + } + + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputData_->Read(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "read data failed."); + return 0; + } + return readSize; +} + +bool HeifStreamWrapper::rewind() +{ + return inputData_->Seek(0); +} + +bool HeifStreamWrapper::seek(size_t position) +{ + return inputData_->Seek(position); +} + +bool HeifStreamWrapper::hasLength() const +{ + return inputData_->Tell() != inputData_->GetStreamSize(); +} + +size_t HeifStreamWrapper::getLength() const +{ + return inputData_->GetStreamSize(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/adapter/frameworks/hwjpegcodec/.BUILD.gn.swp b/adapter/frameworks/hwjpegcodec/.BUILD.gn.swp new file mode 100644 index 0000000000000000000000000000000000000000..39681471c5924a3a7a56f9e992861f3bbf6bec8a Binary files /dev/null and b/adapter/frameworks/hwjpegcodec/.BUILD.gn.swp differ diff --git a/adapter/frameworks/hwjpegcodec/BUILD.gn_old b/adapter/frameworks/hwjpegcodec/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..f48ba395e739195a3e417e9c77b16709aaa1438f --- /dev/null +++ b/adapter/frameworks/hwjpegcodec/BUILD.gn_old @@ -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("//build/ohos.gni") +config("hwjpegadapter_public_config") { + visibility = [ ":*" ] +} + +ohos_shared_library("hwjpegadapter") { + sources = [ "//foundation/multimedia/image_standard/adapter/frameworks/hwjpegcodec/src/hw_jpeg_decompressor_adapter.cpp" ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin/include", + "//third_party/libjpeg-turbo", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/hwjpegcodec/include", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + public_configs = [ ":hwjpegadapter_public_config" ] + +# aosp_deps = [ +# "shared_library:libcutils", +# "shared_library:libhidlbase", +# "shared_library:libjpeg", +# "shared_library:libutils", +# "shared_library:vendor.huawei.hardware.jpegdec@1.0", +# ] + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/hwjpegcodec/include/hw_jpeg_decompressor_adapter.h b/adapter/frameworks/hwjpegcodec/include/hw_jpeg_decompressor_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..2e34b2c4bc8c0813d494d51bb67fe910dea5fa39 --- /dev/null +++ b/adapter/frameworks/hwjpegcodec/include/hw_jpeg_decompressor_adapter.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2009 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HW_JPEG_DECOMPRESSOR_ADAPTER_H +#define HW_JPEG_DECOMPRESSOR_ADAPTER_H + +#include +#include +#include "abs_image_decoder.h" +#include "cutils/native_handle.h" +#include "hilog/log.h" +#include "hw_jpeg_decompressor_interface.h" +#include "jerror.h" +#include "jpeglib.h" +#include "log_tags.h" +#include "vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h" + +namespace OHOS { +namespace Media { +constexpr int32_t HISI_JPEG_DECODE_OUT_UNKNOWN = -1; +constexpr int32_t HISI_JPEG_DECODE_OUT_RGB565 = 7; +constexpr int32_t HISI_JPEG_DECODE_OUT_RGBA8888 = 9; +constexpr int32_t HISI_JPEG_DECODE_OUT_BGRA8888 = 10; + +using ::android::hardware::hidl_vec; +using vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info; +using vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode; +using vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info; +using vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t; +using vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error; +using vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl; +using vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl; + +// use for message to HAL. +struct JpegOutInfo : public native_handle { + int32_t sharedFd; + int32_t outWidth; + int32_t outHeight; + int32_t byteStride; + int32_t size; + int32_t alignSize; + int32_t outHnd; + int32_t colorFormat; + uint64_t outBufferAddr; +}; + +struct JpegInInfo : public native_handle { + int32_t sharedFd; + int32_t dataSize; + int32_t alignSize; + int32_t ionHnd; + uint64_t inBufferAddr; +}; + +class HwJpegDecompressorAdapter : public ImagePlugin::HwJpegDecompressorInterface { +public: + HwJpegDecompressorAdapter() = default; + ~HwJpegDecompressorAdapter() = default; + bool LockDevice() override; + void UnlockDevice() override; + bool CheckHardwareSupport(const jpeg_decompress_struct *cinfo) override; + uint8_t *GetInputBuffer(size_t bufferSize) override; + bool HardwareDecode(const jpeg_decompress_struct *jpgDinfo, const uint8_t *inputData, size_t bufferSize, + ImagePlugin::DecodeContext &context) override; + void ReleaseInputBuffer(uint8_t *addr) override; + +private: + DISALLOW_COPY_AND_MOVE(HwJpegDecompressorAdapter); + size_t GetCompressPos(const uint8_t *inBufMapAddr, size_t buffersize); + bool GetDecodeInfo(const jpeg_decompress_struct *jpgDinfo, jpeg_decompress_hidl_t *decInfo); + bool FillHuffTable(const JHUFF_TBL *inHuffTable, jpeg_huff_hidl_tbl &outHuffTable); + bool FillQuantTable(const JQUANT_TBL *inQuantTable, jpeg_quant_hidl_tbl &outQuantTable); + bool FillComponentInfo(const jpeg_decompress_struct *jpgDinfo, jpeg_decompress_hidl_t *decInfo); + uint8_t *GetOutputBuffer(const jpeg_decompress_struct *cinfo, native_handle_t *&handle); + static void ReleaseBuffer(void *addr, void *context, uint32_t size); + int32_t ComputeDecodeOutColorFormat(uint32_t colorFormat); + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "HwJpegDecompressorAdapter" + }; + android::sp jpegDecode_ = nullptr; + native_handle_t *inBufHnd_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // HW_JPEG_DECOMPRESSOR_ADAPTER_H \ No newline at end of file diff --git a/adapter/frameworks/hwjpegcodec/src/hw_jpeg_decompressor_adapter.cpp b/adapter/frameworks/hwjpegcodec/src/hw_jpeg_decompressor_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c805003b4d5c7ef418a30250c8b54a00f68ebbab --- /dev/null +++ b/adapter/frameworks/hwjpegcodec/src/hw_jpeg_decompressor_adapter.cpp @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2009 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hw_jpeg_decompressor_adapter.h" + +#include +#include +#include "jerror.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace ImagePlugin; +using namespace MultimediaPlugin; + +constexpr int32_t JPEG_INFO_BITS_LENGTH = 17; +constexpr int32_t JPEG_INFO_HUFFVAL_LENGTH = 256; + +constexpr uint64_t JPEG_INFO_SAMPLE_111111 = 0x010101010101; +constexpr uint64_t JPEG_INFO_SAMPLE_121111 = 0x010201010101; +constexpr uint64_t JPEG_INFO_SAMPLE_211111 = 0x020101010101; +constexpr uint64_t JPEG_INFO_SAMPLE_221111 = 0x020201010101; +constexpr uint8_t BYTE_COUNT = 8; +constexpr uint8_t JPEG_COMPNENT_NUM_ALPHA = 1; +constexpr uint8_t JPEG_COMPNENT_NUM_RGB = 3; +constexpr uint8_t NEXT_POS_NUM_TWO = 2; + +bool HwJpegDecompressorAdapter::HardwareDecode(const jpeg_decompress_struct *jpgDinfo, const uint8_t *inputData, + size_t bufferSize, DecodeContext &context) +{ + if (jpgDinfo == nullptr || inputData == nullptr || inBufHnd_ == nullptr) { + HiLog::Error(LABEL, "hardware decompress error, input parameter is null."); + return false; + } + // find the compress data start position. + size_t compressPos = GetCompressPos(inputData, bufferSize); + if (compressPos == 0) { + HiLog::Error(LABEL, "get compress data addr abnormal, compressPos:%{public}zu.", compressPos); + return false; + } + // get decode info for HAL from libjpeg struct. + jpeg_decompress_hidl_t decInfo; + if (!GetDecodeInfo(jpgDinfo, &decInfo)) { + HiLog::Error(LABEL, "get HAL decode info failed."); + return false; + } + // do hardware decode. + hwdecode_region_info regionInfo; + errno_t ret = memset_s(®ionInfo, sizeof(regionInfo), 0, sizeof(regionInfo)); + if (ret != EOK) { + HiLog::Error(LABEL, "region info memset failed, error_type: %{public}d.", ret); + return false; + } + // alloc output buffer. + native_handle_t *outBufHnd = nullptr; + uint8_t *outputData = GetOutputBuffer(jpgDinfo, outBufHnd); + if (outputData == nullptr) { + HiLog::Error(LABEL, "get output buffer failed, alloc buffer error."); + return false; + } + uint32_t sampleSize = 1; // default sample size. + if (jpegDecode_->DoDecode(decInfo, android::hardware::hidl_handle(outBufHnd), + android::hardware::hidl_handle(inBufHnd_), regionInfo, sampleSize, + compressPos) != JPEG_Error::NONE) { + HiLog::Error(LABEL, "hardware jpeg decoder decompress image failed."); + ReleaseBuffer(outputData, outBufHnd, static_cast(outBufHnd)->alignSize); + return false; + } + context.pixelsBuffer.buffer = outputData; + context.pixelsBuffer.context = outBufHnd; + context.pixelsBuffer.bufferSize = static_cast(outBufHnd)->alignSize; + context.allocatorType = AllocatorType::CUSTOM_ALLOC; + context.freeFunc = ReleaseBuffer; + return true; +} + +int32_t HwJpegDecompressorAdapter::ComputeDecodeOutColorFormat(uint32_t colorFormat) +{ + // note:the third-party RGBA correspond hisi BGRA + int32_t outputColorFormat = HISI_JPEG_DECODE_OUT_UNKNOWN; + switch (colorFormat) { + case JCS_EXT_RGBA: { + outputColorFormat = HISI_JPEG_DECODE_OUT_BGRA8888; + break; + } + case JCS_RGB565: { + outputColorFormat = HISI_JPEG_DECODE_OUT_RGB565; + break; + } + case JCS_EXT_BGRA: { + outputColorFormat = HISI_JPEG_DECODE_OUT_RGBA8888; + break; + } + default: { + HiLog::Error(LABEL, "libjpeg decode format:[%{public}d] is unsupported!", colorFormat); + break; + } + } + return outputColorFormat; +} + +uint8_t *HwJpegDecompressorAdapter::GetOutputBuffer(const jpeg_decompress_struct *cinfo, native_handle_t *&handle) +{ + if (cinfo == nullptr) { + HiLog::Error(LABEL, "get output buffer failed, jpeg decompress info is null!"); + return nullptr; + } + uint32_t width = cinfo->output_width; + uint32_t height = cinfo->output_height; + uint32_t colorFormat = cinfo->out_color_space; + JpegOutInfo *outInfo = nullptr; + void *outBufMapAddr = nullptr; + int32_t outputColorFormat = ComputeDecodeOutColorFormat(colorFormat); + jpegDecode_->Alloc_OutBuffer(width, height, outputColorFormat, [&](const auto &allocrlt, const auto &buffer) { + if (allocrlt == JPEG_Error::NONE) { + handle = native_handle_clone(((android::hardware::hidl_handle)buffer).getNativeHandle()); + } + }); + if (handle == nullptr) { + HiLog::Error(LABEL, "jpeg hal failed to alloc output buffer."); + return nullptr; + } + outInfo = static_cast(handle); + outBufMapAddr = mmap(nullptr, outInfo->alignSize, PROT_READ | PROT_WRITE, MAP_SHARED, outInfo->data[0], 0); + if (outBufMapAddr == MAP_FAILED) { + HiLog::Error(LABEL, "output buffer map abnormal."); + ReleaseBuffer(nullptr, handle, 0); + return nullptr; + } + return static_cast(outBufMapAddr); +} + +void HwJpegDecompressorAdapter::ReleaseBuffer(void *addr, void *context, uint32_t size) +{ + native_handle_t *handle = static_cast(context); + if (addr != nullptr) { + munmap(addr, size); + } + if (handle != nullptr) { + native_handle_close(handle); + native_handle_delete(handle); + } +} + +void HwJpegDecompressorAdapter::ReleaseInputBuffer(uint8_t *addr) +{ + uint32_t inBufSize = 0; + if (inBufHnd_ != nullptr) { + inBufSize = static_cast(inBufHnd_)->alignSize; + } + ReleaseBuffer(addr, inBufHnd_, inBufSize); + inBufHnd_ = nullptr; +} + +bool HwJpegDecompressorAdapter::LockDevice() +{ + jpegDecode_ = IJpegDecode::tryGetService(); + if (jpegDecode_.get() == nullptr) { + HiLog::Error(LABEL, "get hardware jpeg service failed."); + return false; + } + if (jpegDecode_->LockDevice() != JPEG_Error::NONE) { + HiLog::Error(LABEL, "lock hardware device failed."); + return false; + } + return true; +} + +void HwJpegDecompressorAdapter::UnlockDevice() +{ + if (jpegDecode_.get() == nullptr) { + return; + } + jpegDecode_->UnLockDevice(); +} + +bool HwJpegDecompressorAdapter::FillHuffTable(const JHUFF_TBL *inHuffTable, jpeg_huff_hidl_tbl &outHuffTable) +{ + errno_t ret = EOK; + if (inHuffTable != nullptr) { + outHuffTable.table_flag = true; + ret = memcpy_s(&outHuffTable.bits[0], JPEG_INFO_BITS_LENGTH, &inHuffTable->bits[0], JPEG_INFO_BITS_LENGTH); + if (ret != EOK) { + HiLog::Error(LABEL, "huff table memcpy failed, error_type: %{public}d.", ret); + return false; + } + ret = memcpy_s(&outHuffTable.huffval[0], JPEG_INFO_HUFFVAL_LENGTH, &inHuffTable->huffval[0], + JPEG_INFO_HUFFVAL_LENGTH); + if (ret != EOK) { + HiLog::Error(LABEL, "huff value memcpy failed, error_type: %{public}d.", ret); + return false; + } + } else { + ret = memset_s(&outHuffTable, sizeof(outHuffTable), 0, sizeof(outHuffTable)); + if (ret != EOK) { + HiLog::Error(LABEL, "huff table memset failed, error_type: %{public}d.", ret); + return false; + } + } + return true; +} + +bool HwJpegDecompressorAdapter::FillQuantTable(const JQUANT_TBL *inQuantTable, jpeg_quant_hidl_tbl &outQuantTable) +{ + errno_t ret = EOK; + if (inQuantTable != nullptr) { + outQuantTable.table_flag = true; + ret = memcpy_s(&outQuantTable.quantval[0], DCTSIZE2 * sizeof(uint16_t), &inQuantTable->quantval[0], + DCTSIZE2 * sizeof(uint16_t)); + if (ret != EOK) { + HiLog::Error(LABEL, "quant table memcpy failed, error_type: %{public}d.", ret); + return false; + } + } else { + ret = memset_s(&outQuantTable, sizeof(outQuantTable), 0, sizeof(outQuantTable)); + if (ret != EOK) { + HiLog::Error(LABEL, "quant table memset failed, error_type: %{public}d.", ret); + return false; + } + } + return true; +} + +bool HwJpegDecompressorAdapter::FillComponentInfo(const jpeg_decompress_struct *jpgDinfo, + jpeg_decompress_hidl_t *decInfo) +{ + if (decInfo == nullptr || jpgDinfo == nullptr) { + HiLog::Error(LABEL, "fill component info error, input parameter is null."); + return false; + } + decInfo->comp_info.resize(jpgDinfo->num_components); + for (int32_t i = 0; i < jpgDinfo->num_components; i++) { + jpeg_comp_hidl_info compInfo; + compInfo.h_samp_factor = jpgDinfo->comp_info[i].h_samp_factor; + compInfo.v_samp_factor = jpgDinfo->comp_info[i].v_samp_factor; + compInfo.quant_tbl_no = jpgDinfo->comp_info[i].quant_tbl_no; + compInfo.component_index = jpgDinfo->comp_info[i].component_index; + compInfo.component_id = jpgDinfo->comp_info[i].component_id; + compInfo.dc_tbl_no = jpgDinfo->comp_info[i].dc_tbl_no; + compInfo.ac_tbl_no = jpgDinfo->comp_info[i].ac_tbl_no; + compInfo.info_flag = true; + decInfo->comp_info[i] = compInfo; + } + return true; +} + +bool HwJpegDecompressorAdapter::GetDecodeInfo(const jpeg_decompress_struct *jpgDinfo, jpeg_decompress_hidl_t *decInfo) +{ + if (decInfo == nullptr || jpgDinfo == nullptr) { + HiLog::Error(LABEL, "get decode info input parameter is null."); + return false; + } + decInfo->num_components = jpgDinfo->num_components; + decInfo->arith_code = jpgDinfo->arith_code; + decInfo->data_precision = jpgDinfo->data_precision; + decInfo->image_height = jpgDinfo->image_height; + decInfo->image_width = jpgDinfo->image_width; + decInfo->progressive_mode = jpgDinfo->progressive_mode; + decInfo->restart_interval = jpgDinfo->restart_interval; + if (!FillComponentInfo(jpgDinfo, decInfo)) { + HiLog::Error(LABEL, "fill component info failed."); + return false; + } + decInfo->dc_huff_tbl_ptrs.resize(NUM_HUFF_TBLS); + decInfo->ac_huff_tbl_ptrs.resize(NUM_HUFF_TBLS); + for (int32_t i = 0; i < NUM_HUFF_TBLS; i++) { + jpeg_huff_hidl_tbl huffTable; + if (!FillHuffTable(jpgDinfo->dc_huff_tbl_ptrs[i], huffTable)) { + HiLog::Error(LABEL, "fill dc huff table failed."); + return false; + } + decInfo->dc_huff_tbl_ptrs[i] = huffTable; + if (!FillHuffTable(jpgDinfo->ac_huff_tbl_ptrs[i], huffTable)) { + HiLog::Error(LABEL, "fill ac huff table failed."); + return false; + } + decInfo->ac_huff_tbl_ptrs[i] = huffTable; + } + decInfo->quant_tbl_ptrs.resize(NUM_QUANT_TBLS); + for (int32_t i = 0; i < NUM_QUANT_TBLS; i++) { + jpeg_quant_hidl_tbl quantTable; + if (!FillQuantTable(jpgDinfo->quant_tbl_ptrs[i], quantTable)) { + HiLog::Error(LABEL, "fill quant table failed."); + return false; + } + decInfo->quant_tbl_ptrs[i] = quantTable; + } + return true; +} + +bool HwJpegDecompressorAdapter::CheckHardwareSupport(const jpeg_decompress_struct *cinfo) +{ + if (cinfo == nullptr) { + HiLog::Error(LABEL, "check hardware support failed, input parameter error!"); + return false; + } + if (((cinfo->num_components != JPEG_COMPNENT_NUM_ALPHA) && (cinfo->num_components != JPEG_COMPNENT_NUM_RGB)) || + (cinfo->arith_code) || (cinfo->progressive_mode) || (cinfo->data_precision != BYTE_COUNT)) { + HiLog::Error(LABEL, + "hardware decoder cannot handle num_components:%{public}d, progressive_mode:%{public}d, " + "data_precision:%{public}d.", + cinfo->num_components, cinfo->progressive_mode, cinfo->data_precision); + return false; + } + if (cinfo->comp_info == nullptr) { + HiLog::Error(LABEL, "jpeg decompress info factor is null."); + return false; + } + // JPEG hardware decode only support 111111 121111 211111 221111 and xx0000 + // h_samp_factor/v_samp_factor in range (0...255) + uint64_t sampleValue = 0; + for (int32_t i = 0; i < cinfo->num_components; i++) { + sampleValue = sampleValue << BYTE_COUNT; + sampleValue |= (static_cast(cinfo->comp_info[i].h_samp_factor) & 0xFF); + sampleValue = sampleValue << BYTE_COUNT; + sampleValue |= (static_cast(cinfo->comp_info[i].v_samp_factor) & 0xFF); + } + switch (sampleValue) { + case JPEG_INFO_SAMPLE_111111: + case JPEG_INFO_SAMPLE_121111: + case JPEG_INFO_SAMPLE_211111: + case JPEG_INFO_SAMPLE_221111: + return true; + default: { + if ((sampleValue & 0xFFFFFFFF) == 0) { + return true; + } + break; + } + } + return false; +} + +size_t HwJpegDecompressorAdapter::GetCompressPos(const uint8_t *inBufMapAddr, size_t bufferSize) +{ + const uint8_t *curr = inBufMapAddr; + size_t lh = 0; + size_t ll = 0; + size_t pos = 0; + size_t ret = 0; + while (bufferSize > (pos + NEXT_POS_NUM_TWO) && *curr++ == 0xff) { + uint8_t value = *curr++; + pos += NEXT_POS_NUM_TWO; + if (value == 0xD8 || value == 0xD9) { + continue; + } + if ((pos + NEXT_POS_NUM_TWO) > bufferSize) { + HiLog::Warn(LABEL, "next pos %{public}zu may be large than bufferSize %{public}zu", pos, bufferSize); + break; + } + lh = *curr; + ll = *(curr + 1); + curr += (lh << BYTE_COUNT) + ll; + pos = curr - inBufMapAddr; + HiLog::Debug(LABEL, "pos %{public}zu, lh = %{public}zx, ll = %{public}zx ", pos, lh, ll); + if (value == 0xDA) { + ret = pos; + break; + } + } + return ret; +} + +uint8_t *HwJpegDecompressorAdapter::GetInputBuffer(size_t bufferSize) +{ + void *inBufMapAddr = nullptr; + jpegDecode_->Alloc_InBuffer(bufferSize, [&](const auto &tmpError, const auto &tmpbuffer) { + if (tmpError == JPEG_Error::NONE) { + inBufHnd_ = native_handle_clone(((android::hardware::hidl_handle)tmpbuffer).getNativeHandle()); + } + }); + if (inBufHnd_ == nullptr) { + HiLog::Error(LABEL, "alloc input buffer failed."); + return nullptr; + } + JpegInInfo *inInfo = static_cast(inBufHnd_); + inBufMapAddr = mmap(nullptr, inInfo->alignSize, PROT_READ | PROT_WRITE, MAP_SHARED, inInfo->data[0], 0); + if (inBufMapAddr == MAP_FAILED) { + ReleaseInputBuffer(nullptr); + return nullptr; + } + return static_cast(inBufMapAddr); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/adapter/frameworks/libbmpplugin/BUILD.gn_old b/adapter/frameworks/libbmpplugin/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..e53c7c4f42cdf98fb0c9bf7a48de29188cb2df00 --- /dev/null +++ b/adapter/frameworks/libbmpplugin/BUILD.gn_old @@ -0,0 +1,94 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("bmpplugin") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin/src/bmp_decoder.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin/src/bmp_stream.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin/src/plugin_export.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//third_party/flutter/skia/include/codec", + "//third_party/flutter/skia/third_party/externals/libjpeg-turbo", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/third_party/libjpeg-turbo", + "//third_party/flutter/skia", + ] + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//foundation/multimedia/image_standard/mock/native/include/secure", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/win", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + ] + deps = [ + "//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + + libs = [ "//foundation/multimedia/image_standard/libskia.lib" ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/mac", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + "//utils/native/base/include", + ] + deps = [ + "//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + deps = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +# aosp_deps = [ "shared_library:libhwui" ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_prebuilt_etc("bmppluginmetadata") { + source = "bmpplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/libbmpplugin/bmpplugin.pluginmeta b/adapter/frameworks/libbmpplugin/bmpplugin.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..0ffc1cac68e8343cc6bf4f6ad4c875cfb288428b --- /dev/null +++ b/adapter/frameworks/libbmpplugin/bmpplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibBmpPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libbmpplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::BmpDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/bmp" + } + ] + } + ] +} diff --git a/adapter/frameworks/libbmpplugin/include/bmp_decoder.h b/adapter/frameworks/libbmpplugin/include/bmp_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..356db0bd5643dc8c8cfb7906b6644614ed981bd1 --- /dev/null +++ b/adapter/frameworks/libbmpplugin/include/bmp_decoder.h @@ -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. + */ + +#ifndef BMP_DECODER_H +#define BMP_DECODER_H + +#include +#include +#include "SkCodec.h" +#include "abs_image_decoder.h" +#include "bmp_stream.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +enum class BmpDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSED = 2, + IMAGE_DECODING = 3, + IMAGE_ERROR = 4, + IMAGE_DECODED = 5 +}; + +class BmpDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + BmpDecoder() = default; + virtual ~BmpDecoder() override{}; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + +private: + DISALLOW_COPY_AND_MOVE(BmpDecoder); + bool DecodeHeader(); + PlAlphaType ConvertToAlphaType(SkAlphaType alphaType); + SkColorType ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat); + InputDataStream *stream_ = nullptr; + std::unique_ptr codec_ = nullptr; + SkImageInfo info_; + SkColorType desireColor_ = kUnknown_SkColorType; + BmpDecodingState state_ = BmpDecodingState::UNDECIDED; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // BMP_DECODER_H diff --git a/adapter/frameworks/libbmpplugin/include/bmp_stream.h b/adapter/frameworks/libbmpplugin/include/bmp_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..a9f65e13f250b9c8f47e202bd2cca0dcae9fbce1 --- /dev/null +++ b/adapter/frameworks/libbmpplugin/include/bmp_stream.h @@ -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. + */ + +#ifndef BMP_STREAM_H +#define BMP_STREAM_H + +#include +#include +#include "SkStream.h" +#include "hilog/log.h" +#include "input_data_stream.h" +#include "log_tags.h" +#include "nocopyable.h" + +namespace OHOS { +namespace ImagePlugin { +class BmpStream : public SkStream { +public: + BmpStream() = default; + explicit BmpStream(InputDataStream *stream); + virtual ~BmpStream() override{}; + /** + * Reads or skips size number of bytes. + * if buffer is null, skip size bytes, return how many bytes skipped. + * else copy size bytes into buffer, return how many bytes copied. + */ + size_t read(void *buffer, size_t size) override; + /** + * Peeks size number of bytes. + */ + size_t peek(void *buffer, size_t size) const override; + /** + * Returns true when all the bytes in the stream have been read. + */ + bool isAtEnd() const override; + +private: + DISALLOW_COPY_AND_MOVE(BmpStream); + ImagePlugin::InputDataStream *inputStream_ = nullptr; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // BMP_STREAM_H \ No newline at end of file diff --git a/adapter/frameworks/libbmpplugin/src/bmp_decoder.cpp b/adapter/frameworks/libbmpplugin/src/bmp_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea964a16bf9106393b83f9456a98b702f63db40d --- /dev/null +++ b/adapter/frameworks/libbmpplugin/src/bmp_decoder.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bmp_decoder.h" +#include "image_utils.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace Media; +using namespace std; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "BmpDecoder" }; +namespace { +constexpr uint32_t BMP_IMAGE_NUM = 1; +} + +void BmpDecoder::SetSource(InputDataStream &sourceStream) +{ + stream_ = &sourceStream; + state_ = BmpDecodingState::SOURCE_INITED; +} + +void BmpDecoder::Reset() +{ + if (stream_ != nullptr) { + stream_->Seek(0); + } + codec_.release(); + info_.reset(); + desireColor_ = kUnknown_SkColorType; +} + +uint32_t BmpDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= BMP_IMAGE_NUM) { + HiLog::Error(LABEL, "GetImageSize failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < BmpDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= BmpDecodingState::BASE_INFO_PARSED) { + size.width = info_.width(); + size.height = info_.height(); + return SUCCESS; + } + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + size.width = info_.width(); + size.height = info_.height(); + state_ = BmpDecodingState::BASE_INFO_PARSED; + return SUCCESS; +} + +uint32_t BmpDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + if (index >= BMP_IMAGE_NUM) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid index:%{public}u, range:%{public}u", index, + BMP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < BmpDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= BmpDecodingState::IMAGE_DECODING) { + Reset(); + state_ = BmpDecodingState::SOURCE_INITED; + } + if (state_ < BmpDecodingState::BASE_INFO_PARSED) { + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + state_ = BmpDecodingState::BASE_INFO_PARSED; + } + PlPixelFormat desiredFormat = opts.desiredPixelFormat; + desireColor_ = ConvertToColorType(desiredFormat, info.pixelFormat); + info.size.width = info_.width(); + info.size.height = info_.height(); + info.alphaType = ConvertToAlphaType(info_.alphaType()); + state_ = BmpDecodingState::IMAGE_DECODING; + return SUCCESS; +} + +uint32_t BmpDecoder::Decode(uint32_t index, DecodeContext &context) +{ + if (index >= BMP_IMAGE_NUM) { + HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (codec_ == nullptr) { + HiLog::Error(LABEL, "Decode failed, codec is null"); + return ERR_IMAGE_DECODE_FAILED; + } + if (state_ != BmpDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + + SkImageInfo dstInfo = info_.makeColorType(desireColor_); + if (ImageUtils::CheckMulOverflow(dstInfo.width(), dstInfo.height(), dstInfo.bytesPerPixel())) { + HiLog::Error(LABEL, "Decode failed, width:%{public}d, height:%{public}d is too large", + dstInfo.width(), dstInfo.height()); + return ERR_IMAGE_DECODE_FAILED; + } + if (context.pixelsBuffer.buffer == nullptr) { + uint64_t byteCount = static_cast(dstInfo.height()) * dstInfo.width() * dstInfo.bytesPerPixel(); + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int fd = AshmemCreate("BMP RawData", byteCount); + if (fd < 0) { + return ERR_SHAMEM_DATA_ABNORMAL; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return ERR_SHAMEM_DATA_ABNORMAL; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "Decode failed, alloc output buffer size:[%{public}llu] error", + static_cast(byteCount)); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#ifdef _WIN32 + memset(outputBuffer, 0, byteCount); +#else + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + HiLog::Error(LABEL, "Decode failed, memset buffer failed"); + free(outputBuffer); + outputBuffer = nullptr; + return ERR_IMAGE_DECODE_FAILED; + } +#endif + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + } + uint8_t *dstBuffer = static_cast(context.pixelsBuffer.buffer); + size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel(); + SkCodec::Result ret = codec_->getPixels(dstInfo, dstBuffer, rowBytes); + if (ret != SkCodec::kSuccess) { + HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret); + state_ = BmpDecodingState::IMAGE_ERROR; + return ERR_IMAGE_DECODE_ABNORMAL; + } + state_ = BmpDecodingState::IMAGE_DECODED; + return SUCCESS; +} + +uint32_t BmpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + // currently not support increment decode + return ERR_IMAGE_DATA_UNSUPPORT; +} + +bool BmpDecoder::DecodeHeader() +{ + codec_ = SkCodec::MakeFromStream(make_unique(stream_)); + if (codec_ == nullptr) { + HiLog::Error(LABEL, "create codec from stream failed"); + return false; + } + info_ = codec_->getInfo(); + return true; +} + +PlAlphaType BmpDecoder::ConvertToAlphaType(SkAlphaType alphaType) +{ + switch (alphaType) { + case kOpaque_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + case kPremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL; + case kUnpremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + default: + HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType); + break; + } + return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; +} + +SkColorType BmpDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat) +{ + switch (format) { + case PlPixelFormat::UNKNOWN: + case PlPixelFormat::RGBA_8888: { + outputFormat = PlPixelFormat::RGBA_8888; + return kRGBA_8888_SkColorType; + } + case PlPixelFormat::BGRA_8888: { + outputFormat = PlPixelFormat::BGRA_8888; + return kBGRA_8888_SkColorType; + } + case PlPixelFormat::ALPHA_8: { + SkColorType colorType = info_.colorType(); + if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) { + outputFormat = PlPixelFormat::ALPHA_8; + return kAlpha_8_SkColorType; + } + break; + } + case PlPixelFormat::RGB_565: { + if (info_.isOpaque()) { + outputFormat = PlPixelFormat::RGB_565; + return kRGB_565_SkColorType; + } + break; + } + default: { + break; + } + } + HiLog::Debug(LABEL, "unsupported convert to format:%{public}d, set default RGBA", format); + outputFormat = PlPixelFormat::RGBA_8888; + return kRGBA_8888_SkColorType; +} +} // namespace ImagePlugin +} // namespace OHOS \ No newline at end of file diff --git a/adapter/frameworks/libbmpplugin/src/bmp_stream.cpp b/adapter/frameworks/libbmpplugin/src/bmp_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6694bce8bed4098442a5bbe0b21624db89f8214e --- /dev/null +++ b/adapter/frameworks/libbmpplugin/src/bmp_stream.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bmp_stream.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "BmpStream" }; +BmpStream::BmpStream(InputDataStream *stream) : inputStream_(stream) {} + +size_t BmpStream::read(void *buffer, size_t size) +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "read failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + size_t curPosition = static_cast(inputStream_->Tell()); + if (!inputStream_->Seek(curPosition + size)) { + HiLog::Error(LABEL, "read failed, curpositon=%{public}zu, skip size=%{public}zu", curPosition, size); + return 0; + } + return size; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Read(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "read failed, desire read size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +size_t BmpStream::peek(void *buffer, size_t size) const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "peek failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + HiLog::Error(LABEL, "peek failed, output buffer is null"); + return 0; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Peek(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "peek failed, desire peek size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +bool BmpStream::isAtEnd() const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "get stream status failed, inputStream_ is null."); + return false; + } + size_t size = inputStream_->GetStreamSize(); + return (inputStream_->Tell() == size); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libbmpplugin/src/plugin_export.cpp b/adapter/frameworks/libbmpplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e109dfbf5a44560a16d8741d58e6a75a9a92f90c --- /dev/null +++ b/adapter/frameworks/libbmpplugin/src/plugin_export.cpp @@ -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. + */ + +#include "plugin_export.h" +#include "bmp_decoder.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibBmpPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::BmpDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibBmpPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/adapter/frameworks/libhwjpegplugin/BUILD.gn_old b/adapter/frameworks/libhwjpegplugin/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..72a9129e5f09c8aa102802aad28f667e9d480b09 --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/BUILD.gn_old @@ -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("//build/ohos.gni") + +ohos_shared_library("hwjpegplugin") { + ###### For OHOS adapter define begin ##### + # Use Adapter: define "DUAL_ADAPTER" + # Abandon Adapter: delete the define "DUAL_ADAPTER" + defines = [ "DUAL_ADAPTER" ] + + # Use Adapter: Set DUAL_ADAPTER true + # Abandon Adapter: Set DUAL_ADAPTER false + DUAL_ADAPTER = true + + ###### For OHOS adapter define end ##### + + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor_wrapper.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin/src/plugin_export.cpp", + ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/hwjpegcodec/include", + "//third_party/flutter/skia/third_party/externals/libjpeg-turbo", + "//third_party/flutter/skia/include/codec", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/third_party/libjpeg-turbo", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { + deps += [ "//foundation/multimedia/image_standard/adapter/frameworks/hwjpegcodec:hwjpegadapter" ] +# aosp_deps = [ +# "shared_library:libcutils", +# "shared_library:libhidlbase", +# "shared_library:libjpeg", +# "shared_library:libutils", +# "shared_library:vendor.huawei.hardware.jpegdec@1.0", +# ] + } else { + deps += [ "//third_party/libjpeg-turbo:libjpeg-turbo" ] + include_dirs += [ "//third_party/libjpeg-turbo" ] + } + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + part_name = "multimedia_image" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("hwjpegpluginmetadata") { + source = "hwjpegplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/libhwjpegplugin/hwjpegplugin.pluginmeta b/adapter/frameworks/libhwjpegplugin/hwjpegplugin.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..4af51f517cf86c43e43225349bae5aa904c8b474 --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/hwjpegplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibHwJpegPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libhwjpegplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::HwJpegDecompressor", + "services": [ + { + "interfaceID":4, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/jpeg" + } + ] + } + ] +} diff --git a/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor.h b/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor.h new file mode 100644 index 0000000000000000000000000000000000000000..96d9f065f7566ac04ee44da57d738fd22f53c086 --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor.h @@ -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. + */ + +#ifndef HW_JPEG_DECOMPRESSOR_H +#define HW_JPEG_DECOMPRESSOR_H + +#include +#include +#include "abs_image_decoder.h" +#include "abs_image_decompress_component.h" +#include "hilog/log.h" +#include "hw_jpeg_decompressor_wrapper.h" +#include "input_data_stream.h" +#include "jerror.h" +#include "jpeglib.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class HwJpegDecompressor : public AbsImageDecompressComponent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + HwJpegDecompressor(); + ~HwJpegDecompressor() = default; + uint32_t Decompress(void *decompressInfo, InputDataStream *stream, DecodeContext &context) override; + +private: + DISALLOW_COPY_AND_MOVE(HwJpegDecompressor); + bool CheckOriginalImageSize(uint32_t srcWidth, uint32_t srcHeight, uint32_t comps); + bool CheckOutputImageSize(uint32_t outWidth, uint32_t comps); + uint8_t *GetInputBuffer(size_t &bufferSize); + uint32_t DoDecompress(DecodeContext &context); + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "HwJpegDecompressor" + }; + jpeg_decompress_struct *decodeInfo_ = nullptr; + InputDataStream *stream_ = nullptr; + std::unique_ptr hwDecompressor_ = nullptr; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HW_JPEG_DECOMPRESSOR_H diff --git a/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor_interface.h b/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..24b2ab8074601e05e517c673d87acd8578d3df68 --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor_interface.h @@ -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. + */ + +#ifndef HW_JPEG_DECOMPRESSOR_INTERFACE_H +#define HW_JPEG_DECOMPRESSOR_INTERFACE_H + +#include +#include +#include "abs_image_decoder.h" +#include "jpeglib.h" + +namespace OHOS { +namespace ImagePlugin { +class HwJpegDecompressorInterface { +public: + HwJpegDecompressorInterface() = default; + virtual ~HwJpegDecompressorInterface() = default; + virtual bool LockDevice() = 0; + virtual void UnlockDevice() = 0; + virtual bool CheckHardwareSupport(const jpeg_decompress_struct *cinfo) = 0; + virtual uint8_t *GetInputBuffer(size_t bufferSize) = 0; + virtual bool HardwareDecode(const jpeg_decompress_struct *cinfo, const uint8_t *inputData, size_t bufferSize, + ImagePlugin::DecodeContext &context) = 0; + virtual void ReleaseInputBuffer(uint8_t *addr) = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HW_JPEG_DECOMPRESSOR_INTERFACE_H \ No newline at end of file diff --git a/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor_wrapper.h b/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..5adb27f72e3aa1f9ca4ddb4a108065b4636093d4 --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/include/hw_jpeg_decompressor_wrapper.h @@ -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. + */ + +#ifndef HW_JPEG_DECOMPRESSOR_WRAPPER_H +#define HW_JPEG_DECOMPRESSOR_WRAPPER_H + +#include +#include "hw_jpeg_decompressor_interface.h" + +namespace OHOS { +namespace ImagePlugin { +class HwJpegDecompressorWrapper { +public: + static std::unique_ptr CreateHwJpegDecompressor(); +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HW_JPEG_DECOMPRESSOR_WRAPPER_H \ No newline at end of file diff --git a/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor.cpp b/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..362e5daebb5ead6ef88ce503f124a113996a26d9 --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hw_jpeg_decompressor.h" +#include +#include +#include "jerror.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; + +constexpr uint32_t JPEG_SOURCE_SIZE_MAX = 8192; +constexpr uint32_t JPEG_SOURCE_SIZE_MIN = 512; + +HwJpegDecompressor::HwJpegDecompressor() +{ + hwDecompressor_ = HwJpegDecompressorWrapper::CreateHwJpegDecompressor(); +} + +bool HwJpegDecompressor::CheckOriginalImageSize(uint32_t srcWidth, uint32_t srcHeight, uint32_t comps) +{ + // check origal image size. + if (srcWidth > JPEG_SOURCE_SIZE_MAX || srcWidth < JPEG_SOURCE_SIZE_MIN || srcHeight > JPEG_SOURCE_SIZE_MAX || + srcHeight < JPEG_SOURCE_SIZE_MIN) { + HiLog::Error(LABEL, "image size:[%{public}u, %{public}u] out of hardware range:(%{public}u, %{public}u).", + srcWidth, srcHeight, JPEG_SOURCE_SIZE_MIN, JPEG_SOURCE_SIZE_MAX); + return false; + } + // check row bytes is aligned with 128 bits(16 Bytes). + uint64_t imageRowBytes = static_cast(srcWidth) * comps; + if (imageRowBytes & 0xF) { + HiLog::Error(LABEL, "row bytes is not aligned with 16 bytes, row bytes=%{public}llu.", + static_cast(imageRowBytes)); + return false; + } + return true; +} + +bool HwJpegDecompressor::CheckOutputImageSize(uint32_t outWidth, uint32_t comps) +{ + // check output row bytes is aligned with 16 Bytes. + uint64_t outputRowBytes = static_cast(outWidth) * comps; + if (outputRowBytes & 0xF) { + HiLog::Error(LABEL, "output row bytes is not aligned with 16 bytes, row bytes=%{public}llu.", + static_cast(outputRowBytes)); + return false; + } + return true; +} + +uint8_t *HwJpegDecompressor::GetInputBuffer(size_t &bufferSize) +{ + if (stream_ == nullptr || hwDecompressor_ == nullptr) { + HiLog::Error(LABEL, "get input buffer failed, stream is null."); + return nullptr; + } + bufferSize = stream_->GetStreamSize(); + if (bufferSize == 0) { + HiLog::Error(LABEL, "get input buffer failed, stream size is zero."); + return nullptr; + } + HiLog::Debug(LABEL, "get stream size=%{public}zu.", bufferSize); + uint32_t positionRecord = stream_->Tell(); + uint8_t *inBufMapAddr = hwDecompressor_->GetInputBuffer(bufferSize); + if (inBufMapAddr == nullptr) { + HiLog::Error(LABEL, "get input buffer failed, alloc buffer error."); + return nullptr; + } + stream_->Seek(0); + uint32_t readSize = 0; + stream_->Read(bufferSize, inBufMapAddr, bufferSize, readSize); + stream_->Seek(positionRecord); + return inBufMapAddr; +} + +uint32_t HwJpegDecompressor::DoDecompress(DecodeContext &context) +{ + if (hwDecompressor_ == nullptr) { + HiLog::Error(LABEL, "do decompress error, hardware decoder is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + // check jpeg_decompress_struct is ok for hardware support. + if (!hwDecompressor_->CheckHardwareSupport(decodeInfo_)) { + HiLog::Error(LABEL, "hardware jpeg decoder cannot support."); + return ERR_IMAGE_HW_DECODE_UNSUPPORT; + } + // file input ion buffer. + size_t bufferSize = 0; + uint8_t *inputDataAddr = GetInputBuffer(bufferSize); + if (!hwDecompressor_->HardwareDecode(decodeInfo_, inputDataAddr, bufferSize, context)) { + HiLog::Error(LABEL, "hardware decoder decode image failed."); + hwDecompressor_->ReleaseInputBuffer(inputDataAddr); + return ERR_IMAGE_DECODE_ABNORMAL; + } + hwDecompressor_->ReleaseInputBuffer(inputDataAddr); + return SUCCESS; +} + +uint32_t HwJpegDecompressor::Decompress(void *decompressInfo, InputDataStream *stream, DecodeContext &context) +{ + if (decompressInfo == nullptr || stream == nullptr) { + HiLog::Error(LABEL, "jpeg hardware decode error, input parameter is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + decodeInfo_ = static_cast(decompressInfo); + stream_ = stream; + uint32_t srcWidth = decodeInfo_->image_width; + uint32_t srcHeight = decodeInfo_->image_height; + uint32_t srcComps = decodeInfo_->num_components; + if (!CheckOriginalImageSize(srcWidth, srcHeight, srcComps)) { + HiLog::Error(LABEL, "check original image size failed, hardware jpeg decoder cannot support."); + return ERR_IMAGE_HW_DECODE_UNSUPPORT; + } + uint32_t outWidth = decodeInfo_->output_width; + uint32_t outComps = decodeInfo_->output_components; + if (!CheckOutputImageSize(outWidth, outComps)) { + HiLog::Error(LABEL, "check output image size failed, hardware jpeg decoder cannot support."); + return ERR_IMAGE_HW_DECODE_UNSUPPORT; + } + if (hwDecompressor_ == nullptr) { + HiLog::Error(LABEL, "hardware jpeg decoder is null."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + // get hardware service + if (!hwDecompressor_->LockDevice()) { + HiLog::Error(LABEL, "lock hardware device failed!"); + return ERR_IMAGE_DECODE_ABNORMAL; + } + uint32_t ret = DoDecompress(context); + hwDecompressor_->UnlockDevice(); + return ret; +} +} // namespace ImagePlugin +} // namespace OHOS \ No newline at end of file diff --git a/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor_wrapper.cpp b/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efdb118449cf126f4b8fc6c3832c61dee602813f --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/src/hw_jpeg_decompressor_wrapper.cpp @@ -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. + */ + +#include "hw_jpeg_decompressor_wrapper.h" + +#ifdef DUAL_ADAPTER +#include "hw_jpeg_decompressor_adapter.h" +#endif + +namespace OHOS { +namespace ImagePlugin { +std::unique_ptr HwJpegDecompressorWrapper::CreateHwJpegDecompressor() +{ +#ifdef DUAL_ADAPTER + return std::make_unique(); +#else + return nullptr; +#endif +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libhwjpegplugin/src/plugin_export.cpp b/adapter/frameworks/libhwjpegplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4dffac42e131a136b4d0dc7db4a07ed25562c89e --- /dev/null +++ b/adapter/frameworks/libhwjpegplugin/src/plugin_export.cpp @@ -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. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "hw_jpeg_decompressor.h" +#include "log_tags.h" +#include "plugin_utils.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibHwJpegPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::HwJpegDecompressor) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibHwJpegPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/adapter/frameworks/librawplugin/BUILD.gn_old b/adapter/frameworks/librawplugin/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..f609ae1fd1c8449900ae8a6861abf0d621defe04 --- /dev/null +++ b/adapter/frameworks/librawplugin/BUILD.gn_old @@ -0,0 +1,90 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("rawplugin") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/librawplugin/src/plugin_export.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/librawplugin/src/raw_decoder.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/librawplugin/src/raw_stream.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/adapter/frameworks/librawplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//third_party/flutter/skia/include/codec", + "//third_party/flutter/skia", + "//third_party/flutter/skia/include/core", + + ] + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//foundation/multimedia/image_standard/mock/native/include/secure", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/win", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + ] + deps = [ + "//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_fontmgr_ohos", + "//third_party/flutter:ace_fontmgr_standard", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_skia_ohos", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_fontconfig.json", + "//third_party/flutter:ace_jsoncpp", + "//utils/native/base:utils", + + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +# aosp_deps = [ "shared_library:libhwui" ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_prebuilt_etc("rawpluginmetadata") { + source = "rawplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/librawplugin/include/raw_decoder.h b/adapter/frameworks/librawplugin/include/raw_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..7348d251c6862b824428bcd2db9b87f19a9a65fa --- /dev/null +++ b/adapter/frameworks/librawplugin/include/raw_decoder.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RAW_DECODER_H +#define RAW_DECODER_H + +#include +#include +#include "SkCodec.h" +#include "abs_image_decoder.h" +#include "raw_stream.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +enum class RawDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSED = 2, + IMAGE_DECODING = 3, + IMAGE_ERROR = 4, + IMAGE_DECODED = 5 +}; + +class RawDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + RawDecoder() = default; + virtual ~RawDecoder() override{}; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + uint32_t GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) override; + +private: + DISALLOW_COPY_AND_MOVE(RawDecoder); + bool DecodeHeader(); + PlAlphaType ConvertToAlphaType(SkAlphaType alphaType); + SkColorType ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat); + uint32_t AllocateMemory(SkImageInfo dstInfo, DecodeContext &context); + std::string ConvertEncodedFormatToString(SkEncodedImageFormat format); + InputDataStream *stream_ = nullptr; + std::unique_ptr codec_ = nullptr; + SkImageInfo info_; + SkColorType desireColor_ = kUnknown_SkColorType; + RawDecodingState state_ = RawDecodingState::UNDECIDED; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // RAW_DECODER_H diff --git a/adapter/frameworks/librawplugin/include/raw_stream.h b/adapter/frameworks/librawplugin/include/raw_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..160d8f34eedf3582794be6b7194380de6b2e0d19 --- /dev/null +++ b/adapter/frameworks/librawplugin/include/raw_stream.h @@ -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. + */ + +#ifndef RAW_STREAM_H +#define RAW_STREAM_H + +#include +#include +#include "SkStream.h" +#include "hilog/log.h" +#include "input_data_stream.h" +#include "log_tags.h" +#include "nocopyable.h" + +namespace OHOS { +namespace ImagePlugin { +class RawStream : public SkStream { +public: + RawStream() = default; + explicit RawStream(InputDataStream *stream); + virtual ~RawStream() override{}; + /** + * Reads or skips size number of bytes. + * if buffer is null, skip size bytes, return how many bytes skipped. + * else copy size bytes into buffer, return how many bytes copied. + */ + size_t read(void *buffer, size_t size) override; + /** + * Peeks size number of bytes. + */ + size_t peek(void *buffer, size_t size) const override; + /** + * Returns true when all the bytes in the stream have been read. + */ + bool isAtEnd() const override; + +private: + DISALLOW_COPY_AND_MOVE(RawStream); + ImagePlugin::InputDataStream *inputStream_ = nullptr; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // RAW_STREAM_H \ No newline at end of file diff --git a/adapter/frameworks/librawplugin/rawplugin.pluginmeta b/adapter/frameworks/librawplugin/rawplugin.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..69a92dfc9deb56e096a23296069baf062db3f249 --- /dev/null +++ b/adapter/frameworks/librawplugin/rawplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibRawPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"librawplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::RawDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/x-raw" + } + ] + } + ] +} diff --git a/adapter/frameworks/librawplugin/src/plugin_export.cpp b/adapter/frameworks/librawplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5089318abd117313f81530ea57655c9f2ec4050 --- /dev/null +++ b/adapter/frameworks/librawplugin/src/plugin_export.cpp @@ -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. + */ + + +#include "plugin_export.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "raw_decoder.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibRawPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::RawDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibRawPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/adapter/frameworks/librawplugin/src/raw_decoder.cpp b/adapter/frameworks/librawplugin/src/raw_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1087f98dd1cfeabdab698d13c192eb1c5f2f18f1 --- /dev/null +++ b/adapter/frameworks/librawplugin/src/raw_decoder.cpp @@ -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. + */ + + +#include "raw_decoder.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace Media; +using namespace std; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "RawDecoder" }; +namespace { +constexpr uint32_t RAW_IMAGE_NUM = 1; +} + +void RawDecoder::SetSource(InputDataStream &sourceStream) +{ + stream_ = &sourceStream; + state_ = RawDecodingState::SOURCE_INITED; +} + +void RawDecoder::Reset() +{ + if (stream_ != nullptr) { + stream_->Seek(0); + } + codec_.release(); + info_.reset(); + desireColor_ = kUnknown_SkColorType; +} + +uint32_t RawDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= RAW_IMAGE_NUM) { + HiLog::Error(LABEL, "GetImageSize failed, invalid index:%{public}u, range:%{public}u", index, RAW_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < RawDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= RawDecodingState::BASE_INFO_PARSED) { + size.width = info_.width(); + size.height = info_.height(); + return SUCCESS; + } + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + size.width = info_.width(); + size.height = info_.height(); + state_ = RawDecodingState::BASE_INFO_PARSED; + return SUCCESS; +} + +uint32_t RawDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + if (index >= RAW_IMAGE_NUM) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid index:%{public}u, range:%{public}u", index, + RAW_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < RawDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= RawDecodingState::IMAGE_DECODING) { + Reset(); + state_ = RawDecodingState::SOURCE_INITED; + } + if (state_ < RawDecodingState::BASE_INFO_PARSED) { + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + state_ = RawDecodingState::BASE_INFO_PARSED; + } + PlPixelFormat desiredFormat = opts.desiredPixelFormat; + desireColor_ = ConvertToColorType(desiredFormat, info.pixelFormat); + info.size.width = info_.width(); + info.size.height = info_.height(); + info.alphaType = ConvertToAlphaType(info_.alphaType()); + state_ = RawDecodingState::IMAGE_DECODING; + return SUCCESS; +} + +uint32_t RawDecoder::AllocateMemory(SkImageInfo dstInfo, DecodeContext &context) +{ + size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel(); + uint64_t byteCount = static_cast(dstInfo.height()) * rowBytes; + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { +#ifndef _WIN32 + int fd = AshmemCreate("Common RawData", byteCount); + if (fd < 0) { + return ERR_SHAMEM_DATA_ABNORMAL; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + void *ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return ERR_SHAMEM_DATA_ABNORMAL; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "Decode failed, alloc output buffer size:[%{public}llu] error", + static_cast(byteCount)); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#ifdef _WIN32 + memset(outputBuffer, 0, byteCount); +#else + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + HiLog::Error(LABEL, "Decode failed, memset buffer failed"); + free(outputBuffer); + outputBuffer = nullptr; + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#endif + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + return SUCCESS; +} + +uint32_t RawDecoder::Decode(uint32_t index, DecodeContext &context) +{ + HiLog::Error(LABEL, "Decode begin"); + if (index >= RAW_IMAGE_NUM) { + HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, RAW_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (codec_ == nullptr) { + HiLog::Error(LABEL, "Decode failed, codec is null"); + return ERR_IMAGE_DECODE_FAILED; + } + if (state_ != RawDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + SkImageInfo dstInfo = info_.makeColorType(desireColor_); + size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel(); + if (context.pixelsBuffer.buffer == nullptr) { + uint32_t resultCode = AllocateMemory(dstInfo, context); + if (resultCode != SUCCESS) { + return resultCode; + } + } + HiLog::Error(LABEL, "AllocateMemory end"); + uint8_t *dstBuffer = static_cast(context.pixelsBuffer.buffer); + SkCodec::Result ret = codec_->getPixels(dstInfo, dstBuffer, rowBytes); + if (ret != SkCodec::kSuccess) { + HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret); + state_ = RawDecodingState::IMAGE_ERROR; + return ERR_IMAGE_DECODE_ABNORMAL; + } + state_ = RawDecodingState::IMAGE_DECODED; + HiLog::Error(LABEL, "Decode end"); + return SUCCESS; +} + +uint32_t RawDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + // currently not support increment decode + return ERR_IMAGE_DATA_UNSUPPORT; +} + +bool RawDecoder::DecodeHeader() +{ + HiLog::Error(LABEL, "DecodeHeader begin"); + codec_ = SkCodec::MakeFromStream(make_unique(stream_)); + if (codec_ == nullptr) { + HiLog::Error(LABEL, "create codec from stream failed"); + return false; + } + info_ = codec_->getInfo(); + HiLog::Error(LABEL, "DecodeHeader end"); + return true; +} + +string RawDecoder::ConvertEncodedFormatToString(SkEncodedImageFormat format) +{ + string mimeType; + switch (format) { + case SkEncodedImageFormat::kJPEG: + mimeType = "image/jpeg"; + break; + case SkEncodedImageFormat::kDNG: + mimeType = "image/x-adobe-dng"; + break; + default: + mimeType = ""; + break; + } + return mimeType; +} + +uint32_t RawDecoder::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) +{ + HiLog::Info(LABEL, "[GetImagePropertyString] enter raw plugin, key:%{public}s", key.c_str()); + uint32_t errorCode = SUCCESS; + + if (state_ < RawDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + + if (state_ < RawDecodingState::BASE_INFO_PARSED) { + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImagePropertyString failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + state_ = RawDecodingState::BASE_INFO_PARSED; + } + + if (key == ACTUAL_IMAGE_ENCODED_FORMAT) { + SkEncodedImageFormat format = codec_->getEncodedFormat(); + HiLog::Info(LABEL, "getEncodedFormat format %{public}d", format); + value = ConvertEncodedFormatToString(format); + if (value == "") { + HiLog::Error(LABEL, "getEncodedFormat error format %{public}d", format); + return ERR_IMAGE_DATA_UNSUPPORT; + } + } else { + HiLog::Error(LABEL, "[GetImagePropertyString]key(%{public}s) not supported", key.c_str()); + return ERR_IMAGE_INVALID_PARAMETER; + } + + return errorCode; +} + +PlAlphaType RawDecoder::ConvertToAlphaType(SkAlphaType alphaType) +{ + switch (alphaType) { + case kOpaque_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + case kPremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL; + case kUnpremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + default: + HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType); + break; + } + return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; +} + +SkColorType RawDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat) +{ + switch (format) { + case PlPixelFormat::BGRA_8888: { + outputFormat = PlPixelFormat::BGRA_8888; + return kBGRA_8888_SkColorType; + } + case PlPixelFormat::ALPHA_8: { + SkColorType colorType = info_.colorType(); + if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) { + outputFormat = PlPixelFormat::ALPHA_8; + return kAlpha_8_SkColorType; + } + break; + } + case PlPixelFormat::RGB_565: { + if (info_.isOpaque()) { + outputFormat = PlPixelFormat::RGB_565; + return kRGB_565_SkColorType; + } + break; + } + default: { + break; + } + } + HiLog::Debug(LABEL, "unsupport convert to format:%{public}d, set default RGBA", format); + outputFormat = PlPixelFormat::RGBA_8888; + return kRGBA_8888_SkColorType; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/librawplugin/src/raw_stream.cpp b/adapter/frameworks/librawplugin/src/raw_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a9a770cecf034ed21343e4351685183a6e14c71 --- /dev/null +++ b/adapter/frameworks/librawplugin/src/raw_stream.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "raw_stream.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "RawStream" }; +RawStream::RawStream(InputDataStream *stream) : inputStream_(stream) {} + +size_t RawStream::read(void *buffer, size_t size) +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "read failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + size_t curPosition = static_cast(inputStream_->Tell()); + if (!inputStream_->Seek(curPosition + size)) { + HiLog::Error(LABEL, "read failed, curpositon=%{public}zu, skip size=%{public}zu", curPosition, size); + return 0; + } + return size; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Read(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "read failed, desire read size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +size_t RawStream::peek(void *buffer, size_t size) const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "peek failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + HiLog::Error(LABEL, "peek failed, output buffer is null"); + return 0; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Peek(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "peek failed, desire peek size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +bool RawStream::isAtEnd() const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "get stream status failed, inputStream_ is null."); + return false; + } + size_t size = inputStream_->GetStreamSize(); + return (inputStream_->Tell() == size); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libskiaplugin/BUILD.gn b/adapter/frameworks/libskiaplugin/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..609d19a2075a47a22e17e20ea394ce16fcdbeb67 --- /dev/null +++ b/adapter/frameworks/libskiaplugin/BUILD.gn @@ -0,0 +1,92 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("skiaplugin") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/libskiaplugin/src/plugin_export.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libskiaplugin/src/skia_decoder.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libskiaplugin/src/skia_stream.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/adapter/frameworks/libskiaplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + ] + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//foundation/multimedia/image_standard/mock/native/include/secure", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/win", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + "//third_party/flutter/skia/include/codec", + "//third_party/flutter/skia", + "//third_party/flutter/skia/include/core", + + ] + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + + libs = [ "//foundation/multimedia/image_standard/libskia.lib" ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/mac", + "//libs/android_libs/sdk/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + "//utils/native/base/include", + ] + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + deps = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + external_deps = [ "hilog:libhilog" ] + android_deps = [ "shared_library:libhwui" ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_prebuilt_etc("skiapluginmetadata") { + source = "skiaplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/libskiaplugin/include/skia_decoder.h b/adapter/frameworks/libskiaplugin/include/skia_decoder.h new file mode 100755 index 0000000000000000000000000000000000000000..03f2a237490429fbb9c64e5c0910ed9116c10122 --- /dev/null +++ b/adapter/frameworks/libskiaplugin/include/skia_decoder.h @@ -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. + */ + +#ifndef SKIA_DECODER_H +#define SKIA_DECODER_H + + +#include +#include +#include "abs_image_decoder.h" +#include "hilog/log.h" +#include "image_type.h" +#include "log_tags.h" +#include "SkCodec.h" +#include "SkAndroidCodec.h" +#include "skia_stream.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +enum class SkiaDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSED = 2, + IMAGE_DECODING = 3, + IMAGE_ERROR = 4, + IMAGE_DECODED = 5 +}; +class SkiaDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + SkiaDecoder() = default; + virtual ~SkiaDecoder() override {}; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PlDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + bool HasProperty(std::string key) override; + +private: + DISALLOW_COPY_AND_MOVE(SkiaDecoder); + const std::string SKIA_DECODER = "SKIA_DECODER"; + bool DecodeHeader(); + PlAlphaType ConvertToAlphaType(SkAlphaType alphaType); + SkColorType ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat); + uint32_t AllocShareMemory(DecodeContext &context, uint64_t byteCount); + uint32_t AllocHeapBuffer(DecodeContext &context, uint64_t byteCount); + InputDataStream *stream_ = nullptr; + std::unique_ptr acodec_ = nullptr; + uint32_t sampleSize_ = 0; + SkImageInfo info_; + SkColorType desireColor_ = kUnknown_SkColorType; + SkiaDecodingState state_ = SkiaDecodingState::UNDECIDED; +}; +} // namespace Media +} // namespace OHOS + +#endif // SKIA_DECODER_H diff --git a/adapter/frameworks/libskiaplugin/include/skia_stream.h b/adapter/frameworks/libskiaplugin/include/skia_stream.h new file mode 100755 index 0000000000000000000000000000000000000000..41c175e59d902c9b0046af6c559e4c17cf9363f0 --- /dev/null +++ b/adapter/frameworks/libskiaplugin/include/skia_stream.h @@ -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. + */ + +#ifndef SKIA_STREAM_H +#define SKIA_STREAM_H + +#include +#include +#include "SkStream.h" +#include "hilog/log.h" +#include "input_data_stream.h" +#include "log_tags.h" +#include "nocopyable.h" + +namespace OHOS { +namespace ImagePlugin { +class SkiaStream : public SkStream { +public: + SkiaStream() = default; + explicit SkiaStream(InputDataStream *stream); + virtual ~SkiaStream() override{}; + /** + * Reads or skips size number of bytes. + * if buffer is null, skip size bytes, return how many bytes skipped. + * else copy size bytes into buffer, return how many bytes copied. + */ + size_t read(void *buffer, size_t size) override; + /** + * Peeks size number of bytes. + */ + size_t peek(void *buffer, size_t size) const override; + /** + * Returns true when all the bytes in the stream have been read. + */ + bool isAtEnd() const override; + +private: + DISALLOW_COPY_AND_MOVE(SkiaStream); + ImagePlugin::InputDataStream *inputStream_ = nullptr; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // SKIA_STREAM_H \ No newline at end of file diff --git a/adapter/frameworks/libskiaplugin/skiaplugin.pluginmeta b/adapter/frameworks/libskiaplugin/skiaplugin.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..ce42f5196b35d848644d0e4f9f2f7033712fb565 --- /dev/null +++ b/adapter/frameworks/libskiaplugin/skiaplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibSkiaPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libskiaplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::SkiaDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/x-skia" + } + ] + } + ] +} diff --git a/adapter/frameworks/libskiaplugin/src/plugin_export.cpp b/adapter/frameworks/libskiaplugin/src/plugin_export.cpp new file mode 100755 index 0000000000000000000000000000000000000000..0378d0fbe8cbfbffd4c087209e250d26d92410fc --- /dev/null +++ b/adapter/frameworks/libskiaplugin/src/plugin_export.cpp @@ -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. + */ + +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_export.h" +#include "plugin_utils.h" +#include "skia_decoder.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibSkiaPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::SkiaDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "SkiaPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/adapter/frameworks/libskiaplugin/src/skia_decoder.cpp b/adapter/frameworks/libskiaplugin/src/skia_decoder.cpp new file mode 100755 index 0000000000000000000000000000000000000000..67826ee01440003c04f98d173c406bec063923a1 --- /dev/null +++ b/adapter/frameworks/libskiaplugin/src/skia_decoder.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "skia_decoder.h" +#include "image_utils.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace Media; +using namespace std; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "SkiaDecoder" }; +namespace { +constexpr uint32_t IMAGE_NUM = 1; +} + +void SkiaDecoder::SetSource(InputDataStream &sourceStream) +{ + stream_ = &sourceStream; + state_ = SkiaDecodingState::SOURCE_INITED; +} + +void SkiaDecoder::Reset() +{ + if (stream_ != nullptr) { + stream_->Seek(0); + } + acodec_.release(); + info_.reset(); + desireColor_ = kUnknown_SkColorType; +} + +uint32_t SkiaDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= IMAGE_NUM) { + HiLog::Error(LABEL, "GetImageSize failed, invalid index:%{public}u, range:%{public}u", index, IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < SkiaDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= SkiaDecodingState::BASE_INFO_PARSED) { + size.width = info_.width(); + size.height = info_.height(); + return SUCCESS; + } + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + size.width = info_.width(); + size.height = info_.height(); + state_ = SkiaDecodingState::BASE_INFO_PARSED; + return SUCCESS; +} + +uint32_t SkiaDecoder::SetDecodeOptions(uint32_t index, const PlDecodeOptions &opts, PlImageInfo &info) +{ + if (index >= IMAGE_NUM) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid index:%{public}u, range:%{public}u", index, + IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < SkiaDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= SkiaDecodingState::IMAGE_DECODING) { + Reset(); + state_ = SkiaDecodingState::SOURCE_INITED; + } + if (state_ < SkiaDecodingState::BASE_INFO_PARSED) { + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + state_ = SkiaDecodingState::BASE_INFO_PARSED; + } + HiLog::Info(LABEL, "SetDecodeOptions sampleSize:%{public}d, degree:%{public}f", + opts.sampleSize, opts.rotateDegrees); + PlPixelFormat desiredFormat = opts.desiredPixelFormat; + sampleSize_ = opts.sampleSize; + desireColor_ = ConvertToColorType(desiredFormat, info.pixelFormat); + auto alphaType = info_.isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; + // we need compute new info, compute sample dimensions + auto sampledDims = acodec_->getSampledDimensions(sampleSize_); + HiLog::Info(LABEL, "SetDecodeOptions sampledDims, width:%{public}d, height:%{public}d", + sampledDims.width(), sampledDims.height()); + info_ = info_.makeColorType(desireColor_) + .makeWH(sampledDims.width(), sampledDims.height()) + .makeAlphaType(alphaType); + info.size.width = info_.width(); + info.size.height = info_.height(); + info.alphaType = ConvertToAlphaType(info_.alphaType()); + state_ = SkiaDecodingState::IMAGE_DECODING; + return SUCCESS; +} + +bool SkiaDecoder::HasProperty(std::string key) +{ + if (key == SKIA_DECODER) { + return true; + } + return false; +} + +uint32_t SkiaDecoder::AllocShareMemory(DecodeContext &context, uint64_t byteCount) +{ +#if !defined(_WIN32) && !defined(_APPLE) + int fd = AshmemCreate("BMP RawData", byteCount); + if (fd < 0) { + return ERR_SHAMEM_DATA_ABNORMAL; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return ERR_SHAMEM_DATA_ABNORMAL; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.pixelsBuffer.bufferSize = byteCount; + context.freeFunc = nullptr; +#endif + return SUCCESS; +} + +uint32_t SkiaDecoder::AllocHeapBuffer(DecodeContext &context, uint64_t byteCount) +{ + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "Decode failed, alloc failed!"); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#ifdef _WIN32 + memset(outputBuffer, 0, byteCount); +#else + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + free(outputBuffer); + outputBuffer = nullptr; + return ERR_IMAGE_DECODE_FAILED; + } +#endif + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.pixelsBuffer.bufferSize = byteCount; + context.freeFunc = nullptr; + return SUCCESS; +} + +uint32_t SkiaDecoder::Decode(uint32_t index, DecodeContext &context) +{ + if (index >= IMAGE_NUM) { + HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (acodec_ == nullptr) { + HiLog::Error(LABEL, "Decode failed, codec is null"); + return ERR_IMAGE_DECODE_FAILED; + } + if (state_ != SkiaDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + + SkImageInfo dstInfo = info_; + if (ImageUtils::CheckMulOverflow(dstInfo.width(), dstInfo.height(), dstInfo.bytesPerPixel())) { + HiLog::Error(LABEL, "Decode failed, width:%{public}d, height:%{public}d is too large", + dstInfo.width(), dstInfo.height()); + return ERR_IMAGE_DECODE_FAILED; + } + + if (context.pixelsBuffer.buffer == nullptr) { + uint64_t byteCount = static_cast(dstInfo.height()) * dstInfo.width() * dstInfo.bytesPerPixel(); + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { + if (AllocShareMemory(context, byteCount) != SUCCESS) { + return ERR_IMAGE_DECODE_FAILED; + } + } else { + if (AllocHeapBuffer(context, byteCount) != SUCCESS) { + return ERR_IMAGE_DECODE_FAILED; + } + } + } + uint8_t *dstBuffer = static_cast(context.pixelsBuffer.buffer); + size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel(); + SkAndroidCodec::AndroidOptions options; + options.fSampleSize = sampleSize_; + auto result = acodec_->getAndroidPixels(dstInfo, dstBuffer, rowBytes, &options); + if (result != SkCodec::kSuccess) { + HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", result); + state_ = SkiaDecodingState::IMAGE_ERROR; + return ERR_IMAGE_DECODE_ABNORMAL; + } + state_ = SkiaDecodingState::IMAGE_DECODED; + return SUCCESS; +} + +uint32_t SkiaDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + // currently not support increment decode + return ERR_IMAGE_DATA_UNSUPPORT; +} + +bool SkiaDecoder::DecodeHeader() +{ + HiLog::Info(LABEL, "stream_->GetStreamType() %{public}d", stream_->GetStreamType()); + if (stream_->GetStreamType() == ImagePlugin::BUFFER_SOURCE_TYPE) { + std::unique_ptr stream = + std::make_unique(stream_->GetDataPtr(), stream_->GetStreamSize(), false); + acodec_ = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromStream(std::move(stream))); + } else { + acodec_ = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromStream(make_unique(stream_))); + } + if (!acodec_) { + HiLog::Error(LABEL, "Could not create acodec_"); + return false; + } + info_ = acodec_->getInfo(); + return true; +} + +PlAlphaType SkiaDecoder::ConvertToAlphaType(SkAlphaType alphaType) +{ + switch (alphaType) { + case kOpaque_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + case kPremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL; + case kUnpremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + default: + HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType); + break; + } + return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; +} + +SkColorType SkiaDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat) +{ + switch (format) { + case PlPixelFormat::UNKNOWN: + case PlPixelFormat::RGBA_8888: { + outputFormat = PlPixelFormat::RGBA_8888; + return kRGBA_8888_SkColorType; + } + case PlPixelFormat::BGRA_8888: { + outputFormat = PlPixelFormat::BGRA_8888; + return kBGRA_8888_SkColorType; + } + case PlPixelFormat::ALPHA_8: { + SkColorType colorType = info_.colorType(); + if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) { + outputFormat = PlPixelFormat::ALPHA_8; + return kAlpha_8_SkColorType; + } + break; + } + case PlPixelFormat::RGB_565: { + if (info_.isOpaque()) { + outputFormat = PlPixelFormat::RGB_565; + return kRGB_565_SkColorType; + } + break; + } + default: { + break; + } + } + HiLog::Debug(LABEL, "unsupport conver to format:%{public}d, set default RGBA", format); + outputFormat = PlPixelFormat::RGBA_8888; + return kRGBA_8888_SkColorType; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libskiaplugin/src/skia_stream.cpp b/adapter/frameworks/libskiaplugin/src/skia_stream.cpp new file mode 100755 index 0000000000000000000000000000000000000000..e95f27c2043fc772660d84376199511ce6996a8c --- /dev/null +++ b/adapter/frameworks/libskiaplugin/src/skia_stream.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "skia_stream.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "SkiaStream" }; + +SkiaStream::SkiaStream(InputDataStream *stream) : inputStream_(stream) {} + +size_t SkiaStream::read(void *buffer, size_t size) +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "read failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + size_t curPosition = static_cast(inputStream_->Tell()); + if (!inputStream_->Seek(curPosition + size)) { + HiLog::Error(LABEL, "read failed, curpositon=%{public}zu, skip size=%{public}zu", curPosition, size); + return 0; + } + return size; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Read(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "read failed, desire read size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +size_t SkiaStream::peek(void *buffer, size_t size) const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "peek failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + HiLog::Error(LABEL, "peek failed, output buffer is null"); + return 0; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Peek(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "peek failed, desire peek size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +bool SkiaStream::isAtEnd() const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "get stream status failed, inputStream_ is null."); + return false; + } + size_t size = inputStream_->GetStreamSize(); + return (inputStream_->Tell() == size); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libwbmpplugin/BUILD.gn_old b/adapter/frameworks/libwbmpplugin/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..a84e16a02cc94be7d5d0f1f563099a0918985d97 --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/BUILD.gn_old @@ -0,0 +1,91 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("wbmpplugin") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin/src/plugin_export.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin/src/wbmp_decoder.cpp", + "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin/src/wbmp_stream.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//third_party/flutter/skia/include/codec", + "//third_party/flutter/skia", + "//third_party/flutter/skia/include/core", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//foundation/multimedia/image_standard/mock/native/include/secure", + #"${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + #"${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + #"${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/win", + #"${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + ] + deps = [ + "//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + + #libs = [ "//foundation/multimedia/image_standard/libskia.lib" ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/codec", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/mac", + "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + "//utils/native/base/include", + ] + deps = [ + "//foundation/graphic/ide/libs/skia:skia", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +# aosp_deps = [ "shared_library:libhwui" ] + } + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_prebuilt_etc("wbmppluginmetadata") { + source = "wbmpplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/libwbmpplugin/include/wbmp_decoder.h b/adapter/frameworks/libwbmpplugin/include/wbmp_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..65af4fb0c4d219a9d8efebc7edbd88a0ac9e97f5 --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/include/wbmp_decoder.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef WBMP_DECODER_H +#define WBMP_DECODER_H + +#include +#include +#include "SkCodec.h" +#include "abs_image_decoder.h" +#include "wbmp_stream.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +enum class WbmpDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSED = 2, + IMAGE_DECODING = 3, + IMAGE_ERROR = 4, + IMAGE_DECODED = 5 +}; + +class WbmpDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + WbmpDecoder() = default; + virtual ~WbmpDecoder() override{}; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + +private: + DISALLOW_COPY_AND_MOVE(WbmpDecoder); + bool DecodeHeader(); + PlAlphaType ConvertToAlphaType(SkAlphaType alphaType); + SkColorType ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat); + uint32_t AllocateMemory(SkImageInfo dstInfo, DecodeContext &context); + + InputDataStream *stream_ = nullptr; + std::unique_ptr codec_ = nullptr; + SkImageInfo info_; + SkColorType desireColor_ = kUnknown_SkColorType; + WbmpDecodingState state_ = WbmpDecodingState::UNDECIDED; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // WBMP_DECODER_H diff --git a/adapter/frameworks/libwbmpplugin/include/wbmp_stream.h b/adapter/frameworks/libwbmpplugin/include/wbmp_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..a4dc791d9eef2769547f96e8875cfc54e739de0e --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/include/wbmp_stream.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WBMP_STREAM_H +#define WBMP_STREAM_H + +#include +#include +#include "SkStream.h" +#include "hilog/log.h" +#include "input_data_stream.h" +#include "log_tags.h" +#include "nocopyable.h" + +namespace OHOS { +namespace ImagePlugin { +class WbmpStream : public SkStream { +public: + WbmpStream() = default; + explicit WbmpStream(InputDataStream *stream); + virtual ~WbmpStream() override{}; + /** + * Reads or skips size number of bytes. + * if buffer is null, skip size bytes, return how many bytes skipped. + * else copy size bytes into buffer, return how many bytes copied. + */ + size_t read(void *buffer, size_t size) override; + /** + * Peeks size number of bytes. + */ + size_t peek(void *buffer, size_t size) const override; + /** + * Returns true when all the bytes in the stream have been read. + */ + bool isAtEnd() const override; + +private: + DISALLOW_COPY_AND_MOVE(WbmpStream); + + ImagePlugin::InputDataStream *inputStream_ = nullptr; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // WBMP_STREAM_H \ No newline at end of file diff --git a/adapter/frameworks/libwbmpplugin/src/plugin_export.cpp b/adapter/frameworks/libwbmpplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..984ea35ed1f355e5866186a8996e7d5a3a729eb4 --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/src/plugin_export.cpp @@ -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. + */ + + +#include "plugin_export.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "wbmp_decoder.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibWbmpPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::WbmpDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibWbmpPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/adapter/frameworks/libwbmpplugin/src/wbmp_decoder.cpp b/adapter/frameworks/libwbmpplugin/src/wbmp_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34c748ed7863eccced01daba15c3e70c8b38baea --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/src/wbmp_decoder.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wbmp_decoder.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace Media; +using namespace std; + +namespace { +constexpr uint32_t WBMP_IMAGE_NUM = 1; +} +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WbmpDecoder" }; + +void WbmpDecoder::SetSource(InputDataStream &sourceStream) +{ + stream_ = &sourceStream; + state_ = WbmpDecodingState::SOURCE_INITED; +} + +void WbmpDecoder::Reset() +{ + if (stream_ != nullptr) { + stream_->Seek(0); + } + codec_.release(); + info_.reset(); + desireColor_ = kUnknown_SkColorType; +} + +uint32_t WbmpDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= WBMP_IMAGE_NUM) { + HiLog::Error(LABEL, "GetImageSize failed, invalid index:%{public}u, range:%{public}u", index, WBMP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < WbmpDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= WbmpDecodingState::BASE_INFO_PARSED) { + size.width = info_.width(); + size.height = info_.height(); + return SUCCESS; + } + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + size.width = info_.width(); + size.height = info_.height(); + state_ = WbmpDecodingState::BASE_INFO_PARSED; + return SUCCESS; +} + +uint32_t WbmpDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + if (index >= WBMP_IMAGE_NUM) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid index:%{public}u, range:%{public}u", index, + WBMP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < WbmpDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "SetDecodeOptions failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= WbmpDecodingState::IMAGE_DECODING) { + Reset(); + state_ = WbmpDecodingState::SOURCE_INITED; + } + if (state_ < WbmpDecodingState::BASE_INFO_PARSED) { + if (!DecodeHeader()) { + HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + state_ = WbmpDecodingState::BASE_INFO_PARSED; + } + PlPixelFormat desiredFormat = opts.desiredPixelFormat; + desireColor_ = ConvertToColorType(desiredFormat, info.pixelFormat); + info.size.width = info_.width(); + info.size.height = info_.height(); + info.alphaType = ConvertToAlphaType(info_.alphaType()); + state_ = WbmpDecodingState::IMAGE_DECODING; + return SUCCESS; +} + +uint32_t WbmpDecoder::AllocateMemory(SkImageInfo dstInfo, DecodeContext &context) +{ + size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel(); + uint64_t byteCount = static_cast(dstInfo.height()) * rowBytes; + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int fd = AshmemCreate("Wbmp RawData", byteCount); + if (fd < 0) { + return ERR_SHAMEM_DATA_ABNORMAL; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return ERR_SHAMEM_DATA_ABNORMAL; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "Decode failed, alloc output buffer size:[%{public}llu] error", + static_cast(byteCount)); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#ifdef _WIN32 + memset(outputBuffer, 0, byteCount); +#else + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + HiLog::Error(LABEL, "Decode failed, memset buffer failed"); + free(outputBuffer); + outputBuffer = nullptr; + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#endif + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + return SUCCESS; +} + +uint32_t WbmpDecoder::Decode(uint32_t index, DecodeContext &context) +{ + if (index >= WBMP_IMAGE_NUM) { + HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, WBMP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (codec_ == nullptr) { + HiLog::Error(LABEL, "Decode failed, codec is null"); + return ERR_IMAGE_DECODE_FAILED; + } + if (state_ != WbmpDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + SkImageInfo dstInfo = info_.makeColorType(desireColor_); + size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel(); + if (context.pixelsBuffer.buffer == nullptr) { + uint32_t resultCode = AllocateMemory(dstInfo, context); + if (resultCode != SUCCESS) { + return resultCode; + } + } + uint8_t *dstBuffer = static_cast(context.pixelsBuffer.buffer); + SkCodec::Result ret = codec_->getPixels(dstInfo, dstBuffer, rowBytes); + if (ret != SkCodec::kSuccess) { + HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret); + state_ = WbmpDecodingState::IMAGE_ERROR; + return ERR_IMAGE_DECODE_ABNORMAL; + } + state_ = WbmpDecodingState::IMAGE_DECODED; + return SUCCESS; +} + +uint32_t WbmpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + // currently not support increment decode + return ERR_IMAGE_DATA_UNSUPPORT; +} + +bool WbmpDecoder::DecodeHeader() +{ + codec_ = SkCodec::MakeFromStream(make_unique(stream_)); + if (codec_ == nullptr) { + HiLog::Error(LABEL, "create codec from stream failed"); + return false; + } + info_ = codec_->getInfo(); + return true; +} + +PlAlphaType WbmpDecoder::ConvertToAlphaType(SkAlphaType alphaType) +{ + switch (alphaType) { + case kOpaque_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + case kPremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL; + case kUnpremul_SkAlphaType: + return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + default: + HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType); + break; + } + return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; +} + +SkColorType WbmpDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat) +{ + switch (format) { + case PlPixelFormat::BGRA_8888: { + outputFormat = PlPixelFormat::BGRA_8888; + return kBGRA_8888_SkColorType; + } + case PlPixelFormat::ALPHA_8: { + SkColorType colorType = info_.colorType(); + if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) { + outputFormat = PlPixelFormat::ALPHA_8; + return kAlpha_8_SkColorType; + } + break; + } + case PlPixelFormat::RGB_565: { + if (info_.isOpaque()) { + outputFormat = PlPixelFormat::RGB_565; + return kRGB_565_SkColorType; + } + break; + } + default: { + break; + } + } + HiLog::Debug(LABEL, "unsupport conver to format:%{public}d, set default RGBA", format); + outputFormat = PlPixelFormat::RGBA_8888; + return kRGBA_8888_SkColorType; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libwbmpplugin/src/wbmp_stream.cpp b/adapter/frameworks/libwbmpplugin/src/wbmp_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9b2b78eb99d4c8079ef7f57e6be8a70aa2fc605 --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/src/wbmp_stream.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "wbmp_stream.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WbmpStream" }; +WbmpStream::WbmpStream(InputDataStream *stream) : inputStream_(stream) {} + +size_t WbmpStream::read(void *buffer, size_t size) +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "read failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + size_t curPosition = static_cast(inputStream_->Tell()); + if (!inputStream_->Seek(curPosition + size)) { + HiLog::Error(LABEL, "read failed, curpositon=%{public}zu, skip size=%{public}zu", curPosition, size); + return 0; + } + return size; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Read(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "read failed, desire read size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +size_t WbmpStream::peek(void *buffer, size_t size) const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "peek failed, inputStream_ is null"); + return 0; + } + if (buffer == nullptr) { + HiLog::Error(LABEL, "peek failed, output buffer is null"); + return 0; + } + uint32_t desireSize = static_cast(size); + uint32_t bufferSize = desireSize; + uint32_t readSize = desireSize; + if (!inputStream_->Peek(desireSize, static_cast(buffer), bufferSize, readSize)) { + HiLog::Error(LABEL, "peek failed, desire peek size=%{public}u", desireSize); + return 0; + } + return readSize; +} + +bool WbmpStream::isAtEnd() const +{ + if (inputStream_ == nullptr) { + HiLog::Error(LABEL, "get stream status failed, inputStream_ is null."); + return false; + } + size_t size = inputStream_->GetStreamSize(); + return (inputStream_->Tell() == size); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/adapter/frameworks/libwbmpplugin/wbmpplugin.pluginmeta b/adapter/frameworks/libwbmpplugin/wbmpplugin.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..ee5de90a0a09118d87bfb9f531dde1c818e33d93 --- /dev/null +++ b/adapter/frameworks/libwbmpplugin/wbmpplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibWbmpPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libwbmpplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::WbmpDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/vnd.wap.wbmp" + } + ] + } + ] +} diff --git a/adapter/frameworks/pixelconverter/BUILD.gn b/adapter/frameworks/pixelconverter/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9b6de22a6ebcfb02efbfe783dff28710ee85de76 --- /dev/null +++ b/adapter/frameworks/pixelconverter/BUILD.gn @@ -0,0 +1,253 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +config("pixelconvertadapter_public_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/communication/ipc/utils/include", + "//foundation/multimedia/utils/lite/interfaces/kits", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/include/encode", + "//third_party/flutter/skia", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/src/ports", + "//third_party/flutter/skia/src/images", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/third_party/externals/freetype/include/freetype", + "//third_party/flutter/skia/include/private", + "//third_party/bounds_checking_function/include", +# "//utils/jni/jnikit/include", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/core", + ] + + if (use_mingw_win) { + include_dirs += [ +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/win", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + "//foundation/multimedia/image_standard/mock/native/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/communication/ipc/utils/include", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/include/encode", + "//third_party/flutter/skia", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/src/ports", + "//third_party/flutter/skia/src/images", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/third_party/externals/freetype/include/freetype", + "//third_party/bounds_checking_function/include", + ] + } else if (use_clang_mac) { + include_dirs += [ +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config/mac", +# "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/skia/include/config", + "//foundation/multimedia/image_standard/mock/native/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/include/encode", + "//third_party/flutter/skia", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/src/ports", + "//third_party/flutter/skia/src/images", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/third_party/externals/freetype/include/freetype", + "//third_party/bounds_checking_function/include", + ] + } else { + include_dirs += [ + "//utils/native/base/include", + "//foundation/communication/ipc/utils/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/include/encode", + "//third_party/flutter/skia", + "//third_party/flutter/skia/src/ports/skia_ohos", + "//third_party/flutter/skia/src/ports", + "//third_party/flutter/skia/src/images", + "//third_party/expat/lib", + "//third_party/flutter/skia/include/private", + "//third_party/flutter/skia/third_party/externals/freetype/include/freetype", + "//third_party/bounds_checking_function/include", + ] + } +} + +ohos_shared_library("pixelconvertadapter") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/src/pixel_convert_adapter.cpp", + #"//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/src/pixel_map_jni_utils.cpp", + ] + + public_configs = [ ":pixelconvertadapter_public_config" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_fontmgr_windows", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_typeface_freetype", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/communication/ipc/utils/include", + "//utils/jni:utils_jnikit_win", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_fontmgr_mac", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + #"//utils/jni:utils_jnikit_mac", + ] + } else { + #deps = [ + # "//utils/jni:utils_jnikit", + # ] + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + #"//third_party/flutter/skia:skia", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_fontmgr_ohos", + "//third_party/flutter:ace_fontmgr_standard", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_libsfntly_ohos", + "//third_party/flutter:ace_libfreetype2", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontconfig.json", + "//third_party/flutter:ace_jsoncpp", + "//utils/native/base:utils", + #"//utils/jni:utils_jnikit_mac", + ] + + #aosp_deps = [ "shared_library:libhwui" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_static_library("pixelconvertadapter_static") { + sources = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/src/pixel_convert_adapter.cpp", + #"//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/src/pixel_map_jni_utils.cpp", + ] + public_configs = [ ":pixelconvertadapter_public_config" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_fontmgr_windows", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_skia_windows", + "//third_party/flutter:ace_libfreetype2", + + #"//third_party/flutter/skia:skia", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + #"//utils/jni:utils_jnikit_win", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_fontmgr_mac", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_skia_mac", + "//third_party/flutter:ace_libfreetype2", + #"//third_party/flutter/skia:skia", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + #"//utils/jni:utils_jnikit_mac", + ] + } else { + #deps = [ "//utils/jni:utils_jnikit" ] + deps = [ + #"//foundation/graphic/ide/libs/skia:skia", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_fontmgr_ohos", + "//third_party/flutter:ace_fontmgr_standard", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_webp", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_skia_ohos", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_fontconfig.json", + "//third_party/flutter:ace_jsoncpp", + "//utils/native/base:utils", + + #"//third_party/flutter/skia:skia", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + #"//utils/jni:utils_jnikit_mac", + ] + + #aosp_deps = [ "shared_library:libhwui" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } +} diff --git a/adapter/frameworks/pixelconverter/include/pixel_convert_adapter.h b/adapter/frameworks/pixelconverter/include/pixel_convert_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..c2958f5b1b2b1f7c2e89e7e25a432c0a2f876b87 --- /dev/null +++ b/adapter/frameworks/pixelconverter/include/pixel_convert_adapter.h @@ -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. + */ + +#ifndef PIXEL_CONVERT_ADAPTER_H +#define PIXEL_CONVERT_ADAPTER_H + +#include "hilog/log.h" +#include "image_type.h" +#include "log_tags.h" + +namespace OHOS { +namespace Media { +class PixelConvertAdapter { +public: + static bool WritePixelsConvert(const void *srcPixels, uint32_t srcRowBytes, const ImageInfo &srcInfo, + void *dstPixels, const Position &dstPos, uint32_t dstRowBytes, + const ImageInfo &dstInfo); + static bool ReadPixelsConvert(const void *srcPixels, const Position &srcPos, uint32_t srcRowBytes, + const ImageInfo &srcInfo, void *dstPixels, uint32_t dstRowBytes, + const ImageInfo &dstInfo); + static bool EraseBitmap(const void *srcPixels, uint32_t srcRowBytes, const ImageInfo &srcInfo, uint32_t color); +}; +} // namespace Media +} // namespace OHOS + +#endif // PIXEL_CONVERT_ADAPTER_H \ No newline at end of file diff --git a/adapter/frameworks/pixelconverter/include/pixel_map_jni_utils.h b/adapter/frameworks/pixelconverter/include/pixel_map_jni_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..724c6744bb065b06bbee0fa1cb3b175a0dba3db1 --- /dev/null +++ b/adapter/frameworks/pixelconverter/include/pixel_map_jni_utils.h @@ -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. + */ + +#ifndef PIXEL_MAP_JNI_UTILS_H +#define PIXEL_MAP_JNI_UTILS_H + +#include "hilog/log.h" +#include "jkit_utils.h" +#include "log_tags.h" + +namespace OHOS { +namespace Media { +class PixelMapJniUtilsAdapter { +public: + static jarray GetBufferBaseArray(JNIEnv *env, jobject jbuffer); + static bool GetBufferBaseArrayOffset(JNIEnv *env, jobject jbuffer, jint &offset); +}; +} // namespace Media +} // namespace OHOS + +#endif // PIXEL_MAP_JNI_UTILS_H \ No newline at end of file diff --git a/adapter/frameworks/pixelconverter/src/pixel_convert_adapter.cpp b/adapter/frameworks/pixelconverter/src/pixel_convert_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8395dda723a23e865190369a725b7153ae377d9c --- /dev/null +++ b/adapter/frameworks/pixelconverter/src/pixel_convert_adapter.cpp @@ -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. + */ + +#include "pixel_convert_adapter.h" +#include "include/core/SkBitmap.h" +#include "include/core/SkCanvas.h" +#include "include/core/SkColor.h" +#include "include/core/SkColorSpace.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPaint.h" +#include "include/core/SkPixmap.h" +#ifdef _WIN32 +#include +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelConvertAdapter" }; + +static SkColorType PixelFormatConvert(const PixelFormat &pixelFormat) +{ + SkColorType colorType; + switch (pixelFormat) { + case PixelFormat::BGRA_8888: + colorType = SkColorType::kBGRA_8888_SkColorType; + break; + case PixelFormat::RGBA_8888: + colorType = SkColorType::kRGBA_8888_SkColorType; + break; + case PixelFormat::RGB_565: + colorType = SkColorType::kRGB_565_SkColorType; + break; + case PixelFormat::ALPHA_8: + colorType = SkColorType::kAlpha_8_SkColorType; + break; + default: + colorType = SkColorType::kUnknown_SkColorType; + break; + } + return colorType; +} + +bool PixelConvertAdapter::WritePixelsConvert(const void *srcPixels, uint32_t srcRowBytes, const ImageInfo &srcInfo, + void *dstPixels, const Position &dstPos, uint32_t dstRowBytes, + const ImageInfo &dstInfo) +{ + // basic valid check, other parameters valid check in writePixels method + if (srcPixels == nullptr || dstPixels == nullptr) { + HiLog::Error(LABEL, "src or dst pixels invalid."); + return false; + } + SkAlphaType srcAlphaType = static_cast(srcInfo.alphaType); + SkAlphaType dstAlphaType = static_cast(dstInfo.alphaType); + SkColorType srcColorType = PixelFormatConvert(srcInfo.pixelFormat); + SkColorType dstColorType = PixelFormatConvert(dstInfo.pixelFormat); + SkImageInfo srcImageInfo = SkImageInfo::Make(srcInfo.size.width, srcInfo.size.height, srcColorType, srcAlphaType); + SkImageInfo dstImageInfo = SkImageInfo::Make(dstInfo.size.width, dstInfo.size.height, dstColorType, dstAlphaType); + + SkBitmap dstBitmap; + SkPixmap srcPixmap(srcImageInfo, srcPixels, srcRowBytes); + if (!dstBitmap.installPixels(dstImageInfo, dstPixels, dstRowBytes)) { + HiLog::Error(LABEL, "WritePixelsConvert dst bitmap install pixels failed."); + return false; + } + if (!dstBitmap.writePixels(srcPixmap, dstPos.x, dstPos.y)) { + HiLog::Error(LABEL, "WritePixelsConvert dst bitmap write pixels by source failed."); + return false; + } + + return true; +} + +bool PixelConvertAdapter::ReadPixelsConvert(const void *srcPixels, const Position &srcPos, uint32_t srcRowBytes, + const ImageInfo &srcInfo, void *dstPixels, uint32_t dstRowBytes, + const ImageInfo &dstInfo) +{ + // basic valid check, other parameters valid check in readPixels method + if (srcPixels == nullptr || dstPixels == nullptr) { + HiLog::Error(LABEL, "src or dst pixels invalid."); + return false; + } + SkAlphaType srcAlphaType = static_cast(srcInfo.alphaType); + SkAlphaType dstAlphaType = static_cast(dstInfo.alphaType); + SkColorType srcColorType = PixelFormatConvert(srcInfo.pixelFormat); + SkColorType dstColorType = PixelFormatConvert(dstInfo.pixelFormat); + SkImageInfo srcImageInfo = SkImageInfo::Make(srcInfo.size.width, srcInfo.size.height, srcColorType, srcAlphaType); + SkImageInfo dstImageInfo = SkImageInfo::Make(dstInfo.size.width, dstInfo.size.height, dstColorType, dstAlphaType); + + SkBitmap srcBitmap; + if (!srcBitmap.installPixels(srcImageInfo, const_cast(srcPixels), srcRowBytes)) { + HiLog::Error(LABEL, "ReadPixelsConvert src bitmap install pixels failed."); + return false; + } + if (!srcBitmap.readPixels(dstImageInfo, dstPixels, dstRowBytes, srcPos.x, srcPos.y)) { + HiLog::Error(LABEL, "ReadPixelsConvert read dst pixels from source failed."); + return false; + } + return true; +} + +bool PixelConvertAdapter::EraseBitmap(const void *srcPixels, uint32_t srcRowBytes, const ImageInfo &srcInfo, + uint32_t color) +{ + if (srcPixels == nullptr) { + HiLog::Error(LABEL, "srcPixels is null."); + return false; + } + SkAlphaType srcAlphaType = static_cast(srcInfo.alphaType); + SkColorType srcColorType = PixelFormatConvert(srcInfo.pixelFormat); + SkImageInfo srcImageInfo = SkImageInfo::Make(srcInfo.size.width, srcInfo.size.height, srcColorType, srcAlphaType); + SkBitmap srcBitmap; + if (!srcBitmap.installPixels(srcImageInfo, const_cast(srcPixels), srcRowBytes)) { + HiLog::Error(LABEL, "ReadPixelsConvert src bitmap install pixels failed."); + return false; + } + const SkColor4f skColor = SkColor4f::FromColor(color); + SkPaint paint; + paint.setColor4f(skColor, SkColorSpace::MakeSRGB().get()); + paint.setBlendMode(SkBlendMode::kSrc); + SkCanvas canvas(srcBitmap); + canvas.drawPaint(paint); + return true; +} +} // namespace Media +} // namespace OHOS diff --git a/adapter/frameworks/pixelconverter/src/pixel_map_jni_utils.cpp b/adapter/frameworks/pixelconverter/src/pixel_map_jni_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c38c616d038ba004a3d5b61d5305c142ac75166 --- /dev/null +++ b/adapter/frameworks/pixelconverter/src/pixel_map_jni_utils.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pixel_map_jni_utils.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelMapJniUtilsAdapter" +}; + +jarray PixelMapJniUtilsAdapter::GetBufferBaseArray(JNIEnv *env, jobject jbuffer) +{ + jclass nioAccessClass = env->FindClass("java/nio/NIOAccess"); + if (nioAccessClass == nullptr) { + HiLog::Error(LABEL, "GetNioBufferBaseArray nioAccessClass is null."); + return nullptr; + } + jmethodID getBaseArrayMethod = + env->GetStaticMethodID(nioAccessClass, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); + if (getBaseArrayMethod == nullptr) { + HiLog::Error(LABEL, "GetNioBufferBaseArray getBaseArrayMethod is null."); + env->DeleteLocalRef(nioAccessClass); + return nullptr; + } + jarray bufferArray = static_cast(env->CallStaticObjectMethod(nioAccessClass, getBaseArrayMethod, jbuffer)); + env->DeleteLocalRef(nioAccessClass); + return bufferArray; +} + +bool PixelMapJniUtilsAdapter::GetBufferBaseArrayOffset(JNIEnv *env, jobject jbuffer, jint &offset) +{ + jclass nioAccessClass = env->FindClass("java/nio/NIOAccess"); + if (nioAccessClass == nullptr) { + HiLog::Error(LABEL, "GetNioBufferBaseArray nioAccessClass is null."); + return false; + } + jmethodID getOffsetMethod = env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); + if (getOffsetMethod == nullptr) { + HiLog::Error(LABEL, "GetNioBufferBaseArray getOffsetMethod is null."); + env->DeleteLocalRef(nioAccessClass); + return false; + } + offset = env->CallStaticIntMethod(nioAccessClass, getOffsetMethod, jbuffer); + env->DeleteLocalRef(nioAccessClass); + return true; +} +} // namespace Media +} // namespace OHOS diff --git a/adapter/frameworks/receiver/BUILD.gn b/adapter/frameworks/receiver/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7b092ed136c3296d8393f57de296f31ca93dbef7 --- /dev/null +++ b/adapter/frameworks/receiver/BUILD.gn @@ -0,0 +1,85 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +config("imagereceiver_adapter_private_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/multimedia/image/adapter/frameworks/receiver/include/private", + ] +} + +config("imagereceiver_adapter_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/multimedia/image/adapter/frameworks/receiver/include/base", + "//foundation/multimedia/image/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/image/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//utils/native/base/include", + "//utils/jni/jnikit/include", + ] +} + +config("build_config") { + cflags = [ + "-Wno-inconsistent-missing-override", + "-Wno-thread-safety-attributes", + ] +} + +ohos_shared_library("imagereceiver_adapter") { + sources = [ + "//foundation/multimedia/image/adapter/frameworks/receiver/src/image_receiver_adapter.cpp", + "//foundation/multimedia/image/adapter/frameworks/receiver/src/image_receiver_utils.cpp", + ] + + deps = [ + "//foundation/multimedia/utils:multimedia_utils", + "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + + external_deps = [ + "graphic:libagp", + "graphic:libagp_adapter", + "hilog:libhilog", + ] + + configs = [ ":imagereceiver_adapter_private_config" ] + + public_configs = [ + ":imagereceiver_adapter_config", + ":build_config", + ] + + aosp_deps = [ + "shared_library:android.hardware.graphics.bufferqueue@1.0", + "shared_library:android.hardware.graphics.bufferqueue@2.0", + "shared_library:libbinder", + "shared_library:libcutils", + "shared_library:libgui", + "shared_library:libhidlbase", + "shared_library:libhidltransport", + "shared_library:liblog", + "shared_library:libmedia_jni_utils", + "shared_library:libmedia_omx", + "shared_library:libnativewindow", + "shared_library:libui", + "shared_library:libutils", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/frameworks/receiver/include/base/image_receiver_adapter.h b/adapter/frameworks/receiver/include/base/image_receiver_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..13b565b0da2d8638255a9f81725f2cbf7e417667 --- /dev/null +++ b/adapter/frameworks/receiver/include/base/image_receiver_adapter.h @@ -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. + */ + +#ifndef IMAGE_RECEIVER_ADAPTER_H +#define IMAGE_RECEIVER_ADAPTER_H + +#include +#include +#include "hilog/log.h" +#include "image_format.h" +#include "image_receiver_utils.h" +#include "image_type.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" + +namespace OHOS { +namespace Media { +// global jni class cache +struct ImageReceiverCache { + jfieldID nativeContext; + jmethodID onEventFromNative; // callback +} g_imageReceiverCache; + +struct ImageCache { + jfieldID nativeBuffer; + jfieldID timestamp; + jfieldID components; +} g_imageCache; + +struct ComponentCache { + jclass clazz; + jmethodID constructor; +} g_componentCache; + +struct SurfaceCache { + jclass clazz; + jmethodID constructor; +} g_surfaceCache; + +class ImageReceiverAdapter { +public: + ImageReceiverAdapter() = default; + ~ImageReceiverAdapter() = default; + static void InitImageReceiverContext(JNIEnv *env, jobject thiz, jobject weakThiz, jint width, jint height, + jint format, jint capacity, jlong usage); + static jboolean ReadNextImage(JNIEnv *env, jobject thiz, jobject image); + static void ReleaseFreeBuffers(JNIEnv *env, jobject thiz); + static void ReleaseReceiver(JNIEnv *env, jobject thiz); + static jint GetFormat(JNIEnv *env, jobject thiz, jint receiverFormat); + static Media::Size GetSize(JNIEnv *env, jobject thiz); + static jobjectArray GetComponents(JNIEnv *env, jobject thiz, jint componentNum, jint receiverFormat); + static void ReleaseImage(JNIEnv *env, jobject thiz, jobject imageReceiver); + static void CacheActiveClass(JNIEnv *env, jclass clazz); + static jobject GetSurface(JNIEnv *env, jobject thiz); + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageReceiverAdapter" + }; + static bool CacheImageClass(JNIEnv *env); + static bool CacheSurfaceClass(JNIEnv *env); + static ComponentType GetComponentType(int32_t receiverFormat, int32_t index); +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_RECEIVER_ADAPTER_H \ No newline at end of file diff --git a/adapter/frameworks/receiver/include/base/image_receiver_utils.h b/adapter/frameworks/receiver/include/base/image_receiver_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ecb18a7fb8211a74283a7f47d4ba5086230e9cad --- /dev/null +++ b/adapter/frameworks/receiver/include/base/image_receiver_utils.h @@ -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. + */ + +#ifndef IMAGE_RECEIVER_UTILS_H +#define IMAGE_RECEIVER_UTILS_H + +#include +#include +#include "hilog/log.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +class ImageReceiverUtils { +public: + static bool LogWhenNull(void *obj, const std::string &msg); + static bool ThrowExceptionWhenNull(void *obj, JNIEnv *env, const std::string &msg); + static void ThrowException(JNIEnv *env, const std::string &msg); + static std::string GetFmtMsg(const char *fmt, ...); + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageReceiverUtils" + }; +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_RECEIVER_UTILS_H \ No newline at end of file diff --git a/adapter/frameworks/receiver/include/private/image_receiver_private.h b/adapter/frameworks/receiver/include/private/image_receiver_private.h new file mode 100644 index 0000000000000000000000000000000000000000..084e92be86a61b9f1339eb8a048e9cb6c8ba1848 --- /dev/null +++ b/adapter/frameworks/receiver/include/private/image_receiver_private.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2019 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_RECEIVER_PRIVATE_H +#define IMAGE_RECEIVER_PRIVATE_H + +#include +#include +#include +#include +#include +#include +#include "agp_view/agp_ui_surface.h" +#include "hilog/log.h" +#include "image_format.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class ImageReceiverContext : public android::ConsumerBase::FrameAvailableListener { +public: + ImageReceiverContext(JNIEnv *env, jobject weakThiz, jclass clazz, int32_t capacity); + virtual ~ImageReceiverContext(); + virtual void onFrameAvailable(const android::BufferItem &item); // android virtual method + android::BufferItem *PopBufferItem(); + void PushBufferItem(android::BufferItem *buffer); + void SetBufferConsumer(const android::sp &consumer) + { + bufferConsumer_ = consumer; + } + android::BufferItemConsumer *GetBufferConsumer() + { + return bufferConsumer_.get(); + } + void SetProducer(const android::sp &producer) + { + bufferProducer_ = producer; + } + android::IGraphicBufferProducer *GetProducer() + { + return bufferProducer_.get(); + } + void SetBufferFormat(int32_t format) + { + format_ = format; + } + int32_t GetBufferFormat() const + { + return format_; + } + void SetBufferDataspace(android_dataspace dataSpace) + { + dataSpace_ = dataSpace; + } + android_dataspace GetBufferDataspace() const + { + return dataSpace_; + } + void SetBufferWidth(int32_t width) + { + width_ = width; + } + int32_t GetBufferWidth() const + { + return width_; + } + void SetBufferHeight(int32_t height) + { + height_ = height; + } + int32_t GetBufferHeight() const + { + return height_; + } + DISALLOW_COPY_AND_MOVE(ImageReceiverContext); + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageReceiverContext" + }; + android::List buffers_; + android::sp bufferConsumer_; + android::sp bufferProducer_; + jobject weakThiz_; + jclass clazz_; + int32_t width_; + int32_t height_; + android_dataspace dataSpace_; + int32_t format_; +}; + +class ImageReceiverCommon { +public: + ImageReceiverCommon() = default; + ~ImageReceiverCommon() = default; + static bool InitBufferConsumer(JNIEnv *env, android::sp context, + android::sp bufferConsumer, + android::String8 consumerName, jint width, jint height, int nativeFormat, + android_dataspace nativeDataspace); + static bool CheckNoOpaqueFormat(JNIEnv *env, android::sp context, android::BufferItem *buffer, + android::BufferItemConsumer *bufferConsumer); + static void SetNativeContext(JNIEnv *env, jobject thiz, android::sp context); + static ImageReceiverContext *GetImageReceiverContext(JNIEnv *env, jobject thiz); + static android::BufferItem *GetBufferItem(JNIEnv *env, jobject image); + static bool GetLockedImage(JNIEnv *env, jobject thiz, android::LockedImage *image); + static android::sp UnlockImageIfLocked(JNIEnv *env, jobject image); + static uint32_t GetProcessUniqueId(); + // format transform + static android::PublicFormat ConvertReceiverFormatToAndroidPublic(int32_t receiverFormat); + static ImageFormat ConvertAndroidPublicToReceiverFormat(android::PublicFormat publicFormat); + +private: + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageReceiverCommon" + }; +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_RECEIVER_PRIVATE_H \ No newline at end of file diff --git a/adapter/frameworks/receiver/src/image_receiver_adapter.cpp b/adapter/frameworks/receiver/src/image_receiver_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..479b284a0c9293cd2b6393c945acbff437731b65 --- /dev/null +++ b/adapter/frameworks/receiver/src/image_receiver_adapter.cpp @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2019 The Android Open Source Project + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_receiver_adapter.h" +#include "image_receiver_private.h" + +namespace OHOS { +namespace Media { +static constexpr int32_t DEFAULT_SIZE = -1; +static constexpr int32_t MAX_COMPONENT_NUM = 3; + +using namespace OHOS::HiviewDFX; + +void ImageReceiverAdapter::InitImageReceiverContext(JNIEnv *env, jobject thiz, jobject weakThiz, jint width, + jint height, jint format, jint capacity, jlong usage) +{ + HiLog::Debug(LABEL, + "width:%{public}d, height:%{public}d, format:%{public}d, capacity:%{public}d, " + "usage:%{public}ld.", + width, height, format, capacity, static_cast(usage)); + android::PublicFormat publicFormat = ImageReceiverCommon::ConvertReceiverFormatToAndroidPublic(format); + int nativeFormat = android::mapPublicFormatToHalFormat(publicFormat); + android_dataspace nativeDataspace = android::mapPublicFormatToHalDataspace(publicFormat); + android::sp graphicProducer; + android::sp graphicConsumer; + android::BufferQueue::createBufferQueue(&graphicProducer, &graphicConsumer); + uint64_t consumerUsage = usage; // ImageReceiver default use HardwareBuffer::USAGE_CPU_READ_OFTEN + android::sp bufferConsumer = + new (std::nothrow) android::BufferItemConsumer(graphicConsumer, consumerUsage, capacity, true); + if (bufferConsumer == nullptr) { + std::string errMsg = + ImageReceiverUtils::GetFmtMsg("allocate cumsumer buffer(format:0x%x) failed.", nativeFormat); + ImageReceiverUtils::ThrowException(env, errMsg); + return; + } + if (consumerUsage & GRALLOC_USAGE_PROTECTED) { + graphicConsumer->setConsumerIsProtected(true); + } + jclass receiverClazz = env->GetObjectClass(thiz); + if (ImageReceiverUtils::ThrowExceptionWhenNull(receiverClazz, env, "get ImageReceiver class fail.")) { + return; + } + android::sp context( + new (std::nothrow)ImageReceiverContext(env, weakThiz, receiverClazz, capacity)); + env->DeleteLocalRef(receiverClazz); + if (context == nullptr) { + ImageReceiverUtils::ThrowException(env, "allocate image receiver context memory error."); + return; + } + uint32_t uniqueId = ImageReceiverCommon::GetProcessUniqueId(); + android::String8 consumerName = android::String8::format("ImageReceiver-%dx%df%xc%d-%d-%d", width, height, format, + capacity, getpid(), uniqueId); + if (!ImageReceiverCommon::InitBufferConsumer(env, context, bufferConsumer, consumerName, width, height, + nativeFormat, nativeDataspace)) { + HiLog::Error(LABEL, "init buffer consumer failed."); + return; + } + context->SetBufferConsumer(bufferConsumer); + context->SetProducer(graphicProducer); + context->SetBufferFormat(nativeFormat); + context->SetBufferDataspace(nativeDataspace); + context->SetBufferWidth(width); + context->SetBufferHeight(height); + ImageReceiverCommon::SetNativeContext(env, thiz, context); +} + +jboolean ImageReceiverAdapter::ReadNextImage(JNIEnv *env, jobject thiz, jobject image) +{ + ImageReceiverContext *context = ImageReceiverCommon::GetImageReceiverContext(env, thiz); + if (ImageReceiverUtils::ThrowExceptionWhenNull(context, env, "ImageReceiver is not initialized or was closed.")) { + return false; + } + android::BufferItem *buffer = context->PopBufferItem(); + if (ImageReceiverUtils::LogWhenNull(buffer, "buffer item is null, maybe exceed maximum of buffers.")) { + return false; + } + android::BufferItemConsumer *bufferConsumer = context->GetBufferConsumer(); + if (ImageReceiverUtils::LogWhenNull(bufferConsumer, "buffer consumer is null.")) { + return false; + } + int32_t ret = bufferConsumer->acquireBuffer(buffer, 0); + if (ret != SUCCESS) { + context->PushBufferItem(buffer); + if (ret != android::BufferQueue::NO_BUFFER_AVAILABLE) { + if (ret == android::INVALID_OPERATION) { + HiLog::Error(LABEL, "get image exceed maximum of buffers."); + } else { + std::string errMsg = ImageReceiverUtils::GetFmtMsg("get image occurs unknown error:%d.", ret); + ImageReceiverUtils::ThrowException(env, errMsg); + } + } + return false; + } + if (!ImageReceiverCommon::CheckNoOpaqueFormat(env, context, buffer, bufferConsumer)) { + HiLog::Error(LABEL, "check no opaque format failed."); + return false; + } + // set image instance member variables + env->SetLongField(image, g_imageCache.nativeBuffer, reinterpret_cast(buffer)); + env->SetLongField(image, g_imageCache.timestamp, static_cast(buffer->mTimestamp)); + return true; +} + +void ImageReceiverAdapter::ReleaseFreeBuffers(JNIEnv *env, jobject thiz) +{ + ImageReceiverContext *context = ImageReceiverCommon::GetImageReceiverContext(env, thiz); + if (ImageReceiverUtils::ThrowExceptionWhenNull(context, env, "ImageReceiver is not initialized or was closed.")) { + return; + } + android::BufferItemConsumer *bufferConsumer = context->GetBufferConsumer(); + if (ImageReceiverUtils::ThrowExceptionWhenNull(bufferConsumer, env, "consumer buffer item is null.")) { + return; + } + int32_t ret = bufferConsumer->discardFreeBuffers(); + if (ret != SUCCESS) { + std::string errMsg = ImageReceiverUtils::GetFmtMsg("release free buffers failed:%d", ret); + ImageReceiverUtils::ThrowException(env, errMsg); + } +} + +void ImageReceiverAdapter::CacheActiveClass(JNIEnv *env, jclass clazz) +{ + if (g_componentCache.clazz != nullptr && g_surfaceCache.clazz != nullptr) { + HiLog::Debug(LABEL, "global active class was initialized."); + return; + } + // ImageReceiver mapping + g_imageReceiverCache.nativeContext = env->GetFieldID(clazz, "nativeContext", "J"); + if (ImageReceiverUtils::LogWhenNull(g_imageReceiverCache.nativeContext, + "can't find ImageReceiver.nativeContext.")) { + return; + } + g_imageReceiverCache.onEventFromNative = + env->GetStaticMethodID(clazz, "onEventFromNative", "(Ljava/lang/Object;)V"); + if (ImageReceiverUtils::LogWhenNull(g_imageReceiverCache.onEventFromNative, + "can't find ImageReceiver.onEventFromNative.")) { + return; + } + if (!CacheImageClass(env)) { + HiLog::Error(LABEL, "cache image attribute failed."); + return; + } + if (!CacheSurfaceClass(env)) { + HiLog::Error(LABEL, "cache surface attribute failed."); + return; + } +} + +bool ImageReceiverAdapter::CacheImageClass(JNIEnv *env) +{ + jclass imageClazz = env->FindClass("ohos/media/image/Image"); + if (ImageReceiverUtils::LogWhenNull(imageClazz, "find Image class fail.")) { + return false; + } + g_imageCache.nativeBuffer = env->GetFieldID(imageClazz, "nativeBuffer", "J"); + if (ImageReceiverUtils::LogWhenNull(g_imageCache.nativeBuffer, "can't find Image.nativeBuffer.")) { + env->DeleteLocalRef(imageClazz); + return false; + } + g_imageCache.timestamp = env->GetFieldID(imageClazz, "timestamp", "J"); + if (ImageReceiverUtils::LogWhenNull(g_imageCache.timestamp, "can't find Image.timestamp.")) { + env->DeleteLocalRef(imageClazz); + return false; + } + g_imageCache.components = env->GetFieldID(imageClazz, "components", "[Lohos/media/image/Image$Component;"); + if (ImageReceiverUtils::LogWhenNull(g_imageCache.components, "can't find Image.component.")) { + env->DeleteLocalRef(imageClazz); + return false; + } + // Image$Component constructor mapping + jclass componentClazz = env->FindClass("ohos/media/image/Image$Component"); + if (ImageReceiverUtils::LogWhenNull(componentClazz, "can't find Image$Component class.")) { + env->DeleteLocalRef(imageClazz); + return false; + } + g_componentCache.constructor = env->GetMethodID(componentClazz, "", "(IIILjava/nio/ByteBuffer;)V"); + if (ImageReceiverUtils::LogWhenNull(g_componentCache.constructor, "can't find Component constructor.")) { + env->DeleteLocalRef(imageClazz); + env->DeleteLocalRef(componentClazz); + return false; + } + env->DeleteLocalRef(imageClazz); + g_componentCache.clazz = reinterpret_cast(env->NewGlobalRef(componentClazz)); + return true; +} + +bool ImageReceiverAdapter::CacheSurfaceClass(JNIEnv *env) +{ + // Surface constructor mapping + jclass surfaceClazz = env->FindClass("ohos/agp/graphics/Surface"); + if (ImageReceiverUtils::LogWhenNull(surfaceClazz, "can't find Surface class.")) { + return false; + } + g_surfaceCache.constructor = env->GetMethodID(surfaceClazz, "", "(J)V"); + if (ImageReceiverUtils::LogWhenNull(g_surfaceCache.constructor, "can't find Surface constructor.")) { + env->DeleteLocalRef(surfaceClazz); + return false; + } + g_surfaceCache.clazz = reinterpret_cast(env->NewGlobalRef(surfaceClazz)); + return true; +} + +jobject ImageReceiverAdapter::GetSurface(JNIEnv *env, jobject thiz) +{ + ImageReceiverContext *context = ImageReceiverCommon::GetImageReceiverContext(env, thiz); + if (ImageReceiverUtils::ThrowExceptionWhenNull(context, env, "ImageReceiver is not initialized or was closed.")) { + return nullptr; + } + android::IGraphicBufferProducer *graphicProducer = context->GetProducer(); + if (ImageReceiverUtils::ThrowExceptionWhenNull(graphicProducer, env, "graphic buffer producer is null.")) { + return nullptr; + } + const android::sp &bufferProducer = graphicProducer; + AGP::UISurface *zSurface = new (std::nothrow) AGP::UISurface(bufferProducer, true); + if (zSurface == nullptr) { + HiLog::Error(LABEL, "create surface pointer fail."); + return nullptr; + } + jobject surfaceObj = + env->NewObject(g_surfaceCache.clazz, g_surfaceCache.constructor, reinterpret_cast(zSurface)); + if (ImageReceiverUtils::LogWhenNull(surfaceObj, "create surface jni class fail.")) { + delete zSurface; + zSurface = nullptr; + return nullptr; + } + return surfaceObj; +} + +void ImageReceiverAdapter::ReleaseReceiver(JNIEnv *env, jobject thiz) +{ + ImageReceiverContext *context = ImageReceiverCommon::GetImageReceiverContext(env, thiz); + if (ImageReceiverUtils::LogWhenNull(context, "ImageReceiver is not initialized or was closed.")) { + return; + } + android::BufferItemConsumer *consumer = context->GetBufferConsumer(); + if (consumer != nullptr) { + consumer->abandon(); + consumer->setFrameAvailableListener(nullptr); + } + ImageReceiverCommon::SetNativeContext(env, thiz, nullptr); +} + +jint ImageReceiverAdapter::GetFormat(JNIEnv *env, jobject thiz, jint receiverFormat) +{ + android::PublicFormat publicFormat = ImageReceiverCommon::ConvertReceiverFormatToAndroidPublic(receiverFormat); + if (android::isFormatOpaque(static_cast(publicFormat))) { + return static_cast(ImageFormat::UNKNOWN); + } + int32_t nativeFormat = android::mapPublicFormatToHalFormat(publicFormat); + android::BufferItem *buffer = ImageReceiverCommon::GetBufferItem(env, thiz); + if (ImageReceiverUtils::LogWhenNull(buffer, "image buffer item is null.")) { + return static_cast(ImageFormat::UNKNOWN); + } + int32_t actualFormat = android::applyFormatOverrides(buffer->mGraphicBuffer->getPixelFormat(), nativeFormat); + // override the image format to HAL_PIXEL_FORMAT_YCbCr_420_888 if the actual format is NV21 or YV12. + if (android::isPossiblyYUV(actualFormat)) { + actualFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; + } + android::PublicFormat publicFmt = android::mapHalFormatDataspaceToPublicFormat(actualFormat, buffer->mDataSpace); + ImageFormat imageFmt = ImageReceiverCommon::ConvertAndroidPublicToReceiverFormat(publicFmt); + return static_cast(imageFmt); +} + +Media::Size ImageReceiverAdapter::GetSize(JNIEnv *env, jobject thiz) +{ + Size size; + android::BufferItem *buffer = ImageReceiverCommon::GetBufferItem(env, thiz); + if (ImageReceiverUtils::LogWhenNull(buffer, "image buffer item is null.")) { + return size; + } + size.width = android::getBufferWidth(buffer); + size.height = android::getBufferHeight(buffer); + return size; +} + +jobjectArray ImageReceiverAdapter::GetComponents(JNIEnv *env, jobject thiz, jint componentNum, jint receiverFormat) +{ + android::PublicFormat publicFormat = ImageReceiverCommon::ConvertReceiverFormatToAndroidPublic(receiverFormat); + int32_t nativeFormat = android::mapPublicFormatToHalFormat(publicFormat); + if (android::isFormatOpaque(nativeFormat) && componentNum > 0) { + std::string errMsg = ImageReceiverUtils::GetFmtMsg("format 0x%x is opaque, components number %d must be 0", + nativeFormat, componentNum); + ImageReceiverUtils::ThrowException(env, errMsg); + return nullptr; + } + jobjectArray components = env->NewObjectArray(componentNum, g_componentCache.clazz, nullptr); + if (ImageReceiverUtils::ThrowExceptionWhenNull(components, env, "create components array failed.")) { + return nullptr; + } + if (android::isFormatOpaque(nativeFormat)) { + return components; // opaque components size is 0 + } + android::LockedImage lockedImage = android::LockedImage(); + if (!ImageReceiverCommon::GetLockedImage(env, thiz, &lockedImage)) { + env->DeleteLocalRef(components); + return nullptr; + } + + int32_t rowStride = 0; + int32_t pixelStride = 0; + uint8_t *dataPtr = nullptr; + uint32_t dataSize = 0; + jobject byteBuffer = nullptr; + for (int32_t index = 0; index < componentNum; index++) { + int32_t ret = android::getLockedImageInfo(&lockedImage, index, nativeFormat, &dataPtr, &dataSize, &pixelStride, + &rowStride); + if (ret != SUCCESS) { + env->DeleteLocalRef(components); + HiLog::Error(LABEL, "get lock image info error:%{public}d", ret); + return nullptr; + } + byteBuffer = env->NewDirectByteBuffer(dataPtr, dataSize); + if (byteBuffer == nullptr) { + env->DeleteLocalRef(components); + ImageReceiverUtils::ThrowException(env, "allocate byte buffer failed, maybe memory not enough."); + return nullptr; + } + int32_t componentType = static_cast(GetComponentType(receiverFormat, index)); + jobject component = env->NewObject(g_componentCache.clazz, g_componentCache.constructor, componentType, + rowStride, pixelStride, byteBuffer); + env->SetObjectArrayElement(components, index, component); + env->DeleteLocalRef(component); + env->DeleteLocalRef(byteBuffer); + } + return components; +} + +void ImageReceiverAdapter::ReleaseImage(JNIEnv *env, jobject thiz, jobject imageReceiver) +{ + ImageReceiverContext *context = ImageReceiverCommon::GetImageReceiverContext(env, imageReceiver); + if (ImageReceiverUtils::LogWhenNull(context, "maybe ImageReceiver#release called before Image#release.")) { + return; + } + android::BufferItem *buffer = ImageReceiverCommon::GetBufferItem(env, thiz); + if (ImageReceiverUtils::LogWhenNull(buffer, "image buffer item is null.")) { + return; + } + android::sp releaseFence = ImageReceiverCommon::UnlockImageIfLocked(env, thiz); + android::BufferItemConsumer *bufferConsumer = context->GetBufferConsumer(); + if (ImageReceiverUtils::LogWhenNull(buffer, "image buffer consumer is null.")) { + return; + } + bufferConsumer->releaseBuffer(*buffer, releaseFence); + env->SetLongField(thiz, g_imageCache.nativeBuffer, reinterpret_cast(nullptr)); + context->PushBufferItem(buffer); + HiLog::Debug(LABEL, "image (format:0x%{public}x) has been released.", context->GetBufferFormat()); +} + +ComponentType ImageReceiverAdapter::GetComponentType(int32_t receiverFormat, int32_t index) +{ + ImageFormat imageFormat = static_cast(receiverFormat); + ComponentType result = ComponentType::UNKNOWN; + switch (imageFormat) { + case ImageFormat::NV21: + case ImageFormat::YUV420_888: + if (index >= MAX_COMPONENT_NUM) { + break; + } + result = (index == 0) ? ComponentType::YUV_Y : ((index == 1) ? ComponentType::YUV_U : ComponentType::YUV_V); + break; + case ImageFormat::JPEG: + result = (index == 0) ? ComponentType::JPEG : ComponentType::UNKNOWN; + break; + case ImageFormat::RAW10: + result = (index == 0) ? ComponentType::RAW10 : ComponentType::UNKNOWN; + break; + case ImageFormat::RAW16: + result = (index == 0) ? ComponentType::RAW16 : ComponentType::UNKNOWN; + break; + case ImageFormat::H264: + result = (index == 0) ? ComponentType::H264 : ComponentType::UNKNOWN; + break; + case ImageFormat::H265: + result = (index == 0) ? ComponentType::H265 : ComponentType::UNKNOWN; + break; + default: + HiLog::Error(LABEL, "unknown image format:%d", receiverFormat); + break; + } + return result; +} + +ImageReceiverContext::ImageReceiverContext(JNIEnv *env, jobject weakThiz, jclass clazz, int32_t capacity) +{ + weakThiz_ = env->NewGlobalRef(weakThiz); + clazz_ = reinterpret_cast(env->NewGlobalRef(clazz)); + format_ = static_cast(ImageFormat::UNKNOWN); + dataSpace_ = HAL_DATASPACE_UNKNOWN; + width_ = DEFAULT_SIZE; + height_ = DEFAULT_SIZE; + for (int32_t i = 0; i < capacity; i++) { + android::BufferItem *buffer = new (std::nothrow) android::BufferItem; + if (buffer == nullptr) { + HiLog::Error(LABEL, "allocate buffer item %{public}d memory error.", i); + continue; + } + buffers_.push_back(buffer); + } +} + +ImageReceiverContext::~ImageReceiverContext() +{ + Jkit jkit; + JNIEnv *jniEnv = jkit.Get(); + if (jniEnv != nullptr) { + jniEnv->DeleteGlobalRef(weakThiz_); + jniEnv->DeleteGlobalRef(clazz_); + } else { + HiLog::Warn(LABEL, "leaking jni global object references."); + } + // delete buffer items + for (android::List::iterator iter = buffers_.begin(); iter != buffers_.end(); ++iter) { + delete *iter; + *iter = nullptr; + } + buffers_.clear(); + if (bufferConsumer_ != nullptr) { + bufferConsumer_.clear(); + } + bufferConsumer_ = nullptr; +} + +// android virtual method +void ImageReceiverContext::onFrameAvailable(const android::BufferItem &item) +{ + Jkit jkit; + JNIEnv *jniEnv = jkit.Get(); + if (jniEnv != nullptr) { + jniEnv->CallStaticVoidMethod(clazz_, g_imageReceiverCache.onEventFromNative, weakThiz_); + HiLog::Debug(LABEL, "onFrameAvailable event post success."); + } else { + HiLog::Warn(LABEL, "onFrameAvailable event will not post cause by jniEnv is null."); + } +} + +android::BufferItem *ImageReceiverContext::PopBufferItem() +{ + if (buffers_.empty()) { + return nullptr; + } + // return a buffer item and remove it from the list + android::List::iterator iter = buffers_.begin(); + android::BufferItem *buffer = *iter; + buffers_.erase(iter); + return buffer; +} + +void ImageReceiverContext::PushBufferItem(android::BufferItem *buffer) +{ + // clear the graphic buffer and push buffer item back to the list + buffer->mGraphicBuffer = nullptr; + buffers_.push_back(buffer); +} + +bool ImageReceiverCommon::InitBufferConsumer(JNIEnv *env, android::sp context, + android::sp bufferConsumer, + android::String8 consumerName, jint width, jint height, int nativeFormat, + android_dataspace nativeDataspace) +{ + bufferConsumer->setName(consumerName); + bufferConsumer->setFrameAvailableListener(context); + int32_t ret = bufferConsumer->setDefaultBufferSize(width, height); + if (ret != SUCCESS) { + std::string errMsg = ImageReceiverUtils::GetFmtMsg("set format 0x%x default buffer size:[%d, %d] failed:%d.", + nativeFormat, width, height, ret); + ImageReceiverUtils::ThrowException(env, errMsg); + return false; + } + ret = bufferConsumer->setDefaultBufferFormat(nativeFormat); + if (ret != SUCCESS) { + std::string errMsg = + ImageReceiverUtils::GetFmtMsg("set default buffer format 0x%x failed:%d.", nativeFormat, ret); + ImageReceiverUtils::ThrowException(env, errMsg); + return false; + } + ret = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace); + if (ret != SUCCESS) { + std::string errMsg = + ImageReceiverUtils::GetFmtMsg("set default buffer data space 0x%x failed:%d.", nativeDataspace, ret); + ImageReceiverUtils::ThrowException(env, errMsg); + return false; + } + return true; +} + +bool ImageReceiverCommon::CheckNoOpaqueFormat(JNIEnv *env, android::sp context, + android::BufferItem *buffer, android::BufferItemConsumer *bufferConsumer) +{ + if (!android::isFormatOpaque(context->GetBufferFormat())) { + android::Point point = buffer->mCrop.leftTop(); + if (point.x != 0 || point.y != 0) { + std::string errMsg = + ImageReceiverUtils::GetFmtMsg("crop left top [%d, %d] must to be at origin", point.x, point.y); + ImageReceiverUtils::ThrowException(env, errMsg); + return false; + } + // check producer buffer settings is same as image receiver settings + int32_t producerWidth = getBufferWidth(buffer); + int32_t producerHeight = getBufferHeight(buffer); + int32_t producerFormat = buffer->mGraphicBuffer->getPixelFormat(); + int32_t receiverWidth = context->GetBufferWidth(); + int32_t receiverHeight = context->GetBufferHeight(); + int32_t receiverFormat = context->GetBufferFormat(); + if ((producerFormat != HAL_PIXEL_FORMAT_BLOB) && (receiverFormat != HAL_PIXEL_FORMAT_BLOB) && + (producerWidth != receiverWidth || producerHeight != receiverHeight)) { + HiLog::Debug(LABEL, + "producer size [%{public}d, %{public}d] mismatch receiver size [%{public}d, " + "%{public}d]", + producerWidth, producerHeight, receiverWidth, receiverHeight); + } + if (producerFormat != receiverFormat) { + if (receiverFormat == HAL_PIXEL_FORMAT_YCbCr_420_888 && android::isPossiblyYUV(producerFormat)) { + HiLog::Debug(LABEL, "treat producer format 0x%{public}x as HAL_PIXEL_FORMAT_YCbCr_420_888.", + producerFormat); + } else if (receiverFormat == HAL_PIXEL_FORMAT_BLOB && producerFormat == HAL_PIXEL_FORMAT_RGBA_8888) { + HiLog::Debug(LABEL, "receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer."); + } else { + bufferConsumer->releaseBuffer(*buffer); + context->PushBufferItem(buffer); + std::string errMsg = ImageReceiverUtils::GetFmtMsg("producer format:0x%x mismatch receiver format:0x%x", + producerFormat, receiverFormat); + ImageReceiverUtils::ThrowException(env, errMsg); + return false; + } + } + } + return true; +} + +void ImageReceiverCommon::SetNativeContext(JNIEnv *env, jobject thiz, android::sp context) +{ + if (context != nullptr) { + context->incStrong(reinterpret_cast(SetNativeContext)); + env->SetLongField(thiz, g_imageReceiverCache.nativeContext, reinterpret_cast(context.get())); + } else { + ImageReceiverContext *ctx = GetImageReceiverContext(env, thiz); + if (ctx != nullptr) { + ctx->decStrong(reinterpret_cast(SetNativeContext)); + env->SetLongField(thiz, g_imageReceiverCache.nativeContext, reinterpret_cast(nullptr)); + } + } +} + +ImageReceiverContext *ImageReceiverCommon::GetImageReceiverContext(JNIEnv *env, jobject thiz) +{ + ImageReceiverContext *context = + reinterpret_cast(env->GetLongField(thiz, g_imageReceiverCache.nativeContext)); + return context; +} + +bool ImageReceiverCommon::GetLockedImage(JNIEnv *env, jobject thiz, android::LockedImage *image) +{ + android::BufferItem *buffer = GetBufferItem(env, thiz); + if (ImageReceiverUtils::ThrowExceptionWhenNull(buffer, env, "lock image buffer item is null.")) { + return false; + } + int fenceFd = buffer->mFence->dup(); + int32_t ret = android::lockImageFromBuffer(buffer, GRALLOC_USAGE_SW_READ_OFTEN, fenceFd, image); + if (ret != SUCCESS) { + ::close(fenceFd); + std::string errMsg = ImageReceiverUtils::GetFmtMsg("lock image buffer (format:0x%x) failed:%d", + buffer->mGraphicBuffer->getPixelFormat(), ret); + ImageReceiverUtils::ThrowException(env, errMsg); + return false; + } + // assignment + image->crop = buffer->mCrop; + image->timestamp = buffer->mTimestamp; + image->dataSpace = buffer->mDataSpace; + image->frameNumber = buffer->mFrameNumber; + return true; +} + +android::sp ImageReceiverCommon::UnlockImageIfLocked(JNIEnv *env, jobject image) +{ + android::BufferItem *buffer = GetBufferItem(env, image); + if (ImageReceiverUtils::ThrowExceptionWhenNull(buffer, env, "unlock image buffer item is null.")) { + return android::Fence::NO_FENCE; + } + bool isBufferLocked = false; + jobject components = nullptr; + if (!android::isFormatOpaque(buffer->mGraphicBuffer->getPixelFormat())) { + components = env->GetObjectField(image, g_imageCache.components); + } + isBufferLocked = (components != nullptr); + if (isBufferLocked) { + int32_t fenceFd = -1; + int32_t ret = buffer->mGraphicBuffer->unlockAsync(&fenceFd); + if (ret != SUCCESS) { + std::string errMsg = ImageReceiverUtils::GetFmtMsg("async unlock buffer failed:%d", ret); + ImageReceiverUtils::ThrowException(env, errMsg); + return android::Fence::NO_FENCE; + } + android::sp releaseFence = new (std::nothrow) android::Fence(fenceFd); + if (releaseFence == nullptr) { + HiLog::Error(LABEL, "allocate releaseFence memory error."); + } + return releaseFence; + } + return android::Fence::NO_FENCE; +} + +android::BufferItem *ImageReceiverCommon::GetBufferItem(JNIEnv *env, jobject image) +{ + return reinterpret_cast(env->GetLongField(image, g_imageCache.nativeBuffer)); +} + +uint32_t ImageReceiverCommon::GetProcessUniqueId() +{ + static volatile int32_t g_Counter = 0; + return android_atomic_inc(&g_Counter); +} + +// only mapping several formats supported by ImageFormat at present +android::PublicFormat ImageReceiverCommon::ConvertReceiverFormatToAndroidPublic(int32_t receiverFormat) +{ + android::PublicFormat result = android::PublicFormat::UNKNOWN; + ImageFormat imageFormat = static_cast(receiverFormat); + switch (imageFormat) { + case ImageFormat::NV21: + result = android::PublicFormat::NV21; + break; + case ImageFormat::YUV420_888: + result = android::PublicFormat::YUV_420_888; + break; + case ImageFormat::JPEG: + result = android::PublicFormat::JPEG; + break; + case ImageFormat::RAW10: + result = android::PublicFormat::RAW10; + break; + case ImageFormat::RAW16: + result = android::PublicFormat::RAW_SENSOR; + break; + case ImageFormat::H264: + result = android::PublicFormat::H264; + break; + case ImageFormat::H265: + result = android::PublicFormat::H265; + break; + default: + result = android::PublicFormat::UNKNOWN; + break; + } + return result; +} + +ImageFormat ImageReceiverCommon::ConvertAndroidPublicToReceiverFormat(android::PublicFormat publicFormat) +{ + ImageFormat result = ImageFormat::UNKNOWN; + switch (publicFormat) { + case android::PublicFormat::NV21: + result = ImageFormat::NV21; + break; + case android::PublicFormat::YUV_420_888: + result = ImageFormat::YUV420_888; + break; + case android::PublicFormat::JPEG: + result = ImageFormat::JPEG; + break; + case android::PublicFormat::RAW10: + result = ImageFormat::RAW10; + break; + case android::PublicFormat::RAW_SENSOR: + result = ImageFormat::RAW16; + break; + case android::PublicFormat::H264: + result = ImageFormat::H264; + break; + case android::PublicFormat::H265: + result = ImageFormat::H265; + break; + default: + result = ImageFormat::UNKNOWN; + break; + } + return result; +} +} // namespace Media +} // namespace OHOS diff --git a/adapter/frameworks/receiver/src/image_receiver_utils.cpp b/adapter/frameworks/receiver/src/image_receiver_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6451f1078c06505898991ff08fc967085fb8e24 --- /dev/null +++ b/adapter/frameworks/receiver/src/image_receiver_utils.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_receiver_utils.h" + +namespace OHOS { +namespace Media { +static constexpr uint32_t ERR_MSG_BUFFER_SIZE = 256; + +using namespace OHOS::HiviewDFX; + +bool ImageReceiverUtils::LogWhenNull(void *obj, const std::string &msg) +{ + if (obj != nullptr) { + return false; + } + if (!msg.empty()) { + HiLog::Error(LABEL, "%{public}s", msg.c_str()); + } + return true; +} + +bool ImageReceiverUtils::ThrowExceptionWhenNull(void *obj, JNIEnv *env, const std::string &msg) +{ + if (obj != nullptr) { + return false; + } + ThrowException(env, msg); + return true; +} + +void ImageReceiverUtils::ThrowException(JNIEnv *env, const std::string &msg) +{ + if (!msg.empty()) { + HiLog::Error(LABEL, "%{public}s", msg.c_str()); + JkitThrowIllegalStateException(env, msg.c_str()); + } +} + +std::string ImageReceiverUtils::GetFmtMsg(const char *fmt, ...) +{ + char buffer[ERR_MSG_BUFFER_SIZE] = { 0 }; + va_list args; + va_start(args, fmt); + int32_t ret = vsnprintf_s(buffer, ERR_MSG_BUFFER_SIZE, (ERR_MSG_BUFFER_SIZE - 1), fmt, args); + if (ret <= 0) { + HiLog::Error(LABEL, "fail to build format error message:%{public}d", ret); + } + va_end(args); + std::string result = buffer; + return result; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/adapter/hals/jpegdec/BUILD.gn b/adapter/hals/jpegdec/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..1aba118a93e731baa24b395e5c0657e09470ac1b --- /dev/null +++ b/adapter/hals/jpegdec/BUILD.gn @@ -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("//build/ohos.gni") + +config("jpegdec_public_config") { + visibility = [ ":*" ] + include_dirs = + [ "//foundation/multimedia/image_standard/adapter/hals/jpegdec/include" ] +} + +ohos_shared_library("jpegdec") { + sources = [ + "src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp", + "src/vendor/huawei/hardware/jpegdec/1.0/types.cpp", + ] + + defines = [ "_USING_LIBCXX" ] + + include_dirs = [ "include" ] + + public_configs = [ ":jpegdec_public_config" ] + + if (is_clang) { + cflags = [ + "-Wno-inconsistent-missing-override", + "-Wno-thread-safety-analysis", + "-Wno-thread-safety-attributes", + ] + } + + aosp_deps = [ + "shared_library:libbinder", + "shared_library:libcutils", + "shared_library:libhidlbase", + "shared_library:libhidltransport", + "shared_library:liblog", + "shared_library:libutils", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BnHwJpegDecode.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BnHwJpegDecode.h new file mode 100755 index 0000000000000000000000000000000000000000..9aba40c7925fe40a2add4278cb169bc547ef26fc --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BnHwJpegDecode.h @@ -0,0 +1,98 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BNHWJPEGDECODE_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BNHWJPEGDECODE_H + +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +struct BnHwJpegDecode : public ::android::hidl::base::V1_0::BnHwBase { + explicit BnHwJpegDecode(const ::android::sp &_hidl_impl); + explicit BnHwJpegDecode(const ::android::sp &_hidl_impl, const std::string& HidlInstrumentor_package, const std::string& HidlInstrumentor_interface); + + virtual ~BnHwJpegDecode(); + + ::android::status_t onTransact( + uint32_t _hidl_code, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + uint32_t _hidl_flags = 0, + TransactCallback _hidl_cb = nullptr) override; + + + /** + * The pure class is what this class wraps. + */ + typedef IJpegDecode Pure; + + /** + * Type tag for use in template logic that indicates this is a 'native' class. + */ + typedef android::hardware::details::bnhw_tag _hidl_tag; + + ::android::sp getImpl() { return _hidl_mImpl; } + // Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. + static ::android::status_t _hidl_DoDecode( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb); + + + static ::android::status_t _hidl_Alloc_OutBuffer( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb); + + + static ::android::status_t _hidl_Alloc_InBuffer( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb); + + + static ::android::status_t _hidl_LockDevice( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb); + + + static ::android::status_t _hidl_UnLockDevice( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb); + + + static ::android::status_t _hidl_GetDecodeStatus( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb); + + + +private: + // Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. + + // Methods from ::android::hidl::base::V1_0::IBase follow. + ::android::hardware::Return ping(); + using getDebugInfo_cb = ::android::hidl::base::V1_0::IBase::getDebugInfo_cb; + ::android::hardware::Return getDebugInfo(getDebugInfo_cb _hidl_cb); + + ::android::sp _hidl_mImpl; +}; + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BNHWJPEGDECODE_H diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BpHwJpegDecode.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BpHwJpegDecode.h new file mode 100755 index 0000000000000000000000000000000000000000..1b103478d5d58e9430b635dbc8f9afec6c9b6a52 --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BpHwJpegDecode.h @@ -0,0 +1,68 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BPHWJPEGDECODE_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BPHWJPEGDECODE_H + +#include + +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +struct BpHwJpegDecode : public ::android::hardware::BpInterface, public ::android::hardware::details::HidlInstrumentor { + explicit BpHwJpegDecode(const ::android::sp<::android::hardware::IBinder> &_hidl_impl); + + /** + * The pure class is what this class wraps. + */ + typedef IJpegDecode Pure; + + /** + * Type tag for use in template logic that indicates this is a 'proxy' class. + */ + typedef android::hardware::details::bphw_tag _hidl_tag; + + virtual bool isRemote() const override { return true; } + + // Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. + static ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> _hidl_DoDecode(::android::hardware::IInterface* _hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos); + static ::android::hardware::Return _hidl_Alloc_OutBuffer(::android::hardware::IInterface* _hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb); + static ::android::hardware::Return _hidl_Alloc_InBuffer(::android::hardware::IInterface* _hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, int32_t size, Alloc_InBuffer_cb _hidl_cb); + static ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> _hidl_LockDevice(::android::hardware::IInterface* _hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor); + static ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> _hidl_UnLockDevice(::android::hardware::IInterface* _hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor); + static ::android::hardware::Return _hidl_GetDecodeStatus(::android::hardware::IInterface* _hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, GetDecodeStatus_cb _hidl_cb); + + // Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> DoDecode(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos) override; + ::android::hardware::Return Alloc_OutBuffer(int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb) override; + ::android::hardware::Return Alloc_InBuffer(int32_t size, Alloc_InBuffer_cb _hidl_cb) override; + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> LockDevice() override; + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> UnLockDevice() override; + ::android::hardware::Return GetDecodeStatus(GetDecodeStatus_cb _hidl_cb) override; + + // Methods from ::android::hidl::base::V1_0::IBase follow. + ::android::hardware::Return interfaceChain(interfaceChain_cb _hidl_cb) override; + ::android::hardware::Return debug(const ::android::hardware::hidl_handle& fd, const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options) override; + ::android::hardware::Return interfaceDescriptor(interfaceDescriptor_cb _hidl_cb) override; + ::android::hardware::Return getHashChain(getHashChain_cb _hidl_cb) override; + ::android::hardware::Return setHALInstrumentation() override; + ::android::hardware::Return linkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient, uint64_t cookie) override; + ::android::hardware::Return ping() override; + ::android::hardware::Return getDebugInfo(getDebugInfo_cb _hidl_cb) override; + ::android::hardware::Return notifySyspropsChanged() override; + ::android::hardware::Return unlinkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient) override; + +private: + std::mutex _hidl_mMutex; + std::vector<::android::sp<::android::hardware::hidl_binder_death_recipient>> _hidl_mDeathRecipients; +}; + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BPHWJPEGDECODE_H diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BsJpegDecode.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BsJpegDecode.h new file mode 100755 index 0000000000000000000000000000000000000000..12e8dd0500ead02a93a9172b7debee96160496f9 --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/BsJpegDecode.h @@ -0,0 +1,556 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BSJPEGDECODE_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BSJPEGDECODE_H + +#include +#include +#include +#include + +#include +#include +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +struct BsJpegDecode : IJpegDecode, ::android::hardware::details::HidlInstrumentor { + explicit BsJpegDecode(const ::android::sp impl); + + /** + * The pure class is what this class wraps. + */ + typedef IJpegDecode Pure; + + typedef android::hardware::details::bs_tag _hidl_tag; + + // Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> DoDecode(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos) override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::DoDecode::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&cinfo); + _hidl_args.push_back((void *)&out_info); + _hidl_args.push_back((void *)&in_info); + _hidl_args.push_back((void *)®ion_info); + _hidl_args.push_back((void *)&samplesize); + _hidl_args.push_back((void *)&compressPos); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "DoDecode", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->DoDecode(cinfo, out_info, in_info, region_info, samplesize, compressPos); + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error = _hidl_return; + (void) _hidl_out_error; + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "DoDecode", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return Alloc_OutBuffer(int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::Alloc_OutBuffer::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&outwidth); + _hidl_args.push_back((void *)&outheight); + _hidl_args.push_back((void *)&color_format); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_OutBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->Alloc_OutBuffer(outwidth, outheight, color_format, [&](const auto &_hidl_out_error, const auto &_hidl_out_outinfo) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_outinfo); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_OutBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_error, _hidl_out_outinfo); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return Alloc_InBuffer(int32_t size, Alloc_InBuffer_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::Alloc_InBuffer::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&size); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_InBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->Alloc_InBuffer(size, [&](const auto &_hidl_out_error, const auto &_hidl_out_outinfo) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_outinfo); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_InBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_error, _hidl_out_outinfo); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> LockDevice() override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::LockDevice::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "LockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->LockDevice(); + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error = _hidl_return; + (void) _hidl_out_error; + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "LockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> UnLockDevice() override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::UnLockDevice::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "UnLockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->UnLockDevice(); + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error = _hidl_return; + (void) _hidl_out_error; + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "UnLockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return GetDecodeStatus(GetDecodeStatus_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::GetDecodeStatus::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "GetDecodeStatus", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->GetDecodeStatus([&](const auto &_hidl_out_error, const auto &_hidl_out_status) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_status); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "GetDecodeStatus", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_error, _hidl_out_status); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + + // Methods from ::android::hidl::base::V1_0::IBase follow. + ::android::hardware::Return interfaceChain(interfaceChain_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::interfaceChain::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "interfaceChain", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->interfaceChain([&](const auto &_hidl_out_descriptors) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_descriptors); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "interfaceChain", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_descriptors); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return debug(const ::android::hardware::hidl_handle& fd, const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options) override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::debug::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&fd); + _hidl_args.push_back((void *)&options); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "debug", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->debug(fd, options); + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "debug", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return interfaceDescriptor(interfaceDescriptor_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::interfaceDescriptor::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "interfaceDescriptor", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->interfaceDescriptor([&](const auto &_hidl_out_descriptor) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_descriptor); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "interfaceDescriptor", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_descriptor); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return getHashChain(getHashChain_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::getHashChain::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "getHashChain", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->getHashChain([&](const auto &_hidl_out_hashchain) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_hashchain); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "getHashChain", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_hashchain); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return setHALInstrumentation() override { + configureInstrumentation(); + return ::android::hardware::Void(); + } + + ::android::hardware::Return linkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient, uint64_t cookie) override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::linkToDeath::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&recipient); + _hidl_args.push_back((void *)&cookie); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "linkToDeath", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->linkToDeath(recipient, cookie); + + bool _hidl_out_success = _hidl_return; + (void) _hidl_out_success; + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_success); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "linkToDeath", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return ping() override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::ping::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "ping", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->ping(); + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "ping", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return getDebugInfo(getDebugInfo_cb _hidl_cb) override { + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::getDebugInfo::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "getDebugInfo", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->getDebugInfo([&](const auto &_hidl_out_info) { + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_info); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "getDebugInfo", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(_hidl_out_info); + }); + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + ::android::hardware::Return notifySyspropsChanged() override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::notifySyspropsChanged::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "notifySyspropsChanged", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = addOnewayTask([mImpl = this->mImpl + #ifdef __ANDROID_DEBUGGABLE__ + , mEnableInstrumentation = this->mEnableInstrumentation, mInstrumentationCallbacks = this->mInstrumentationCallbacks + #endif // __ANDROID_DEBUGGABLE__ + ] { + mImpl->notifySyspropsChanged(); + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "notifySyspropsChanged", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + }); + return _hidl_return; + } + ::android::hardware::Return unlinkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient) override { + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::unlinkToDeath::passthrough"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&recipient); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_ENTRY, "android.hidl.base", "1.0", "IBase", "unlinkToDeath", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Status _hidl_error = ::android::hardware::Status::ok(); + auto _hidl_return = mImpl->unlinkToDeath(recipient); + + bool _hidl_out_success = _hidl_return; + (void) _hidl_out_success; + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_success); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::PASSTHROUGH_EXIT, "android.hidl.base", "1.0", "IBase", "unlinkToDeath", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + if (!_hidl_error.isOk()) return _hidl_error; + return _hidl_return; + } + +private: + const ::android::sp mImpl; + ::android::hardware::details::TaskRunner mOnewayQueue; + + ::android::hardware::Return addOnewayTask(std::function); + +}; + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_BSJPEGDECODE_H diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IHwJpegDecode.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IHwJpegDecode.h new file mode 100755 index 0000000000000000000000000000000000000000..3f16a7f78dc48081b3eebac3df553530207b8dc9 --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IHwJpegDecode.h @@ -0,0 +1,25 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_IHWJPEGDECODE_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_IHWJPEGDECODE_H + +#include + +#include +#include +#include + +#include +#include +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_IHWJPEGDECODE_H diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h new file mode 100755 index 0000000000000000000000000000000000000000..dc8bd261b2f39b8bd3e350bb498b6faa3d058365 --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h @@ -0,0 +1,196 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_IJPEGDECODE_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_IJPEGDECODE_H + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +struct IJpegDecode : public ::android::hidl::base::V1_0::IBase { + /** + * Type tag for use in template logic that indicates this is a 'pure' class. + */ + typedef android::hardware::details::i_tag _hidl_tag; + + /** + * Fully qualified interface name: "vendor.huawei.hardware.jpegdec@1.0::IJpegDecode" + */ + static const char* descriptor; + + /** + * Returns whether this object's implementation is outside of the current process. + */ + virtual bool isRemote() const override { return false; } + + virtual ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> DoDecode(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos) = 0; + + /** + * Return callback for Alloc_OutBuffer + */ + using Alloc_OutBuffer_cb = std::function; + virtual ::android::hardware::Return Alloc_OutBuffer(int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb) = 0; + + /** + * Return callback for Alloc_InBuffer + */ + using Alloc_InBuffer_cb = std::function; + virtual ::android::hardware::Return Alloc_InBuffer(int32_t size, Alloc_InBuffer_cb _hidl_cb) = 0; + + virtual ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> LockDevice() = 0; + + virtual ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> UnLockDevice() = 0; + + /** + * Return callback for GetDecodeStatus + */ + using GetDecodeStatus_cb = std::function; + virtual ::android::hardware::Return GetDecodeStatus(GetDecodeStatus_cb _hidl_cb) = 0; + + /** + * Return callback for interfaceChain + */ + using interfaceChain_cb = std::function& descriptors)>; + virtual ::android::hardware::Return interfaceChain(interfaceChain_cb _hidl_cb) override; + + virtual ::android::hardware::Return debug(const ::android::hardware::hidl_handle& fd, const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options) override; + + /** + * Return callback for interfaceDescriptor + */ + using interfaceDescriptor_cb = std::function; + virtual ::android::hardware::Return interfaceDescriptor(interfaceDescriptor_cb _hidl_cb) override; + + /** + * Return callback for getHashChain + */ + using getHashChain_cb = std::function>& hashchain)>; + virtual ::android::hardware::Return getHashChain(getHashChain_cb _hidl_cb) override; + + virtual ::android::hardware::Return setHALInstrumentation() override; + + virtual ::android::hardware::Return linkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient, uint64_t cookie) override; + + virtual ::android::hardware::Return ping() override; + + /** + * Return callback for getDebugInfo + */ + using getDebugInfo_cb = std::function; + virtual ::android::hardware::Return getDebugInfo(getDebugInfo_cb _hidl_cb) override; + + virtual ::android::hardware::Return notifySyspropsChanged() override; + + virtual ::android::hardware::Return unlinkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient) override; + + // cast static functions + /** + * This performs a checked cast based on what the underlying implementation actually is. + */ + static ::android::hardware::Return<::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>> castFrom(const ::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>& parent, bool emitError = false); + /** + * This performs a checked cast based on what the underlying implementation actually is. + */ + static ::android::hardware::Return<::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>> castFrom(const ::android::sp<::android::hidl::base::V1_0::IBase>& parent, bool emitError = false); + + // helper methods for interactions with the hwservicemanager + /** + * This gets the service of this type with the specified instance name. If the + * service is currently not available or not in the VINTF manifest on a Trebilized + * device, this will return nullptr. This is useful when you don't want to block + * during device boot. If getStub is true, this will try to return an unwrapped + * passthrough implementation in the same process. This is useful when getting an + * implementation from the same partition/compilation group. + * + * In general, prefer getService(std::string,bool) + */ + static ::android::sp tryGetService(const std::string &serviceName="default", bool getStub=false); + /** + * Deprecated. See tryGetService(std::string, bool) + */ + static ::android::sp tryGetService(const char serviceName[], bool getStub=false) { std::string str(serviceName ? serviceName : ""); return tryGetService(str, getStub); } + /** + * Deprecated. See tryGetService(std::string, bool) + */ + static ::android::sp tryGetService(const ::android::hardware::hidl_string& serviceName, bool getStub=false) { std::string str(serviceName.c_str()); return tryGetService(str, getStub); } + /** + * Calls tryGetService("default", bool). This is the recommended instance name for singleton services. + */ + static ::android::sp tryGetService(bool getStub) { return tryGetService("default", getStub); } + /** + * This gets the service of this type with the specified instance name. If the + * service is not in the VINTF manifest on a Trebilized device, this will return + * nullptr. If the service is not available, this will wait for the service to + * become available. If the service is a lazy service, this will start the service + * and return when it becomes available. If getStub is true, this will try to + * return an unwrapped passthrough implementation in the same process. This is + * useful when getting an implementation from the same partition/compilation group. + */ + static ::android::sp getService(const std::string &serviceName="default", bool getStub=false); + /** + * Deprecated. See getService(std::string, bool) + */ + static ::android::sp getService(const char serviceName[], bool getStub=false) { std::string str(serviceName ? serviceName : ""); return getService(str, getStub); } + /** + * Deprecated. See getService(std::string, bool) + */ + static ::android::sp getService(const ::android::hardware::hidl_string& serviceName, bool getStub=false) { std::string str(serviceName.c_str()); return getService(str, getStub); } + /** + * Calls getService("default", bool). This is the recommended instance name for singleton services. + */ + static ::android::sp getService(bool getStub) { return getService("default", getStub); } + /** + * Registers a service with the service manager. For Trebilized devices, the service + * must also be in the VINTF manifest. + */ + __attribute__ ((warn_unused_result))::android::status_t registerAsService(const std::string &serviceName="default"); + /** + * Registers for notifications for when a service is registered. + */ + static bool registerForNotifications( + const std::string &serviceName, + const ::android::sp<::android::hidl::manager::V1_0::IServiceNotification> ¬ification); +}; + +// +// type declarations for package +// + +static inline std::string toString(const ::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>& o); + +// +// type header definitions for package +// + +static inline std::string toString(const ::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>& o) { + std::string os = "[class or subclass of "; + os += ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode::descriptor; + os += "]"; + os += o->isRemote() ? "@remote" : "@local"; + return os; +} + + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +// +// global type declarations for package +// + + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_IJPEGDECODE_H diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h.d b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h.d new file mode 100755 index 0000000000000000000000000000000000000000..c8207d6cabde08d100b5bb6ccaae7391caef9d2f --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/IJpegDecode.h.d @@ -0,0 +1,5 @@ +vendor/huawei/hardware/jpegdec/1.0/types.h: \ + system/libhidl/transport/base/1.0/IBase.hal \ + system/libhidl/transport/base/1.0/types.hal \ + vendor/huawei/interfaces/jpegdec/1.0/IJpegDecode.hal \ + vendor/huawei/interfaces/jpegdec/1.0/types.hal \ diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/hwtypes.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/hwtypes.h new file mode 100755 index 0000000000000000000000000000000000000000..aaf5fbc5fef8557de80d60b80f849a99cbedbdab --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/hwtypes.h @@ -0,0 +1,34 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_HWTYPES_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_HWTYPES_H + +#include + + +#include +#include +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { +::android::status_t readEmbeddedFromParcel( + const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t &obj, + const ::android::hardware::Parcel &parcel, + size_t parentHandle, + size_t parentOffset); + +::android::status_t writeEmbeddedToParcel( + const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t &obj, + ::android::hardware::Parcel *parcel, + size_t parentHandle, + size_t parentOffset); + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_HWTYPES_H diff --git a/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/types.h b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/types.h new file mode 100755 index 0000000000000000000000000000000000000000..a322550849757f87e2c80c483327ba200db55b78 --- /dev/null +++ b/adapter/hals/jpegdec/include/vendor/huawei/hardware/jpegdec/1.0/types.h @@ -0,0 +1,531 @@ +#ifndef HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_TYPES_H +#define HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_TYPES_H + +#include +#include +#include +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +// Forward declaration for forward reference support: +enum class JPEG_Error : int32_t; +struct hwdecode_region_info; +struct jpeg_quant_hidl_tbl; +struct jpeg_huff_hidl_tbl; +struct jpeg_comp_hidl_info; +struct jpeg_decompress_hidl_t; + +enum class JPEG_Error : int32_t { + NONE = 0, + BAD_DESCRIPTOR = 1, + BAD_BUFFER = 2, + BAD_VALUE = 3, + NOT_SHARED = 4, + NO_RESOURCES = 5, + UNDEFINED = 6, + UNSUPPORTED = 7, +}; + +struct hwdecode_region_info final { + int32_t left __attribute__ ((aligned(4))); + int32_t right __attribute__ ((aligned(4))); + int32_t top __attribute__ ((aligned(4))); + int32_t bottom __attribute__ ((aligned(4))); + int32_t flag __attribute__ ((aligned(4))); + int32_t rsv __attribute__ ((aligned(4))); +}; + +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info, left) == 0, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info, right) == 4, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info, top) == 8, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info, bottom) == 12, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info, flag) == 16, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info, rsv) == 20, "wrong offset"); +static_assert(sizeof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info) == 24, "wrong size"); +static_assert(__alignof(::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info) == 4, "wrong alignment"); + +struct jpeg_quant_hidl_tbl final { + ::android::hardware::hidl_array quantval __attribute__ ((aligned(2))); + bool table_flag __attribute__ ((aligned(1))); +}; + +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl, quantval) == 0, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl, table_flag) == 128, "wrong offset"); +static_assert(sizeof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl) == 130, "wrong size"); +static_assert(__alignof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl) == 2, "wrong alignment"); + +struct jpeg_huff_hidl_tbl final { + ::android::hardware::hidl_array bits __attribute__ ((aligned(1))); + ::android::hardware::hidl_array huffval __attribute__ ((aligned(1))); + bool table_flag __attribute__ ((aligned(1))); +}; + +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl, bits) == 0, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl, huffval) == 17, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl, table_flag) == 273, "wrong offset"); +static_assert(sizeof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl) == 274, "wrong size"); +static_assert(__alignof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl) == 1, "wrong alignment"); + +struct jpeg_comp_hidl_info final { + int32_t component_id __attribute__ ((aligned(4))); + int32_t component_index __attribute__ ((aligned(4))); + int32_t h_samp_factor __attribute__ ((aligned(4))); + int32_t v_samp_factor __attribute__ ((aligned(4))); + int32_t quant_tbl_no __attribute__ ((aligned(4))); + int32_t dc_tbl_no __attribute__ ((aligned(4))); + int32_t ac_tbl_no __attribute__ ((aligned(4))); + bool info_flag __attribute__ ((aligned(1))); +}; + +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, component_id) == 0, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, component_index) == 4, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, h_samp_factor) == 8, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, v_samp_factor) == 12, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, quant_tbl_no) == 16, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, dc_tbl_no) == 20, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, ac_tbl_no) == 24, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info, info_flag) == 28, "wrong offset"); +static_assert(sizeof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info) == 32, "wrong size"); +static_assert(__alignof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info) == 4, "wrong alignment"); + +struct jpeg_decompress_hidl_t final { + uint32_t image_width __attribute__ ((aligned(4))); + uint32_t image_height __attribute__ ((aligned(4))); + int32_t data_precision __attribute__ ((aligned(4))); + int32_t num_components __attribute__ ((aligned(4))); + uint32_t restart_interval __attribute__ ((aligned(4))); + bool arith_code __attribute__ ((aligned(1))); + bool progressive_mode __attribute__ ((aligned(1))); + ::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info> comp_info __attribute__ ((aligned(8))); + ::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl> dc_huff_tbl_ptrs __attribute__ ((aligned(8))); + ::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl> ac_huff_tbl_ptrs __attribute__ ((aligned(8))); + ::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl> quant_tbl_ptrs __attribute__ ((aligned(8))); +}; + +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, image_width) == 0, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, image_height) == 4, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, data_precision) == 8, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, num_components) == 12, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, restart_interval) == 16, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, arith_code) == 20, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, progressive_mode) == 21, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, comp_info) == 24, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, dc_huff_tbl_ptrs) == 40, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, ac_huff_tbl_ptrs) == 56, "wrong offset"); +static_assert(offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, quant_tbl_ptrs) == 72, "wrong offset"); +static_assert(sizeof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t) == 88, "wrong size"); +static_assert(__alignof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t) == 8, "wrong alignment"); + +// +// type declarations for package +// + +template +static inline std::string toString(int32_t o); +static inline std::string toString(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error o); + +constexpr int32_t operator|(const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error rhs) { + return static_cast(static_cast(lhs) | static_cast(rhs)); +} +constexpr int32_t operator|(const int32_t lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error rhs) { + return static_cast(lhs | static_cast(rhs)); +} +constexpr int32_t operator|(const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error lhs, const int32_t rhs) { + return static_cast(static_cast(lhs) | rhs); +} +constexpr int32_t operator&(const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error rhs) { + return static_cast(static_cast(lhs) & static_cast(rhs)); +} +constexpr int32_t operator&(const int32_t lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error rhs) { + return static_cast(lhs & static_cast(rhs)); +} +constexpr int32_t operator&(const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error lhs, const int32_t rhs) { + return static_cast(static_cast(lhs) & rhs); +} +constexpr int32_t &operator|=(int32_t& v, const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error e) { + v |= static_cast(e); + return v; +} +constexpr int32_t &operator&=(int32_t& v, const ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error e) { + v &= static_cast(e); + return v; +} + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& o); +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& rhs); +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& rhs); + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& o); +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& rhs); +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& rhs); + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& o); +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& rhs); +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& rhs); + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& o); +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& rhs); +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& rhs); + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& o); +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& rhs); +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& rhs); + +// +// type header definitions for package +// + +template<> +inline std::string toString<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(int32_t o) { + using ::android::hardware::details::toHexString; + std::string os; + ::android::hardware::hidl_bitfield<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> flipped = 0; + bool first = true; + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NONE) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NONE)) { + os += (first ? "" : " | "); + os += "NONE"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NONE; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_DESCRIPTOR) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_DESCRIPTOR)) { + os += (first ? "" : " | "); + os += "BAD_DESCRIPTOR"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_DESCRIPTOR; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_BUFFER) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_BUFFER)) { + os += (first ? "" : " | "); + os += "BAD_BUFFER"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_BUFFER; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_VALUE) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_VALUE)) { + os += (first ? "" : " | "); + os += "BAD_VALUE"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_VALUE; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NOT_SHARED) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NOT_SHARED)) { + os += (first ? "" : " | "); + os += "NOT_SHARED"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NOT_SHARED; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NO_RESOURCES) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NO_RESOURCES)) { + os += (first ? "" : " | "); + os += "NO_RESOURCES"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NO_RESOURCES; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNDEFINED) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNDEFINED)) { + os += (first ? "" : " | "); + os += "UNDEFINED"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNDEFINED; + } + if ((o & ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNSUPPORTED) == static_cast(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNSUPPORTED)) { + os += (first ? "" : " | "); + os += "UNSUPPORTED"; + first = false; + flipped |= ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNSUPPORTED; + } + if (o != flipped) { + os += (first ? "" : " | "); + os += toHexString(o & (~flipped)); + }os += " ("; + os += toHexString(o); + os += ")"; + return os; +} + +static inline std::string toString(::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error o) { + using ::android::hardware::details::toHexString; + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NONE) { + return "NONE"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_DESCRIPTOR) { + return "BAD_DESCRIPTOR"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_BUFFER) { + return "BAD_BUFFER"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_VALUE) { + return "BAD_VALUE"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NOT_SHARED) { + return "NOT_SHARED"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NO_RESOURCES) { + return "NO_RESOURCES"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNDEFINED) { + return "UNDEFINED"; + } + if (o == ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNSUPPORTED) { + return "UNSUPPORTED"; + } + std::string os; + os += toHexString(static_cast(o)); + return os; +} + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& o) { + using ::android::hardware::toString; + std::string os; + os += "{"; + os += ".left = "; + os += ::android::hardware::toString(o.left); + os += ", .right = "; + os += ::android::hardware::toString(o.right); + os += ", .top = "; + os += ::android::hardware::toString(o.top); + os += ", .bottom = "; + os += ::android::hardware::toString(o.bottom); + os += ", .flag = "; + os += ::android::hardware::toString(o.flag); + os += ", .rsv = "; + os += ::android::hardware::toString(o.rsv); + os += "}"; return os; +} + +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& rhs) { + if (lhs.left != rhs.left) { + return false; + } + if (lhs.right != rhs.right) { + return false; + } + if (lhs.top != rhs.top) { + return false; + } + if (lhs.bottom != rhs.bottom) { + return false; + } + if (lhs.flag != rhs.flag) { + return false; + } + if (lhs.rsv != rhs.rsv) { + return false; + } + return true; +} + +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& rhs){ + return !(lhs == rhs); +} + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& o) { + using ::android::hardware::toString; + std::string os; + os += "{"; + os += ".quantval = "; + os += ::android::hardware::toString(o.quantval); + os += ", .table_flag = "; + os += ::android::hardware::toString(o.table_flag); + os += "}"; return os; +} + +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& rhs) { + if (lhs.quantval != rhs.quantval) { + return false; + } + if (lhs.table_flag != rhs.table_flag) { + return false; + } + return true; +} + +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl& rhs){ + return !(lhs == rhs); +} + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& o) { + using ::android::hardware::toString; + std::string os; + os += "{"; + os += ".bits = "; + os += ::android::hardware::toString(o.bits); + os += ", .huffval = "; + os += ::android::hardware::toString(o.huffval); + os += ", .table_flag = "; + os += ::android::hardware::toString(o.table_flag); + os += "}"; return os; +} + +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& rhs) { + if (lhs.bits != rhs.bits) { + return false; + } + if (lhs.huffval != rhs.huffval) { + return false; + } + if (lhs.table_flag != rhs.table_flag) { + return false; + } + return true; +} + +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl& rhs){ + return !(lhs == rhs); +} + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& o) { + using ::android::hardware::toString; + std::string os; + os += "{"; + os += ".component_id = "; + os += ::android::hardware::toString(o.component_id); + os += ", .component_index = "; + os += ::android::hardware::toString(o.component_index); + os += ", .h_samp_factor = "; + os += ::android::hardware::toString(o.h_samp_factor); + os += ", .v_samp_factor = "; + os += ::android::hardware::toString(o.v_samp_factor); + os += ", .quant_tbl_no = "; + os += ::android::hardware::toString(o.quant_tbl_no); + os += ", .dc_tbl_no = "; + os += ::android::hardware::toString(o.dc_tbl_no); + os += ", .ac_tbl_no = "; + os += ::android::hardware::toString(o.ac_tbl_no); + os += ", .info_flag = "; + os += ::android::hardware::toString(o.info_flag); + os += "}"; return os; +} + +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& rhs) { + if (lhs.component_id != rhs.component_id) { + return false; + } + if (lhs.component_index != rhs.component_index) { + return false; + } + if (lhs.h_samp_factor != rhs.h_samp_factor) { + return false; + } + if (lhs.v_samp_factor != rhs.v_samp_factor) { + return false; + } + if (lhs.quant_tbl_no != rhs.quant_tbl_no) { + return false; + } + if (lhs.dc_tbl_no != rhs.dc_tbl_no) { + return false; + } + if (lhs.ac_tbl_no != rhs.ac_tbl_no) { + return false; + } + if (lhs.info_flag != rhs.info_flag) { + return false; + } + return true; +} + +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info& rhs){ + return !(lhs == rhs); +} + +static inline std::string toString(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& o) { + using ::android::hardware::toString; + std::string os; + os += "{"; + os += ".image_width = "; + os += ::android::hardware::toString(o.image_width); + os += ", .image_height = "; + os += ::android::hardware::toString(o.image_height); + os += ", .data_precision = "; + os += ::android::hardware::toString(o.data_precision); + os += ", .num_components = "; + os += ::android::hardware::toString(o.num_components); + os += ", .restart_interval = "; + os += ::android::hardware::toString(o.restart_interval); + os += ", .arith_code = "; + os += ::android::hardware::toString(o.arith_code); + os += ", .progressive_mode = "; + os += ::android::hardware::toString(o.progressive_mode); + os += ", .comp_info = "; + os += ::android::hardware::toString(o.comp_info); + os += ", .dc_huff_tbl_ptrs = "; + os += ::android::hardware::toString(o.dc_huff_tbl_ptrs); + os += ", .ac_huff_tbl_ptrs = "; + os += ::android::hardware::toString(o.ac_huff_tbl_ptrs); + os += ", .quant_tbl_ptrs = "; + os += ::android::hardware::toString(o.quant_tbl_ptrs); + os += "}"; return os; +} + +static inline bool operator==(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& rhs) { + if (lhs.image_width != rhs.image_width) { + return false; + } + if (lhs.image_height != rhs.image_height) { + return false; + } + if (lhs.data_precision != rhs.data_precision) { + return false; + } + if (lhs.num_components != rhs.num_components) { + return false; + } + if (lhs.restart_interval != rhs.restart_interval) { + return false; + } + if (lhs.arith_code != rhs.arith_code) { + return false; + } + if (lhs.progressive_mode != rhs.progressive_mode) { + return false; + } + if (lhs.comp_info != rhs.comp_info) { + return false; + } + if (lhs.dc_huff_tbl_ptrs != rhs.dc_huff_tbl_ptrs) { + return false; + } + if (lhs.ac_huff_tbl_ptrs != rhs.ac_huff_tbl_ptrs) { + return false; + } + if (lhs.quant_tbl_ptrs != rhs.quant_tbl_ptrs) { + return false; + } + return true; +} + +static inline bool operator!=(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& lhs, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& rhs){ + return !(lhs == rhs); +} + + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor + +// +// global type declarations for package +// + +namespace android { +namespace hardware { +namespace details { +template<> constexpr std::array<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error, 8> hidl_enum_values<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> = { + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NONE, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_DESCRIPTOR, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_BUFFER, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::BAD_VALUE, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NOT_SHARED, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::NO_RESOURCES, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNDEFINED, + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error::UNSUPPORTED, +}; +} // namespace details +} // namespace hardware +} // namespace android + + +#endif // HIDL_GENERATED_VENDOR_HUAWEI_HARDWARE_JPEGDEC_V1_0_TYPES_H diff --git a/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp b/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp new file mode 100755 index 0000000000000000000000000000000000000000..ffe6c61167d46254484381257817a35aa4aec3f9 --- /dev/null +++ b/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp @@ -0,0 +1,1258 @@ +#define LOG_TAG "vendor.huawei.hardware.jpegdec@1.0::JpegDecode" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +const char* IJpegDecode::descriptor("vendor.huawei.hardware.jpegdec@1.0::IJpegDecode"); + +__attribute__((constructor)) static void static_constructor() { + ::android::hardware::details::getBnConstructorMap().set(IJpegDecode::descriptor, + [](void *iIntf) -> ::android::sp<::android::hardware::IBinder> { + return new BnHwJpegDecode(static_cast(iIntf)); + }); + ::android::hardware::details::getBsConstructorMap().set(IJpegDecode::descriptor, + [](void *iIntf) -> ::android::sp<::android::hidl::base::V1_0::IBase> { + return new BsJpegDecode(static_cast(iIntf)); + }); +}; + +__attribute__((destructor))static void static_destructor() { + ::android::hardware::details::getBnConstructorMap().erase(IJpegDecode::descriptor); + ::android::hardware::details::getBsConstructorMap().erase(IJpegDecode::descriptor); +}; + +// Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. +// no default implementation for: ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> IJpegDecode::DoDecode(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos) +// no default implementation for: ::android::hardware::Return IJpegDecode::Alloc_OutBuffer(int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb) +// no default implementation for: ::android::hardware::Return IJpegDecode::Alloc_InBuffer(int32_t size, Alloc_InBuffer_cb _hidl_cb) +// no default implementation for: ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> IJpegDecode::LockDevice() +// no default implementation for: ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> IJpegDecode::UnLockDevice() +// no default implementation for: ::android::hardware::Return IJpegDecode::GetDecodeStatus(GetDecodeStatus_cb _hidl_cb) + +// Methods from ::android::hidl::base::V1_0::IBase follow. +::android::hardware::Return IJpegDecode::interfaceChain(interfaceChain_cb _hidl_cb){ + _hidl_cb({ + ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode::descriptor, + ::android::hidl::base::V1_0::IBase::descriptor, + }); + return ::android::hardware::Void();} + +::android::hardware::Return IJpegDecode::debug(const ::android::hardware::hidl_handle& fd, const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options){ + (void)fd; + (void)options; + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::interfaceDescriptor(interfaceDescriptor_cb _hidl_cb){ + _hidl_cb(::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode::descriptor); + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::getHashChain(getHashChain_cb _hidl_cb){ + _hidl_cb({ + (uint8_t[32]){106,196,221,203,183,4,97,68,117,94,171,142,124,114,121,135,32,10,117,144,123,3,84,127,151,107,34,165,17,3,223,187} /* 6ac4ddcbb7046144755eab8e7c727987200a75907b03547f976b22a51103dfbb */, + (uint8_t[32]){236,127,215,158,208,45,250,133,188,73,148,38,173,174,62,190,35,239,5,36,243,205,105,87,19,147,36,184,59,24,202,76} /* ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c */}); + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::setHALInstrumentation(){ + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::linkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient, uint64_t cookie){ + (void)cookie; + return (recipient != nullptr); +} + +::android::hardware::Return IJpegDecode::ping(){ + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::getDebugInfo(getDebugInfo_cb _hidl_cb){ + ::android::hidl::base::V1_0::DebugInfo info = {}; + info.pid = -1; + info.ptr = 0; + info.arch = + #if defined(__LP64__) + ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT + #else + ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT + #endif + ; + _hidl_cb(info); + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::notifySyspropsChanged(){ + ::android::report_sysprop_change(); + return ::android::hardware::Void(); +} + +::android::hardware::Return IJpegDecode::unlinkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient){ + return (recipient != nullptr); +} + + +::android::hardware::Return<::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>> IJpegDecode::castFrom(const ::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>& parent, bool /* emitError */) { + return parent; +} + +::android::hardware::Return<::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode>> IJpegDecode::castFrom(const ::android::sp<::android::hidl::base::V1_0::IBase>& parent, bool emitError) { + return ::android::hardware::details::castInterface( + parent, "vendor.huawei.hardware.jpegdec@1.0::IJpegDecode", emitError); +} + +BpHwJpegDecode::BpHwJpegDecode(const ::android::sp<::android::hardware::IBinder> &_hidl_impl) + : BpInterface(_hidl_impl), + ::android::hardware::details::HidlInstrumentor("vendor.huawei.hardware.jpegdec@1.0", "IJpegDecode") { +} + +// Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. +::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> BpHwJpegDecode::_hidl_DoDecode(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks(); + #else + (void) _hidl_this_instrumentor; + #endif // __ANDROID_DEBUGGABLE__ + ::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, "HIDL::IJpegDecode::DoDecode::client"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&cinfo); + _hidl_args.push_back((void *)&out_info); + _hidl_args.push_back((void *)&in_info); + _hidl_args.push_back((void *)®ion_info); + _hidl_args.push_back((void *)&samplesize); + _hidl_args.push_back((void *)&compressPos); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "DoDecode", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Parcel _hidl_data; + ::android::hardware::Parcel _hidl_reply; + ::android::status_t _hidl_err; + ::android::hardware::Status _hidl_status; + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error; + + _hidl_err = _hidl_data.writeInterfaceToken(BpHwJpegDecode::descriptor); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + size_t _hidl_cinfo_parent; + + _hidl_err = _hidl_data.writeBuffer(&cinfo, sizeof(cinfo), &_hidl_cinfo_parent); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = writeEmbeddedToParcel( + cinfo, + &_hidl_data, + _hidl_cinfo_parent, + 0 /* parentOffset */); + + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeNativeHandleNoDup(out_info); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeNativeHandleNoDup(in_info); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + size_t _hidl_region_info_parent; + + _hidl_err = _hidl_data.writeBuffer(®ion_info, sizeof(region_info), &_hidl_region_info_parent); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeInt32(samplesize); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeInt32(compressPos); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(1 /* DoDecode */, _hidl_data, &_hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + if (!_hidl_status.isOk()) { return _hidl_status; } + + _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "DoDecode", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(_hidl_out_error); + +_hidl_error: + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(_hidl_status); +} + +::android::hardware::Return BpHwJpegDecode::_hidl_Alloc_OutBuffer(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks(); + #else + (void) _hidl_this_instrumentor; + #endif // __ANDROID_DEBUGGABLE__ + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + ::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, "HIDL::IJpegDecode::Alloc_OutBuffer::client"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&outwidth); + _hidl_args.push_back((void *)&outheight); + _hidl_args.push_back((void *)&color_format); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_OutBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Parcel _hidl_data; + ::android::hardware::Parcel _hidl_reply; + ::android::status_t _hidl_err; + ::android::hardware::Status _hidl_status; + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error; + ::android::hardware::hidl_handle _hidl_out_outinfo; + + _hidl_err = _hidl_data.writeInterfaceToken(BpHwJpegDecode::descriptor); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeInt32(outwidth); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeInt32(outheight); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeInt32(color_format); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(2 /* Alloc_OutBuffer */, _hidl_data, &_hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + if (!_hidl_status.isOk()) { return _hidl_status; } + + _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + const native_handle_t *_hidl_out_outinfo_ptr; + + _hidl_err = _hidl_reply.readNullableNativeHandleNoDup(&_hidl_out_outinfo_ptr); + + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_out_outinfo = _hidl_out_outinfo_ptr; + _hidl_cb(_hidl_out_error, _hidl_out_outinfo); + + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_outinfo); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_OutBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return(); + +_hidl_error: + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return(_hidl_status); +} + +::android::hardware::Return BpHwJpegDecode::_hidl_Alloc_InBuffer(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, int32_t size, Alloc_InBuffer_cb _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks(); + #else + (void) _hidl_this_instrumentor; + #endif // __ANDROID_DEBUGGABLE__ + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + ::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, "HIDL::IJpegDecode::Alloc_InBuffer::client"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&size); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_InBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Parcel _hidl_data; + ::android::hardware::Parcel _hidl_reply; + ::android::status_t _hidl_err; + ::android::hardware::Status _hidl_status; + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error; + ::android::hardware::hidl_handle _hidl_out_outinfo; + + _hidl_err = _hidl_data.writeInterfaceToken(BpHwJpegDecode::descriptor); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_data.writeInt32(size); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(3 /* Alloc_InBuffer */, _hidl_data, &_hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + if (!_hidl_status.isOk()) { return _hidl_status; } + + _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + const native_handle_t *_hidl_out_outinfo_ptr; + + _hidl_err = _hidl_reply.readNullableNativeHandleNoDup(&_hidl_out_outinfo_ptr); + + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_out_outinfo = _hidl_out_outinfo_ptr; + _hidl_cb(_hidl_out_error, _hidl_out_outinfo); + + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_outinfo); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_InBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return(); + +_hidl_error: + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return(_hidl_status); +} + +::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> BpHwJpegDecode::_hidl_LockDevice(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks(); + #else + (void) _hidl_this_instrumentor; + #endif // __ANDROID_DEBUGGABLE__ + ::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, "HIDL::IJpegDecode::LockDevice::client"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "LockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Parcel _hidl_data; + ::android::hardware::Parcel _hidl_reply; + ::android::status_t _hidl_err; + ::android::hardware::Status _hidl_status; + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error; + + _hidl_err = _hidl_data.writeInterfaceToken(BpHwJpegDecode::descriptor); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(4 /* LockDevice */, _hidl_data, &_hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + if (!_hidl_status.isOk()) { return _hidl_status; } + + _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "LockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(_hidl_out_error); + +_hidl_error: + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(_hidl_status); +} + +::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> BpHwJpegDecode::_hidl_UnLockDevice(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks(); + #else + (void) _hidl_this_instrumentor; + #endif // __ANDROID_DEBUGGABLE__ + ::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, "HIDL::IJpegDecode::UnLockDevice::client"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "UnLockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Parcel _hidl_data; + ::android::hardware::Parcel _hidl_reply; + ::android::status_t _hidl_err; + ::android::hardware::Status _hidl_status; + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error; + + _hidl_err = _hidl_data.writeInterfaceToken(BpHwJpegDecode::descriptor); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(5 /* UnLockDevice */, _hidl_data, &_hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + if (!_hidl_status.isOk()) { return _hidl_status; } + + _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "UnLockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(_hidl_out_error); + +_hidl_error: + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error>(_hidl_status); +} + +::android::hardware::Return BpHwJpegDecode::_hidl_GetDecodeStatus(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, GetDecodeStatus_cb _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks(); + #else + (void) _hidl_this_instrumentor; + #endif // __ANDROID_DEBUGGABLE__ + if (_hidl_cb == nullptr) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_ILLEGAL_ARGUMENT, + "Null synchronous callback passed."); + } + + ::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, "HIDL::IJpegDecode::GetDecodeStatus::client"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "GetDecodeStatus", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::android::hardware::Parcel _hidl_data; + ::android::hardware::Parcel _hidl_reply; + ::android::status_t _hidl_err; + ::android::hardware::Status _hidl_status; + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error; + bool _hidl_out_status; + + _hidl_err = _hidl_data.writeInterfaceToken(BpHwJpegDecode::descriptor); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(6 /* GetDecodeStatus */, _hidl_data, &_hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + if (!_hidl_status.isOk()) { return _hidl_status; } + + _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_error); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_err = _hidl_reply.readBool(&_hidl_out_status); + if (_hidl_err != ::android::OK) { goto _hidl_error; } + + _hidl_cb(_hidl_out_error, _hidl_out_status); + + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_status); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::CLIENT_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "GetDecodeStatus", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return(); + +_hidl_error: + _hidl_status.setFromStatusT(_hidl_err); + return ::android::hardware::Return(_hidl_status); +} + + +// Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. +::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> BpHwJpegDecode::DoDecode(const ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t& cinfo, const ::android::hardware::hidl_handle& out_info, const ::android::hardware::hidl_handle& in_info, const ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info& region_info, int32_t samplesize, int32_t compressPos){ + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> _hidl_out = ::vendor::huawei::hardware::jpegdec::V1_0::BpHwJpegDecode::_hidl_DoDecode(this, this, cinfo, out_info, in_info, region_info, samplesize, compressPos); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::Alloc_OutBuffer(int32_t outwidth, int32_t outheight, int32_t color_format, Alloc_OutBuffer_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::vendor::huawei::hardware::jpegdec::V1_0::BpHwJpegDecode::_hidl_Alloc_OutBuffer(this, this, outwidth, outheight, color_format, _hidl_cb); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::Alloc_InBuffer(int32_t size, Alloc_InBuffer_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::vendor::huawei::hardware::jpegdec::V1_0::BpHwJpegDecode::_hidl_Alloc_InBuffer(this, this, size, _hidl_cb); + + return _hidl_out; +} + +::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> BpHwJpegDecode::LockDevice(){ + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> _hidl_out = ::vendor::huawei::hardware::jpegdec::V1_0::BpHwJpegDecode::_hidl_LockDevice(this, this); + + return _hidl_out; +} + +::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> BpHwJpegDecode::UnLockDevice(){ + ::android::hardware::Return<::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error> _hidl_out = ::vendor::huawei::hardware::jpegdec::V1_0::BpHwJpegDecode::_hidl_UnLockDevice(this, this); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::GetDecodeStatus(GetDecodeStatus_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::vendor::huawei::hardware::jpegdec::V1_0::BpHwJpegDecode::_hidl_GetDecodeStatus(this, this, _hidl_cb); + + return _hidl_out; +} + + +// Methods from ::android::hidl::base::V1_0::IBase follow. +::android::hardware::Return BpHwJpegDecode::interfaceChain(interfaceChain_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_interfaceChain(this, this, _hidl_cb); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::debug(const ::android::hardware::hidl_handle& fd, const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_debug(this, this, fd, options); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::interfaceDescriptor(interfaceDescriptor_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_interfaceDescriptor(this, this, _hidl_cb); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::getHashChain(getHashChain_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_getHashChain(this, this, _hidl_cb); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::setHALInstrumentation(){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_setHALInstrumentation(this, this); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::linkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient, uint64_t cookie){ + ::android::hardware::ProcessState::self()->startThreadPool(); + ::android::hardware::hidl_binder_death_recipient *binder_recipient = new ::android::hardware::hidl_binder_death_recipient(recipient, cookie, this); + std::unique_lock lock(_hidl_mMutex); + _hidl_mDeathRecipients.push_back(binder_recipient); + return (remote()->linkToDeath(binder_recipient) == ::android::OK); +} + +::android::hardware::Return BpHwJpegDecode::ping(){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_ping(this, this); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::getDebugInfo(getDebugInfo_cb _hidl_cb){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_getDebugInfo(this, this, _hidl_cb); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::notifySyspropsChanged(){ + ::android::hardware::Return _hidl_out = ::android::hidl::base::V1_0::BpHwBase::_hidl_notifySyspropsChanged(this, this); + + return _hidl_out; +} + +::android::hardware::Return BpHwJpegDecode::unlinkToDeath(const ::android::sp<::android::hardware::hidl_death_recipient>& recipient){ + std::unique_lock lock(_hidl_mMutex); + for (auto it = _hidl_mDeathRecipients.rbegin();it != _hidl_mDeathRecipients.rend();++it) { + if ((*it)->getRecipient() == recipient) { + ::android::status_t status = remote()->unlinkToDeath(*it); + _hidl_mDeathRecipients.erase(it.base()-1); + return status == ::android::OK; + } + } + return false; +} + + +BnHwJpegDecode::BnHwJpegDecode(const ::android::sp &_hidl_impl) + : ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "vendor.huawei.hardware.jpegdec@1.0", "IJpegDecode") { + _hidl_mImpl = _hidl_impl; + auto prio = ::android::hardware::details::gServicePrioMap->get(_hidl_impl, {SCHED_NORMAL, 0}); + mSchedPolicy = prio.sched_policy; + mSchedPriority = prio.prio; + setRequestingSid(::android::hardware::details::gServiceSidMap->get(_hidl_impl, false)); +} + +BnHwJpegDecode::~BnHwJpegDecode() { + ::android::hardware::details::gBnMap->eraseIfEqual(_hidl_mImpl.get(), this); +} + +// Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. +::android::status_t BnHwJpegDecode::_hidl_DoDecode( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks(); + #endif // __ANDROID_DEBUGGABLE__ + + ::android::status_t _hidl_err = ::android::OK; + if (!_hidl_data.enforceInterface(BnHwJpegDecode::Pure::descriptor)) { + _hidl_err = ::android::BAD_TYPE; + return _hidl_err; + } + + ::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t* cinfo; + ::android::hardware::hidl_handle out_info; + ::android::hardware::hidl_handle in_info; + ::vendor::huawei::hardware::jpegdec::V1_0::hwdecode_region_info* region_info; + int32_t samplesize; + int32_t compressPos; + + size_t _hidl_cinfo_parent; + + _hidl_err = _hidl_data.readBuffer(sizeof(*cinfo), &_hidl_cinfo_parent, const_cast(reinterpret_cast(&cinfo))); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + _hidl_err = readEmbeddedFromParcel( + const_cast<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t &>(*cinfo), + _hidl_data, + _hidl_cinfo_parent, + 0 /* parentOffset */); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + const native_handle_t *out_info_ptr; + + _hidl_err = _hidl_data.readNullableNativeHandleNoDup(&out_info_ptr); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + out_info = out_info_ptr; + const native_handle_t *in_info_ptr; + + _hidl_err = _hidl_data.readNullableNativeHandleNoDup(&in_info_ptr); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + in_info = in_info_ptr; + size_t _hidl_region_info_parent; + + _hidl_err = _hidl_data.readBuffer(sizeof(*region_info), &_hidl_region_info_parent, const_cast(reinterpret_cast(®ion_info))); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + _hidl_err = _hidl_data.readInt32(&samplesize); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + _hidl_err = _hidl_data.readInt32(&compressPos); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::DoDecode::server"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)cinfo); + _hidl_args.push_back((void *)&out_info); + _hidl_args.push_back((void *)&in_info); + _hidl_args.push_back((void *)region_info); + _hidl_args.push_back((void *)&samplesize); + _hidl_args.push_back((void *)&compressPos); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "DoDecode", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error = static_cast(_hidl_this->getImpl().get())->DoDecode(*cinfo, out_info, in_info, *region_info, samplesize, compressPos); + + ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply); + + _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error); + /* _hidl_err ignored! */ + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "DoDecode", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(*_hidl_reply); + return _hidl_err; +} + +::android::status_t BnHwJpegDecode::_hidl_Alloc_OutBuffer( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks(); + #endif // __ANDROID_DEBUGGABLE__ + + ::android::status_t _hidl_err = ::android::OK; + if (!_hidl_data.enforceInterface(BnHwJpegDecode::Pure::descriptor)) { + _hidl_err = ::android::BAD_TYPE; + return _hidl_err; + } + + int32_t outwidth; + int32_t outheight; + int32_t color_format; + + _hidl_err = _hidl_data.readInt32(&outwidth); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + _hidl_err = _hidl_data.readInt32(&outheight); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + _hidl_err = _hidl_data.readInt32(&color_format); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::Alloc_OutBuffer::server"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&outwidth); + _hidl_args.push_back((void *)&outheight); + _hidl_args.push_back((void *)&color_format); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_OutBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + bool _hidl_callbackCalled = false; + + ::android::hardware::Return _hidl_ret = static_cast(_hidl_this->getImpl().get())->Alloc_OutBuffer(outwidth, outheight, color_format, [&](const auto &_hidl_out_error, const auto &_hidl_out_outinfo) { + if (_hidl_callbackCalled) { + LOG_ALWAYS_FATAL("Alloc_OutBuffer: _hidl_cb called a second time, but must be called once."); + } + _hidl_callbackCalled = true; + + ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply); + + _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error); + /* _hidl_err ignored! */ + + _hidl_err = _hidl_reply->writeNativeHandleNoDup(_hidl_out_outinfo); + /* _hidl_err ignored! */ + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_outinfo); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_OutBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(*_hidl_reply); + }); + + _hidl_ret.assertOk(); + if (!_hidl_callbackCalled) { + LOG_ALWAYS_FATAL("Alloc_OutBuffer: _hidl_cb not called, but must be called once."); + } + + return _hidl_err; +} + +::android::status_t BnHwJpegDecode::_hidl_Alloc_InBuffer( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks(); + #endif // __ANDROID_DEBUGGABLE__ + + ::android::status_t _hidl_err = ::android::OK; + if (!_hidl_data.enforceInterface(BnHwJpegDecode::Pure::descriptor)) { + _hidl_err = ::android::BAD_TYPE; + return _hidl_err; + } + + int32_t size; + + _hidl_err = _hidl_data.readInt32(&size); + if (_hidl_err != ::android::OK) { return _hidl_err; } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::Alloc_InBuffer::server"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&size); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_InBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + bool _hidl_callbackCalled = false; + + ::android::hardware::Return _hidl_ret = static_cast(_hidl_this->getImpl().get())->Alloc_InBuffer(size, [&](const auto &_hidl_out_error, const auto &_hidl_out_outinfo) { + if (_hidl_callbackCalled) { + LOG_ALWAYS_FATAL("Alloc_InBuffer: _hidl_cb called a second time, but must be called once."); + } + _hidl_callbackCalled = true; + + ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply); + + _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error); + /* _hidl_err ignored! */ + + _hidl_err = _hidl_reply->writeNativeHandleNoDup(_hidl_out_outinfo); + /* _hidl_err ignored! */ + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_outinfo); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "Alloc_InBuffer", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(*_hidl_reply); + }); + + _hidl_ret.assertOk(); + if (!_hidl_callbackCalled) { + LOG_ALWAYS_FATAL("Alloc_InBuffer: _hidl_cb not called, but must be called once."); + } + + return _hidl_err; +} + +::android::status_t BnHwJpegDecode::_hidl_LockDevice( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks(); + #endif // __ANDROID_DEBUGGABLE__ + + ::android::status_t _hidl_err = ::android::OK; + if (!_hidl_data.enforceInterface(BnHwJpegDecode::Pure::descriptor)) { + _hidl_err = ::android::BAD_TYPE; + return _hidl_err; + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::LockDevice::server"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "LockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error = static_cast(_hidl_this->getImpl().get())->LockDevice(); + + ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply); + + _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error); + /* _hidl_err ignored! */ + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "LockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(*_hidl_reply); + return _hidl_err; +} + +::android::status_t BnHwJpegDecode::_hidl_UnLockDevice( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks(); + #endif // __ANDROID_DEBUGGABLE__ + + ::android::status_t _hidl_err = ::android::OK; + if (!_hidl_data.enforceInterface(BnHwJpegDecode::Pure::descriptor)) { + _hidl_err = ::android::BAD_TYPE; + return _hidl_err; + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::UnLockDevice::server"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "UnLockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + ::vendor::huawei::hardware::jpegdec::V1_0::JPEG_Error _hidl_out_error = static_cast(_hidl_this->getImpl().get())->UnLockDevice(); + + ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply); + + _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error); + /* _hidl_err ignored! */ + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "UnLockDevice", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(*_hidl_reply); + return _hidl_err; +} + +::android::status_t BnHwJpegDecode::_hidl_GetDecodeStatus( + ::android::hidl::base::V1_0::BnHwBase* _hidl_this, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + TransactCallback _hidl_cb) { + #ifdef __ANDROID_DEBUGGABLE__ + bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled(); + const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks(); + #endif // __ANDROID_DEBUGGABLE__ + + ::android::status_t _hidl_err = ::android::OK; + if (!_hidl_data.enforceInterface(BnHwJpegDecode::Pure::descriptor)) { + _hidl_err = ::android::BAD_TYPE; + return _hidl_err; + } + + atrace_begin(ATRACE_TAG_HAL, "HIDL::IJpegDecode::GetDecodeStatus::server"); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_ENTRY, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "GetDecodeStatus", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + bool _hidl_callbackCalled = false; + + ::android::hardware::Return _hidl_ret = static_cast(_hidl_this->getImpl().get())->GetDecodeStatus([&](const auto &_hidl_out_error, const auto &_hidl_out_status) { + if (_hidl_callbackCalled) { + LOG_ALWAYS_FATAL("GetDecodeStatus: _hidl_cb called a second time, but must be called once."); + } + _hidl_callbackCalled = true; + + ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply); + + _hidl_err = _hidl_reply->writeInt32((int32_t)_hidl_out_error); + /* _hidl_err ignored! */ + + _hidl_err = _hidl_reply->writeBool(_hidl_out_status); + /* _hidl_err ignored! */ + + atrace_end(ATRACE_TAG_HAL); + #ifdef __ANDROID_DEBUGGABLE__ + if (UNLIKELY(mEnableInstrumentation)) { + std::vector _hidl_args; + _hidl_args.push_back((void *)&_hidl_out_error); + _hidl_args.push_back((void *)&_hidl_out_status); + for (const auto &callback: mInstrumentationCallbacks) { + callback(InstrumentationEvent::SERVER_API_EXIT, "vendor.huawei.hardware.jpegdec", "1.0", "IJpegDecode", "GetDecodeStatus", &_hidl_args); + } + } + #endif // __ANDROID_DEBUGGABLE__ + + _hidl_cb(*_hidl_reply); + }); + + _hidl_ret.assertOk(); + if (!_hidl_callbackCalled) { + LOG_ALWAYS_FATAL("GetDecodeStatus: _hidl_cb not called, but must be called once."); + } + + return _hidl_err; +} + + +// Methods from ::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode follow. + +// Methods from ::android::hidl::base::V1_0::IBase follow. +::android::hardware::Return BnHwJpegDecode::ping() { + return ::android::hardware::Void(); +} +::android::hardware::Return BnHwJpegDecode::getDebugInfo(getDebugInfo_cb _hidl_cb) { + ::android::hidl::base::V1_0::DebugInfo info = {}; + info.pid = ::android::hardware::details::getPidIfSharable(); + info.ptr = ::android::hardware::details::debuggable()? reinterpret_cast(this) : 0; + info.arch = + #if defined(__LP64__) + ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT + #else + ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT + #endif + ; + _hidl_cb(info); + return ::android::hardware::Void(); +} + +::android::status_t BnHwJpegDecode::onTransact( + uint32_t _hidl_code, + const ::android::hardware::Parcel &_hidl_data, + ::android::hardware::Parcel *_hidl_reply, + uint32_t _hidl_flags, + TransactCallback _hidl_cb) { + ::android::status_t _hidl_err = ::android::OK; + + switch (_hidl_code) { + case 1 /* DoDecode */: + { + bool _hidl_is_oneway = _hidl_flags & 1u /* oneway */; + if (_hidl_is_oneway != false) { + return ::android::UNKNOWN_ERROR; + } + + _hidl_err = ::vendor::huawei::hardware::jpegdec::V1_0::BnHwJpegDecode::_hidl_DoDecode(this, _hidl_data, _hidl_reply, _hidl_cb); + break; + } + + case 2 /* Alloc_OutBuffer */: + { + bool _hidl_is_oneway = _hidl_flags & 1u /* oneway */; + if (_hidl_is_oneway != false) { + return ::android::UNKNOWN_ERROR; + } + + _hidl_err = ::vendor::huawei::hardware::jpegdec::V1_0::BnHwJpegDecode::_hidl_Alloc_OutBuffer(this, _hidl_data, _hidl_reply, _hidl_cb); + break; + } + + case 3 /* Alloc_InBuffer */: + { + bool _hidl_is_oneway = _hidl_flags & 1u /* oneway */; + if (_hidl_is_oneway != false) { + return ::android::UNKNOWN_ERROR; + } + + _hidl_err = ::vendor::huawei::hardware::jpegdec::V1_0::BnHwJpegDecode::_hidl_Alloc_InBuffer(this, _hidl_data, _hidl_reply, _hidl_cb); + break; + } + + case 4 /* LockDevice */: + { + bool _hidl_is_oneway = _hidl_flags & 1u /* oneway */; + if (_hidl_is_oneway != false) { + return ::android::UNKNOWN_ERROR; + } + + _hidl_err = ::vendor::huawei::hardware::jpegdec::V1_0::BnHwJpegDecode::_hidl_LockDevice(this, _hidl_data, _hidl_reply, _hidl_cb); + break; + } + + case 5 /* UnLockDevice */: + { + bool _hidl_is_oneway = _hidl_flags & 1u /* oneway */; + if (_hidl_is_oneway != false) { + return ::android::UNKNOWN_ERROR; + } + + _hidl_err = ::vendor::huawei::hardware::jpegdec::V1_0::BnHwJpegDecode::_hidl_UnLockDevice(this, _hidl_data, _hidl_reply, _hidl_cb); + break; + } + + case 6 /* GetDecodeStatus */: + { + bool _hidl_is_oneway = _hidl_flags & 1u /* oneway */; + if (_hidl_is_oneway != false) { + return ::android::UNKNOWN_ERROR; + } + + _hidl_err = ::vendor::huawei::hardware::jpegdec::V1_0::BnHwJpegDecode::_hidl_GetDecodeStatus(this, _hidl_data, _hidl_reply, _hidl_cb); + break; + } + + default: + { + return ::android::hidl::base::V1_0::BnHwBase::onTransact( + _hidl_code, _hidl_data, _hidl_reply, _hidl_flags, _hidl_cb); + } + } + + if (_hidl_err == ::android::UNEXPECTED_NULL) { + _hidl_err = ::android::hardware::writeToParcel( + ::android::hardware::Status::fromExceptionCode(::android::hardware::Status::EX_NULL_POINTER), + _hidl_reply); + }return _hidl_err; +} + +BsJpegDecode::BsJpegDecode(const ::android::sp<::vendor::huawei::hardware::jpegdec::V1_0::IJpegDecode> impl) : ::android::hardware::details::HidlInstrumentor("vendor.huawei.hardware.jpegdec@1.0", "IJpegDecode"), mImpl(impl) { + mOnewayQueue.start(3000 /* similar limit to binderized */); +} + +::android::hardware::Return BsJpegDecode::addOnewayTask(std::function fun) { + if (!mOnewayQueue.push(fun)) { + return ::android::hardware::Status::fromExceptionCode( + ::android::hardware::Status::EX_TRANSACTION_FAILED, + "Passthrough oneway function queue exceeds maximum size."); + } + return ::android::hardware::Status(); +} + +::android::sp IJpegDecode::tryGetService(const std::string &serviceName, const bool getStub) { + return ::android::hardware::details::getServiceInternal(serviceName, false, getStub); +} + +::android::sp IJpegDecode::getService(const std::string &serviceName, const bool getStub) { + return ::android::hardware::details::getServiceInternal(serviceName, true, getStub); +} + +::android::status_t IJpegDecode::registerAsService(const std::string &serviceName) { + return ::android::hardware::details::registerAsServiceInternal(this, serviceName); +} + +bool IJpegDecode::registerForNotifications( + const std::string &serviceName, + const ::android::sp<::android::hidl::manager::V1_0::IServiceNotification> ¬ification) { + const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm + = ::android::hardware::defaultServiceManager(); + if (sm == nullptr) { + return false; + } + ::android::hardware::Return success = + sm->registerForNotifications("vendor.huawei.hardware.jpegdec@1.0::IJpegDecode", + serviceName, notification); + return success.isOk() && success; +} + +static_assert(sizeof(::android::hardware::MQDescriptor) == 32, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_handle) == 16, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_memory) == 40, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_string) == 16, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_vec) == 16, "wrong size"); + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor diff --git a/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp.d b/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp.d new file mode 100755 index 0000000000000000000000000000000000000000..0c94d1157cc4c95c42faf9a5b9b67a505ba7b794 --- /dev/null +++ b/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/JpegDecodeAll.cpp.d @@ -0,0 +1,5 @@ +vendor/huawei/hardware/jpegdec/1.0/types.cpp: \ + system/libhidl/transport/base/1.0/IBase.hal \ + system/libhidl/transport/base/1.0/types.hal \ + vendor/huawei/interfaces/jpegdec/1.0/IJpegDecode.hal \ + vendor/huawei/interfaces/jpegdec/1.0/types.hal \ diff --git a/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/types.cpp b/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/types.cpp new file mode 100755 index 0000000000000000000000000000000000000000..9f1b52b08f4ec7ffc2d7f37f3e97fb7c20ab48ac --- /dev/null +++ b/adapter/hals/jpegdec/src/vendor/huawei/hardware/jpegdec/1.0/types.cpp @@ -0,0 +1,129 @@ +#define LOG_TAG "vendor.huawei.hardware.jpegdec@1.0::types" + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace vendor { +namespace huawei { +namespace hardware { +namespace jpegdec { +namespace V1_0 { + +::android::status_t readEmbeddedFromParcel( + const jpeg_decompress_hidl_t &obj, + const ::android::hardware::Parcel &parcel, + size_t parentHandle, + size_t parentOffset) { + ::android::status_t _hidl_err = ::android::OK; + + size_t _hidl_comp_info_child; + + _hidl_err = ::android::hardware::readEmbeddedFromParcel( + const_cast<::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_comp_hidl_info> &>(obj.comp_info), + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, comp_info), &_hidl_comp_info_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + size_t _hidl_dc_huff_tbl_ptrs_child; + + _hidl_err = ::android::hardware::readEmbeddedFromParcel( + const_cast<::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl> &>(obj.dc_huff_tbl_ptrs), + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, dc_huff_tbl_ptrs), &_hidl_dc_huff_tbl_ptrs_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + size_t _hidl_ac_huff_tbl_ptrs_child; + + _hidl_err = ::android::hardware::readEmbeddedFromParcel( + const_cast<::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_huff_hidl_tbl> &>(obj.ac_huff_tbl_ptrs), + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, ac_huff_tbl_ptrs), &_hidl_ac_huff_tbl_ptrs_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + size_t _hidl_quant_tbl_ptrs_child; + + _hidl_err = ::android::hardware::readEmbeddedFromParcel( + const_cast<::android::hardware::hidl_vec<::vendor::huawei::hardware::jpegdec::V1_0::jpeg_quant_hidl_tbl> &>(obj.quant_tbl_ptrs), + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, quant_tbl_ptrs), &_hidl_quant_tbl_ptrs_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + return _hidl_err; +} + +::android::status_t writeEmbeddedToParcel( + const jpeg_decompress_hidl_t &obj, + ::android::hardware::Parcel *parcel, + size_t parentHandle, + size_t parentOffset) { + ::android::status_t _hidl_err = ::android::OK; + + size_t _hidl_comp_info_child; + + _hidl_err = ::android::hardware::writeEmbeddedToParcel( + obj.comp_info, + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, comp_info), &_hidl_comp_info_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + size_t _hidl_dc_huff_tbl_ptrs_child; + + _hidl_err = ::android::hardware::writeEmbeddedToParcel( + obj.dc_huff_tbl_ptrs, + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, dc_huff_tbl_ptrs), &_hidl_dc_huff_tbl_ptrs_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + size_t _hidl_ac_huff_tbl_ptrs_child; + + _hidl_err = ::android::hardware::writeEmbeddedToParcel( + obj.ac_huff_tbl_ptrs, + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, ac_huff_tbl_ptrs), &_hidl_ac_huff_tbl_ptrs_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + size_t _hidl_quant_tbl_ptrs_child; + + _hidl_err = ::android::hardware::writeEmbeddedToParcel( + obj.quant_tbl_ptrs, + parcel, + parentHandle, + parentOffset + offsetof(::vendor::huawei::hardware::jpegdec::V1_0::jpeg_decompress_hidl_t, quant_tbl_ptrs), &_hidl_quant_tbl_ptrs_child); + + if (_hidl_err != ::android::OK) { return _hidl_err; } + + return _hidl_err; +} + +static_assert(sizeof(::android::hardware::MQDescriptor) == 32, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_handle) == 16, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_memory) == 40, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_string) == 16, "wrong size"); +static_assert(sizeof(::android::hardware::hidl_vec) == 16, "wrong size"); + +} // namespace V1_0 +} // namespace jpegdec +} // namespace hardware +} // namespace huawei +} // namespace vendor diff --git "a/figures/Image\347\273\204\344\273\266\346\236\266\346\236\204\345\233\276.png" "b/figures/Image\347\273\204\344\273\266\346\236\266\346\236\204\345\233\276.png" new file mode 100755 index 0000000000000000000000000000000000000000..dcf04c00f32d25b42d13516778623f268b4a249c Binary files /dev/null and "b/figures/Image\347\273\204\344\273\266\346\236\266\346\236\204\345\233\276.png" differ diff --git a/figures/image-architecture.png b/figures/image-architecture.png new file mode 100755 index 0000000000000000000000000000000000000000..14a875687bd930398333ce88896b46a8328749d5 Binary files /dev/null and b/figures/image-architecture.png differ diff --git a/frameworks/innerkitsimpl/codec/src/image_packer.cpp b/frameworks/innerkitsimpl/codec/src/image_packer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ddd26e41ea724189a60572e3e876bdb87c79ca0 --- /dev/null +++ b/frameworks/innerkitsimpl/codec/src/image_packer.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_packer.h" + +#include "buffer_packer_stream.h" +#include "file_packer_stream.h" +#include "image/abs_image_encoder.h" +#include "image_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "ostream_packer_stream.h" +#include "plugin_server.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace ImagePlugin; +using namespace MultimediaPlugin; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImagePacker" }; +static constexpr uint8_t QUALITY_MAX = 100; + +PluginServer &ImagePacker::pluginServer_ = ImageUtils::GetPluginServer(); + +uint32_t ImagePacker::GetSupportedFormats(std::set &formats) +{ + formats.clear(); + std::vector classInfos; + uint32_t ret = + pluginServer_.PluginServerGetClassInfo(AbsImageEncoder::SERVICE_DEFAULT, classInfos); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "get class info from plugin server,ret:%{public}u.", ret); + return ret; + } + for (auto &info : classInfos) { + std::map &capbility = info.capabilities; + auto iter = capbility.find(IMAGE_ENCODE_FORMAT); + if (iter == capbility.end()) { + continue; + } + AttrData &attr = iter->second; + std::string format; + if (attr.GetValue(format) != SUCCESS) { + HiLog::Error(LABEL, "attr data get format failed."); + continue; + } + formats.insert(format); + } + return SUCCESS; +} + +uint32_t ImagePacker::StartPackingImpl(const PackOption &option) +{ + if (!GetEncoderPlugin(option)) { + HiLog::Error(LABEL, "StartPackingImpl get encoder plugin failed."); + return ERR_IMAGE_MISMATCHED_FORMAT; + } + PlEncodeOptions plOpts; + CopyOptionsToPlugin(option, plOpts); + return encoder_->StartEncode(*packerStream_.get(), plOpts); +} + +uint32_t ImagePacker::StartPacking(uint8_t *outputData, uint32_t maxSize, const PackOption &option) +{ + if (!IsPackOptionValid(option)) { + HiLog::Error(LABEL, "array startPacking option invalid %{public}s, %{public}u.", option.format.c_str(), + option.quality); + return ERR_IMAGE_INVALID_PARAMETER; + } + + if (outputData == nullptr) { + HiLog::Error(LABEL, "output buffer is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + BufferPackerStream *stream = new (std::nothrow) BufferPackerStream(outputData, maxSize); + if (stream == nullptr) { + HiLog::Error(LABEL, "make buffer packer stream failed."); + return ERR_IMAGE_DATA_ABNORMAL; + } + FreeOldPackerStream(); + packerStream_ = std::unique_ptr(stream); + return StartPackingImpl(option); +} + +uint32_t ImagePacker::StartPacking(const std::string &filePath, const PackOption &option) +{ + if (!IsPackOptionValid(option)) { + HiLog::Error(LABEL, "filepath startPacking option invalid %{public}s, %{public}u.", option.format.c_str(), + option.quality); + return ERR_IMAGE_INVALID_PARAMETER; + } + FilePackerStream *stream = new (std::nothrow) FilePackerStream(filePath); + if (stream == nullptr) { + HiLog::Error(LABEL, "make file packer stream failed."); + return ERR_IMAGE_DATA_ABNORMAL; + } + FreeOldPackerStream(); + packerStream_ = std::unique_ptr(stream); + return StartPackingImpl(option); +} + +uint32_t ImagePacker::StartPacking(std::ostream &outputStream, const PackOption &option) +{ + if (!IsPackOptionValid(option)) { + HiLog::Error(LABEL, "outputStream startPacking option invalid %{public}s, %{public}u.", option.format.c_str(), + option.quality); + return ERR_IMAGE_INVALID_PARAMETER; + } + OstreamPackerStream *stream = new (std::nothrow) OstreamPackerStream(outputStream); + if (stream == nullptr) { + HiLog::Error(LABEL, "make ostream packer stream failed."); + return ERR_IMAGE_DATA_ABNORMAL; + } + FreeOldPackerStream(); + packerStream_ = std::unique_ptr(stream); + return StartPackingImpl(option); +} + +// JNI adapter method, this method be called by jni and the outputStream be created by jni, here we manage the lifecycle +// of the outputStream +uint32_t ImagePacker::StartPackingAdapter(PackerStream &outputStream, const PackOption &option) +{ + FreeOldPackerStream(); + packerStream_ = std::unique_ptr(&outputStream); + + if (!IsPackOptionValid(option)) { + HiLog::Error(LABEL, "packer stream option invalid %{public}s, %{public}u.", option.format.c_str(), + option.quality); + return ERR_IMAGE_INVALID_PARAMETER; + } + return StartPackingImpl(option); +} + +uint32_t ImagePacker::AddImage(PixelMap &pixelMap) +{ + if (encoder_ == nullptr) { + HiLog::Error(LABEL, "AddImage get encoder plugin failed."); + return ERR_IMAGE_MISMATCHED_FORMAT; + } + return encoder_->AddImage(pixelMap); +} + +uint32_t ImagePacker::AddImage(ImageSource &source) +{ + DecodeOptions opts; + uint32_t ret = SUCCESS; + if (pixelMap_ != nullptr) { + pixelMap_.reset(); // release old inner pixelmap + } + pixelMap_ = source.CreatePixelMap(opts, ret); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "image source create pixel map failed."); + return ret; + } + return AddImage(*pixelMap_.get()); +} + +uint32_t ImagePacker::AddImage(ImageSource &source, uint32_t index) +{ + DecodeOptions opts; + uint32_t ret = SUCCESS; + if (pixelMap_ != nullptr) { + pixelMap_.reset(); // release old inner pixelmap + } + pixelMap_ = source.CreatePixelMap(index, opts, ret); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "image source create pixel map failed."); + return ret; + } + return AddImage(*pixelMap_.get()); +} + +uint32_t ImagePacker::FinalizePacking() +{ + if (encoder_ == nullptr) { + HiLog::Error(LABEL, "FinalizePacking get encoder plugin failed."); + return ERR_IMAGE_MISMATCHED_FORMAT; + } + return encoder_->FinalizeEncode(); +} + +uint32_t ImagePacker::FinalizePacking(int64_t &packedSize) +{ + uint32_t ret = FinalizePacking(); + packedSize = (packerStream_ != nullptr) ? packerStream_->BytesWritten() : 0; + return ret; +} + +bool ImagePacker::GetEncoderPlugin(const PackOption &option) +{ + std::map capabilities; + capabilities.insert(std::map::value_type(IMAGE_ENCODE_FORMAT, AttrData(option.format))); + if (encoder_ != nullptr) { + encoder_.reset(); + } + encoder_ = std::unique_ptr( + pluginServer_.CreateObject(AbsImageEncoder::SERVICE_DEFAULT, capabilities)); + return (encoder_ != nullptr); +} + +void ImagePacker::CopyOptionsToPlugin(const PackOption &opts, PlEncodeOptions &plOpts) +{ + plOpts.numberHint = opts.numberHint; + plOpts.quality = opts.quality; +} + +void ImagePacker::FreeOldPackerStream() +{ + if (packerStream_ != nullptr) { + packerStream_.reset(); + } +} + +bool ImagePacker::IsPackOptionValid(const PackOption &option) +{ + if (option.quality > QUALITY_MAX || option.format.empty()) { + return false; + } + return true; +} + +// class reference need explicit constructor and destructor, otherwise unique_ptr use unnormal +ImagePacker::ImagePacker() +{} + +ImagePacker::~ImagePacker() +{} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp b/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80234930f68f218d68a9c09a1019b16be22bc05c --- /dev/null +++ b/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_packer_ex.h" + +namespace OHOS { +namespace Media { +uint32_t ImagePackerEx::StartPacking(PackerStream &outputStream, const PackOption &option) +{ + return StartPackingAdapter(outputStream, option); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80004752c7329f9a8241b35e82fccd7b76ce5681 --- /dev/null +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -0,0 +1,1164 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_source.h" + +#include +#include +#include "buffer_source_stream.h" +#if !defined(_WIN32) && !defined(_APPLE) +#include "bytrace.h" +#endif +#include "file_source_stream.h" +#include "image/abs_image_decoder.h" +#include "image/abs_image_format_agent.h" +#include "image/image_plugin_type.h" +#include "image_log.h" +#include "image_utils.h" +#include "incremental_source_stream.h" +#include "istream_source_stream.h" +#include "media_errors.h" +#include "pixel_map.h" +#include "plugin_server.h" +#include "post_proc.h" +#include "source_stream.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +using namespace ImagePlugin; +using namespace MultimediaPlugin; + +static const map PIXEL_FORMAT_MAP = { + { PixelFormat::UNKNOWN, PlPixelFormat::UNKNOWN }, { PixelFormat::ARGB_8888, PlPixelFormat::ARGB_8888 }, + { PixelFormat::ALPHA_8, PlPixelFormat::ALPHA_8 }, { PixelFormat::RGB_565, PlPixelFormat::RGB_565 }, + { PixelFormat::RGBA_F16, PlPixelFormat::RGBA_F16 }, { PixelFormat::RGBA_8888, PlPixelFormat::RGBA_8888 }, + { PixelFormat::BGRA_8888, PlPixelFormat::BGRA_8888 }, { PixelFormat::RGB_888, PlPixelFormat::RGB_888 }, + { PixelFormat::NV21, PlPixelFormat::NV21 }, { PixelFormat::NV12, PlPixelFormat::NV12 }, + { PixelFormat::CMYK, PlPixelFormat::CMYK } +}; + +static const map COLOR_SPACE_MAP = { + { ColorSpace::UNKNOWN, PlColorSpace::UNKNOWN }, + { ColorSpace::DISPLAY_P3, PlColorSpace::DISPLAY_P3 }, + { ColorSpace::SRGB, PlColorSpace::SRGB }, + { ColorSpace::LINEAR_SRGB, PlColorSpace::LINEAR_SRGB }, + { ColorSpace::EXTENDED_SRGB, PlColorSpace::EXTENDED_SRGB }, + { ColorSpace::LINEAR_EXTENDED_SRGB, PlColorSpace::LINEAR_EXTENDED_SRGB }, + { ColorSpace::GENERIC_XYZ, PlColorSpace::GENERIC_XYZ }, + { ColorSpace::GENERIC_LAB, PlColorSpace::GENERIC_LAB }, + { ColorSpace::ACES, PlColorSpace::ACES }, + { ColorSpace::ACES_CG, PlColorSpace::ACES_CG }, + { ColorSpace::ADOBE_RGB_1998, PlColorSpace::ADOBE_RGB_1998 }, + { ColorSpace::DCI_P3, PlColorSpace::DCI_P3 }, + { ColorSpace::ITU_709, PlColorSpace::ITU_709 }, + { ColorSpace::ITU_2020, PlColorSpace::ITU_2020 }, + { ColorSpace::ROMM_RGB, PlColorSpace::ROMM_RGB }, + { ColorSpace::NTSC_1953, PlColorSpace::NTSC_1953 }, + { ColorSpace::SMPTE_C, PlColorSpace::SMPTE_C } +}; + +namespace InnerFormat { + const string RAW_FORMAT = "image/x-raw"; + const string EXTENDED_FORMAT = "image/x-skia"; + const string RAW_EXTENDED_FORMATS[] = { + "image/x-sony-arw", + "image/x-canon-cr2", + "image/x-adobe-dng", + "image/x-nikon-nef", + "image/x-nikon-nrw", + "image/x-olympus-orf", + "image/x-fuji-raf", + "image/x-panasonic-rw2", + "image/x-pentax-pef", + "image/x-samsung-srw", + }; +} + +PluginServer &ImageSource::pluginServer_ = ImageUtils::GetPluginServer(); +ImageSource::FormatAgentMap ImageSource::formatAgentMap_ = InitClass(); + +uint32_t ImageSource::GetSupportedFormats(set &formats) +{ + IMAGE_LOGD("[ImageSource]get supported image type."); + + formats.clear(); + vector classInfos; + uint32_t ret = pluginServer_.PluginServerGetClassInfo(AbsImageDecoder::SERVICE_DEFAULT, + classInfos); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]get class info from plugin server,ret:%{public}u.", ret); + return ret; + } + + for (auto &info : classInfos) { + map &capbility = info.capabilities; + auto iter = capbility.find(IMAGE_ENCODE_FORMAT); + if (iter == capbility.end()) { + continue; + } + + AttrData &attr = iter->second; + const string *format = nullptr; + if (attr.GetValue(format) != SUCCESS) { + IMAGE_LOGE("[ImageSource]attr data get format failed."); + continue; + } + + if (*format == InnerFormat::RAW_FORMAT) { + formats.insert(std::begin(InnerFormat::RAW_EXTENDED_FORMATS), std::end(InnerFormat::RAW_EXTENDED_FORMATS)); + } else { + formats.insert(*format); + } + } + return SUCCESS; +} + +unique_ptr ImageSource::CreateImageSource(unique_ptr is, const SourceOptions &opts, + uint32_t &errorCode) +{ +#if !defined(_WIN32) && !defined(_APPLE) + StartTrace(BYTRACE_TAG_ZIMAGE, "CreateImageSource by istream"); +#endif + IMAGE_LOGD("[ImageSource]create Imagesource with stream."); + + unique_ptr streamPtr = IstreamSourceStream::CreateSourceStream(move(is)); + if (streamPtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create istream source stream."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + + ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); + if (sourcePtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create ImageSource with stream."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + errorCode = SUCCESS; +#if !defined(_WIN32) && !defined(_APPLE) + FinishTrace(BYTRACE_TAG_ZIMAGE, "CreateImageSource by istream"); +#endif + return unique_ptr(sourcePtr); +} + +unique_ptr ImageSource::CreateImageSource(const uint8_t *data, uint32_t size, const SourceOptions &opts, + uint32_t &errorCode) +{ +#if !defined(_WIN32) && !defined(_APPLE) + StartTrace(BYTRACE_TAG_ZIMAGE, "CreateImageSource by data"); +#endif + IMAGE_LOGD("[ImageSource]create Imagesource with buffer."); + + if (data == nullptr || size == 0) { + IMAGE_LOGE("[ImageSource]parameter error."); + errorCode = ERR_IMAGE_DATA_ABNORMAL; + return nullptr; + } + + unique_ptr streamPtr = BufferSourceStream::CreateSourceStream(data, size); + if (streamPtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create buffer source stream."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + + ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); + if (sourcePtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create ImageSource with buffer."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + errorCode = SUCCESS; +#if !defined(_WIN32) && !defined(_APPLE) + FinishTrace(BYTRACE_TAG_ZIMAGE, "CreateImageSource by data"); +#endif + return unique_ptr(sourcePtr); +} + +unique_ptr ImageSource::CreateImageSource(const std::string &pathName, const SourceOptions &opts, + uint32_t &errorCode) +{ +#if !defined(_WIN32) && !defined(_APPLE) + StartTrace(BYTRACE_TAG_ZIMAGE, "CreateImageSource by path"); +#endif + IMAGE_LOGD("[ImageSource]create Imagesource with pathName."); + + unique_ptr streamPtr = FileSourceStream::CreateSourceStream(pathName); + if (streamPtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create file source stream."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + + ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); + if (sourcePtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create ImageSource with pathName."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + errorCode = SUCCESS; +#if !defined(_WIN32) && !defined(_APPLE) + FinishTrace(BYTRACE_TAG_ZIMAGE, "CreateImageSource by path"); +#endif + return unique_ptr(sourcePtr); +} + +unique_ptr ImageSource::CreateIncrementalImageSource(const IncrementalSourceOptions &opts, + uint32_t &errorCode) +{ + IMAGE_LOGD("[ImageSource]create incremental ImageSource."); + + unique_ptr streamPtr = IncrementalSourceStream::CreateSourceStream(opts.incrementalMode); + if (streamPtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create incremental source stream."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + + ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts.sourceOptions); + if (sourcePtr == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create incremental ImageSource."); + errorCode = ERR_IMAGE_SOURCE_DATA; + return nullptr; + } + sourcePtr->SetIncrementalSource(true); + errorCode = SUCCESS; + return unique_ptr(sourcePtr); +} + +void ImageSource::Reset() +{ + // if use skia now, no need reset + if (mainDecoder_ != nullptr && mainDecoder_->HasProperty(SKIA_DECODER)) { + return; + } + imageStatusMap_.clear(); + decodeState_ = SourceDecodingState::UNRESOLVED; + sourceStreamPtr_->Seek(0); + mainDecoder_ = nullptr; +} + +unique_ptr ImageSource::CreatePixelMap(uint32_t index, const DecodeOptions &opts, uint32_t &errorCode) +{ +#if !defined(_WIN32) && !defined(_APPLE) + StartTrace(BYTRACE_TAG_ZIMAGE, "CreatePixelMap"); +#endif + std::unique_lock guard(decodingMutex_); + opts_ = opts; + bool useSkia = opts_.sampleSize != 1; + if (useSkia) { + // we need reset to initial state to choose correct decoder + Reset(); + } + auto iter = GetValidImageStatus(index, errorCode); + if (iter == imageStatusMap_.end()) { + IMAGE_LOGE("[ImageSource]get valid image status fail on create pixel map, ret:%{public}u.", errorCode); + return nullptr; + } + // the mainDecoder_ may be borrowed by Incremental decoding, so needs to be checked. + if (InitMainDecoder() != SUCCESS) { + IMAGE_LOGE("[ImageSource]image decode plugin is null."); + errorCode = ERR_IMAGE_PLUGIN_CREATE_FAILED; + return nullptr; + } + unique_ptr pixelMap = make_unique(); + if (pixelMap == nullptr) { + IMAGE_LOGE("[ImageSource]create the pixel map unique_ptr fail."); + errorCode = ERR_IMAGE_MALLOC_ABNORMAL; + return nullptr; + } + + ImagePlugin::PlImageInfo plInfo; + errorCode = SetDecodeOptions(mainDecoder_, index, opts, plInfo); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[ImageSource]set decode options error (index:%{public}u), ret:%{public}u.", index, errorCode); + return nullptr; + } + + for (auto listener : decodeListeners_) { + guard.unlock(); + listener->OnEvent((int)DecodeEvent::EVENT_HEADER_DECODE); + guard.lock(); + } + + errorCode = UpdatePixelMapInfo(opts, plInfo, *(pixelMap.get())); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[ImageSource]update pixelmap info error ret:%{public}u.", errorCode); + return nullptr; + } + + DecodeContext context; + FinalOutputStep finalOutputStep; + if (!useSkia) { + bool hasNinePatch = mainDecoder_->HasProperty(NINE_PATCH); + finalOutputStep = GetFinalOutputStep(opts, *(pixelMap.get()), hasNinePatch); + IMAGE_LOGD("[ImageSource]finalOutputStep:%{public}d. opts.allocatorType %{public}d", + finalOutputStep, opts.allocatorType); + + if (finalOutputStep == FinalOutputStep::NO_CHANGE) { + context.allocatorType = opts.allocatorType; + } else { + context.allocatorType = AllocatorType::HEAP_ALLOC; + } + } + + errorCode = mainDecoder_->Decode(index, context); + if (context.ifPartialOutput) { + for (auto listener : decodeListeners_) { + guard.unlock(); + listener->OnEvent((int)DecodeEvent::EVENT_PARTIAL_DECODE); + guard.lock(); + } + } + if (!useSkia) { + ninePatchInfo_.ninePatch = context.ninePatchContext.ninePatch; + ninePatchInfo_.patchSize = context.ninePatchContext.patchSize; + } + guard.unlock(); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[ImageSource]decode source fail, ret:%{public}u.", errorCode); + if (context.pixelsBuffer.buffer != nullptr) { + if (context.freeFunc != nullptr) { + context.freeFunc(context.pixelsBuffer.buffer, context.pixelsBuffer.context, + context.pixelsBuffer.bufferSize); + } else { + free(context.pixelsBuffer.buffer); + } + } + return nullptr; + } + pixelMap->SetPixelsAddr(context.pixelsBuffer.buffer, context.pixelsBuffer.context, context.pixelsBuffer.bufferSize, + context.allocatorType, context.freeFunc); + DecodeOptions procOpts; + CopyOptionsToProcOpts(opts, procOpts, *(pixelMap.get())); + PostProc postProc; + errorCode = postProc.DecodePostProc(procOpts, *(pixelMap.get()), finalOutputStep); + if (errorCode != SUCCESS) { + return nullptr; + } + + if (!context.ifPartialOutput) { + for (auto listener : decodeListeners_) { + listener->OnEvent((int)DecodeEvent::EVENT_COMPLETE_DECODE); + } + } +#if !defined(_WIN32) && !defined(_APPLE) + FinishTrace(BYTRACE_TAG_ZIMAGE, "CreatePixelMap"); +#endif + return pixelMap; +} + +unique_ptr ImageSource::CreateIncrementalPixelMap(uint32_t index, const DecodeOptions &opts, + uint32_t &errorCode) +{ + IncrementalPixelMap *incPixelMapPtr = new (std::nothrow) IncrementalPixelMap(index, opts, this); + if (incPixelMapPtr == nullptr) { + IMAGE_LOGE("[ImageSource]create the incremental pixel map unique_ptr fail."); + errorCode = ERR_IMAGE_MALLOC_ABNORMAL; + return nullptr; + } + errorCode = SUCCESS; + return unique_ptr(incPixelMapPtr); +} + +uint32_t ImageSource::PromoteDecoding(uint32_t index, const DecodeOptions &opts, PixelMap &pixelMap, + ImageDecodingState &state, uint8_t &decodeProgress) +{ + state = ImageDecodingState::UNRESOLVED; + decodeProgress = 0; + uint32_t ret = SUCCESS; + std::unique_lock guard(decodingMutex_); + auto imageStatusIter = GetValidImageStatus(index, ret); + if (imageStatusIter == imageStatusMap_.end()) { + IMAGE_LOGE("[ImageSource]get valid image status fail on promote decoding, ret:%{public}u.", ret); + return ret; + } + auto incrementalRecordIter = incDecodingMap_.find(&pixelMap); + if (incrementalRecordIter == incDecodingMap_.end()) { + ret = AddIncrementalContext(pixelMap, incrementalRecordIter); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]failed to add context on incremental decoding, ret:%{public}u.", ret); + return ret; + } + } + if (incrementalRecordIter->second.IncrementalState == ImageDecodingState::BASE_INFO_PARSED) { + IMAGE_LOGD("[ImageSource]promote decode : set decode options."); + ImagePlugin::PlImageInfo plInfo; + ret = SetDecodeOptions(incrementalRecordIter->second.decoder, index, opts, plInfo); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]set decode options error (image index:%{public}u), ret:%{public}u.", index, ret); + return ret; + } + + auto iter = decodeEventMap_.find((int)DecodeEvent::EVENT_HEADER_DECODE); + if (iter == decodeEventMap_.end()) { + decodeEventMap_.insert(std::pair((int)DecodeEvent::EVENT_HEADER_DECODE, 1)); + for (auto listener : decodeListeners_) { + guard.unlock(); + listener->OnEvent((int)DecodeEvent::EVENT_HEADER_DECODE); + guard.lock(); + } + } + ret = UpdatePixelMapInfo(opts, plInfo, pixelMap); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]update pixelmap info error (image index:%{public}u), ret:%{public}u.", index, ret); + return ret; + } + incrementalRecordIter->second.IncrementalState = ImageDecodingState::IMAGE_DECODING; + } + if (incrementalRecordIter->second.IncrementalState == ImageDecodingState::IMAGE_DECODING) { + ret = DoIncrementalDecoding(index, opts, pixelMap, incrementalRecordIter->second); + decodeProgress = incrementalRecordIter->second.decodingProgress; + state = incrementalRecordIter->second.IncrementalState; + if (isIncrementalCompleted_) { + PostProc postProc; + ret = postProc.DecodePostProc(opts, pixelMap); + if (state == ImageDecodingState::IMAGE_DECODED) { + auto iter = decodeEventMap_.find((int)DecodeEvent::EVENT_COMPLETE_DECODE); + if (iter == decodeEventMap_.end()) { + decodeEventMap_.insert(std::pair((int)DecodeEvent::EVENT_COMPLETE_DECODE, 1)); + for (auto listener : decodeListeners_) { + guard.unlock(); + listener->OnEvent((int)DecodeEvent::EVENT_COMPLETE_DECODE); + guard.lock(); + } + } + } + } + return ret; + } + + // IMAGE_ERROR or IMAGE_DECODED. + state = incrementalRecordIter->second.IncrementalState; + decodeProgress = incrementalRecordIter->second.decodingProgress; + if (incrementalRecordIter->second.IncrementalState == ImageDecodingState::IMAGE_ERROR) { + IMAGE_LOGE("[ImageSource]invalid imageState %{public}d on incremental decoding.", + incrementalRecordIter->second.IncrementalState); + return ERR_IMAGE_DECODE_ABNORMAL; + } + return SUCCESS; +} + +void ImageSource::DetachIncrementalDecoding(PixelMap &pixelMap) +{ + std::lock_guard guard(decodingMutex_); + auto iter = incDecodingMap_.find(&pixelMap); + if (iter == incDecodingMap_.end()) { + return; + } + + if (mainDecoder_ == nullptr) { + // return back the decoder to mainDecoder_. + mainDecoder_ = std::move(iter->second.decoder); + iter->second.decoder = nullptr; + } + incDecodingMap_.erase(iter); +} + +uint32_t ImageSource::UpdateData(const uint8_t *data, uint32_t size, bool isCompleted) +{ + if (sourceStreamPtr_ == nullptr) { + IMAGE_LOGE("[ImageSource]image source update data, source stream is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + std::lock_guard guard(decodingMutex_); + if (isCompleted) { + isIncrementalCompleted_ = isCompleted; + } + return sourceStreamPtr_->UpdateData(data, size, isCompleted); +} + +DecodeEvent ImageSource::GetDecodeEvent() +{ + return decodeEvent_; +} + +uint32_t ImageSource::GetImageInfo(uint32_t index, ImageInfo &imageInfo) +{ + uint32_t ret = SUCCESS; + std::unique_lock guard(decodingMutex_); + auto iter = GetValidImageStatus(index, ret); + if (iter == imageStatusMap_.end()) { + guard.unlock(); + IMAGE_LOGE("[ImageSource]get valid image status fail on get image info, ret:%{public}u.", ret); + return ret; + } + ImageInfo &info = (iter->second).imageInfo; + if (info.size.width == 0 || info.size.height == 0) { + IMAGE_LOGE("[ImageSource]get the image size fail on get image info, width:%{public}d, height:%{public}d.", + info.size.width, info.size.height); + return ERR_IMAGE_DECODE_FAILED; + } + + imageInfo = info; + return SUCCESS; +} + +uint32_t ImageSource::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) +{ + std::unique_lock guard(decodingMutex_); + uint32_t ret; + auto iter = GetValidImageStatus(0, ret); + if (iter == imageStatusMap_.end()) { + IMAGE_LOGE("[ImageSource]get valid image status fail on get image property, ret:%{public}u.", ret); + return ret; + } + + ret = mainDecoder_->GetImagePropertyInt(index, key, value); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource] GetImagePropertyInt fail, ret:%{public}u", ret); + return ret; + } + + return SUCCESS; +} + +const SourceInfo &ImageSource::GetSourceInfo(uint32_t &errorCode) +{ + std::lock_guard guard(decodingMutex_); + errorCode = DecodeSourceInfo(true); + return sourceInfo_; +} + +void ImageSource::RegisterListener(PeerListener *listener) +{ + if (listener == nullptr) { + return; + } + std::lock_guard guard(listenerMutex_); + listeners_.insert(listener); +} + +void ImageSource::UnRegisterListener(PeerListener *listener) +{ + if (listener == nullptr) { + return; + } + std::lock_guard guard(listenerMutex_); + auto iter = listeners_.find(listener); + if (iter != listeners_.end()) { + listeners_.erase(iter); + } +} + +void ImageSource::AddDecodeListener(DecodeListener *listener) +{ + if (listener == nullptr) { + IMAGE_LOGE("AddDecodeListener listener null"); + return; + } + std::lock_guard guard(listenerMutex_); + decodeListeners_.insert(listener); +} + +void ImageSource::RemoveDecodeListener(DecodeListener *listener) +{ + if (listener == nullptr) { + IMAGE_LOGE("RemoveDecodeListener listener null"); + return; + } + std::lock_guard guard(listenerMutex_); + auto iter = decodeListeners_.find(listener); + if (iter != decodeListeners_.end()) { + decodeListeners_.erase(iter); + } +} + +ImageSource::~ImageSource() +{ + std::lock_guard guard(listenerMutex_); + for (const auto &listener : listeners_) { + listener->OnPeerDestory(); + } +} + +bool ImageSource::IsStreamCompleted() +{ + std::lock_guard guard(decodingMutex_); + return sourceStreamPtr_->IsStreamCompleted(); +} + +// ------------------------------- private method ------------------------------- +ImageSource::ImageSource(unique_ptr &&stream, const SourceOptions &opts) + : sourceStreamPtr_(stream.release()) +{ + sourceInfo_.encodedFormat = opts.formatHint; + sourceInfo_.baseDensity = opts.baseDensity; +} + +ImageSource::FormatAgentMap ImageSource::InitClass() +{ + vector classInfos; + pluginServer_.PluginServerGetClassInfo(AbsImageFormatAgent::SERVICE_DEFAULT, classInfos); + set formats; + for (auto &info : classInfos) { + auto &capabilities = info.capabilities; + auto iter = capabilities.find(IMAGE_ENCODE_FORMAT); + if (iter == capabilities.end()) { + continue; + } + + AttrData &attr = iter->second; + string format; + if (SUCCESS != attr.GetValue(format)) { + IMAGE_LOGE("[ImageSource]attr data get format:[%{public}s] failed.", format.c_str()); + continue; + } + formats.insert(move(format)); + } + + FormatAgentMap tempAgentMap; + AbsImageFormatAgent *formatAgent = nullptr; + for (auto format : formats) { + map capabilities = { { IMAGE_ENCODE_FORMAT, AttrData(format) } }; + formatAgent = + pluginServer_.CreateObject(AbsImageFormatAgent::SERVICE_DEFAULT, capabilities); + if (formatAgent == nullptr) { + continue; + } + tempAgentMap.insert(FormatAgentMap::value_type(std::move(format), formatAgent)); + } + return tempAgentMap; +} + +uint32_t ImageSource::CheckEncodedFormat(AbsImageFormatAgent &agent) +{ + uint32_t size = agent.GetHeaderSize(); + ImagePlugin::DataStreamBuffer outData; + if (sourceStreamPtr_ == nullptr) { + IMAGE_LOGE("[ImageSource]check image format, source stream is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (!sourceStreamPtr_->Peek(size, outData)) { + IMAGE_LOGE("[ImageSource]stream peek the data fail."); + return ERR_IMAGE_SOURCE_DATA; + } + + if (outData.inputStreamBuffer == nullptr || outData.dataSize < size) { + IMAGE_LOGE("[ImageSource]the ouData is incomplete."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + + if (!agent.CheckFormat(outData.inputStreamBuffer, size)) { + IMAGE_LOGE("[ImageSource]check mismatched format :%{public}s.", agent.GetFormatType().c_str()); + return ERR_IMAGE_MISMATCHED_FORMAT; + } + return SUCCESS; +} + +uint32_t ImageSource::CheckFormatHint(const string &formatHint, FormatAgentMap::iterator &formatIter) +{ + uint32_t ret = ERROR; + formatIter = formatAgentMap_.find(formatHint); + if (formatIter == formatAgentMap_.end()) { + IMAGE_LOGE("[ImageSource]check input format fail."); + return ret; + } + AbsImageFormatAgent *agent = formatIter->second; + ret = CheckEncodedFormat(*agent); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + IMAGE_LOGE("[ImageSource]image source incomplete."); + } + return ret; + } + return SUCCESS; +} + +uint32_t ImageSource::GetEncodedFormat(const string &formatHint, string &format) +{ + bool streamIncomplete = false; + auto hintIter = formatAgentMap_.end(); + if (!formatHint.empty()) { + uint32_t ret = CheckFormatHint(formatHint, hintIter); + if (ret == ERR_IMAGE_SOURCE_DATA) { + IMAGE_LOGE("[ImageSource]image source data error."); + return ret; + } else if (ret == SUCCESS) { + format = hintIter->first; + IMAGE_LOGD("[ImageSource]check input image format success, format:%{public}s.", format.c_str()); + return SUCCESS; + } else if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + streamIncomplete = true; + } + } + + for (auto iter = formatAgentMap_.begin(); iter != formatAgentMap_.end(); ++iter) { + string curFormat = iter->first; + if (iter == hintIter || curFormat == InnerFormat::RAW_FORMAT) { + continue; // has been checked before. + } + AbsImageFormatAgent *agent = iter->second; + auto ret = CheckEncodedFormat(*agent); + if (ret == ERR_IMAGE_MISMATCHED_FORMAT) { + continue; + } else if (ret == SUCCESS) { + IMAGE_LOGI("[ImageSource]GetEncodedFormat success format :%{public}s.", iter->first.c_str()); + format = iter->first; + return SUCCESS; + } else if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + streamIncomplete = true; + } + } + + if (streamIncomplete) { + IMAGE_LOGE("[ImageSource]image source incomplete."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + + // default return raw image + format = InnerFormat::RAW_FORMAT; + IMAGE_LOGI("[ImageSource]image default to raw format."); + return SUCCESS; +} + +uint32_t ImageSource::OnSourceRecognized(bool isAcquiredImageNum) +{ + uint32_t ret = InitMainDecoder(); + if (ret != SUCCESS) { + sourceInfo_.state = SourceInfoState::UNSUPPORTED_FORMAT; + decodeState_ = SourceDecodingState::UNSUPPORTED_FORMAT; + IMAGE_LOGE("[ImageSource]image decode error, ret:[%{public}u].", ret); + return ret; + } + + // for raw image, we need check the original format after decoder initialzation + string value; + ret = mainDecoder_->GetImagePropertyString(0, ACTUAL_IMAGE_ENCODED_FORMAT, value); + if (ret == SUCCESS) { + // update new format + sourceInfo_.encodedFormat = value; + IMAGE_LOGI("[ImageSource] update new format, value:%{public}s", value.c_str()); + } else { + IMAGE_LOGD("[ImageSource] GetImagePropertyString fail, ret:%{public}u", ret); + } + + if (isAcquiredImageNum) { + ret = mainDecoder_->GetTopLevelImageNum(sourceInfo_.topLevelImageNum); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + sourceInfo_.state = SourceInfoState::SOURCE_INCOMPLETE; + IMAGE_LOGE("[ImageSource]image source data incomplete."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + sourceInfo_.state = SourceInfoState::FILE_INFO_ERROR; + decodeState_ = SourceDecodingState::FILE_INFO_ERROR; + IMAGE_LOGE("[ImageSource]image source error."); + return ret; + } + } + sourceInfo_.state = SourceInfoState::FILE_INFO_PARSED; + decodeState_ = SourceDecodingState::FILE_INFO_DECODED; + return SUCCESS; +} + +uint32_t ImageSource::OnSourceUnresolved() +{ + string formatResult; + auto ret = GetEncodedFormat(sourceInfo_.encodedFormat, formatResult); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + IMAGE_LOGE("[ImageSource]image source incomplete."); + sourceInfo_.state = SourceInfoState::SOURCE_INCOMPLETE; + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } else if (ret == ERR_IMAGE_UNKNOWN_FORMAT) { + IMAGE_LOGE("[ImageSource]image unknown format."); + sourceInfo_.state = SourceInfoState::UNKNOWN_FORMAT; + decodeState_ = SourceDecodingState::UNKNOWN_FORMAT; + return ERR_IMAGE_UNKNOWN_FORMAT; + } + sourceInfo_.state = SourceInfoState::SOURCE_ERROR; + decodeState_ = SourceDecodingState::SOURCE_ERROR; + IMAGE_LOGE("[ImageSource]image source error."); + return ret; + } + sourceInfo_.encodedFormat = formatResult; + decodeState_ = SourceDecodingState::FORMAT_RECOGNIZED; + return SUCCESS; +} + +uint32_t ImageSource::DecodeSourceInfo(bool isAcquiredImageNum) +{ + uint32_t ret = SUCCESS; + if (decodeState_ >= SourceDecodingState::FILE_INFO_DECODED) { + if (isAcquiredImageNum) { + decodeState_ = SourceDecodingState::FORMAT_RECOGNIZED; + } else { + return SUCCESS; + } + } + if (decodeState_ == SourceDecodingState::UNRESOLVED) { + ret = OnSourceUnresolved(); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]unresolved source: check format failed, ret:[%{public}d].", ret); + return ret; + } + } + if (decodeState_ == SourceDecodingState::FORMAT_RECOGNIZED) { + ret = OnSourceRecognized(isAcquiredImageNum); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]recognized source: get source info failed, ret:[%{public}d].", ret); + return ret; + } + return SUCCESS; + } + IMAGE_LOGE("[ImageSource]invalid source state %{public}d on decode source info.", decodeState_); + switch (decodeState_) { + case SourceDecodingState::SOURCE_ERROR: { + ret = ERR_IMAGE_SOURCE_DATA; + break; + } + case SourceDecodingState::UNKNOWN_FORMAT: { + ret = ERR_IMAGE_UNKNOWN_FORMAT; + break; + } + case SourceDecodingState::UNSUPPORTED_FORMAT: { + ret = ERR_IMAGE_PLUGIN_CREATE_FAILED; + break; + } + case SourceDecodingState::FILE_INFO_ERROR: { + ret = ERR_IMAGE_DECODE_FAILED; + break; + } + default: { + ret = ERROR; + break; + } + } + return ret; +} + +uint32_t ImageSource::DecodeImageInfo(uint32_t index, ImageStatusMap::iterator &iter) +{ + uint32_t ret = DecodeSourceInfo(false); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]decode the image fail, ret:%{public}d.", ret); + return ret; + } + if (mainDecoder_ == nullptr) { + IMAGE_LOGE("[ImageSource]get image size, image decode plugin is null."); + return ERR_IMAGE_PLUGIN_CREATE_FAILED; + } + ImagePlugin::PlSize size; + ret = mainDecoder_->GetImageSize(index, size); + if (ret == SUCCESS) { + ImageDecodingStatus imageStatus; + imageStatus.imageInfo.size.width = size.width; + imageStatus.imageInfo.size.height = size.height; + imageStatus.imageState = ImageDecodingState::BASE_INFO_PARSED; + auto result = imageStatusMap_.insert(ImageStatusMap::value_type(index, imageStatus)); + iter = result.first; + return SUCCESS; + } else if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + IMAGE_LOGE("[ImageSource]source data incomplete."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } else { + ImageDecodingStatus imageStatus; + imageStatus.imageState = ImageDecodingState::BASE_INFO_ERROR; + auto result = imageStatusMap_.insert(ImageStatusMap::value_type(index, imageStatus)); + iter = result.first; + IMAGE_LOGE("[ImageSource]decode the image info fail."); + return ERR_IMAGE_DECODE_FAILED; + } +} + +uint32_t ImageSource::InitMainDecoder() +{ + if (mainDecoder_ != nullptr) { + return SUCCESS; + } + uint32_t result = SUCCESS; + mainDecoder_ = std::unique_ptr(CreateDecoder(result)); + return result; +} + +AbsImageDecoder *ImageSource::CreateDecoder(uint32_t &errorCode) +{ + // in normal mode, we can get actual encoded format to the user + // but we need transfer to skia codec for adaption, "image/x-skia" + std::string encodedFormat = sourceInfo_.encodedFormat; + if (opts_.sampleSize != 1) { + encodedFormat = InnerFormat::EXTENDED_FORMAT; + } + map capabilities = { { IMAGE_ENCODE_FORMAT, AttrData(encodedFormat) } }; + auto decoder = pluginServer_.CreateObject(AbsImageDecoder::SERVICE_DEFAULT, capabilities); + if (decoder == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create decoder object."); + errorCode = ERR_IMAGE_PLUGIN_CREATE_FAILED; + return nullptr; + } + errorCode = SUCCESS; + decoder->SetSource(*sourceStreamPtr_); + return decoder; +} + +uint32_t ImageSource::SetDecodeOptions(std::unique_ptr &decoder, uint32_t index, + const DecodeOptions &opts, ImagePlugin::PlImageInfo &plInfo) +{ + PixelDecodeOptions plOptions; + CopyOptionsToPlugin(opts, plOptions); + uint32_t ret = decoder->SetDecodeOptions(index, plOptions, plInfo); + if (ret != SUCCESS) { + IMAGE_LOGE("[ImageSource]decoder plugin set decode options fail (image index:%{public}u), ret:%{public}u.", + index, ret); + return ret; + } + auto iter = imageStatusMap_.find(index); + if (iter != imageStatusMap_.end()) { + ImageInfo &info = (iter->second).imageInfo; + IMAGE_LOGD("[ImageSource]SetDecodeOptions plInfo.pixelFormat %{public}d", plInfo.pixelFormat); + + PlPixelFormat format = plInfo.pixelFormat; + auto find_item = std::find_if(PIXEL_FORMAT_MAP.begin(), PIXEL_FORMAT_MAP.end(), + [format](const std::map::value_type item) { + return item.second == format; + }); + if (find_item != PIXEL_FORMAT_MAP.end()) { + info.pixelFormat = (*find_item).first; + } + IMAGE_LOGD("[ImageSource]SetDecodeOptions info.pixelFormat %{public}d", info.pixelFormat); + } + return SUCCESS; +} + +uint32_t ImageSource::UpdatePixelMapInfo(const DecodeOptions &opts, ImagePlugin::PlImageInfo &plInfo, + PixelMap &pixelMap) +{ + pixelMap.SetEditable(opts.editable); + + ImageInfo info; + info.baseDensity = sourceInfo_.baseDensity; + info.size.width = plInfo.size.width; + info.size.height = plInfo.size.height; + info.pixelFormat = static_cast(plInfo.pixelFormat); + info.alphaType = static_cast(plInfo.alphaType); + return pixelMap.SetImageInfo(info); +} + +void ImageSource::CopyOptionsToPlugin(const DecodeOptions &opts, PixelDecodeOptions &plOpts) +{ + plOpts.CropRect.left = opts.CropRect.left; + plOpts.CropRect.top = opts.CropRect.top; + plOpts.CropRect.width = opts.CropRect.width; + plOpts.CropRect.height = opts.CropRect.height; + plOpts.desiredSize.width = opts.desiredSize.width; + plOpts.desiredSize.height = opts.desiredSize.height; + plOpts.rotateDegrees = opts.rotateDegrees; + plOpts.sampleSize = opts.sampleSize; + auto formatSearch = PIXEL_FORMAT_MAP.find(opts.desiredPixelFormat); + plOpts.desiredPixelFormat = + (formatSearch != PIXEL_FORMAT_MAP.end()) ? formatSearch->second : PlPixelFormat::RGBA_8888; + auto colorSearch = COLOR_SPACE_MAP.find(opts.desiredColorSpace); + plOpts.desiredColorSpace = (colorSearch != COLOR_SPACE_MAP.end()) ? colorSearch->second : PlColorSpace::UNKNOWN; + plOpts.allowPartialImage = opts.allowPartialImage; + plOpts.editable = opts.editable; +} + +void ImageSource::CopyOptionsToProcOpts(const DecodeOptions &opts, DecodeOptions &procOpts, PixelMap &pixelMap) +{ + procOpts.fitDensity = opts.fitDensity; + procOpts.CropRect.left = opts.CropRect.left; + procOpts.CropRect.top = opts.CropRect.top; + procOpts.CropRect.width = opts.CropRect.width; + procOpts.CropRect.height = opts.CropRect.height; + procOpts.desiredSize.width = opts.desiredSize.width; + procOpts.desiredSize.height = opts.desiredSize.height; + procOpts.rotateDegrees = opts.rotateDegrees; + procOpts.sampleSize = opts.sampleSize; + procOpts.desiredPixelFormat = opts.desiredPixelFormat; + if (opts.allocatorType == AllocatorType::DEFAULT) { + procOpts.allocatorType = AllocatorType::HEAP_ALLOC; + } else { + procOpts.allocatorType = opts.allocatorType; + } + procOpts.desiredColorSpace = opts.desiredColorSpace; + procOpts.allowPartialImage = opts.allowPartialImage; + procOpts.editable = opts.editable; + // we need preference_ when post processing + procOpts.preference = preference_; +} + +ImageSource::ImageStatusMap::iterator ImageSource::GetValidImageStatus(uint32_t index, uint32_t &errorCode) +{ + auto iter = imageStatusMap_.find(index); + if (iter == imageStatusMap_.end()) { + errorCode = DecodeImageInfo(index, iter); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[ImageSource]image info decode fail, ret:%{public}u.", errorCode); + return imageStatusMap_.end(); + } + } else if (iter->second.imageState < ImageDecodingState::BASE_INFO_PARSED) { + IMAGE_LOGE("[ImageSource]invalid imageState %{public}d on get image status.", iter->second.imageState); + errorCode = ERR_IMAGE_DECODE_FAILED; + return imageStatusMap_.end(); + } + errorCode = SUCCESS; + return iter; +} + +uint32_t ImageSource::AddIncrementalContext(PixelMap &pixelMap, IncrementalRecordMap::iterator &iterator) +{ + uint32_t ret = SUCCESS; + IncrementalDecodingContext context; + if (mainDecoder_ != nullptr) { + // borrowed decoder from the mainDecoder_. + context.decoder = std::move(mainDecoder_); + } else { + context.decoder = std::unique_ptr(CreateDecoder(ret)); + } + if (context.decoder == nullptr) { + IMAGE_LOGE("[ImageSource]failed to create decoder on add incremental context, ret:%{public}u.", ret); + return ret; + } + // mainDecoder has parsed base info in DecodeImageInfo(); + context.IncrementalState = ImageDecodingState::BASE_INFO_PARSED; + auto result = incDecodingMap_.insert(IncrementalRecordMap::value_type(&pixelMap, std::move(context))); + iterator = result.first; + return SUCCESS; +} + +uint32_t ImageSource::DoIncrementalDecoding(uint32_t index, const DecodeOptions &opts, PixelMap &pixelMap, + IncrementalDecodingContext &recordContext) +{ + IMAGE_LOGD("[ImageSource]do incremental decoding: begin."); + uint8_t *pixelAddr = static_cast(pixelMap.GetWritablePixels()); + ProgDecodeContext context; + context.decodeContext.pixelsBuffer.buffer = pixelAddr; + uint32_t ret = recordContext.decoder->PromoteIncrementalDecode(index, context); + if (context.decodeContext.pixelsBuffer.buffer != nullptr && pixelAddr == nullptr) { + pixelMap.SetPixelsAddr(context.decodeContext.pixelsBuffer.buffer, context.decodeContext.pixelsBuffer.context, + context.decodeContext.pixelsBuffer.bufferSize, context.decodeContext.allocatorType, + context.decodeContext.freeFunc); + } + IMAGE_LOGD("[ImageSource]do incremental decoding progress:%{public}u.", context.totalProcessProgress); + recordContext.decodingProgress = context.totalProcessProgress; + if (ret != SUCCESS && ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + recordContext.IncrementalState = ImageDecodingState::IMAGE_ERROR; + IMAGE_LOGE("[ImageSource]do incremental decoding source fail, ret:%{public}u.", ret); + return ret; + } + if (ret == SUCCESS) { + recordContext.IncrementalState = ImageDecodingState::IMAGE_DECODED; + IMAGE_LOGI("[ImageSource]do incremental decoding success."); + } + return ret; +} + +const NinePatchInfo &ImageSource::GetNinePatchInfo() const +{ + return ninePatchInfo_; +} + +void ImageSource::SetMemoryUsagePreference(const MemoryUsagePreference preference) +{ + preference_ = preference; +} + +MemoryUsagePreference ImageSource::GetMemoryUsagePreference() +{ + return preference_; +} + +void ImageSource::SetIncrementalSource(const bool isIncrementalSource) +{ + isIncrementalSource_ = isIncrementalSource; +} + +bool ImageSource::IsIncrementalSource() +{ + return isIncrementalSource_; +} + +FinalOutputStep ImageSource::GetFinalOutputStep(const DecodeOptions &opts, PixelMap &pixelMap, bool hasNinePatch) +{ + ImageInfo info; + pixelMap.GetImageInfo(info); + ImageInfo dstImageInfo; + dstImageInfo.size = opts.desiredSize; + dstImageInfo.pixelFormat = opts.desiredPixelFormat; + if (opts.desiredPixelFormat == PixelFormat::UNKNOWN) { + if (preference_ == MemoryUsagePreference::LOW_RAM && info.alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) { + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + } else { + dstImageInfo.pixelFormat = PixelFormat::RGBA_8888; + } + } + // decode use, this value may be changed by real pixelFormat + if (pixelMap.GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) { + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + } else { + dstImageInfo.alphaType = pixelMap.GetAlphaType(); + } + bool densityChange = HasDensityChange(opts, info, hasNinePatch); + bool sizeChange = ImageSizeChange(pixelMap.GetWidth(), pixelMap.GetHeight(), + opts.desiredSize.width, opts.desiredSize.height); + bool rotateChange = !ImageUtils::FloatCompareZero(opts.rotateDegrees); + bool convertChange = ImageConverChange(opts.CropRect, dstImageInfo, info); + if (sizeChange) { + return FinalOutputStep::SIZE_CHANGE; + } else if (densityChange) { + return FinalOutputStep::DENSITY_CHANGE; + } + if (rotateChange) { + return FinalOutputStep::ROTATE_CHANGE; + } + if (convertChange) { + return FinalOutputStep::CONVERT_CHANGE; + } + return FinalOutputStep::NO_CHANGE; +} + +bool ImageSource::HasDensityChange(const DecodeOptions &opts, ImageInfo &srcImageInfo, bool hasNinePatch) +{ + return !hasNinePatch && (srcImageInfo.baseDensity > 0) && + (opts.fitDensity > 0) && (srcImageInfo.baseDensity != opts.fitDensity); +} + +bool ImageSource::ImageSizeChange(int32_t width, int32_t height, int32_t desiredWidth, int32_t desiredHeight) +{ + bool sizeChange = false; + if (desiredWidth > 0 && desiredHeight > 0 && width > 0 && height > 0) { + float scaleX = static_cast(desiredWidth) / static_cast(width); + float scaleY = static_cast(desiredHeight) / static_cast(height); + if ((fabs(scaleX - 1.0f) >= EPSILON) && (fabs(scaleY - 1.0f) >= EPSILON)) { + sizeChange = true; + } + } + return sizeChange; +} + +bool ImageSource::ImageConverChange(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo) +{ + bool hasPixelConvert = false; + dstImageInfo.alphaType = ImageUtils::GetValidAlphaTypeByFormat(dstImageInfo.alphaType, dstImageInfo.pixelFormat); + if (dstImageInfo.pixelFormat != srcImageInfo.pixelFormat || dstImageInfo.alphaType != srcImageInfo.alphaType) { + hasPixelConvert = true; + } + CropValue value = PostProc::GetCropValue(cropRect, srcImageInfo.size); + if (value == CropValue::NOCROP && !hasPixelConvert) { + IMAGE_LOGD("[ImageSource]no need crop and pixel convert."); + return false; + } else if (value == CropValue::INVALID) { + IMAGE_LOGE("[ImageSource]invalid corp region, top:%{public}d, left:%{public}d, " + "width:%{public}d, height:%{public}d", + cropRect.top, cropRect.left, cropRect.width, cropRect.height); + return false; + } + return true; +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/common/include/image_packer_ex.h b/frameworks/innerkitsimpl/common/include/image_packer_ex.h new file mode 100644 index 0000000000000000000000000000000000000000..09485a2f0a09fc5ceb3190d6073a866eced022c8 --- /dev/null +++ b/frameworks/innerkitsimpl/common/include/image_packer_ex.h @@ -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. + */ + +#ifndef IMAGE_PACKER_EX_H +#define IMAGE_PACKER_EX_H + +#include "image_packer.h" +#include "packer_stream.h" + +namespace OHOS { +namespace Media { +class ImagePackerEx : public ImagePacker { +public: + ImagePackerEx() = default; + ~ImagePackerEx() = default; + using ImagePacker::StartPacking; + uint32_t StartPacking(PackerStream &outputStream, const PackOption &option); + +private: + DISALLOW_COPY_AND_MOVE(ImagePackerEx); +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_PACKER_EX_H diff --git a/frameworks/innerkitsimpl/common/include/pixel_map_utils.h b/frameworks/innerkitsimpl/common/include/pixel_map_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ae0b91b452def23084ee18985e3410f51bd62fb4 --- /dev/null +++ b/frameworks/innerkitsimpl/common/include/pixel_map_utils.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PIXEL_MAP_UTILS_H +#define PIXEL_MAP_UTILS_H + +#include "image_type.h" +#include "log_tags.h" +#include "pixel_map.h" + +namespace OHOS { +namespace Media { +// Define bytes per pixel +constexpr int8_t ALPHA_8_BYTES = 1; +constexpr int8_t RGB_565_BYTES = 2; +constexpr int8_t RGB_888_BYTES = 3; +constexpr int8_t ARGB_8888_BYTES = 4; +constexpr int8_t YUV420_BYTES = 2; // in fact NV21 one pixel used 1.5 bytes. + +// Define shift bits of bytes per pixel +constexpr int8_t ALPHA_8_SHIFT = 0; +constexpr int8_t RGB_565_SHIFT = 1; +constexpr int8_t ARGB_8888_SHIFT = 2; + +// Convert RGB565 16bit pixel to 32bit pixel +constexpr uint8_t RGB565_R_BITS = 5; +constexpr uint8_t RGB565_G_BITS = 6; +constexpr uint8_t RGB565_B_BITS = 5; + +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr uint8_t RGB565_R_SHIFT = 0; +constexpr uint8_t RGB565_G_SHIFT = RGB565_R_BITS; +constexpr uint8_t RGB565_B_SHIFT = RGB565_R_BITS + RGB565_G_BITS; +constexpr uint16_t RGB565_R_MASK = 0x001F; +constexpr uint16_t RGB565_G_MASK = 0x07E0; +constexpr uint16_t RGB565_B_MASK = 0xF800; +#else +constexpr uint8_t RGB565_R_SHIFT = RGB565_B_BITS + RGB565_G_BITS; +constexpr uint8_t RGB565_G_SHIFT = RGB565_B_BITS; +constexpr uint8_t RGB565_B_SHIFT = 0; +constexpr uint16_t RGB565_R_MASK = 0xF800; +constexpr uint16_t RGB565_G_MASK = 0x07E0; +constexpr uint16_t RGB565_B_MASK = 0x001F; +#endif +constexpr uint8_t BYTE_BITS = 8; +constexpr uint8_t RGB565_CONVERT_BIT = 2; +constexpr uint8_t ARGB8888_CONVERT_BIT = 24; + +// Convert for ARGB_8888 32bit pixel +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr uint8_t ARGB32_A_SHIFT = 0; +constexpr uint8_t ARGB32_R_SHIFT = 8; +constexpr uint8_t ARGB32_G_SHIFT = 16; +constexpr uint8_t ARGB32_B_SHIFT = 24; +#else +constexpr uint8_t ARGB32_A_SHIFT = 24; +constexpr uint8_t ARGB32_R_SHIFT = 16; +constexpr uint8_t ARGB32_G_SHIFT = 8; +constexpr uint8_t ARGB32_B_SHIFT = 0; +#endif + +// Convert for RGBA_8888 32bit pixel +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr uint8_t RGBA32_R_SHIFT = 0; +constexpr uint8_t RGBA32_G_SHIFT = 8; +constexpr uint8_t RGBA32_B_SHIFT = 16; +constexpr uint8_t RGBA32_A_SHIFT = 24; +#else +constexpr uint8_t RGBA32_R_SHIFT = 24; +constexpr uint8_t RGBA32_G_SHIFT = 16; +constexpr uint8_t RGBA32_B_SHIFT = 8; +constexpr uint8_t RGBA32_A_SHIFT = 0; +#endif + +// Convert for BGRA_8888 32bit pixel +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr uint8_t BGRA32_B_SHIFT = 0; +constexpr uint8_t BGRA32_G_SHIFT = 8; +constexpr uint8_t BGRA32_R_SHIFT = 16; +constexpr uint8_t BGRA32_A_SHIFT = 24; +#else +constexpr uint8_t BGRA32_B_SHIFT = 24; +constexpr uint8_t BGRA32_G_SHIFT = 16; +constexpr uint8_t BGRA32_R_SHIFT = 8; +constexpr uint8_t BGRA32_A_SHIFT = 0; +#endif + +constexpr uint8_t BYTE_FULL = 0xFF; +constexpr uint8_t BYTE_ZERO = 0; +constexpr uint8_t ONE_PIXEL_SIZE = 1; + +/* + * For RGB_565 + * 1. get R(5-bits)/G(6-bits)/B(5-bits) channel value form color value(uint16_t) + * 2. convert R(5-bits)/G(6-bits)/B(5-bits) value to R(8-bits)/G(8-bits)/B(8-bits) + * 3. construct normalized color value with A(255)/R(8-bits)/G(8-bits)/B(8-bits) + * 4. the normalized color format: (A << 24 | R << 16 | G << 8 | B << 0) + */ +static uint8_t GetRGB565Channel(uint16_t color, uint16_t mask, uint8_t shift) +{ + return (color & mask) >> shift; +} + +static uint8_t RGB565To32(uint8_t channel, uint8_t bits) +{ + return (channel << (BYTE_BITS - bits)) | (channel >> (RGB565_CONVERT_BIT * bits - BYTE_BITS)); +} + +static uint8_t RGB565ToR32(uint16_t color) +{ + return RGB565To32(GetRGB565Channel(color, RGB565_R_MASK, RGB565_R_SHIFT), RGB565_R_BITS); +} + +static uint8_t RGB565ToG32(uint16_t color) +{ + return RGB565To32(GetRGB565Channel(color, RGB565_G_MASK, RGB565_G_SHIFT), RGB565_G_BITS); +} + +static uint8_t RGB565ToB32(uint16_t color) +{ + return RGB565To32(GetRGB565Channel(color, RGB565_B_MASK, RGB565_B_SHIFT), RGB565_B_BITS); +} + +/* + * For ARGB_8888 + * 1. get A(8-bits)/R(8-bits)/G(8-bits)/B(8-bits) channel value form color value(uint32_t) + * 2. construct normalized color value with A(8-bits)/R(8-bits)/G(8-bits)/B(8-bits) + * 3. the normalized color format: (A << 24 | R << 16 | G << 8 | B << 0) + */ +static uint8_t GetColorComp(uint32_t color, uint8_t shift) +{ + return ((color) << (ARGB8888_CONVERT_BIT - shift)) >> ARGB8888_CONVERT_BIT; +} + +static uint32_t GetColorARGB(uint8_t a, uint8_t r, uint8_t g, uint8_t b) +{ + return ((a << ARGB_A_SHIFT) | (r << ARGB_R_SHIFT) | (g << ARGB_G_SHIFT) | (b << ARGB_B_SHIFT)); +} + +static ImageInfo MakeImageInfo(int width, int height, PixelFormat pf, AlphaType at, ColorSpace cs = ColorSpace::SRGB) +{ + ImageInfo info; + info.size.width = width; + info.size.height = height; + info.pixelFormat = pf; + info.alphaType = at; + info.colorSpace = cs; + return info; +} +} // namespace Media +} // namespace OHOS + +#endif // PIXEL_MAP_UTILS_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/common/src/incremental_pixel_map.cpp b/frameworks/innerkitsimpl/common/src/incremental_pixel_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..988d32f1d5703a3ca0ccc5297e45ac85d2c39bfb --- /dev/null +++ b/frameworks/innerkitsimpl/common/src/incremental_pixel_map.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "hilog/log.h" +#include "image_source.h" +#include "incremental_pixel_map.h" +#include "log_tags.h" +#include "media_errors.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "IncrementalPixelMap" }; + +static IncrementalDecodingState ConvertImageStateToIncrementalState(ImageDecodingState imageState) +{ + switch (imageState) { + case ImageDecodingState::UNRESOLVED: { + return IncrementalDecodingState::UNRESOLVED; + } + case ImageDecodingState::BASE_INFO_ERROR: { + return IncrementalDecodingState::BASE_INFO_ERROR; + } + case ImageDecodingState::BASE_INFO_PARSED: { + return IncrementalDecodingState::BASE_INFO_PARSED; + } + case ImageDecodingState::IMAGE_DECODING: { + return IncrementalDecodingState::IMAGE_DECODING; + } + case ImageDecodingState::IMAGE_ERROR: { + return IncrementalDecodingState::IMAGE_ERROR; + } + case ImageDecodingState::PARTIAL_IMAGE: { + return IncrementalDecodingState::PARTIAL_IMAGE; + } + case ImageDecodingState::IMAGE_DECODED: { + return IncrementalDecodingState::IMAGE_DECODED; + } + default: { + HiLog::Error(LABEL, "unexpected imageState %{public}d.", imageState); + return IncrementalDecodingState::UNRESOLVED; + } + } +} + +IncrementalPixelMap::~IncrementalPixelMap() +{ + if (imageSource_ == nullptr) { + return; + } + DetachSource(); +} + +IncrementalPixelMap::IncrementalPixelMap(uint32_t index, const DecodeOptions opts, ImageSource *imageSource) + : index_(index), opts_(opts), imageSource_(imageSource) +{ + if (imageSource_ != nullptr) { + imageSource_->RegisterListener(static_cast(this)); + } +} + +uint32_t IncrementalPixelMap::PromoteDecoding(uint8_t &decodeProgress) +{ + if (imageSource_ == nullptr) { + if (decodingStatus_.state == IncrementalDecodingState::BASE_INFO_ERROR || + decodingStatus_.state == IncrementalDecodingState::IMAGE_ERROR) { + HiLog::Error(LABEL, "promote decode failed for state %{public}d, errorDetail %{public}u.", + decodingStatus_.state, decodingStatus_.errorDetail); + return decodingStatus_.errorDetail; + } + HiLog::Error(LABEL, "promote decode failed or terminated, image source is null."); + return ERR_IMAGE_SOURCE_DATA; + } + ImageDecodingState imageState = ImageDecodingState::UNRESOLVED; + uint32_t ret = + imageSource_->PromoteDecoding(index_, opts_, *(static_cast(this)), imageState, decodeProgress); + decodingStatus_.state = ConvertImageStateToIncrementalState(imageState); + if (decodeProgress > decodingStatus_.decodingProgress) { + decodingStatus_.decodingProgress = decodeProgress; + } + if (ret != SUCCESS && ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + DetachSource(); + decodingStatus_.errorDetail = ret; + HiLog::Error(LABEL, "promote decode failed, ret=%{public}u.", ret); + } + if (ret == SUCCESS) { + DetachSource(); + } + return ret; +} + +void IncrementalPixelMap::DetachFromDecoding() +{ + if (imageSource_ == nullptr) { + return; + } + DetachSource(); +} + +const IncrementalDecodingStatus &IncrementalPixelMap::GetDecodingStatus() +{ + return decodingStatus_; +} + +void IncrementalPixelMap::OnPeerDestory() +{ + imageSource_ = nullptr; +} + +void IncrementalPixelMap::DetachSource() +{ + imageSource_->DetachIncrementalDecoding(*(static_cast(this))); + imageSource_->UnRegisterListener(this); + imageSource_ = nullptr; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/common/src/pixel_map.cpp b/frameworks/innerkitsimpl/common/src/pixel_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a537f99f8db6ee7a73ad3b7dd485db946eec442d --- /dev/null +++ b/frameworks/innerkitsimpl/common/src/pixel_map.cpp @@ -0,0 +1,1191 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pixel_map.h" +#include +#include +#include "hilog/log.h" +#include "image_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_convert_adapter.h" +#include "pixel_map_utils.h" +#include "pixel_map_parcel.h" +#include "post_proc.h" +#include "parcel.h" +#include "ipc_file_descriptor.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +#if !defined(_WIN32) && !defined(_APPLE) +#include +#include "ashmem.h" +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelMap" }; +constexpr int32_t MAX_DIMENSION = INT32_MAX >> 2; +constexpr uint8_t FOUR_BYTE_SHIFT = 2; +constexpr uint8_t BGRA_ALPHA_INDEX = 3; +constexpr uint8_t BGRA_BYTES = 4; +constexpr uint8_t PER_PIXEL_LEN = 1; + +PixelMap::~PixelMap() +{ + FreePixelMap(); +} + +void PixelMap::FreePixelMap() +{ + if (data_ == nullptr) { + return; + } + switch (allocatorType_) { + case AllocatorType::HEAP_ALLOC: { + free(data_); + data_ = nullptr; + break; + } + case AllocatorType::CUSTOM_ALLOC: { + if (custFreePixelMap_ != nullptr) { + custFreePixelMap_(data_, context_, pixelsSize_); + } + data_ = nullptr; + context_ = nullptr; + break; + } + case AllocatorType::SHARE_MEM_ALLOC: { + ReleaseSharedMemory(data_, context_, pixelsSize_); + data_ = nullptr; + context_ = nullptr; + break; + } + default: { + HiLog::Error(LABEL, "unknown allocator type:[%{public}d].", allocatorType_); + return; + } + } +} + +void PixelMap::ReleaseSharedMemory(void *addr, void *context, uint32_t size) +{ +#if !defined(_WIN32) && !defined(_APPLE) + int *fd = static_cast(context); + if (addr != nullptr) { + ::munmap(addr, size); + } + if (fd != nullptr) { + ::close(*fd); + delete fd; + } +#endif +} + +void PixelMap::SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, CustomFreePixelMap func) +{ + FreePixelMap(); + data_ = static_cast(addr); + context_ = context; + pixelsSize_ = size; + allocatorType_ = type; + custFreePixelMap_ = func; +} + +unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, const InitializationOptions &opts) +{ + return Create(colors, colorLength, 0, opts.size.width, opts); +} + +unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t stride, + const InitializationOptions &opts) +{ + if (!CheckParams(colors, colorLength, offset, stride, opts)) { + return nullptr; + } + unique_ptr dstPixelMap = make_unique(); + if (dstPixelMap == nullptr) { + HiLog::Error(LABEL, "create pixelMap pointer fail"); + return nullptr; + } + + ImageInfo srcImageInfo = + MakeImageInfo(stride, opts.size.height, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + PixelFormat dstPixelFormat = (opts.pixelFormat == PixelFormat::UNKNOWN ? PixelFormat::RGBA_8888 : opts.pixelFormat); + AlphaType dstAlphaType = + (opts.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) ? AlphaType::IMAGE_ALPHA_TYPE_PREMUL : opts.alphaType; + dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(dstAlphaType, dstPixelFormat); + ImageInfo dstImageInfo = MakeImageInfo(opts.size.width, opts.size.height, dstPixelFormat, dstAlphaType); + if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) { + HiLog::Error(LABEL, "set image info fail"); + return nullptr; + } + uint32_t bufferSize = dstPixelMap->GetByteCount(); + if (bufferSize == 0) { + HiLog::Error(LABEL, "malloc parameter is zero"); + return nullptr; + } + void *dstPixels = malloc(bufferSize); + if (dstPixels == nullptr) { + HiLog::Error(LABEL, "allocate memory size %{public}u fail", bufferSize); + return nullptr; + } + + Position dstPosition; + if (!PixelConvertAdapter::WritePixelsConvert(reinterpret_cast(colors + offset), + static_cast(stride) << FOUR_BYTE_SHIFT, srcImageInfo, + dstPixels, dstPosition, dstPixelMap->GetRowBytes(), dstImageInfo)) { + HiLog::Error(LABEL, "pixel convert in adapter failed."); + free(dstPixels); + dstPixels = nullptr; + return nullptr; + } + dstPixelMap->SetEditable(opts.editable); + dstPixelMap->SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + return dstPixelMap; +} + +bool PixelMap::CheckParams(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t stride, + const InitializationOptions &opts) +{ + if (colors == nullptr || colorLength <= 0 || colorLength > PIXEL_MAP_MAX_RAM_SIZE) { + HiLog::Error(LABEL, "colors invalid"); + return false; + } + int32_t dstWidth = opts.size.width; + int32_t dstHeight = opts.size.height; + if (dstWidth <= 0 || dstHeight <= 0) { + HiLog::Error(LABEL, "initial options size invalid"); + return false; + } + if (stride < dstWidth) { + HiLog::Error(LABEL, "stride: %{public}d must >= width: %{public}d", stride, dstWidth); + return false; + } + if (stride > MAX_DIMENSION) { + HiLog::Error(LABEL, "stride %{public}d is out of range", stride); + return false; + } + int64_t lastLine = static_cast(dstHeight - 1) * stride + offset; + if (offset < 0 || static_cast(offset) + dstWidth > colorLength || lastLine + dstWidth > colorLength) { + HiLog::Error(LABEL, "colors length: %{public}u, offset: %{public}d, stride: %{public}d is invalid", + colorLength, offset, stride); + return false; + } + return true; +} + +unique_ptr PixelMap::Create(const InitializationOptions &opts) +{ + unique_ptr dstPixelMap = make_unique(); + if (dstPixelMap == nullptr) { + HiLog::Error(LABEL, "create pixelMap pointer fail"); + return nullptr; + } + PixelFormat dstPixelFormat = (opts.pixelFormat == PixelFormat::UNKNOWN ? PixelFormat::RGBA_8888 : opts.pixelFormat); + AlphaType dstAlphaType = + (opts.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) ? AlphaType::IMAGE_ALPHA_TYPE_PREMUL : opts.alphaType; + dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(dstAlphaType, dstPixelFormat); + ImageInfo dstImageInfo = MakeImageInfo(opts.size.width, opts.size.height, dstPixelFormat, dstAlphaType); + if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) { + HiLog::Error(LABEL, "set image info fail"); + return nullptr; + } + uint32_t bufferSize = dstPixelMap->GetByteCount(); + uint8_t *dstPixels = static_cast(calloc(bufferSize, 1)); + if (dstPixels == nullptr) { + HiLog::Error(LABEL, "allocate memory size %{public}u fail", bufferSize); + return nullptr; + } + // update alpha opaque + UpdatePixelsAlpha(dstImageInfo.alphaType, dstImageInfo.pixelFormat, dstPixels, *dstPixelMap.get()); + dstPixelMap->SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + dstPixelMap->SetEditable(opts.editable); + return dstPixelMap; +} + +void PixelMap::UpdatePixelsAlpha(const AlphaType &alphaType, const PixelFormat &pixelFormat, uint8_t *dstPixels, + PixelMap dstPixelMap) +{ + if (alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) { + int8_t alphaIndex = -1; + if (pixelFormat == PixelFormat::RGBA_8888 || pixelFormat == PixelFormat::BGRA_8888) { + alphaIndex = BGRA_ALPHA_INDEX; + } else if (pixelFormat == PixelFormat::ARGB_8888) { + alphaIndex = 0; + } + if (alphaIndex != -1) { + uint8_t pixelBytes = dstPixelMap.GetPixelBytes(); + uint32_t bufferSize = dstPixelMap.GetByteCount(); + uint32_t i = alphaIndex; + while (i < bufferSize) { + dstPixels[i] = ALPHA_OPAQUE; + i += pixelBytes; + } + } + } +} + +unique_ptr PixelMap::Create(PixelMap &source, const InitializationOptions &opts) +{ + Rect rect; + return Create(source, rect, opts); +} + +unique_ptr PixelMap::Create(PixelMap &source, const Rect &srcRect, const InitializationOptions &opts) +{ + ImageInfo srcImageInfo; + source.GetImageInfo(srcImageInfo); + PostProc postProc; + CropValue cropType = PostProc::GetCropValue(srcRect, srcImageInfo.size); + if (cropType == CropValue::INVALID) { + HiLog::Error(LABEL, "src crop range is invalid"); + return nullptr; + } + ImageInfo dstImageInfo; + InitDstImageInfo(opts, srcImageInfo, dstImageInfo); + Size targetSize = dstImageInfo.size; + // use source if match + bool isHasConvert = postProc.HasPixelConvert(srcImageInfo, dstImageInfo); + if (opts.useSourceIfMatch && !source.IsEditable() && !opts.editable && (cropType == CropValue::NOCROP) && + !isHasConvert && IsSameSize(srcImageInfo.size, dstImageInfo.size)) { + source.useSourceAsResponse_ = true; + return unique_ptr(&source); + } + unique_ptr dstPixelMap = make_unique(); + if (dstPixelMap == nullptr) { + HiLog::Error(LABEL, "create pixelmap pointer fail"); + return nullptr; + } + if (cropType == CropValue::VALID) { + dstImageInfo.size.width = srcRect.width; + dstImageInfo.size.height = srcRect.height; + } else { + dstImageInfo.size = srcImageInfo.size; + } + if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) { + return nullptr; + } + // dst pixelmap is source crop and convert pixelmap + if ((cropType == CropValue::VALID) || isHasConvert) { + if (!SourceCropAndConvert(source, srcImageInfo, dstImageInfo, srcRect, *dstPixelMap.get())) { + return nullptr; + } + } else { + // only maybe size changed, copy source as scale operation + if (!CopyPixelMap(source, *dstPixelMap.get())) { + return nullptr; + } + } + if (!ScalePixelMap(targetSize, dstImageInfo.size, opts.scaleMode, *dstPixelMap.get())) { + return nullptr; + } + dstPixelMap->SetEditable(opts.editable); + return dstPixelMap; +} + +bool PixelMap::SourceCropAndConvert(PixelMap &source, const ImageInfo &srcImageInfo, const ImageInfo &dstImageInfo, + const Rect &srcRect, PixelMap &dstPixelMap) +{ + uint32_t bufferSize = dstPixelMap.GetByteCount(); + void *dstPixels = malloc(bufferSize); + if (dstPixels == nullptr) { + HiLog::Error(LABEL, "allocate memory size %{public}u fail", bufferSize); + return false; + } + + Position srcPosition{ srcRect.left, srcRect.top }; + if (!PixelConvertAdapter::ReadPixelsConvert(source.GetPixels(), srcPosition, source.GetRowBytes(), srcImageInfo, + dstPixels, dstPixelMap.GetRowBytes(), dstImageInfo)) { + HiLog::Error(LABEL, "pixel convert in adapter failed."); + free(dstPixels); + dstPixels = nullptr; + return false; + } + dstPixelMap.SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + return true; +} + +bool PixelMap::ScalePixelMap(const Size &targetSize, const Size &dstSize, const ScaleMode &scaleMode, + PixelMap &dstPixelMap) +{ + if (dstSize.width == targetSize.width && dstSize.height == targetSize.height) { + return true; + } + PostProc postProc; + if (scaleMode == ScaleMode::FIT_TARGET_SIZE) { + if (!postProc.ScalePixelMap(targetSize, dstPixelMap)) { + HiLog::Error(LABEL, "scale FIT_TARGET_SIZE fail"); + return false; + } + } + if (scaleMode == ScaleMode::CENTER_CROP) { + if (!postProc.CenterScale(targetSize, dstPixelMap)) { + HiLog::Error(LABEL, "scale CENTER_CROP fail"); + return false; + } + } + return true; +} + +void PixelMap::InitDstImageInfo(const InitializationOptions &opts, const ImageInfo &srcImageInfo, + ImageInfo &dstImageInfo) +{ + dstImageInfo.size = opts.size; + if (dstImageInfo.size.width == 0 && dstImageInfo.size.height == 0) { + dstImageInfo.size = srcImageInfo.size; + } + dstImageInfo.pixelFormat = opts.pixelFormat; + if (dstImageInfo.pixelFormat == PixelFormat::UNKNOWN) { + dstImageInfo.pixelFormat = srcImageInfo.pixelFormat; + } + dstImageInfo.alphaType = opts.alphaType; + if (dstImageInfo.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) { + dstImageInfo.alphaType = srcImageInfo.alphaType; + } +} + +bool PixelMap::CopyPixelMap(PixelMap &source, PixelMap &dstPixelMap) +{ + uint32_t bufferSize = source.GetByteCount(); + if (bufferSize == 0 || source.GetPixels() == nullptr) { + HiLog::Error(LABEL, "source pixelMap data invalid"); + return false; + } + uint8_t *dstPixels = static_cast(malloc(bufferSize)); + if (dstPixels == nullptr) { + HiLog::Error(LABEL, "allocate memory size %{public}u fail", bufferSize); + return false; + } + errno_t errRet = memcpy_s(dstPixels, bufferSize, source.GetPixels(), bufferSize); + if (errRet != 0) { + HiLog::Error(LABEL, "copy source memory size %{public}u fail, errorCode = %{public}d", bufferSize, errRet); + free(dstPixels); + dstPixels = nullptr; + return false; + } + dstPixelMap.SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + return true; +} + +bool PixelMap::IsSameSize(const Size &src, const Size &dst) +{ + return (src.width == dst.width) && (src.height == dst.height); +} + +bool PixelMap::GetPixelFormatDetail(const PixelFormat format) +{ + switch (format) { + case PixelFormat::RGBA_8888: { + pixelBytes_ = ARGB_8888_BYTES; + colorProc_ = RGBA8888ToARGB; + break; + } + case PixelFormat::BGRA_8888: { + pixelBytes_ = ARGB_8888_BYTES; + colorProc_ = BGRA8888ToARGB; + break; + } + case PixelFormat::ARGB_8888: { + pixelBytes_ = ARGB_8888_BYTES; + colorProc_ = ARGB8888ToARGB; + break; + } + case PixelFormat::ALPHA_8: { + pixelBytes_ = ALPHA_8_BYTES; + colorProc_ = ALPHA8ToARGB; + break; + } + case PixelFormat::RGB_565: { + pixelBytes_ = RGB_565_BYTES; + colorProc_ = RGB565ToARGB; + break; + } + case PixelFormat::RGB_888: { + pixelBytes_ = RGB_888_BYTES; + colorProc_ = RGB888ToARGB; + break; + } + case PixelFormat::NV12: + case PixelFormat::NV21: { + pixelBytes_ = YUV420_BYTES; + break; + } + case PixelFormat::CMYK: + pixelBytes_ = ARGB_8888_BYTES; + break; + default: { + HiLog::Error(LABEL, "pixel format:[%{public}d] not supported.", format); + return false; + } + } + return true; +} + +uint32_t PixelMap::SetImageInfo(ImageInfo &info) +{ + return SetImageInfo(info, false); +} + +uint32_t PixelMap::SetImageInfo(ImageInfo &info, bool isReused) +{ + if (info.size.width <= 0 || info.size.height <= 0) { + HiLog::Error(LABEL, "pixel map image info invalid."); + return ERR_IMAGE_DATA_ABNORMAL; + } + if (!GetPixelFormatDetail(info.pixelFormat)) { + return ERR_IMAGE_DATA_UNSUPPORT; + } + + if (pixelBytes_ <= 0) { + ResetPixelMap(); + HiLog::Error(LABEL, "pixel map bytes is invalid."); + return ERR_IMAGE_DATA_ABNORMAL; + } + + if ((static_cast(pixelBytes_) * info.size.width) > PIXEL_MAP_MAX_RAM_SIZE) { + ResetPixelMap(); + HiLog::Error(LABEL, "image size is out of range."); + return ERR_IMAGE_TOO_LARGE; + } + if (info.pixelFormat == PixelFormat::ALPHA_8) { + rowDataSize_ = pixelBytes_ * ((info.size.width + 3) / 4 * 4); + HiLog::Info(LABEL, "ALPHA_8 rowDataSize_ %{public}d.", rowDataSize_); + } else { + rowDataSize_ = pixelBytes_ * info.size.width; + } + if (info.size.height > (PIXEL_MAP_MAX_RAM_SIZE / rowDataSize_)) { + ResetPixelMap(); + HiLog::Error(LABEL, "pixel map byte count out of range."); + return ERR_IMAGE_TOO_LARGE; + } + if (!isReused) { + FreePixelMap(); + } + imageInfo_ = info; + return SUCCESS; +} + +const uint8_t *PixelMap::GetPixel8(int32_t x, int32_t y) +{ + if (!CheckValidParam(x, y) || (pixelBytes_ != ALPHA_8_BYTES)) { + HiLog::Error(LABEL, "get addr8 pixel position:(%{public}d, %{public}d) pixel bytes:%{public}d invalid.", x, y, + pixelBytes_); + return nullptr; + } + return (data_ + y * rowDataSize_ + x); +} + +const uint16_t *PixelMap::GetPixel16(int32_t x, int32_t y) +{ + if (!CheckValidParam(x, y) || (pixelBytes_ != RGB_565_BYTES)) { + HiLog::Error(LABEL, "get addr16 pixel position:(%{public}d, %{public}d) pixel bytes:%{public}d invalid.", x, y, + pixelBytes_); + return nullptr; + } + // convert uint8_t* to uint16_t* + return reinterpret_cast(data_ + y * rowDataSize_ + (static_cast(x) << RGB_565_SHIFT)); +} + +const uint32_t *PixelMap::GetPixel32(int32_t x, int32_t y) +{ + if (!CheckValidParam(x, y) || (pixelBytes_ != ARGB_8888_BYTES)) { + HiLog::Error(LABEL, "get addr32 pixel position:(%{public}d, %{public}d) pixel bytes:%{public}d invalid.", x, y, + pixelBytes_); + return nullptr; + } + // convert uint8_t* to uint32_t* + return reinterpret_cast(data_ + y * rowDataSize_ + (static_cast(x) << ARGB_8888_SHIFT)); +} + +const uint8_t *PixelMap::GetPixel(int32_t x, int32_t y) +{ + if (!CheckValidParam(x, y)) { + HiLog::Error(LABEL, "input pixel position:(%{public}d, %{public}d) invalid.", x, y); + return nullptr; + } + return (data_ + y * rowDataSize_ + (static_cast(x) * pixelBytes_)); +} + +bool PixelMap::GetARGB32Color(int32_t x, int32_t y, uint32_t &color) +{ + if (colorProc_ == nullptr) { + HiLog::Error(LABEL, "pixel format not supported."); + return false; + } + const uint8_t *src = GetPixel(x, y); + if (src == nullptr) { + HiLog::Error(LABEL, "get pixel color error."); + return false; + } + // use founction point for frequently called interface + return colorProc_(src, ONE_PIXEL_SIZE * pixelBytes_, &color, ONE_PIXEL_SIZE); +} + +bool PixelMap::ALPHA8ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount) +{ + if (inCount != outCount) { + HiLog::Error(LABEL, "input count:%{public}u is not match to output count:%{public}u.", inCount, outCount); + return false; + } + const uint8_t *src = in; + for (uint32_t i = 0; i < outCount; i++) { + *out++ = GetColorARGB(*src++, BYTE_ZERO, BYTE_ZERO, BYTE_ZERO); + } + return true; +} + +bool PixelMap::RGB565ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount) +{ + if (((inCount / RGB_565_BYTES) != outCount) && ((inCount % RGB_565_BYTES) != 0)) { + HiLog::Error(LABEL, "input count:%{public}u is not match to output count:%{public}u.", inCount, outCount); + return false; + } + const uint16_t *src = reinterpret_cast(in); + for (uint32_t i = 0; i < outCount; i++) { + uint16_t color = *src++; + *out++ = GetColorARGB(BYTE_FULL, RGB565ToR32(color), RGB565ToG32(color), RGB565ToB32(color)); + } + return true; +} + +bool PixelMap::ARGB8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount) +{ + if (((inCount / ARGB_8888_BYTES) != outCount) && ((inCount % ARGB_8888_BYTES) != 0)) { + HiLog::Error(LABEL, "input count:%{public}u is not match to output count:%{public}u.", inCount, outCount); + return false; + } + const uint32_t *src = reinterpret_cast(in); + for (uint32_t i = 0; i < outCount; i++) { + uint32_t color = *src++; + *out++ = GetColorARGB(GetColorComp(color, ARGB32_A_SHIFT), GetColorComp(color, ARGB32_R_SHIFT), + GetColorComp(color, ARGB32_G_SHIFT), GetColorComp(color, ARGB32_B_SHIFT)); + } + return true; +} + +bool PixelMap::RGBA8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount) +{ + if (((inCount / ARGB_8888_BYTES) != outCount) && ((inCount % ARGB_8888_BYTES) != 0)) { + HiLog::Error(LABEL, "input count:%{public}u is not match to output count:%{public}u.", inCount, outCount); + return false; + } + const uint32_t *src = reinterpret_cast(in); + for (uint32_t i = 0; i < outCount; i++) { + uint32_t color = *src++; + *out++ = GetColorARGB(GetColorComp(color, RGBA32_A_SHIFT), GetColorComp(color, RGBA32_R_SHIFT), + GetColorComp(color, RGBA32_G_SHIFT), GetColorComp(color, RGBA32_B_SHIFT)); + } + return true; +} + +bool PixelMap::BGRA8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount) +{ + if (((inCount / ARGB_8888_BYTES) != outCount) && ((inCount % ARGB_8888_BYTES) != 0)) { + HiLog::Error(LABEL, "input count:%{public}u is not match to output count:%{public}u.", inCount, outCount); + return false; + } + const uint32_t *src = reinterpret_cast(in); + for (uint32_t i = 0; i < outCount; i++) { + uint32_t color = *src++; + *out++ = GetColorARGB(GetColorComp(color, BGRA32_A_SHIFT), GetColorComp(color, BGRA32_R_SHIFT), + GetColorComp(color, BGRA32_G_SHIFT), GetColorComp(color, BGRA32_B_SHIFT)); + } + return true; +} + +bool PixelMap::RGB888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount) +{ + if (((inCount / RGB_888_BYTES) != outCount) && ((inCount % RGB_888_BYTES) != 0)) { + HiLog::Error(LABEL, "input count:%{public}u is not match to output count:%{public}u.", inCount, outCount); + return false; + } + const uint8_t *src = in; + for (uint32_t i = 0; i < outCount; i++) { + uint8_t colorR = *src++; + uint8_t colorG = *src++; + uint8_t colorB = *src++; + *out++ = GetColorARGB(BYTE_FULL, colorR, colorG, colorB); + } + return true; +} + +int32_t PixelMap::GetPixelBytes() +{ + return pixelBytes_; +} + +int32_t PixelMap::GetRowBytes() +{ + return rowDataSize_; +} + +int32_t PixelMap::GetByteCount() +{ + return rowDataSize_ * imageInfo_.size.height; +} + +int32_t PixelMap::GetWidth() +{ + return imageInfo_.size.width; +} + +int32_t PixelMap::GetHeight() +{ + return imageInfo_.size.height; +} + +int32_t PixelMap::GetBaseDensity() +{ + return imageInfo_.baseDensity; +} + +void PixelMap::GetImageInfo(ImageInfo &imageInfo) +{ + imageInfo = imageInfo_; +} + +PixelFormat PixelMap::GetPixelFormat() +{ + return imageInfo_.pixelFormat; +} + +ColorSpace PixelMap::GetColorSpace() +{ + return imageInfo_.colorSpace; +} + +AlphaType PixelMap::GetAlphaType() +{ + return imageInfo_.alphaType; +} + +const uint8_t *PixelMap::GetPixels() +{ + return data_; +} + +uint8_t PixelMap::GetARGB32ColorA(uint32_t color) +{ + return (color >> ARGB_A_SHIFT) & ARGB_MASK; +} + +uint8_t PixelMap::GetARGB32ColorR(uint32_t color) +{ + return (color >> ARGB_R_SHIFT) & ARGB_MASK; +} + +uint8_t PixelMap::GetARGB32ColorG(uint32_t color) +{ + return (color >> ARGB_G_SHIFT) & ARGB_MASK; +} + +uint8_t PixelMap::GetARGB32ColorB(uint32_t color) +{ + return (color >> ARGB_B_SHIFT) & ARGB_MASK; +} + +bool PixelMap::IsSameImage(const PixelMap &other) +{ + if (data_ == nullptr || other.data_ == nullptr) { + return false; + } + if (imageInfo_.size.width != other.imageInfo_.size.width || + imageInfo_.size.height != other.imageInfo_.size.height || + imageInfo_.pixelFormat != other.imageInfo_.pixelFormat || imageInfo_.alphaType != other.imageInfo_.alphaType) { + return false; + } + uint64_t size = static_cast(rowDataSize_) * imageInfo_.size.height; + if (memcmp(data_, other.data_, size) != 0) { + return false; + } + return true; +} + +uint32_t PixelMap::ReadPixels(const uint64_t &bufferSize, uint8_t *dst) +{ + if (dst == nullptr) { + HiLog::Error(LABEL, "read pixels by buffer input dst address is null."); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "read pixels by buffer current PixelMap data is null."); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + if (bufferSize < static_cast(pixelsSize_)) { + HiLog::Error(LABEL, "read pixels by buffer input dst buffer(%{public}llu) < current pixelmap size(%{public}u).", + static_cast(bufferSize), pixelsSize_); + return ERR_IMAGE_INVALID_PARAMETER; + } + errno_t ret = memcpy_s(dst, bufferSize, data_, pixelsSize_); + if (ret != 0) { + HiLog::Error(LABEL, "read pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + return SUCCESS; +} + +bool PixelMap::CheckPixelsInput(const uint8_t *dst, const uint64_t &bufferSize, const uint32_t &offset, + const uint32_t &stride, const Rect ®ion) +{ + if (dst == nullptr) { + HiLog::Error(LABEL, "CheckPixelsInput input dst address is null."); + return false; + } + if (region.left < 0 || region.top < 0 || stride > numeric_limits::max() || + static_cast(offset) > bufferSize) { + HiLog::Error( + LABEL, + "CheckPixelsInput left(%{public}d) or top(%{public}d) or stride(%{public}u) or offset(%{public}u) < 0.", + region.left, region.top, stride, offset); + return false; + } + if (region.width <= 0 || region.height <= 0 || region.width > MAX_DIMENSION || region.height > MAX_DIMENSION) { + HiLog::Error(LABEL, "CheckPixelsInput width(%{public}d) or height(%{public}d) is < 0.", region.width, + region.height); + return false; + } + if (region.left > GetWidth() - region.width) { + HiLog::Error(LABEL, "CheckPixelsInput left(%{public}d) + width(%{public}d) is > pixelmap width(%{public}d).", + region.left, region.width, GetWidth()); + return false; + } + if (region.top > GetHeight() - region.height) { + HiLog::Error(LABEL, "CheckPixelsInput top(%{public}d) + height(%{public}d) is > pixelmap height(%{public}d).", + region.top, region.height, GetHeight()); + return false; + } + uint32_t regionStride = static_cast(region.width) * 4; // bytes count, need multiply by 4 + if (stride < regionStride) { + HiLog::Error(LABEL, "CheckPixelsInput left(%{public}d) + width(%{public}d) is > pixelmap width(%{public}d).", + region.left, region.width, GetWidth()); + return false; + } + uint64_t lastLinePos = offset + static_cast(region.height - 1) * stride; // "1" is except the last line. + if (static_cast(offset) > (bufferSize - regionStride) || lastLinePos > (bufferSize - regionStride)) { + HiLog::Error(LABEL, + "CheckPixelsInput fail, height(%{public}d), width(%{public}d), lastLine(%{public}llu), " + "offset(%{public}u), bufferSize:%{public}llu.", + region.height, region.width, static_cast(lastLinePos), offset, + static_cast(bufferSize)); + return false; + } + return true; +} + +uint32_t PixelMap::ReadPixels(const uint64_t &bufferSize, const uint32_t &offset, const uint32_t &stride, + const Rect ®ion, uint8_t *dst) +{ + if (!CheckPixelsInput(dst, bufferSize, offset, stride, region)) { + HiLog::Error(LABEL, "read pixels by rect input parameter fail."); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "read pixels by rect this pixel data is null."); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + ImageInfo dstImageInfo = + MakeImageInfo(region.width, region.height, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + Position srcPosition{ region.left, region.top }; + if (!PixelConvertAdapter::ReadPixelsConvert(data_, srcPosition, rowDataSize_, imageInfo_, dst + offset, stride, + dstImageInfo)) { + HiLog::Error(LABEL, "read pixels by rect call ReadPixelsConvert fail."); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + return SUCCESS; +} + +uint32_t PixelMap::ReadPixel(const Position &pos, uint32_t &dst) +{ + if (pos.x < 0 || pos.y < 0 || pos.x >= GetWidth() || pos.y >= GetHeight()) { + HiLog::Error(LABEL, "read pixel by pos input invalid exception. [x(%{public}d), y(%{public}d)]", pos.x, pos.y); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "read pixel by pos source data is null."); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + ImageInfo dstImageInfo = + MakeImageInfo(PER_PIXEL_LEN, PER_PIXEL_LEN, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + uint32_t dstRowBytes = BGRA_BYTES; + Position srcPosition{ pos.x, pos.y }; + if (!PixelConvertAdapter::ReadPixelsConvert(data_, srcPosition, rowDataSize_, imageInfo_, &dst, dstRowBytes, + dstImageInfo)) { + HiLog::Error(LABEL, "read pixel by pos call ReadPixelsConvert fail."); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + return SUCCESS; +} + +uint32_t PixelMap::ResetConfig(const Size &size, const PixelFormat &format) +{ + if (size.width <= 0 || size.height <= 0) { + HiLog::Error(LABEL, "ResetConfig reset input width(%{public}d) or height(%{public}d) is < 0.", size.width, + size.height); + return ERR_IMAGE_INVALID_PARAMETER; + } + uint32_t bytesPerPixel = ImageUtils::GetPixelBytes(format); + if (bytesPerPixel == 0) { + HiLog::Error(LABEL, "ResetConfig get bytes by per pixel fail."); + return ERR_IMAGE_INVALID_PARAMETER; + } + uint64_t dstSize = static_cast(size.width) * size.height * bytesPerPixel; + if (dstSize > static_cast(pixelsSize_)) { + HiLog::Error(LABEL, "ResetConfig reset dstSize(%{public}llu) > current(%{public}u).", + static_cast(dstSize), pixelsSize_); + return ERR_IMAGE_INVALID_PARAMETER; + } + AlphaType dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(GetAlphaType(), format); + if (dstAlphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) { + HiLog::Error(LABEL, "ResetConfig Failed to get validate alpha type."); + return ERR_IMAGE_INVALID_PARAMETER; + } + ImageInfo dstInfo = MakeImageInfo(size.width, size.height, format, dstAlphaType); + uint32_t ret = SetImageInfo(dstInfo, true); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "ResetConfig call SetImageInfo Failed. ret:%{public}u", ret); + return ERR_IMAGE_CONFIG_FAILED; + } + return SUCCESS; +} + +bool PixelMap::SetAlphaType(const AlphaType &alphaType) +{ + AlphaType type = ImageUtils::GetValidAlphaTypeByFormat(alphaType, imageInfo_.pixelFormat); + if (type == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) { + HiLog::Error(LABEL, "SetAlphaType Failed to get validate alpha type."); + return false; + } + ImageInfo dstInfo = imageInfo_; + dstInfo.alphaType = type; + uint32_t ret = SetImageInfo(dstInfo, true); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "SetAlphaType call SetImageInfo Failed. ret:%{public}u", ret); + return false; + } + return true; +} + +uint32_t PixelMap::WritePixel(const Position &pos, const uint32_t &color) +{ + if (pos.x < 0 || pos.y < 0 || pos.x >= GetWidth() || pos.y >= GetHeight()) { + HiLog::Error(LABEL, + "write pixel by pos but input position is invalid. [x(%{public}d), y(%{public}d)]"\ + "Width() %{public}d, Height() %{public}d, ", + pos.x, pos.y, GetWidth(), GetHeight()); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (!IsEditable()) { + HiLog::Error(LABEL, "write pixel by pos pixelmap is not editable."); + return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY; + } + if (!ImageUtils::IsValidImageInfo(imageInfo_)) { + HiLog::Error(LABEL, "write pixel by pos current pixelmap image info is invalid."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "write pixel by pos but current pixelmap data is nullptr."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + ImageInfo srcImageInfo = + MakeImageInfo(PER_PIXEL_LEN, PER_PIXEL_LEN, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + uint32_t srcRowBytes = BGRA_BYTES; + Position dstPosition{ pos.x, pos.y }; // source is per pixel. + if (!PixelConvertAdapter::WritePixelsConvert(&color, srcRowBytes, srcImageInfo, data_, dstPosition, rowDataSize_, + imageInfo_)) { + HiLog::Error(LABEL, "write pixel by pos call WritePixelsConvert fail."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + return SUCCESS; +} + +uint32_t PixelMap::WritePixels(const uint8_t *source, const uint64_t &bufferSize, const uint32_t &offset, + const uint32_t &stride, const Rect ®ion) +{ + if (!CheckPixelsInput(source, bufferSize, offset, stride, region)) { + HiLog::Error(LABEL, "write pixel by rect input parameter fail."); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (!IsEditable()) { + HiLog::Error(LABEL, "write pixel by rect pixelmap data is not editable."); + return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY; + } + if (!ImageUtils::IsValidImageInfo(imageInfo_)) { + HiLog::Error(LABEL, "write pixel by rect current pixelmap image info is invalid."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "write pixel by rect current pixel map data is null."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + uint32_t bytesPerPixel = ImageUtils::GetPixelBytes(imageInfo_.pixelFormat); + if (bytesPerPixel == 0) { + HiLog::Error(LABEL, "write pixel by rect get bytes by per pixel fail."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + Position dstPosition{ region.left, region.top }; + ImageInfo srcInfo = + MakeImageInfo(region.width, region.height, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + if (!PixelConvertAdapter::WritePixelsConvert(source + offset, stride, srcInfo, data_, dstPosition, rowDataSize_, + imageInfo_)) { + HiLog::Error(LABEL, "write pixel by rect call WritePixelsConvert fail."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + return SUCCESS; +} + +uint32_t PixelMap::WritePixels(const uint8_t *source, const uint64_t &bufferSize) +{ + if (source == nullptr || bufferSize < static_cast(pixelsSize_)) { + HiLog::Error(LABEL, "write pixels by buffer source is nullptr or size(%{public}llu) < pixelSize(%{public}u).", + static_cast(bufferSize), pixelsSize_); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (!IsEditable()) { + HiLog::Error(LABEL, "write pixels by buffer pixelmap data is not editable."); + return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY; + } + if (!ImageUtils::IsValidImageInfo(imageInfo_)) { + HiLog::Error(LABEL, "write pixels by buffer current pixelmap image info is invalid."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "write pixels by buffer current pixelmap data is nullptr."); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + errno_t ret = memcpy_s(data_, pixelsSize_, source, pixelsSize_); + if (ret != 0) { + HiLog::Error(LABEL, "write pixels by buffer memcpy to pixelmap data from source fail, error:%{public}d", ret); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } + return SUCCESS; +} + +bool PixelMap::WritePixels(const uint32_t &color) +{ + if (!IsEditable()) { + HiLog::Error(LABEL, "erase pixels by color pixelmap data is not editable."); + return false; + } + if (!ImageUtils::IsValidImageInfo(imageInfo_)) { + HiLog::Error(LABEL, "erase pixels by color current pixelmap image info is invalid."); + return false; + } + if (data_ == nullptr) { + HiLog::Error(LABEL, "erase pixels by color current pixel map data is null."); + return false; + } + ImageInfo srcInfo = + MakeImageInfo(imageInfo_.size.width, imageInfo_.size.height, imageInfo_.pixelFormat, imageInfo_.alphaType); + if (!PixelConvertAdapter::EraseBitmap(data_, rowDataSize_, srcInfo, color)) { + HiLog::Error(LABEL, "erase pixels by color call EraseBitmap fail."); + return false; + } + return true; +} + +AllocatorType PixelMap::GetAllocatorType() +{ + return allocatorType_; +} + +void *PixelMap::GetFd() const +{ + return context_; +} + +bool PixelMap::WriteFileDescriptor(Parcel &data, int fd) const +{ + if (fd < 0) { + return false; + } + int dupFd = dup(fd); + if (dupFd < 0) { + return false; + } + sptr descriptor = new IPCFileDescriptor(dupFd); + return data.WriteObject(descriptor); +} + +int PixelMap::ReadFileDescriptor(Parcel &data) +{ + sptr descriptor = data.ReadObject(); + if (descriptor == nullptr) { + return -1; + } + int fd = descriptor->GetFd(); + if (fd < 0) { + return -1; + } + return dup(fd); +} + +bool PixelMap::Marshalling(Parcel &data) const +{ + int32_t PIXEL_MAP_INFO_MAX_LENGTH = 128; + int32_t bufferSize = rowDataSize_ * imageInfo_.size.height; + + if (static_cast(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH) > data.GetDataCapacity() && + !data.SetDataCapacity(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH)) { + HiLog::Error(LABEL, "set parcel max capacity:[%{public}d] failed.", bufferSize + PIXEL_MAP_INFO_MAX_LENGTH); + return false; + } + if (!data.WriteInt32(imageInfo_.size.width)) { + HiLog::Error(LABEL, "write pixel map width:[%{public}d] to parcel failed.", imageInfo_.size.width); + return false; + } + if (!data.WriteInt32(imageInfo_.size.height)) { + HiLog::Error(LABEL, "write pixel map height:[%{public}d] to parcel failed.", imageInfo_.size.height); + return false; + } + if (!data.WriteInt32(static_cast(imageInfo_.pixelFormat))) { + HiLog::Error(LABEL, "write pixel map pixel format:[%{public}d] to parcel failed.", imageInfo_.pixelFormat); + return false; + } + if (!data.WriteInt32(static_cast(imageInfo_.colorSpace))) { + HiLog::Error(LABEL, "write pixel map color space:[%{public}d] to parcel failed.", imageInfo_.colorSpace); + return false; + } + if (!data.WriteInt32(static_cast(imageInfo_.alphaType))) { + HiLog::Error(LABEL, "write pixel map alpha type:[%{public}d] to parcel failed.", imageInfo_.alphaType); + return false; + } + if (!data.WriteInt32(imageInfo_.baseDensity)) { + HiLog::Error(LABEL, "write pixel map base density:[%{public}d] to parcel failed.", imageInfo_.baseDensity); + return false; + } + if (!data.WriteInt32(bufferSize)) { + HiLog::Error(LABEL, "write pixel map buffer size:[%{public}d] to parcel failed.", bufferSize); + return false; + } + if (!data.WriteInt32(static_cast(allocatorType_))) { + HiLog::Error(LABEL, "write pixel map allocator type:[%{public}d] to parcel failed.", + allocatorType_); + return false; + } + if (allocatorType_ == AllocatorType::SHARE_MEM_ALLOC) { + int *fd = static_cast(context_); + if (*fd < 0) { + HiLog::Error(LABEL, "write pixel map failed, fd < 0."); + return false; + } + if (!WriteFileDescriptor(data, *fd)) { + HiLog::Error(LABEL, "write pixel map fd:[%{public}d] to parcel failed.", *fd); + return false; + } + } else { + const uint8_t *addr = data_; + if (addr == nullptr) { + HiLog::Error(LABEL, "write to parcel failed, pixel memory is null."); + return false; + } + if (!data.WriteBuffer(addr, bufferSize)) { + HiLog::Error(LABEL, "write pixel map buffer to parcel failed."); + return false; + } + } + return true; +} + +PixelMap *PixelMap::Unmarshalling(Parcel &data) +{ + PixelMap *pixelMap = new PixelMap(); + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "create pixelmap pointer fail"); + return nullptr; + } + + ImageInfo imgInfo; + imgInfo.size.width = data.ReadInt32(); + imgInfo.size.height = data.ReadInt32(); + imgInfo.pixelFormat = static_cast(data.ReadInt32()); + imgInfo.colorSpace = static_cast(data.ReadInt32()); + imgInfo.alphaType = static_cast(data.ReadInt32()); + imgInfo.baseDensity = data.ReadInt32(); + int32_t bufferSize = data.ReadInt32(); + AllocatorType allocType = static_cast(data.ReadInt32()); + uint8_t *base = nullptr; + void *context = nullptr; + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { + int fd = ReadFileDescriptor(data); + if (fd < 0) { + HiLog::Error(LABEL, "fd < 0"); + return nullptr; + } + HiLog::Debug(LABEL, "ReadFileDescriptor fd %{public}d.", fd); + void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + HiLog::Error(LABEL, "shared memory map failed"); + return nullptr; + } + context = new int32_t(); + if (context == nullptr) { + HiLog::Error(LABEL, "alloc context error."); + ::munmap(ptr, bufferSize); + ::close(fd); + return nullptr; + } + *static_cast(context) = fd; + base = static_cast(ptr); + } else { + const uint8_t *addr = data.ReadBuffer(bufferSize); + if (addr == nullptr) { + HiLog::Error(LABEL, "read buffer from parcel failed, read buffer addr is null"); + return nullptr; + } + base = static_cast(malloc(bufferSize)); + if (base == nullptr) { + HiLog::Error(LABEL, "alloc output pixel memory size:[%{public}d] error.", bufferSize); + return nullptr; + } + if (memcpy_s(base, bufferSize, addr, bufferSize) != 0) { + free(base); + base = nullptr; + HiLog::Error(LABEL, "memcpy pixel data size:[%{public}d] error.", bufferSize); + return nullptr; + } + } + + uint32_t ret = pixelMap->SetImageInfo(imgInfo); + if (ret != SUCCESS) { + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { + int *fd = static_cast(context); + if (base != nullptr) { + ::munmap(base, bufferSize); + } + if (fd != nullptr) { + ::close(*fd); + delete fd; + } + } else if (allocType == AllocatorType::HEAP_ALLOC) { + if (base != nullptr) { + free(base); + base = nullptr; + } + } + HiLog::Error(LABEL, "create pixel map from parcel failed, set image info error."); + return nullptr; + } + pixelMap->SetPixelsAddr(base, context, bufferSize, allocType, nullptr); + return pixelMap; +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/common/src/pixel_map_parcel.cpp b/frameworks/innerkitsimpl/common/src/pixel_map_parcel.cpp new file mode 100755 index 0000000000000000000000000000000000000000..595dcbbfb1005e77425e74973a3408f7d6851023 --- /dev/null +++ b/frameworks/innerkitsimpl/common/src/pixel_map_parcel.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pixel_map_parcel.h" +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "media_errors.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +#if !defined(_WIN32) && !defined(_APPLE) +#include +#include "ashmem.h" +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelMapParcel" }; + +constexpr int32_t PIXEL_MAP_INFO_MAX_LENGTH = 128; + +void PixelMapParcel::ReleaseMemory(AllocatorType allocType, void *addr, void *context, uint32_t size) +{ + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int *fd = static_cast(context); + if (addr != nullptr) { + ::munmap(addr, size); + } + if (fd != nullptr) { + ::close(*fd); + delete fd; + } +#endif + } else if (allocType == AllocatorType::HEAP_ALLOC) { + if (addr != nullptr) { + free(addr); + addr = nullptr; + } + } +} + +std::unique_ptr PixelMapParcel::CreateFromParcel(OHOS::MessageParcel& data) +{ + unique_ptr pixelMap = make_unique(); + if (pixelMap == nullptr) { + HiLog::Error(LABEL, "create pixelmap pointer fail"); + return nullptr; + } + + ImageInfo imgInfo; + imgInfo.size.width = data.ReadInt32(); + imgInfo.size.height = data.ReadInt32(); + imgInfo.pixelFormat = static_cast(data.ReadInt32()); + imgInfo.colorSpace = static_cast(data.ReadInt32()); + imgInfo.alphaType = static_cast(data.ReadInt32()); + imgInfo.baseDensity = data.ReadInt32(); + int32_t bufferSize = data.ReadInt32(); + AllocatorType allocType = static_cast(data.ReadInt32()); + uint8_t *base = nullptr; + void *context = nullptr; + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int fd = data.ReadFileDescriptor(); + if (fd < 0) { + HiLog::Error(LABEL, "fd < 0"); + return nullptr; + } + HiLog::Debug(LABEL, "ReadFileDescriptor fd %{public}d.", fd); + void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + HiLog::Error(LABEL, "shared memory map failed"); + return nullptr; + } + context = new int32_t(); + if (context == nullptr) { + HiLog::Error(LABEL, "alloc context error."); + ::munmap(ptr, bufferSize); + ::close(fd); + return nullptr; + } + *static_cast(context) = fd; + base = static_cast(ptr); +#endif + } else { + const uint8_t *addr = data.ReadBuffer(bufferSize); + if (addr == nullptr) { + HiLog::Error(LABEL, "read buffer from parcel failed, read buffer addr is null"); + return nullptr; + } + base = static_cast(malloc(bufferSize)); + if (base == nullptr) { + HiLog::Error(LABEL, "alloc output pixel memory size:[%{public}d] error.", bufferSize); + return nullptr; + } + if (memcpy_s(base, bufferSize, addr, bufferSize) != 0) { + free(base); + base = nullptr; + HiLog::Error(LABEL, "memcpy pixel data size:[%{public}d] error.", bufferSize); + return nullptr; + } + } + + uint32_t ret = pixelMap->SetImageInfo(imgInfo); + if (ret != SUCCESS) { + ReleaseMemory(allocType, base, context, bufferSize); + HiLog::Error(LABEL, "create pixel map from parcel failed, set image info error."); + return nullptr; + } + pixelMap->SetPixelsAddr(base, context, bufferSize, allocType, nullptr); + return pixelMap; +} + +bool PixelMapParcel::WriteToParcel(PixelMap* pixelMap, OHOS::MessageParcel& data) +{ + if (pixelMap == nullptr) { + return false; + } + int32_t bufferSize = pixelMap->GetByteCount(); + if (static_cast(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH) > data.GetDataCapacity() && + !data.SetDataCapacity(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH)) { + HiLog::Error(LABEL, "set parcel max capacity:[%{public}d] failed.", bufferSize + PIXEL_MAP_INFO_MAX_LENGTH); + return false; + } + if (!data.WriteInt32(pixelMap->GetWidth())) { + HiLog::Error(LABEL, "write pixel map width:[%{public}d] to parcel failed.", pixelMap->GetWidth()); + return false; + } + if (!data.WriteInt32(pixelMap->GetHeight())) { + HiLog::Error(LABEL, "write pixel map height:[%{public}d] to parcel failed.", pixelMap->GetHeight()); + return false; + } + if (!data.WriteInt32(static_cast(pixelMap->GetPixelFormat()))) { + HiLog::Error(LABEL, "write pixel map pixel format:[%{public}d] to parcel failed.", pixelMap->GetPixelFormat()); + return false; + } + if (!data.WriteInt32(static_cast(pixelMap->GetColorSpace()))) { + HiLog::Error(LABEL, "write pixel map color space:[%{public}d] to parcel failed.", pixelMap->GetColorSpace()); + return false; + } + if (!data.WriteInt32(static_cast(pixelMap->GetAlphaType()))) { + HiLog::Error(LABEL, "write pixel map alpha type:[%{public}d] to parcel failed.", pixelMap->GetAlphaType()); + return false; + } + if (!data.WriteInt32(pixelMap->GetBaseDensity())) { + HiLog::Error(LABEL, "write pixel map base density:[%{public}d] to parcel failed.", pixelMap->GetBaseDensity()); + return false; + } + if (!data.WriteInt32(bufferSize)) { + HiLog::Error(LABEL, "write pixel map buffer size:[%{public}d] to parcel failed.", bufferSize); + return false; + } + if (!data.WriteInt32(static_cast(pixelMap->GetAllocatorType()))) { + HiLog::Error(LABEL, "write pixel map allocator type:[%{public}d] to parcel failed.", + pixelMap->GetAllocatorType()); + return false; + } + if (pixelMap->GetAllocatorType() == AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int *fd = static_cast(pixelMap->GetFd()); + if (*fd < 0) { + HiLog::Error(LABEL, "write pixel map failed, fd < 0."); + return false; + } + if (!data.WriteFileDescriptor(*fd)) { + HiLog::Error(LABEL, "write pixel map fd:[%{public}d] to parcel failed.", *fd); + return false; + } +#endif + } else { + const uint8_t *addr = pixelMap->GetPixels(); + if (addr == nullptr) { + HiLog::Error(LABEL, "write to parcel failed, pixel memory is null."); + return false; + } + if (!data.WriteBuffer(addr, bufferSize)) { + HiLog::Error(LABEL, "write pixel map buffer to parcel failed."); + return false; + } + } + return true; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/converter/include/basic_transformer.h b/frameworks/innerkitsimpl/converter/include/basic_transformer.h new file mode 100644 index 0000000000000000000000000000000000000000..7936b0d10b5a728b32754428d36c1f6b14fa33cf --- /dev/null +++ b/frameworks/innerkitsimpl/converter/include/basic_transformer.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASIC_TRANSFORMER_H +#define BASIC_TRANSFORMER_H + +#include +#include +#include "image_log.h" +#include "image_type.h" +#include "matrix.h" + +namespace OHOS { +namespace Media { +static constexpr uint32_t IMAGE_SUCCESS = 0; // success +static constexpr uint32_t IMAGE_BASE_ERROR = 1000; // base error +static constexpr uint32_t ERR_IMAGE_GENERAL_ERROR = IMAGE_BASE_ERROR + 1; // general error +static constexpr uint32_t ERR_IMAGE_INVALID_PIXEL = IMAGE_BASE_ERROR + 2; // invalid pixel +static constexpr uint32_t ERR_IMAGE_MATRIX_NOT_INVERT = IMAGE_BASE_ERROR + 3; // matrix can not invert +static constexpr uint32_t ERR_IMAGE_ALLOC_MEMORY_FAILED = IMAGE_BASE_ERROR + 4; // alloc memory failed + +static constexpr float FHALF = 0.5f; +static constexpr uint32_t BASIC = 1 << 16; +static constexpr uint32_t HALF_BASIC = 1 << 15; +static constexpr float MULTI_65536 = 65536.0f; +static constexpr uint32_t SUB_VALUE_SHIFT = 12; +static constexpr uint8_t COLOR_DEFAULT = 0; +static constexpr int32_t RGB888_BYTE = 3; + +static inline bool CheckOutOfRange(const Point &pt, const Size &size) +{ + if (pt.x >= 0 && pt.x < size.width && pt.y >= 0 && pt.y < size.height) { + return false; + } + return true; +} + +static inline int32_t ClampMax(int value, int max) +{ + if (value > max) { + value = max; + } + return (value > 0) ? value : 0; +} + +static inline uint32_t GetSubValue(int32_t value) +{ + // In order to speed up the calculation, use offset + return ((value >> SUB_VALUE_SHIFT) & 0xF); +} + +struct PixmapInfo { + ImageInfo imageInfo; + uint8_t *data = nullptr; + uint32_t bufferSize = 0; + bool isAutoDestruct = true; + PixmapInfo(){}; + + ~PixmapInfo() + { + if (isAutoDestruct) { + if (data != nullptr) { + free(data); + data = nullptr; + } + } + } + + explicit PixmapInfo(bool isAuto) + { + isAutoDestruct = isAuto; + } + explicit PixmapInfo(const PixmapInfo &src) + { + Init(src); + } + + void Init(const PixmapInfo &src) + { + imageInfo = src.imageInfo; + data = nullptr; + bufferSize = 0; + } + + void Destroy() + { + if (data != nullptr) { + free(data); + data = nullptr; + } + } + + void PrintPixmapInfo(const std::string &strFlag) const + { + IMAGE_LOGD("[PixmapInfo][%{public}s][width, height:%{public}d, %{public}d]\ + [bufferSize:%{public}u][pixelFormat:%{public}d].", + strFlag.c_str(), imageInfo.size.width, imageInfo.size.height, bufferSize, + static_cast(imageInfo.pixelFormat)); + } +}; + +class BasicTransformer { +public: + using AllocateMem = uint8_t *(*)(const Size &size, const uint64_t bufferSize, int &fd); + + BasicTransformer() + { + ResetParam(); + }; + ~BasicTransformer(){}; + + // Reset pixel map info transform param, back to the original state + void ResetParam(); + + // Reserved interface + void SetTranslateParam(const float tx, const float ty); + + void SetScaleParam(const float sx, const float sy); + + /** Set rotates param by degrees about a point at (px, py). Positive degrees rotates + * clockwise. + * + * @param degrees amount to rotate, in degrees + * @param px x-axis value of the point to rotate about + * @param py y-axis value of the point to rotate about + */ + void SetRotateParam(const float degrees, const float px = 0.0f, const float py = 0.0f); + + /** + * Transform pixel map info. before transform, you should set pixel transform param first. + * @param inPixmap The input pixel map info + * @param outPixmap The output pixel map info, the pixelFormat and colorSpace same as the inPixmap + * @param allocate This is func pointer, if it is null, this function will new heap memory, + * so you must active release memory, if it is not null, that means you need allocate memory by yourself, + * so you should invoke GetDstWH function to get the dest width and height, + * then fill to outPixmap's width and height. + * @return the error no + */ + uint32_t TransformPixmap(const PixmapInfo &inPixmap, PixmapInfo &outPixmap, AllocateMem allocate = nullptr); + + void GetDstDimension(const Size &srcSize, Size &dstSize); + +private: + struct AroundPixels { + uint32_t color00 = 0; + uint32_t color01 = 0; + uint32_t color10 = 0; + uint32_t color11 = 0; + }; + struct AroundPos { + uint32_t x0 = 0; + uint32_t x1 = 0; + uint32_t y0 = 0; + uint32_t y1 = 0; + }; + + uint32_t RightShift16Bit(uint32_t num, int32_t maxNum); + + void GetRotateDimension(Matrix::CalcXYProc fInvProc, const Size &srcSize, Size &dstSize); + + bool DrawPixelmap(const PixmapInfo &pixmapInfo, const int32_t pixelBytes, const Size &size, uint8_t *data); + + bool CheckAllocateBuffer(PixmapInfo &outPixmap, AllocateMem allocate, int &fd, uint64_t &bufferSize, Size &dstSize); + + void BilinearProc(const Point &pt, const PixmapInfo &pixmapInfo, const uint32_t rb, const int32_t shiftBytes, + uint8_t *data); + void GetAroundPixelRGB565(const AroundPos aroundPos, uint8_t *data, uint32_t rb, AroundPixels &aroundPixels); + + void GetAroundPixelRGB888(const AroundPos aroundPos, uint8_t *data, uint32_t rb, AroundPixels &aroundPixels); + + void GetAroundPixelRGBA(const AroundPos aroundPos, uint8_t *data, uint32_t rb, AroundPixels &aroundPixels); + + void GetAroundPixelALPHA8(const AroundPos aroundPos, uint8_t *data, uint32_t rb, AroundPixels &aroundPixels); + + /* Calculate the target pixel based on the pixels of 4 nearby points. + * Fill in new pixels with formula + * f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1) + */ + uint32_t FilterProc(const uint32_t subx, const uint32_t suby, const AroundPixels &aroundPixels); + + void ReleaseBuffer(AllocatorType allocatorType, int fd, int dataSize, uint8_t *buffer); + + Matrix matrix_; + float minX_ = 0.0f; + float minY_ = 0.0f; +}; +} // namespace Media +} // namespace OHOS +#endif // BASIC_TRANSFORMER_H diff --git a/frameworks/innerkitsimpl/converter/include/matrix.h b/frameworks/innerkitsimpl/converter/include/matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..7545c4c4cde235bd4279f0dacafba3d1f3bd0cc1 --- /dev/null +++ b/frameworks/innerkitsimpl/converter/include/matrix.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MATRIX_H +#define MATRIX_H + +#include +#include "image_log.h" +#include "image_type.h" + +namespace OHOS { +namespace Media { +struct Point { + float x = 0.0f; + float y = 0.0f; +}; + +static constexpr int32_t IMAGE_SCALEX = 0; +static constexpr int32_t IMAGE_SKEWX = 1; +static constexpr int32_t IMAGE_TRANSX = 2; +static constexpr int32_t IMAGE_SKEWY = 3; +static constexpr int32_t IMAGE_SCALEY = 4; +static constexpr int32_t IMAGE_TRANSY = 5; +static constexpr int32_t IMAGE_PERSP0 = 6; +static constexpr int32_t IMAGE_PERSP1 = 7; +static constexpr int32_t IMAGE_PERSP2 = 8; +static constexpr int32_t MATIRX_ITEM_NUM = 9; + +static constexpr uint32_t IDENTITY_TYPE = 0; +static constexpr uint32_t TRANSLATE_TYPE = 0x01; +static constexpr uint32_t SCALE_TYPE = 0x02; +static constexpr uint32_t ROTATEORSKEW_TYPE = 0x04; +static constexpr uint32_t PERSPECTIVE_TYPE = 0x08; + +static constexpr float FLOAT_PI = 3.14159265f; +static constexpr float FLOAT_NEAR_ZERO = (1.0f / (1 << 12)); +static constexpr float RADIAN_FACTOR = 180.0f; +static constexpr uint32_t CALCPROC_FACTOR = 0x07; +static constexpr uint32_t OPERTYPE_MASK = 0xF; +static constexpr float MATRIX_EPSILON = 1e-6; + +// Degrees to Radians +static inline float DegreesToRadians(const float degrees) +{ + return degrees * (FLOAT_PI / RADIAN_FACTOR); +} + +// Radians to Degrees +static inline float RadiansToDegrees(const float radians) +{ + return radians * (RADIAN_FACTOR / FLOAT_PI); +} + +static inline float ValueNearToZero(const float radians, bool isSin) +{ + float value = (isSin ? sinf(radians) : cosf(radians)); + return (fabsf(value) <= FLOAT_NEAR_ZERO) ? 0.0f : value; +} + +static inline double MulAddMul(const float a, const float b, const float c, const float d) +{ + return a * b + c * d; +} + +static inline double MulSubMul(const float a, const float b, const float c, const float d) +{ + return a * b - c * d; +} + +static inline float FDivide(const float number, const float denom) +{ + if (std::fabs(denom - 0) < MATRIX_EPSILON) { + return 0.0f; + } + return number / denom; +} + +class Matrix { +public: + enum OperType { + IDENTITY = IDENTITY_TYPE, + TRANSLATE = TRANSLATE_TYPE, + SCALE = SCALE_TYPE, + ROTATEORSKEW = ROTATEORSKEW_TYPE, + PERSPECTIVE = PERSPECTIVE_TYPE, + }; + + using CalcXYProc = void (*)(const Matrix &m, const float x, const float y, Point &result); + + /** The default is the identity matrix + * | 1 0 0 | + * | 0 1 0 | + * | 0 0 1 | + */ + constexpr Matrix() : Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1, IDENTITY){}; + + constexpr Matrix(float sx, float kx, float tx, float ky, float sy, float ty, float p0, float p1, float p2, + uint32_t operType) + : fMat_{ sx, kx, tx, ky, sy, ty, p0, p1, p2 }, operType_(operType){}; + + ~Matrix() = default; + + static const CalcXYProc gCalcXYProcs[]; + + bool IsIdentity() const + { + return GetOperType() == 0; + } + + Matrix &SetTranslate(const float tx, const float ty); + + Matrix &SetScale(const float sx, const float sy); + + Matrix &SetRotate(const float degrees, const float px = 0.0, const float py = 0.0); + + Matrix &SetSinCos(const float sinValue, const float cosValue, const float px, const float py); + + Matrix &SetConcat(const Matrix &m); + + Matrix &Reset(); + + OperType GetOperType() const; + + void SetTranslateAndScale(const float tx, const float ty, const float sx, const float sy); + + static void IdentityXY(const Matrix &m, const float sx, const float sy, Point &pt); + + static void ScaleXY(const Matrix &m, const float sx, const float sy, Point &pt); + + static void TransXY(const Matrix &m, const float tx, const float sy, Point &pt); + + static void RotXY(const Matrix &m, const float rx, const float ry, Point &pt); + + static CalcXYProc GetXYProc(const OperType operType) + { + return gCalcXYProcs[static_cast(operType) & CALCPROC_FACTOR]; + } + + bool Invert(Matrix &invMatrix); + + bool InvertForRotate(Matrix &invMatrix); + + float GetScaleX() const + { + return fMat_[IMAGE_SCALEX]; + } + + float GetScaleY() const + { + return fMat_[IMAGE_SCALEY]; + } + + float GetTransX() const + { + return fMat_[IMAGE_TRANSX]; + } + + float GetTranY() const + { + return fMat_[IMAGE_TRANSY]; + } + + float GetSkewX() const + { + return fMat_[IMAGE_SKEWX]; + } + + float GetSkewY() const + { + return fMat_[IMAGE_SKEWY]; + } + + void Print(); + +private: + /** The fMat_ elements + * | scalex skewx transx | + * | skewy scaley transy | + * | persp0 persp1 persp2 | + */ + float fMat_[MATIRX_ITEM_NUM]; + uint32_t operType_; +}; +} // namespace Media +} // namespace OHOS +#endif // MATRIX_H diff --git a/frameworks/innerkitsimpl/converter/include/pixel_convert.h b/frameworks/innerkitsimpl/converter/include/pixel_convert.h new file mode 100644 index 0000000000000000000000000000000000000000..71eab72800cc2822898425587143725bcea3e31b --- /dev/null +++ b/frameworks/innerkitsimpl/converter/include/pixel_convert.h @@ -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. + */ + +#ifndef PIXEL_CONVERT_H +#define PIXEL_CONVERT_H + +#include +#include +#include "hilog/log.h" +#include "image_type.h" +#include "log_tags.h" + +namespace OHOS { +namespace Media { +enum class AlphaConvertType : uint32_t { + NO_CONVERT = 0, + PREMUL_CONVERT_UNPREMUL = 1, + PREMUL_CONVERT_OPAQUE = 2, + UNPREMUL_CONVERT_PREMUL = 3, + UNPREMUL_CONVERT_OPAQUE = 4, +}; + +// now support AlphaConvertType +struct ProcFuncExtension { + AlphaConvertType alphaConvertType; +}; + +// These values SHOULD be sync with image_type.h PixelFormat +constexpr uint32_t GRAY_BIT = 0x80000001; /* Tow value image, just white or black. */ +constexpr uint32_t GRAY_ALPHA = 0x80000002; +constexpr uint32_t ARGB_8888 = 0x00000001; +constexpr uint32_t RGB_565 = 0x00000002; +constexpr uint32_t RGBA_8888 = 0x00000003; +constexpr uint32_t BGRA_8888 = 0x00000004; +constexpr uint32_t RGB_888 = 0x00000005; +constexpr uint32_t ALPHA_8 = 0x00000006; /* Gray image, 8 bit = 255 color. */ +constexpr uint32_t ABGR_8888 = 0x00000008; +constexpr uint32_t BGR_888 = 0x40000002; +constexpr uint32_t RGB_161616 = 0x40000007; +constexpr uint32_t RGBA_16161616 = 0x40000008; + +constexpr uint32_t CMKY = 0x0000000A; + +constexpr uint32_t SIZE_1_BYTE = 0x00000001; /* a pixel has 8 bit = 1 byte */ +constexpr uint32_t SIZE_2_BYTE = 0x00000002; /* a pixel has 16 bit = 2 byte */ +constexpr uint32_t SIZE_3_BYTE = 0x00000003; +constexpr uint32_t SIZE_4_BYTE = 0x00000004; +constexpr uint32_t SIZE_6_BYTE = 0x00000006; +constexpr uint32_t SIZE_8_BYTE = 0x00000008; + +constexpr uint8_t GRAYSCALE_WHITE = 0xFF; +constexpr uint8_t GRAYSCALE_BLACK = 0x00; +constexpr uint32_t ARGB_WHITE = 0xFFFFFFFF; +constexpr uint32_t ARGB_BLACK = 0xFF000000; +constexpr uint16_t RGB_WHITE = 0xFFFF; +constexpr uint16_t RGB_BLACK = 0x0000; + +constexpr uint8_t ALPHA_OPAQUE = 0xFF; +constexpr uint8_t ALPHA_TRANSPARENT = 0x00; + +constexpr uint32_t GET_8_BIT = 0x80; +constexpr uint32_t GET_1_BIT = 0x01; + +constexpr uint32_t SHIFT_24_BIT = 0x18; +constexpr uint32_t SHIFT_16_BIT = 0x10; +constexpr uint32_t SHIFT_8_BIT = 0x08; +constexpr uint32_t SHIFT_11_BIT = 0x0B; +constexpr uint32_t SHIFT_5_BIT = 0x05; +constexpr uint32_t SHIFT_3_BIT = 0x03; +constexpr uint32_t SHIFT_2_BIT = 0x02; + +constexpr uint8_t SHIFT_5_MASK = 0x1F; +constexpr uint8_t SHIFT_3_MASK = 0x07; + +constexpr uint16_t MAX_15_BIT_VALUE = 0x7FFF; +constexpr float HALF_ONE = 0.5F; +static inline uint32_t Premul255(uint32_t colorComponent, uint32_t alpha) +{ + if (colorComponent > MAX_15_BIT_VALUE || alpha > MAX_15_BIT_VALUE) { + return 0; + } + uint32_t product = colorComponent * alpha + GET_8_BIT; + return ((product + (product >> SHIFT_8_BIT)) >> SHIFT_8_BIT); +} + +static inline uint32_t Unpremul255(uint32_t colorComponent, uint32_t alpha) +{ + if (colorComponent > ALPHA_OPAQUE || alpha > ALPHA_OPAQUE) { + return 0; + } + if (alpha == ALPHA_TRANSPARENT) { + return ALPHA_TRANSPARENT; + } + if (alpha == ALPHA_OPAQUE) { + return colorComponent; + } + uint32_t result = static_cast(colorComponent) * ALPHA_OPAQUE / alpha + HALF_ONE; + return (result > ALPHA_OPAQUE) ? ALPHA_OPAQUE : result; +} + +using ProcFuncType = void (*)(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension); +class PixelConvert { +public: + ~PixelConvert() = default; + static std::unique_ptr Create(const ImageInfo &srcInfo, const ImageInfo &dstInfo); + void Convert(void *destinationPixels, const uint8_t *sourcePixels, uint32_t sourcePixelsNum); + +private: + PixelConvert(ProcFuncType funcPtr, ProcFuncExtension extension, bool isNeedConvert); + static AlphaConvertType GetAlphaConvertType(const AlphaType &srcType, const AlphaType &dstType); + + ProcFuncType procFunc_; + ProcFuncExtension procFuncExtension_; + bool isNeedConvert_ = true; +}; +} // namespace Media +} // namespace OHOS + +#endif /* PIXEL_CONVERT_H */ diff --git a/frameworks/innerkitsimpl/converter/include/post_proc.h b/frameworks/innerkitsimpl/converter/include/post_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..ec3ca58d4af3b6b568c12523285939e99702372d --- /dev/null +++ b/frameworks/innerkitsimpl/converter/include/post_proc.h @@ -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. + */ + +#ifndef POST_PROC_H +#define POST_PROC_H + +#include +#include "basic_transformer.h" +#include "image_type.h" +#include "pixel_map.h" +#include "scan_line_filter.h" + +namespace OHOS { +namespace Media { +enum class CropValue : int32_t { INVALID, VALID, NOCROP }; + +class PostProc { +public: + uint32_t DecodePostProc(const DecodeOptions &opts, PixelMap &pixelMap, + FinalOutputStep finalOutputStep = FinalOutputStep::NO_CHANGE); + uint32_t ConvertProc(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap, ImageInfo &srcImageInfo); + static bool IsHasCrop(const Rect &rect); + bool HasPixelConvert(const ImageInfo &srcImageInfo, ImageInfo &dstImageInfo); + bool RotatePixelMap(float rotateDegrees, PixelMap &pixelMap); + bool ScalePixelMap(const Size &size, PixelMap &pixelMap); + bool ScalePixelMap(float scaleX, float scaleY, PixelMap &pixelMap); + bool CenterScale(const Size &size, PixelMap &pixelMap); + static CropValue GetCropValue(const Rect &rect, const Size &size); + +private: + static uint8_t *AllocSharedMemory(const Size &size, const uint64_t bufferSize, int &fd); + uint32_t NeedScanlineFilter(const Rect &cropRect, const Size &srcSize, const bool &hasPixelConvert); + void GetDstImageInfo(const DecodeOptions &opts, PixelMap &pixelMap, + ImageInfo srcImageInfo, ImageInfo &dstImageInfo); + uint32_t PixelConvertProc(ImageInfo &dstImageInfo, PixelMap &pixelMap, ImageInfo &srcImageInfo); + uint32_t AllocBuffer(ImageInfo imageInfo, uint8_t **resultData, uint64_t &dataSize, int &fd); + bool AllocHeapBuffer(uint64_t bufferSize, uint8_t **buffer); + void ReleaseBuffer(AllocatorType allocatorType, int fd, uint64_t dataSize, uint8_t **buffer); + bool Transform(BasicTransformer &trans, const PixmapInfo &input, PixelMap &pixelMap); + void ConvertPixelMapToPixmapInfo(PixelMap &pixelMap, PixmapInfo &pixmapInfo); + void SetScanlineCropAndConvert(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo, + ScanlineFilter &scanlineFilter, bool hasPixelConvert); + bool CenterDisplay(PixelMap &pixelMap, int32_t srcWidth, int32_t srcHeight, int32_t targetWidth, + int32_t targetHeight); + uint32_t CheckScanlineFilter(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap, + int32_t pixelBytes, ScanlineFilter &scanlineFilter); + DecodeOptions decodeOpts_; +}; +} // namespace Media +} // namespace OHOS + +#endif // POST_PROC_H diff --git a/frameworks/innerkitsimpl/converter/include/scan_line_filter.h b/frameworks/innerkitsimpl/converter/include/scan_line_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..55a733e6a32e77be04009a18c7d4d7fc01ccd7e6 --- /dev/null +++ b/frameworks/innerkitsimpl/converter/include/scan_line_filter.h @@ -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. + */ + +#ifndef SCAN_LINE_FILTER_H +#define SCAN_LINE_FILTER_H + +#include "image_type.h" +#include "pixel_convert.h" + +namespace OHOS { +namespace Media { +enum class FilterRowType : int32_t { NON_REFERENCE_ROW = 0, NORMAL_REFERENCE_ROW = 1, LAST_REFERENCE_ROW = 2 }; +class ScanlineFilter { +public: + ScanlineFilter() = default; + ScanlineFilter(const ScanlineFilter &) = delete; + ScanlineFilter &operator=(const ScanlineFilter &) = delete; + explicit ScanlineFilter(const PixelFormat &srcPixelFormat); + ~ScanlineFilter() = default; + FilterRowType GetFilterRowType(const int32_t rowNum); + void SetSrcPixelFormat(const PixelFormat &srcPixelFormat); + void SetSrcRegion(const Rect ®ion); + void SetPixelConvert(const ImageInfo &srcImageInfo, const ImageInfo &dstImageInfo); + uint32_t FilterLine(void *destRowPixels, uint32_t destRowBytes, const void *srcRowPixels); + +private: + bool ConvertPixels(void *destRowPixels, const uint8_t *startPixel, uint32_t reqPixelNum); + int32_t srcBpp_ = 0; // Bytes per pixel of source image. + Rect srcRegion_; + std::unique_ptr pixelConverter_ = nullptr; + bool needPixelConvert_ = false; +}; +} // namespace Media +} // namespace OHOS + +#endif // SCAN_LINE_FILTER_H diff --git a/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp b/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28b6963526248734ade5880bebb24e7eda43d8be --- /dev/null +++ b/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "basic_transformer.h" +#include +#include +#include +#include "image_utils.h" +#include "pixel_convert.h" +#include "pixel_map.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +#if !defined(_WIN32) && !defined(_APPLE) +#include "ashmem.h" +#include +#endif + +namespace OHOS { +namespace Media { +using namespace std; +void BasicTransformer::ResetParam() +{ + matrix_ = Matrix(); + minX_ = 0.0f; + minY_ = 0.0f; +} + +void BasicTransformer::SetScaleParam(const float sx, const float sy) +{ + Matrix m; + m.SetScale(sx, sy); + matrix_.SetConcat(m); +} + +void BasicTransformer::SetTranslateParam(const float tx, const float ty) +{ + Matrix m; + m.SetTranslate(tx, ty); + matrix_.SetConcat(m); +} + +void BasicTransformer::SetRotateParam(const float degrees, const float px, const float py) +{ + Matrix m; + m.SetRotate(degrees, px, py); + matrix_.SetConcat(m); +} + +void BasicTransformer::GetDstDimension(const Size &srcSize, Size &dstSize) +{ + Matrix::OperType operType = matrix_.GetOperType(); + if ((static_cast(operType) & Matrix::SCALE) == Matrix::SCALE) { + dstSize.width = static_cast(srcSize.width * matrix_.GetScaleX() + FHALF); + dstSize.height = static_cast(srcSize.height * matrix_.GetScaleY() + FHALF); + } + + if ((static_cast(operType) & Matrix::ROTATEORSKEW) == Matrix::ROTATEORSKEW) { + Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType); + GetRotateDimension(fInvProc, srcSize, dstSize); + } +} + +bool BasicTransformer::CheckAllocateBuffer(PixmapInfo &outPixmap, AllocateMem allocate, + int &fd, uint64_t &bufferSize, Size &dstSize) +{ + if (allocate == nullptr) { + outPixmap.data = static_cast(malloc(bufferSize)); + } else { + outPixmap.data = allocate(dstSize, bufferSize, fd); + } + if (outPixmap.data == nullptr) { + IMAGE_LOGE("[BasicTransformer]apply heap memory failed"); + return false; + } + return true; +} + +void BasicTransformer::ReleaseBuffer(AllocatorType allocatorType, int fd, int dataSize, uint8_t *buffer) +{ +#if !defined(_WIN32) && !defined(_APPLE) + if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) { + if (buffer != nullptr) { + ::munmap(buffer, dataSize); + ::close(fd); + } + return; + } +#endif + + if (allocatorType == AllocatorType::HEAP_ALLOC) { + if (buffer != nullptr) { + free(buffer); + } + return; + } +} +uint32_t BasicTransformer::TransformPixmap(const PixmapInfo &inPixmap, PixmapInfo &outPixmap, AllocateMem allocate) +{ + if (inPixmap.data == nullptr) { + IMAGE_LOGE("[BasicTransformer]input data is null."); + return ERR_IMAGE_GENERAL_ERROR; + } + int32_t pixelBytes = ImageUtils::GetPixelBytes(inPixmap.imageInfo.pixelFormat); + if (pixelBytes == 0) { + IMAGE_LOGE("[BasicTransformer]input pixel is invalid."); + return ERR_IMAGE_INVALID_PIXEL; + } + + Size dstSize = inPixmap.imageInfo.size; + GetDstDimension(inPixmap.imageInfo.size, dstSize); + outPixmap.imageInfo.size = dstSize; + if (dstSize.width <= 0 || dstSize.height <= 0) { + IMAGE_LOGE("[BasicTransformer]buffer size is invalid."); + return ERR_IMAGE_ALLOC_MEMORY_FAILED; + } + + uint64_t bufferSize = static_cast(dstSize.width) * dstSize.height * pixelBytes; + if (bufferSize > PIXEL_MAP_MAX_RAM_SIZE) { + IMAGE_LOGE("[BasicTransformer] buffer size:%{public}llu out of range.", + static_cast(bufferSize)); + return ERR_IMAGE_ALLOC_MEMORY_FAILED; + } + int fd = 0; + if (CheckAllocateBuffer(outPixmap, allocate, fd, bufferSize, dstSize) != true) { + return ERR_IMAGE_ALLOC_MEMORY_FAILED; + } + outPixmap.bufferSize = bufferSize; + outPixmap.imageInfo.pixelFormat = inPixmap.imageInfo.pixelFormat; + outPixmap.imageInfo.colorSpace = inPixmap.imageInfo.colorSpace; + outPixmap.imageInfo.alphaType = inPixmap.imageInfo.alphaType; + outPixmap.imageInfo.baseDensity = inPixmap.imageInfo.baseDensity; + +#ifdef _WIN32 + memset(outPixmap.data, COLOR_DEFAULT, bufferSize * sizeof(uint8_t)); +#else + if (memset_s(outPixmap.data, bufferSize * sizeof(uint8_t), COLOR_DEFAULT, bufferSize * sizeof(uint8_t)) != EOK) { + IMAGE_LOGE("[BasicTransformer]apply heap memory failed."); + ReleaseBuffer((allocate == nullptr) ? AllocatorType::HEAP_ALLOC : AllocatorType::SHARE_MEM_ALLOC, + fd, bufferSize, outPixmap.data); + return ERR_IMAGE_GENERAL_ERROR; + } +#endif + + if (!DrawPixelmap(inPixmap, pixelBytes, dstSize, outPixmap.data)) { + IMAGE_LOGE("[BasicTransformer] the matrix can not invert."); + ReleaseBuffer((allocate == nullptr) ? AllocatorType::HEAP_ALLOC : AllocatorType::SHARE_MEM_ALLOC, + fd, bufferSize, outPixmap.data); + return ERR_IMAGE_MATRIX_NOT_INVERT; + } + return IMAGE_SUCCESS; +} + +bool BasicTransformer::DrawPixelmap(const PixmapInfo &pixmapInfo, const int32_t pixelBytes, const Size &size, + uint8_t *data) +{ + Matrix invertMatrix; + bool isInvert = matrix_.Invert(invertMatrix); + if (!isInvert) { + return false; + } + + uint32_t rb = pixmapInfo.imageInfo.size.width * pixelBytes; + Matrix::OperType operType = matrix_.GetOperType(); + Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType); + + for (int32_t y = 0; y < size.height; ++y) { + for (int32_t x = 0; x < size.width; ++x) { + Point srcPoint; + // Center coordinate alignment, need to add 0.5, so the boundary can also be considered + fInvProc(invertMatrix, static_cast(x) + minX_ + FHALF, static_cast(y) + minY_ + FHALF, + srcPoint); + if (CheckOutOfRange(srcPoint, pixmapInfo.imageInfo.size)) { + continue; + } + uint32_t shiftBytes = (y * size.width + x) * pixelBytes; + BilinearProc(srcPoint, pixmapInfo, rb, shiftBytes, data); + } + } + + return true; +} + +void BasicTransformer::GetRotateDimension(Matrix::CalcXYProc fInvProc, const Size &srcSize, Size &dstSize) +{ + Point dstP1; + Point dstP2; + Point dstP3; + Point dstP4; + + float fx = static_cast(srcSize.width); + float fy = static_cast(srcSize.height); + fInvProc(matrix_, 0.0f, 0.0f, dstP1); + fInvProc(matrix_, fx, 0.0f, dstP2); + fInvProc(matrix_, 0.0f, fy, dstP3); + fInvProc(matrix_, fx, fy, dstP4); + + // For rotation, the width and height will change, so you need to take the maximum of the two diagonals. + dstSize.width = static_cast(fmaxf(fabsf(dstP4.x - dstP1.x), fabsf(dstP3.x - dstP2.x)) + FHALF); + dstSize.height = static_cast(fmaxf(fabsf(dstP4.y - dstP1.y), fabsf(dstP3.y - dstP2.y)) + FHALF); + + float min14X = std::min(dstP1.x, dstP4.x); + float min23X = std::min(dstP2.x, dstP3.x); + minX_ = std::min(min14X, min23X); + + float min14Y = std::min(dstP1.y, dstP4.y); + float min23Y = std::min(dstP2.y, dstP3.y); + minY_ = std::min(min14Y, min23Y); +} + +void BasicTransformer::BilinearProc(const Point &pt, const PixmapInfo &pixmapInfo, const uint32_t rb, + const int32_t shiftBytes, uint8_t *data) +{ + uint32_t srcX = (pt.x * MULTI_65536) - HALF_BASIC; + uint32_t srcY = (pt.y * MULTI_65536) - HALF_BASIC; + + AroundPos aroundPos; + aroundPos.x0 = RightShift16Bit(srcX, pixmapInfo.imageInfo.size.width - 1); + aroundPos.x1 = RightShift16Bit(srcX + BASIC, pixmapInfo.imageInfo.size.width - 1); + uint32_t subx = GetSubValue(srcX); + + aroundPos.y0 = RightShift16Bit(srcY, pixmapInfo.imageInfo.size.height - 1); + aroundPos.y1 = RightShift16Bit(srcY + BASIC, pixmapInfo.imageInfo.size.height - 1); + uint32_t suby = GetSubValue(srcY); + + AroundPixels aroundPixels; + switch (pixmapInfo.imageInfo.pixelFormat) { + case PixelFormat::RGBA_8888: + case PixelFormat::ARGB_8888: + case PixelFormat::BGRA_8888: + GetAroundPixelRGBA(aroundPos, pixmapInfo.data, rb, aroundPixels); + break; + case PixelFormat::RGB_565: + GetAroundPixelRGB565(aroundPos, pixmapInfo.data, rb, aroundPixels); + break; + case PixelFormat::RGB_888: + GetAroundPixelRGB888(aroundPos, pixmapInfo.data, rb, aroundPixels); + break; + case PixelFormat::ALPHA_8: + GetAroundPixelALPHA8(aroundPos, pixmapInfo.data, rb, aroundPixels); + break; + default: + IMAGE_LOGE("[BasicTransformer] pixel format not supported, format:%d", pixmapInfo.imageInfo.pixelFormat); + return; + } + + uint32_t *tmp = reinterpret_cast(data + shiftBytes); + *tmp = FilterProc(subx, suby, aroundPixels); +} + +void BasicTransformer::GetAroundPixelRGB565(const AroundPos aroundPos, uint8_t *data, uint32_t rb, + AroundPixels &aroundPixels) +{ + const uint16_t *row0 = reinterpret_cast(data + aroundPos.y0 * rb); + const uint16_t *row1 = reinterpret_cast(data + aroundPos.y1 * rb); + aroundPixels.color00 = row0[aroundPos.x0]; + aroundPixels.color01 = row0[aroundPos.x1]; + aroundPixels.color10 = row1[aroundPos.x0]; + aroundPixels.color11 = row1[aroundPos.x1]; +} + +void BasicTransformer::GetAroundPixelRGB888(const AroundPos aroundPos, uint8_t *data, uint32_t rb, + AroundPixels &aroundPixels) +{ + const uint8_t *row0 = data + aroundPos.y0 * rb; + const uint8_t *row1 = data + aroundPos.y1 * rb; + uint32_t current0 = aroundPos.x0 * RGB888_BYTE; + uint32_t current1 = aroundPos.x1 * RGB888_BYTE; + // The RGB888 format occupies 3 bytes, and an int integer is formed by OR operation. + aroundPixels.color00 = + (row0[current0] << SHIFT_16_BIT) | (row0[current0 + 1] << SHIFT_8_BIT) | (row0[current0 + 2]); + aroundPixels.color01 = + (row0[current1] << SHIFT_16_BIT) | (row0[current1 + 1] << SHIFT_8_BIT) | (row0[current1 + 2]); + aroundPixels.color10 = + (row1[current0] << SHIFT_16_BIT) | (row1[current0 + 1] << SHIFT_8_BIT) | (row1[current0 + 2]); + aroundPixels.color11 = + (row1[current1] << SHIFT_16_BIT) | (row1[current1 + 1] << SHIFT_8_BIT) | (row1[current1 + 2]); +} + +void BasicTransformer::GetAroundPixelRGBA(const AroundPos aroundPos, uint8_t *data, + uint32_t rb, AroundPixels &aroundPixels) +{ + const uint32_t *row0 = reinterpret_cast(data + aroundPos.y0 * rb); + const uint32_t *row1 = reinterpret_cast(data + aroundPos.y1 * rb); + aroundPixels.color00 = row0[aroundPos.x0]; + aroundPixels.color01 = row0[aroundPos.x1]; + aroundPixels.color10 = row1[aroundPos.x0]; + aroundPixels.color11 = row1[aroundPos.x1]; +} + +void BasicTransformer::GetAroundPixelALPHA8(const AroundPos aroundPos, uint8_t *data, uint32_t rb, + AroundPixels &aroundPixels) +{ + const uint8_t *row0 = data + aroundPos.y0 * rb; + const uint8_t *row1 = data + aroundPos.y1 * rb; + aroundPixels.color00 = row0[aroundPos.x0]; + aroundPixels.color01 = row0[aroundPos.x1]; + aroundPixels.color10 = row1[aroundPos.x0]; + aroundPixels.color11 = row1[aroundPos.x1]; +} + +uint32_t BasicTransformer::RightShift16Bit(uint32_t num, int32_t maxNum) +{ + /* + * When the original image coordinates are obtained, + * the first 16 bits are shifted to the left, so the right shift is 16 bits here. + */ + return ClampMax(num >> 16, maxNum); +} + +uint32_t BasicTransformer::FilterProc(const uint32_t subx, const uint32_t suby, const AroundPixels &aroundPixels) +{ + int32_t xy = subx * suby; + // Mask 0xFF00FF ensures that high and low 16 bits can be calculated simultaneously + const uint32_t mask = 0xFF00FF; + + /* All values are first magnified 16 times (left shift 4bit) and then divide 256 (right shift 8bit). + * Reference formula f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1), + * The subx is u, the suby is y, + * color00 is f(i,j), color 01 is f(i,j+1), color 10 is f(i+1,j), color11 is f(i+1,j+1). + */ + int32_t scale = 256 - 16 * suby - 16 * subx + xy; + uint32_t lo = (aroundPixels.color00 & mask) * scale; + uint32_t hi = ((aroundPixels.color00 >> 8) & mask) * scale; + + scale = 16 * subx - xy; + lo += (aroundPixels.color01 & mask) * scale; + hi += ((aroundPixels.color01 >> 8) & mask) * scale; + + scale = 16 * suby - xy; + lo += (aroundPixels.color10 & mask) * scale; + hi += ((aroundPixels.color10 >> 8) & mask) * scale; + + lo += (aroundPixels.color11 & mask) * xy; + hi += ((aroundPixels.color11 >> 8) & mask) * xy; + + return ((lo >> 8) & mask) | (hi & ~mask); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/converter/src/matrix.cpp b/frameworks/innerkitsimpl/converter/src/matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7fbcdb2e00817df2eac5496dbe9eab971c9e03d --- /dev/null +++ b/frameworks/innerkitsimpl/converter/src/matrix.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "matrix.h" + +namespace OHOS { +namespace Media { +Matrix &Matrix::Reset() +{ + *this = Matrix(); + return *this; +} + +Matrix &Matrix::SetTranslate(const float tx, const float ty) +{ + *this = Matrix(1, 0, tx, 0, 1, ty, 0, 1, 1, (tx == 0 || ty == 0) ? IDENTITY : TRANSLATE); + return *this; +} + +Matrix &Matrix::SetScale(const float sx, const float sy) +{ + *this = Matrix(sx, 0, 0, 0, sy, 0, 0, 0, 1, (sx == 1 && sy == 1) ? IDENTITY : SCALE); + return *this; +} + +Matrix &Matrix::SetRotate(const float degrees, const float px, const float py) +{ + float radians = DegreesToRadians(degrees); + return SetSinCos(ValueNearToZero(radians, true), ValueNearToZero(radians, false), px, py); +} + +Matrix &Matrix::SetSinCos(const float sinValue, const float cosValue, const float px, const float py) +{ + const float reverseCosValue = 1.0f - cosValue; + + fMat_[IMAGE_SCALEX] = cosValue; + fMat_[IMAGE_SKEWX] = -sinValue; + fMat_[IMAGE_TRANSX] = sinValue * py + reverseCosValue * px; + + fMat_[IMAGE_SKEWY] = sinValue; + fMat_[IMAGE_SCALEY] = cosValue; + fMat_[IMAGE_TRANSY] = -sinValue * px + reverseCosValue * py; + + fMat_[IMAGE_PERSP0] = fMat_[IMAGE_PERSP1] = 0; + fMat_[IMAGE_PERSP2] = 1; + + operType_ = ROTATEORSKEW; + + return *this; +} + +Matrix &Matrix::SetConcat(const Matrix &m) +{ + OperType aOperType = this->GetOperType(); + OperType bOperType = m.GetOperType(); + + if ((static_cast(aOperType) & OPERTYPE_MASK) == 0) { + *this = m; + } else if (((static_cast(aOperType) | static_cast(bOperType)) & ROTATEORSKEW) == 0) { + SetTranslateAndScale(fMat_[IMAGE_TRANSX] * m.fMat_[IMAGE_TRANSX] + fMat_[IMAGE_TRANSX], + fMat_[IMAGE_TRANSY] * m.fMat_[IMAGE_TRANSY] + fMat_[IMAGE_TRANSY], + fMat_[IMAGE_SCALEX] * m.fMat_[IMAGE_SCALEX], fMat_[IMAGE_SCALEY] * m.fMat_[IMAGE_SCALEY]); + } else { + Matrix src = *this; + fMat_[IMAGE_SCALEX] = static_cast( + MulAddMul(src.fMat_[IMAGE_SCALEX], m.fMat_[IMAGE_SCALEX], src.fMat_[IMAGE_SKEWX], m.fMat_[IMAGE_SKEWY])); + + fMat_[IMAGE_SKEWX] = static_cast( + MulAddMul(src.fMat_[IMAGE_SCALEX], m.fMat_[IMAGE_SKEWX], src.fMat_[IMAGE_SKEWX], m.fMat_[IMAGE_SCALEY])); + + fMat_[IMAGE_TRANSX] = static_cast( + MulAddMul(src.fMat_[IMAGE_SCALEX], m.fMat_[IMAGE_TRANSX], src.fMat_[IMAGE_SKEWX], m.fMat_[IMAGE_TRANSY]) + + src.fMat_[IMAGE_TRANSX]); + + fMat_[IMAGE_SKEWY] = static_cast( + MulAddMul(src.fMat_[IMAGE_SKEWY], m.fMat_[IMAGE_SCALEX], src.fMat_[IMAGE_SCALEY], m.fMat_[IMAGE_SKEWY])); + + fMat_[IMAGE_SCALEY] = static_cast( + MulAddMul(src.fMat_[IMAGE_SKEWY], m.fMat_[IMAGE_SKEWX], src.fMat_[IMAGE_SCALEY], m.fMat_[IMAGE_SCALEY])); + + fMat_[IMAGE_TRANSY] = static_cast( + MulAddMul(src.fMat_[IMAGE_SKEWY], m.fMat_[IMAGE_TRANSX], src.fMat_[IMAGE_SCALEY], m.fMat_[IMAGE_TRANSY]) + + src.fMat_[IMAGE_TRANSY]); + + fMat_[IMAGE_PERSP0] = fMat_[IMAGE_PERSP1] = 0; + fMat_[IMAGE_PERSP2] = 1; + + operType_ = ROTATEORSKEW; + } + return *this; +} + +Matrix::OperType Matrix::GetOperType() const +{ + return (OperType)(operType_ & OPERTYPE_MASK); +} + +void Matrix::SetTranslateAndScale(const float tx, const float ty, const float sx, const float sy) +{ + fMat_[IMAGE_SCALEX] = sx; + fMat_[IMAGE_SKEWX] = 0; + fMat_[IMAGE_TRANSX] = tx; + + fMat_[IMAGE_SKEWY] = 0; + fMat_[IMAGE_SCALEY] = sy; + fMat_[IMAGE_TRANSY] = ty; + + fMat_[IMAGE_PERSP0] = fMat_[IMAGE_PERSP1] = 0; + fMat_[IMAGE_PERSP2] = 1; + + if (sx != 1 || sy != 1) { + operType_ |= SCALE; + } + if (tx != 0 || ty != 0) { + operType_ |= TRANSLATE; + } +} + +bool Matrix::Invert(Matrix &invMatrix) +{ + invMatrix.operType_ = operType_; + if (IsIdentity()) { + invMatrix.Reset(); + return true; + } + + if ((operType_ & (~(TRANSLATE | SCALE))) == 0) { + if (operType_ & SCALE) { + float invScaleX = fMat_[IMAGE_SCALEX]; + float invScaleY = fMat_[IMAGE_SCALEY]; + if (std::fabs(invScaleX) < MATRIX_EPSILON || std::fabs(invScaleY) < MATRIX_EPSILON) { + return false; + } + + // 1.0f used when calculating the inverse matrix + invScaleX = FDivide(1.0f, invScaleX); + invScaleY = FDivide(1.0f, invScaleY); + + invMatrix.fMat_[IMAGE_SCALEX] = invScaleX; + invMatrix.fMat_[IMAGE_SCALEY] = invScaleY; + + invMatrix.fMat_[IMAGE_TRANSX] = -fMat_[IMAGE_TRANSX] * invScaleX; + invMatrix.fMat_[IMAGE_TRANSY] = -fMat_[IMAGE_TRANSY] * invScaleY; + + invMatrix.fMat_[IMAGE_SKEWX] = invMatrix.fMat_[IMAGE_SKEWY] = invMatrix.fMat_[IMAGE_PERSP0] = + invMatrix.fMat_[IMAGE_PERSP1] = 0; + invMatrix.fMat_[IMAGE_PERSP2] = 1; + } else { + invMatrix.SetTranslate(-fMat_[IMAGE_TRANSX], -fMat_[IMAGE_TRANSY]); + } + return true; + } + + return InvertForRotate(invMatrix); +} + +bool Matrix::InvertForRotate(Matrix &invMatrix) +{ + double invDet = MulSubMul(fMat_[IMAGE_SCALEX], fMat_[IMAGE_SCALEY], fMat_[IMAGE_SKEWX], fMat_[IMAGE_SKEWY]); + if (fabsf(static_cast(invDet)) < (FLOAT_NEAR_ZERO * FLOAT_NEAR_ZERO * FLOAT_NEAR_ZERO)) { + return false; + } else { + invDet = 1.0 / invDet; // 1.0 used when calculating the inverse matrix + } + + invMatrix.fMat_[IMAGE_SCALEX] = static_cast(fMat_[IMAGE_SCALEY] * invDet); + invMatrix.fMat_[IMAGE_SKEWX] = static_cast(-fMat_[IMAGE_SKEWX] * invDet); + invMatrix.fMat_[IMAGE_TRANSX] = static_cast( + MulSubMul(fMat_[IMAGE_SKEWX], fMat_[IMAGE_TRANSY], fMat_[IMAGE_SCALEY], fMat_[IMAGE_TRANSX]) * invDet); + + invMatrix.fMat_[IMAGE_SKEWY] = static_cast(-fMat_[IMAGE_SKEWY] * invDet); + invMatrix.fMat_[IMAGE_SCALEY] = static_cast(fMat_[IMAGE_SCALEX] * invDet); + invMatrix.fMat_[IMAGE_TRANSY] = static_cast( + MulSubMul(fMat_[IMAGE_SKEWY], fMat_[IMAGE_TRANSX], fMat_[IMAGE_SCALEX], fMat_[IMAGE_TRANSY]) * invDet); + + invMatrix.fMat_[IMAGE_PERSP0] = invMatrix.fMat_[IMAGE_PERSP1] = 0; + invMatrix.fMat_[IMAGE_PERSP2] = 1; + + return true; +} + +void Matrix::IdentityXY(const Matrix &m, const float sx, const float sy, Point &pt) +{ + if (m.GetOperType() == 0) { + pt.x = sx; + pt.y = sy; + } +} + +void Matrix::ScaleXY(const Matrix &m, const float sx, const float sy, Point &pt) +{ + if ((static_cast(m.GetOperType()) & SCALE) == SCALE) { + pt.x = sx * m.fMat_[IMAGE_SCALEX] + m.fMat_[IMAGE_TRANSX]; + pt.y = sy * m.fMat_[IMAGE_SCALEY] + m.fMat_[IMAGE_TRANSY]; + } +} + +void Matrix::TransXY(const Matrix &m, const float tx, const float ty, Point &pt) +{ + if (m.GetOperType() == TRANSLATE) { + pt.x = tx + m.fMat_[IMAGE_TRANSX]; + pt.y = ty + m.fMat_[IMAGE_TRANSY]; + } +} + +void Matrix::RotXY(const Matrix &m, const float rx, const float ry, Point &pt) +{ + if ((static_cast(m.GetOperType()) & ROTATEORSKEW) == ROTATEORSKEW) { + pt.x = rx * m.fMat_[IMAGE_SCALEX] + ry * m.fMat_[IMAGE_SKEWX] + m.fMat_[IMAGE_TRANSX]; + pt.y = rx * m.fMat_[IMAGE_SKEWY] + ry * m.fMat_[IMAGE_SCALEY] + m.fMat_[IMAGE_TRANSY]; + } +} + +const Matrix::CalcXYProc Matrix::gCalcXYProcs[] = { Matrix::IdentityXY, Matrix::TransXY, Matrix::ScaleXY, + Matrix::ScaleXY, Matrix::RotXY, Matrix::RotXY, + Matrix::RotXY, Matrix::RotXY }; + +// Matrix print function, including 9 elements +void Matrix::Print() +{ + IMAGE_LOGD("[Matrix][%{public}8.4f %{public}8.4f %{public}8.4f]\ + [%{public}8.4f %{public}8.4f %{public}8.4f]\ + [%{public}8.4f %{public}8.4f %{public}8.4f].", + fMat_[0], fMat_[1], fMat_[2], fMat_[3], fMat_[4], fMat_[5], fMat_[6], fMat_[7], fMat_[8]); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp b/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a908795a640ea672801a61b4b664cec67ecf5356 --- /dev/null +++ b/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp @@ -0,0 +1,904 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "pixel_convert.h" + +namespace OHOS { +namespace Media { +using namespace std; +using namespace OHOS::HiviewDFX; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelConvert" }; +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr bool IS_LITTLE_ENDIAN = true; +#else +constexpr bool IS_LITTLE_ENDIAN = false; +#endif + +static void AlphaTypeConvertOnRGB(uint32_t &A, uint32_t &R, uint32_t &G, uint32_t &B, + const ProcFuncExtension &extension) +{ + switch (extension.alphaConvertType) { + case AlphaConvertType::PREMUL_CONVERT_UNPREMUL: + R = Unpremul255(R, A); + G = Unpremul255(G, A); + B = Unpremul255(B, A); + break; + case AlphaConvertType::PREMUL_CONVERT_OPAQUE: + R = Unpremul255(R, A); + G = Unpremul255(G, A); + B = Unpremul255(B, A); + A = ALPHA_OPAQUE; + break; + case AlphaConvertType::UNPREMUL_CONVERT_PREMUL: + R = Premul255(R, A); + G = Premul255(G, A); + B = Premul255(B, A); + break; + case AlphaConvertType::UNPREMUL_CONVERT_OPAQUE: + A = ALPHA_OPAQUE; + break; + default: + break; + } +} + +static uint32_t FillARGB8888(uint32_t A, uint32_t R, uint32_t G, uint32_t B) +{ + if (IS_LITTLE_ENDIAN) { + return ((B << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (R << SHIFT_8_BIT) | A); + } + return ((A << SHIFT_24_BIT) | (R << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | B); +} + +static uint32_t FillABGR8888(uint32_t A, uint32_t B, uint32_t G, uint32_t R) +{ + if (IS_LITTLE_ENDIAN) { + return ((R << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (B << SHIFT_8_BIT) | A); + } + return ((A << SHIFT_24_BIT) | (B << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | R); +} + +static uint32_t FillRGBA8888(uint32_t R, uint32_t G, uint32_t B, uint32_t A) +{ + if (IS_LITTLE_ENDIAN) { + return ((A << SHIFT_24_BIT) | (B << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | R); + } + return ((R << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (B << SHIFT_8_BIT) | A); +} + +static uint32_t FillBGRA8888(uint32_t B, uint32_t G, uint32_t R, uint32_t A) +{ + if (IS_LITTLE_ENDIAN) { + return ((A << SHIFT_24_BIT) | (R << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | B); + } + return ((B << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (R << SHIFT_8_BIT) | A); +} + +static uint16_t FillRGB565(uint32_t R, uint32_t G, uint32_t B) +{ + if (IS_LITTLE_ENDIAN) { + return ((B << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | R); + } + return ((R << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | B); +} + +constexpr uint8_t BYTE_BITS = 8; +constexpr uint8_t BYTE_BITS_MAX_INDEX = 7; +template +static void BitConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t white, + uint32_t black) +{ + destinationRow[0] = (*sourceRow & GET_8_BIT) ? white : black; + uint32_t bitIndex = 0; + uint8_t currentSource = 0; + /* + * 1 byte = 8 bit + * 7: 8 bit index + */ + for (uint32_t i = 1; i < sourceWidth; i++) { + bitIndex = i % BYTE_BITS; + currentSource = *(sourceRow + i / BYTE_BITS); + destinationRow[i] = ((currentSource >> (BYTE_BITS_MAX_INDEX - bitIndex)) & GET_1_BIT) ? white : black; + } +} + +static void BitConvertGray(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint8_t *newDestinationRow = static_cast(destinationRow); + BitConvert(newDestinationRow, sourceRow, sourceWidth, GRAYSCALE_WHITE, GRAYSCALE_BLACK); +} + +static void BitConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BitConvert(newDestinationRow, sourceRow, sourceWidth, ARGB_WHITE, ARGB_BLACK); +} + +static void BitConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + BitConvert(newDestinationRow, sourceRow, sourceWidth, RGB_WHITE, RGB_BLACK); +} + +constexpr uint32_t BRANCH_GRAY_TO_ARGB8888 = 0x00000001; +constexpr uint32_t BRANCH_GRAY_TO_RGB565 = 0x00000002; +template +static void GrayConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = sourceRow[i]; + uint32_t G = sourceRow[i]; + uint32_t B = sourceRow[i]; + if (branch == BRANCH_GRAY_TO_ARGB8888) { + uint32_t A = ALPHA_OPAQUE; + destinationRow[i] = ((A << SHIFT_24_BIT) | (R << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | B); + } else if (branch == BRANCH_GRAY_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = ((R << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | B); + } else { + break; + } + } +} + +static void GrayConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + GrayConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_GRAY_TO_ARGB8888); +} + +static void GrayConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + GrayConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_GRAY_TO_RGB565); +} + +constexpr uint32_t BRANCH_ARGB8888 = 0x10000001; +constexpr uint32_t BRANCH_ALPHA = 0x10000002; +template +static void GrayAlphaConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, + const ProcFuncExtension &extension) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t A = sourceRow[1]; + uint32_t R = sourceRow[0]; + uint32_t G = sourceRow[0]; + uint32_t B = sourceRow[0]; + AlphaTypeConvertOnRGB(A, R, G, B, extension); + if (branch == BRANCH_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_ALPHA) { + destinationRow[i] = A; + } else { + break; + } + sourceRow += SIZE_2_BYTE; + } +} + +static void GrayAlphaConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + GrayAlphaConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888, extension); +} + +static void GrayAlphaConvertAlpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint8_t *newDestinationRow = static_cast(destinationRow); + GrayAlphaConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ALPHA, extension); +} + +constexpr uint32_t BRANCH_BGR888_TO_ARGB8888 = 0x20000001; +constexpr uint32_t BRANCH_BGR888_TO_RGBA8888 = 0x20000002; +constexpr uint32_t BRANCH_BGR888_TO_BGRA8888 = 0x20000003; +constexpr uint32_t BRANCH_BGR888_TO_RGB565 = 0x20000004; +template +static void BGR888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = sourceRow[2]; + uint32_t G = sourceRow[1]; + uint32_t B = sourceRow[0]; + uint32_t A = ALPHA_OPAQUE; + if (branch == BRANCH_BGR888_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_BGR888_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_BGR888_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_BGR888_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = ((B << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | R); + } else { + break; + } + sourceRow += SIZE_3_BYTE; + } +} + +static void BGR888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_ARGB8888); +} + +static void BGR888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGBA8888); +} + +static void BGR888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_BGRA8888); +} + +static void BGR888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGB565); +} + +constexpr uint32_t BRANCH_RGB888_TO_ARGB8888 = 0x30000001; +constexpr uint32_t BRANCH_RGB888_TO_RGBA8888 = 0x30000002; +constexpr uint32_t BRANCH_RGB888_TO_BGRA8888 = 0x30000003; +constexpr uint32_t BRANCH_RGB888_TO_RGB565 = 0x30000004; +template +static void RGB888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = sourceRow[0]; + uint32_t G = sourceRow[1]; + uint32_t B = sourceRow[2]; + uint32_t A = ALPHA_OPAQUE; + if (branch == BRANCH_RGB888_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_RGB888_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_RGB888_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_RGB888_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_3_BYTE; + } +} +static void RGB888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_ARGB8888); +} + +static void RGB888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGBA8888); +} + +static void RGB888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_BGRA8888); +} + +static void RGB888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGB565); +} +constexpr uint32_t BRANCH_RGBA8888_TO_RGBA8888_ALPHA = 0x40000001; +constexpr uint32_t BRANCH_RGBA8888_TO_ARGB8888 = 0x40000002; +constexpr uint32_t BRANCH_RGBA8888_TO_BGRA8888 = 0x40000003; +constexpr uint32_t BRANCH_RGBA8888_TO_RGB565 = 0x40000004; +template +static void RGBA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, + const ProcFuncExtension &extension) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = sourceRow[0]; + uint32_t G = sourceRow[1]; + uint32_t B = sourceRow[2]; + uint32_t A = sourceRow[3]; + AlphaTypeConvertOnRGB(A, R, G, B, extension); + if (branch == BRANCH_RGBA8888_TO_RGBA8888_ALPHA) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_RGBA8888_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_RGBA8888_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_RGBA8888_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_4_BYTE; + } +} + +static void RGBA8888ConvertRGBA8888Alpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGBA8888_ALPHA, extension); +} + +static void RGBA8888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_ARGB8888, extension); +} +static void RGBA8888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_BGRA8888, extension); +} + +static void RGBA8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGB565, extension); +} + +constexpr uint32_t BRANCH_BGRA8888_TO_BGRA8888_ALPHA = 0x80000001; +constexpr uint32_t BRANCH_BGRA8888_TO_ARGB8888 = 0x80000002; +constexpr uint32_t BRANCH_BGRA8888_TO_RGBA8888 = 0x80000003; +constexpr uint32_t BRANCH_BGRA8888_TO_RGB565 = 0x80000004; +template +static void BGRA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, + const ProcFuncExtension &extension) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t B = sourceRow[0]; + uint32_t G = sourceRow[1]; + uint32_t R = sourceRow[2]; + uint32_t A = sourceRow[3]; + AlphaTypeConvertOnRGB(A, R, G, B, extension); + if (branch == BRANCH_BGRA8888_TO_BGRA8888_ALPHA) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_BGRA8888_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_BGRA8888_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_BGRA8888_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_4_BYTE; + } +} + +static void BGRA8888ConvertBGRA8888Alpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_BGRA8888_ALPHA, extension); +} + +static void BGRA8888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_ARGB8888, extension); +} + +static void BGRA8888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGBA8888, extension); +} + +static void BGRA8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGB565, extension); +} + +constexpr uint32_t BRANCH_ARGB8888_TO_ARGB8888_ALPHA = 0x90000001; +constexpr uint32_t BRANCH_ARGB8888_TO_RGBA8888 = 0x90000002; +constexpr uint32_t BRANCH_ARGB8888_TO_BGRA8888 = 0x90000003; +constexpr uint32_t BRANCH_ARGB8888_TO_RGB565 = 0x90000004; +template +static void ARGB8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, + const ProcFuncExtension &extension) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t A = sourceRow[0]; + uint32_t R = sourceRow[1]; + uint32_t G = sourceRow[2]; + uint32_t B = sourceRow[3]; + AlphaTypeConvertOnRGB(A, R, G, B, extension); + if (branch == BRANCH_ARGB8888_TO_ARGB8888_ALPHA) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_ARGB8888_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_ARGB8888_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_ARGB8888_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_4_BYTE; + } +} + +static void ARGB8888ConvertARGB8888Alpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_ARGB8888_ALPHA, extension); +} + +static void ARGB8888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGBA8888, extension); +} + +static void ARGB8888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_BGRA8888, extension); +} + +static void ARGB8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGB565, extension); +} + +constexpr uint32_t BRANCH_RGB161616_TO_ARGB8888 = 0x50000001; +constexpr uint32_t BRANCH_RGB161616_TO_ABGR8888 = 0x50000002; +constexpr uint32_t BRANCH_RGB161616_TO_RGBA8888 = 0x50000003; +constexpr uint32_t BRANCH_RGB161616_TO_BGRA8888 = 0x50000004; +constexpr uint32_t BRANCH_RGB161616_TO_RGB565 = 0x50000005; +template +static void RGB161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = sourceRow[0]; + uint32_t G = sourceRow[2]; + uint32_t B = sourceRow[4]; + uint32_t A = ALPHA_OPAQUE; + if (branch == BRANCH_RGB161616_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_RGB161616_TO_ABGR8888) { + destinationRow[i] = FillABGR8888(A, B, G, R); + } else if (branch == BRANCH_RGB161616_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_RGB161616_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_RGB161616_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = G >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_6_BYTE; + } +} + +static void RGB161616ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_ARGB8888); +} + +static void RGB161616ConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_ABGR8888); +} + +static void RGB161616ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGBA8888); +} + +static void RGB161616ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_BGRA8888); +} + +static void RGB161616ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint16_t *newDestinationRow = static_cast(destinationRow); + RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGB565); +} + +constexpr uint32_t BRANCH_RGBA16161616_TO_ARGB8888 = 0x60000001; +constexpr uint32_t BRANCH_RGBA16161616_TO_ABGR8888 = 0x60000002; +constexpr uint32_t BRANCH_RGBA16161616_TO_RGBA8888 = 0x60000003; +constexpr uint32_t BRANCH_RGBA16161616_TO_BGRA8888 = 0x60000004; +template +static void RGBA16161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch, + const ProcFuncExtension &extension) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = sourceRow[0]; + uint32_t G = sourceRow[2]; + uint32_t B = sourceRow[4]; + uint32_t A = sourceRow[6]; + AlphaTypeConvertOnRGB(A, R, G, B, extension); + if (branch == BRANCH_RGBA16161616_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_RGBA16161616_TO_ABGR8888) { + destinationRow[i] = FillABGR8888(A, B, G, R); + } else if (branch == BRANCH_RGBA16161616_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(A, B, G, R); + } else if (branch == BRANCH_RGBA16161616_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(A, B, G, R); + } else { + break; + } + sourceRow += SIZE_8_BYTE; + } +} + +static void RGBA16161616ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_ARGB8888, extension); +} + +static void RGBA16161616ConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_ABGR8888, extension); +} + +static void RGBA16161616ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_RGBA8888, extension); +} + +static void RGBA16161616ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_BGRA8888, extension); +} + +constexpr uint32_t BRANCH_CMYK_TO_ARGB8888 = 0x70000001; +constexpr uint32_t BRANCH_CMYK_TO_ABGR8888 = 0x70000002; +constexpr uint32_t BRANCH_CMYK_TO_RGBA8888 = 0x70000003; +constexpr uint32_t BRANCH_CMYK_TO_BGRA8888 = 0x70000004; +constexpr uint32_t BRANCH_CMYK_TO_RGB565 = 0x70000005; +template +static void CMYKConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint8_t C = sourceRow[0]; + uint8_t M = sourceRow[1]; + uint8_t Y = sourceRow[2]; + uint8_t K = sourceRow[3]; + uint32_t R = Premul255(C, K); + uint32_t G = Premul255(M, K); + uint32_t B = Premul255(Y, K); + uint32_t A = ALPHA_OPAQUE; + if (branch == BRANCH_CMYK_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_CMYK_TO_ABGR8888) { + destinationRow[i] = FillABGR8888(A, B, G, R); + } else if (branch == BRANCH_CMYK_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_CMYK_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else if (branch == BRANCH_CMYK_TO_RGB565) { + R = R >> SHIFT_3_BIT; + G = R >> SHIFT_2_BIT; + B = B >> SHIFT_3_BIT; + destinationRow[i] = FillRGB565(R, G, B); + } else { + break; + } + sourceRow += SIZE_4_BYTE; + } +} + +static void CMYKConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_ARGB8888); +} + +static void CMYKConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_ABGR8888); +} + +static void CMYKConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_RGBA8888); +} + +static void CMYKConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_BGRA8888); +} + +static void CMYKConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_RGB565); +} + +constexpr uint32_t BRANCH_RGB565_TO_ARGB8888 = 0x11000001; +constexpr uint32_t BRANCH_RGB565_TO_RGBA8888 = 0x11000002; +constexpr uint32_t BRANCH_RGB565_TO_BGRA8888 = 0x11000003; +template +static void RGB565Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch) +{ + for (uint32_t i = 0; i < sourceWidth; i++) { + uint32_t R = (sourceRow[0] >> SHIFT_3_BIT) & SHIFT_5_MASK; + uint32_t G = ((sourceRow[0] & SHIFT_3_MASK) << SHIFT_3_BIT) | ((sourceRow[1] >> SHIFT_5_BIT) & SHIFT_3_MASK); + uint32_t B = sourceRow[1] & SHIFT_5_MASK; + uint32_t A = ALPHA_OPAQUE; + if (branch == BRANCH_RGB565_TO_ARGB8888) { + destinationRow[i] = FillARGB8888(A, R, G, B); + } else if (branch == BRANCH_RGB565_TO_RGBA8888) { + destinationRow[i] = FillRGBA8888(R, G, B, A); + } else if (branch == BRANCH_RGB565_TO_BGRA8888) { + destinationRow[i] = FillBGRA8888(B, G, R, A); + } else { + break; + } + sourceRow += SIZE_2_BYTE; + } +} + +static void RGB565ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_ARGB8888); +} + +static void RGB565ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_RGBA8888); +} + +static void RGB565ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, + const ProcFuncExtension &extension) +{ + uint32_t *newDestinationRow = static_cast(destinationRow); + RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_BGRA8888); +} + +static map g_procMapping; +static mutex g_procMutex; + +static string MakeKey(uint32_t srcFormat, uint32_t dstFormat) +{ + return to_string(srcFormat) + ("_") + to_string(dstFormat); +} + +static void InitGrayProc() +{ + g_procMapping.emplace(MakeKey(GRAY_BIT, ARGB_8888), &BitConvertARGB8888); + g_procMapping.emplace(MakeKey(GRAY_BIT, RGB_565), &BitConvertRGB565); + g_procMapping.emplace(MakeKey(GRAY_BIT, ALPHA_8), &BitConvertGray); + + g_procMapping.emplace(MakeKey(ALPHA_8, ARGB_8888), &GrayConvertARGB8888); + g_procMapping.emplace(MakeKey(ALPHA_8, RGB_565), &GrayConvertRGB565); + + g_procMapping.emplace(MakeKey(GRAY_ALPHA, ARGB_8888), &GrayAlphaConvertARGB8888); + g_procMapping.emplace(MakeKey(GRAY_ALPHA, ALPHA_8), &GrayAlphaConvertAlpha); +} + +static void InitRGBProc() +{ + g_procMapping.emplace(MakeKey(RGB_888, ARGB_8888), &RGB888ConvertARGB8888); + g_procMapping.emplace(MakeKey(RGB_888, RGBA_8888), &RGB888ConvertRGBA8888); + g_procMapping.emplace(MakeKey(RGB_888, BGRA_8888), &RGB888ConvertBGRA8888); + g_procMapping.emplace(MakeKey(RGB_888, RGB_565), &RGB888ConvertRGB565); + + g_procMapping.emplace(MakeKey(BGR_888, ARGB_8888), &BGR888ConvertARGB8888); + g_procMapping.emplace(MakeKey(BGR_888, RGBA_8888), &BGR888ConvertRGBA8888); + g_procMapping.emplace(MakeKey(BGR_888, BGRA_8888), &BGR888ConvertBGRA8888); + g_procMapping.emplace(MakeKey(BGR_888, RGB_565), &BGR888ConvertRGB565); + + g_procMapping.emplace(MakeKey(RGB_161616, ARGB_8888), &RGB161616ConvertARGB8888); + g_procMapping.emplace(MakeKey(RGB_161616, ABGR_8888), &RGB161616ConvertABGR8888); + g_procMapping.emplace(MakeKey(RGB_161616, RGBA_8888), &RGB161616ConvertRGBA8888); + g_procMapping.emplace(MakeKey(RGB_161616, BGRA_8888), &RGB161616ConvertBGRA8888); + g_procMapping.emplace(MakeKey(RGB_161616, RGB_565), &RGB161616ConvertRGB565); + + g_procMapping.emplace(MakeKey(RGB_565, ARGB_8888), &RGB565ConvertARGB8888); + g_procMapping.emplace(MakeKey(RGB_565, RGBA_8888), &RGB565ConvertRGBA8888); + g_procMapping.emplace(MakeKey(RGB_565, BGRA_8888), &RGB565ConvertBGRA8888); +} + +static void InitRGBAProc() +{ + g_procMapping.emplace(MakeKey(RGBA_8888, RGBA_8888), &RGBA8888ConvertRGBA8888Alpha); + g_procMapping.emplace(MakeKey(RGBA_8888, ARGB_8888), &RGBA8888ConvertARGB8888); + g_procMapping.emplace(MakeKey(RGBA_8888, BGRA_8888), &RGBA8888ConvertBGRA8888); + g_procMapping.emplace(MakeKey(RGBA_8888, RGB_565), &RGBA8888ConvertRGB565); + + g_procMapping.emplace(MakeKey(BGRA_8888, RGBA_8888), &BGRA8888ConvertRGBA8888); + g_procMapping.emplace(MakeKey(BGRA_8888, ARGB_8888), &BGRA8888ConvertARGB8888); + g_procMapping.emplace(MakeKey(BGRA_8888, BGRA_8888), &BGRA8888ConvertBGRA8888Alpha); + g_procMapping.emplace(MakeKey(BGRA_8888, RGB_565), &BGRA8888ConvertRGB565); + + g_procMapping.emplace(MakeKey(ARGB_8888, RGBA_8888), &ARGB8888ConvertRGBA8888); + g_procMapping.emplace(MakeKey(ARGB_8888, ARGB_8888), &ARGB8888ConvertARGB8888Alpha); + g_procMapping.emplace(MakeKey(ARGB_8888, BGRA_8888), &ARGB8888ConvertBGRA8888); + g_procMapping.emplace(MakeKey(ARGB_8888, RGB_565), &ARGB8888ConvertRGB565); + + g_procMapping.emplace(MakeKey(RGBA_16161616, ARGB_8888), &RGBA16161616ConvertARGB8888); + g_procMapping.emplace(MakeKey(RGBA_16161616, RGBA_8888), &RGBA16161616ConvertRGBA8888); + g_procMapping.emplace(MakeKey(RGBA_16161616, BGRA_8888), &RGBA16161616ConvertBGRA8888); + g_procMapping.emplace(MakeKey(RGBA_16161616, ABGR_8888), &RGBA16161616ConvertABGR8888); +} + +static void InitCMYKProc() +{ + g_procMapping.emplace(MakeKey(CMKY, ARGB_8888), &CMYKConvertARGB8888); + g_procMapping.emplace(MakeKey(CMKY, RGBA_8888), &CMYKConvertRGBA8888); + g_procMapping.emplace(MakeKey(CMKY, BGRA_8888), &CMYKConvertBGRA8888); + g_procMapping.emplace(MakeKey(CMKY, ABGR_8888), &CMYKConvertABGR8888); + g_procMapping.emplace(MakeKey(CMKY, RGB_565), &CMYKConvertRGB565); +} + +static ProcFuncType GetProcFuncType(uint32_t srcPixelFormat, uint32_t dstPixelFormat) +{ + unique_lock guard(g_procMutex); + if (g_procMapping.empty()) { + InitGrayProc(); + InitRGBProc(); + InitRGBAProc(); + InitCMYKProc(); + } + guard.unlock(); + string procKey = MakeKey(srcPixelFormat, dstPixelFormat); + map::iterator iter = g_procMapping.find(procKey); + if (iter != g_procMapping.end()) { + return iter->second; + } + return nullptr; +} + +PixelConvert::PixelConvert(ProcFuncType funcPtr, ProcFuncExtension extension, bool isNeedConvert) + : procFunc_(funcPtr), procFuncExtension_(extension), isNeedConvert_(isNeedConvert) +{} + +// caller need setting the correct pixelFormat and alphaType +std::unique_ptr PixelConvert::Create(const ImageInfo &srcInfo, const ImageInfo &dstInfo) +{ + if (srcInfo.pixelFormat == PixelFormat::UNKNOWN || dstInfo.pixelFormat == PixelFormat::UNKNOWN) { + HiLog::Error(LABEL, "source or destination pixel format unknown"); + return nullptr; + } + uint32_t srcFormat = static_cast(srcInfo.pixelFormat); + uint32_t dstFormat = static_cast(dstInfo.pixelFormat); + ProcFuncType funcPtr = GetProcFuncType(srcFormat, dstFormat); + if (funcPtr == nullptr) { + HiLog::Error(LABEL, "not found convert function. pixelFormat %{public}u -> %{public}u", srcFormat, dstFormat); + return nullptr; + } + ProcFuncExtension extension; + extension.alphaConvertType = GetAlphaConvertType(srcInfo.alphaType, dstInfo.alphaType); + bool isNeedConvert = true; + if ((srcInfo.pixelFormat == dstInfo.pixelFormat) && (extension.alphaConvertType == AlphaConvertType::NO_CONVERT)) { + isNeedConvert = false; + } + return unique_ptr(new (nothrow) PixelConvert(funcPtr, extension, isNeedConvert)); +} + +AlphaConvertType PixelConvert::GetAlphaConvertType(const AlphaType &srcType, const AlphaType &dstType) +{ + if (srcType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN || dstType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) { + HiLog::Debug(LABEL, "source or destination alpha type unknown"); + return AlphaConvertType::NO_CONVERT; + } + if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL)) { + return AlphaConvertType::PREMUL_CONVERT_UNPREMUL; + } + if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + return AlphaConvertType::PREMUL_CONVERT_OPAQUE; + } + if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL)) { + return AlphaConvertType::UNPREMUL_CONVERT_PREMUL; + } + if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) { + return AlphaConvertType::UNPREMUL_CONVERT_OPAQUE; + } + return AlphaConvertType::NO_CONVERT; +} + +void PixelConvert::Convert(void *destinationPixels, const uint8_t *sourcePixels, uint32_t sourcePixelsNum) +{ + if ((destinationPixels == nullptr) || (sourcePixels == nullptr)) { + HiLog::Error(LABEL, "destinationPixel or sourcePixel is null"); + return; + } + if (!isNeedConvert_) { + HiLog::Debug(LABEL, "no need convert"); + return; + } + procFunc_(destinationPixels, sourcePixels, sourcePixelsNum, procFuncExtension_); +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/converter/src/post_proc.cpp b/frameworks/innerkitsimpl/converter/src/post_proc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..511c5635aed58fda9708b822352f3b8e899fc27f --- /dev/null +++ b/frameworks/innerkitsimpl/converter/src/post_proc.cpp @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "post_proc.h" +#include +#include "basic_transformer.h" +#include "image_log.h" +#include "image_trace.h" +#include "image_utils.h" +#include "media_errors.h" +#include "pixel_convert_adapter.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +#if !defined(_WIN32) && !defined(_APPLE) +#include +#include "ashmem.h" +#endif + +namespace OHOS { +namespace Media { +using namespace std; +constexpr uint32_t NEED_NEXT = 1; +constexpr float EPSILON = 1e-6; +constexpr uint8_t HALF = 2; + +uint32_t PostProc::DecodePostProc(const DecodeOptions &opts, PixelMap &pixelMap, FinalOutputStep finalOutputStep) +{ + ImageInfo srcImageInfo; + pixelMap.GetImageInfo(srcImageInfo); + ImageInfo dstImageInfo; + GetDstImageInfo(opts, pixelMap, srcImageInfo, dstImageInfo); + if (finalOutputStep == FinalOutputStep::ROTATE_CHANGE || finalOutputStep == FinalOutputStep::SIZE_CHANGE || + finalOutputStep == FinalOutputStep::DENSITY_CHANGE) { + decodeOpts_.allocatorType = AllocatorType::HEAP_ALLOC; + } + uint32_t errorCode = ConvertProc(opts.CropRect, dstImageInfo, pixelMap, srcImageInfo); + if (errorCode != SUCCESS) { + IMAGE_LOGE("[PostProc]crop pixel map failed, errcode:%{public}u", errorCode); + return errorCode; + } + decodeOpts_.allocatorType = opts.allocatorType; + bool isNeedRotate = !ImageUtils::FloatCompareZero(opts.rotateDegrees); + if (isNeedRotate) { + if (finalOutputStep == FinalOutputStep::SIZE_CHANGE || finalOutputStep == FinalOutputStep::DENSITY_CHANGE) { + decodeOpts_.allocatorType = AllocatorType::HEAP_ALLOC; + } + if (!RotatePixelMap(opts.rotateDegrees, pixelMap)) { + IMAGE_LOGE("[PostProc]rotate:transform pixel map failed"); + return ERR_IMAGE_TRANSFORM; + } + } + decodeOpts_.allocatorType = opts.allocatorType; + if (opts.desiredSize.height > 0 && opts.desiredSize.width > 0) { + if (!ScalePixelMap(opts.desiredSize, pixelMap)) { + IMAGE_LOGE("[PostProc]scale:transform pixel map failed"); + return ERR_IMAGE_TRANSFORM; + } + } else { + ImageInfo info; + pixelMap.GetImageInfo(info); + if ((finalOutputStep == FinalOutputStep::DENSITY_CHANGE) && (info.baseDensity != 0)) { + int targetWidth = (pixelMap.GetWidth() * opts.fitDensity + (info.baseDensity >> 1)) / info.baseDensity; + int targetHeight = (pixelMap.GetHeight() * opts.fitDensity + (info.baseDensity >> 1)) / info.baseDensity; + Size size; + size.height = targetHeight; + size.width = targetWidth; + if (!ScalePixelMap(size, pixelMap)) { + IMAGE_LOGE("[PostProc]density scale:transform pixel map failed"); + return ERR_IMAGE_TRANSFORM; + } + } + } + return SUCCESS; +} + +void PostProc::GetDstImageInfo(const DecodeOptions &opts, PixelMap &pixelMap, + ImageInfo srcImageInfo, ImageInfo &dstImageInfo) +{ + dstImageInfo.size = opts.desiredSize; + dstImageInfo.pixelFormat = opts.desiredPixelFormat; + dstImageInfo.baseDensity = srcImageInfo.baseDensity; + decodeOpts_ = opts; + if (opts.desiredPixelFormat == PixelFormat::UNKNOWN) { + if (opts.preference == MemoryUsagePreference::LOW_RAM && + srcImageInfo.alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) { + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + } else { + dstImageInfo.pixelFormat = PixelFormat::RGBA_8888; + } + } + // decode use, this value may be changed by real pixelFormat + if (pixelMap.GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) { + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + } else { + dstImageInfo.alphaType = pixelMap.GetAlphaType(); + } +} + +bool PostProc::CenterScale(const Size &size, PixelMap &pixelMap) +{ + int32_t srcWidth = pixelMap.GetWidth(); + int32_t srcHeight = pixelMap.GetHeight(); + int32_t targetWidth = size.width; + int32_t targetHeight = size.height; + if (targetWidth <= 0 || targetHeight <= 0 || srcWidth <= 0 || srcHeight <= 0) { + IMAGE_LOGE("[PostProc]params invalid, targetWidth:%{public}d, targetHeight:%{public}d, " + "srcWidth:%{public}d, srcHeight:%{public}d", + targetWidth, targetHeight, srcWidth, srcHeight); + return false; + } + float widthScale = static_cast(targetWidth) / static_cast(srcWidth); + float heightScale = static_cast(targetHeight) / static_cast(srcHeight); + float scale = max(widthScale, heightScale); + if (!ScalePixelMap(scale, scale, pixelMap)) { + IMAGE_LOGE("[PostProc]center scale pixelmap %{public}f fail", scale); + return false; + } + srcWidth = pixelMap.GetWidth(); + srcHeight = pixelMap.GetHeight(); + if (srcWidth == targetWidth && srcHeight == targetHeight) { + return true; + } + if (srcWidth < targetWidth || srcHeight < targetHeight) { + IMAGE_LOGE("[PostProc]src size [%{public}d, %{public}d] must less than dst size [%{public}d, %{public}d]", + srcWidth, srcHeight, targetWidth, targetHeight); + return false; + } + if (CenterDisplay(pixelMap, srcWidth, srcHeight, targetWidth, targetHeight)) { + return true; + } + return false; +} + +bool PostProc::CenterDisplay(PixelMap &pixelMap, int32_t srcWidth, int32_t srcHeight, int32_t targetWidth, + int32_t targetHeight) +{ + ImageInfo dstImageInfo; + pixelMap.GetImageInfo(dstImageInfo); + dstImageInfo.size.width = targetWidth; + dstImageInfo.size.height = targetHeight; + if (pixelMap.SetImageInfo(dstImageInfo, true) != SUCCESS) { + IMAGE_LOGE("update ImageInfo failed"); + return false; + } + + int32_t left = max(0, srcWidth - targetWidth) / HALF; + int32_t top = max(0, srcHeight - targetHeight) / HALF; + int32_t bufferSize = pixelMap.GetByteCount(); + uint8_t *dstPixels = nullptr; + if (!AllocHeapBuffer(bufferSize, &dstPixels)) { + return false; + } + int32_t copyHeight = srcHeight; + if (srcHeight > targetHeight) { + copyHeight = targetHeight; + } + int32_t copyWidth = srcWidth; + if (srcWidth > targetWidth) { + copyWidth = targetWidth; + } + int32_t pixelBytes = pixelMap.GetPixelBytes(); + uint8_t *srcPixels = const_cast(pixelMap.GetPixels()) + (top * srcWidth + left) * pixelBytes; + uint8_t *dstStartPixel = nullptr; + uint8_t *srcStartPixel = nullptr; + uint32_t targetRowBytes = targetWidth * pixelBytes; + uint32_t srcRowBytes = srcWidth * pixelBytes; + uint32_t copyRowBytes = copyWidth * pixelBytes; + for (int32_t scanLine = 0; scanLine < copyHeight; scanLine++) { + dstStartPixel = dstPixels + scanLine * targetRowBytes; + srcStartPixel = srcPixels + scanLine * srcRowBytes; + errno_t errRet = memcpy_s(dstStartPixel, targetRowBytes, srcStartPixel, copyRowBytes); + if (errRet != 0) { + IMAGE_LOGE("[PostProc]memcpy scanline %{public}d fail, errorCode = %{public}d", scanLine, errRet); + free(dstPixels); + dstPixels = nullptr; + return false; + } + } + pixelMap.SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + return true; +} + +uint32_t PostProc::CheckScanlineFilter(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap, + int32_t pixelBytes, ScanlineFilter &scanlineFilter) +{ + uint64_t bufferSize = static_cast(dstImageInfo.size.width) * dstImageInfo.size.height * pixelBytes; + uint8_t *resultData = nullptr; + int fd = 0; + if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) { + resultData = AllocSharedMemory(dstImageInfo.size, bufferSize, fd); + if (resultData == nullptr) { + IMAGE_LOGE("[PostProc]AllocSharedMemory failed"); + return ERR_IMAGE_CROP; + } + } else { + if (!AllocHeapBuffer(bufferSize, &resultData)) { + return ERR_IMAGE_CROP; + } + } + auto srcData = pixelMap.GetPixels(); + int32_t scanLine = 0; + if (ImageUtils::CheckMulOverflow(dstImageInfo.size.width, pixelBytes)) { + IMAGE_LOGE("[PostProc]size.width:%{public}d, is too large", + dstImageInfo.size.width); + ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData); + return ERR_IMAGE_CROP; + } + uint32_t rowBytes = pixelBytes * dstImageInfo.size.width; + while (scanLine < pixelMap.GetHeight()) { + FilterRowType filterRow = scanlineFilter.GetFilterRowType(scanLine); + if (filterRow == FilterRowType::NON_REFERENCE_ROW) { + scanLine++; + continue; + } + if (filterRow == FilterRowType::LAST_REFERENCE_ROW) { + break; + } + uint32_t ret = scanlineFilter.FilterLine(resultData + ((scanLine - cropRect.top) * rowBytes), rowBytes, + srcData + (scanLine * pixelMap.GetRowBytes())); + if (ret != SUCCESS) { + IMAGE_LOGE("[PostProc]scan line failed, ret:%{public}u", ret); + ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData); + return ret; + } + scanLine++; + } + uint32_t ret = pixelMap.SetImageInfo(dstImageInfo); + if (ret != SUCCESS) { + ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData); + return ret; + } + pixelMap.SetPixelsAddr(resultData, nullptr, bufferSize, decodeOpts_.allocatorType, nullptr); + return ret; +} + +uint32_t PostProc::ConvertProc(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap, + ImageInfo &srcImageInfo) +{ + bool hasPixelConvert = HasPixelConvert(srcImageInfo, dstImageInfo); + uint32_t ret = NeedScanlineFilter(cropRect, srcImageInfo.size, hasPixelConvert); + if (ret != NEED_NEXT) { + return ret; + } + + // we suppose a quick method to scanline in mostly seen cases: NO CROP && hasPixelConvert + if (GetCropValue(cropRect, srcImageInfo.size) == CropValue::NOCROP + && dstImageInfo.pixelFormat == PixelFormat::ARGB_8888 && hasPixelConvert) { + IMAGE_LOGI("[PostProc]no need crop, only pixel convert."); + return PixelConvertProc(dstImageInfo, pixelMap, srcImageInfo); + } + + ScanlineFilter scanlineFilter(srcImageInfo.pixelFormat); + // this method maybe update dst image size to crop size + SetScanlineCropAndConvert(cropRect, dstImageInfo, srcImageInfo, scanlineFilter, hasPixelConvert); + + int32_t pixelBytes = ImageUtils::GetPixelBytes(dstImageInfo.pixelFormat); + if (pixelBytes == 0) { + return ERR_IMAGE_CROP; + } + if (ImageUtils::CheckMulOverflow(dstImageInfo.size.width, dstImageInfo.size.height, pixelBytes)) { + IMAGE_LOGE("[PostProc]size.width:%{public}d, size.height:%{public}d is too large", + dstImageInfo.size.width, dstImageInfo.size.height); + return ERR_IMAGE_CROP; + } + return CheckScanlineFilter(cropRect, dstImageInfo, pixelMap, pixelBytes, scanlineFilter); +} + +uint32_t PostProc::PixelConvertProc(ImageInfo &dstImageInfo, PixelMap &pixelMap, + ImageInfo &srcImageInfo) +{ + uint32_t ret; + int fd = 0; + uint64_t bufferSize = 0; + uint8_t *resultData = nullptr; + + // as no crop, the size is same as src + dstImageInfo.size = srcImageInfo.size; + if (AllocBuffer(dstImageInfo, &resultData, bufferSize, fd) != SUCCESS) { + ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData); + return ERR_IMAGE_CROP; + } + + int32_t pixelBytes = ImageUtils::GetPixelBytes(srcImageInfo.pixelFormat); + if (pixelBytes == 0) { + return ERR_IMAGE_CROP; + } +// uint32_t rowBytes = pixelBytes * dstImageInfo.size.width; + + // copy src buffer to new buffer +/* + auto srcData = pixelMap.GetPixels(); + Position dstPosition; + if (!PixelConvertAdapter::WritePixelsConvert(reinterpret_cast(srcData), rowBytes, srcImageInfo, + resultData, dstPosition, pixelMap.GetRowBytes(), dstImageInfo)) { + IMAGE_LOGE("pixel convert in adapter failed."); + ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData); + return ERR_IMAGE_CROP; + } +*/ + ret = pixelMap.SetImageInfo(dstImageInfo); + if (ret != SUCCESS) { + ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData); + return ret; + } + pixelMap.SetPixelsAddr(resultData, nullptr, bufferSize, decodeOpts_.allocatorType, nullptr); + return ret; +} + +uint32_t PostProc::AllocBuffer(ImageInfo imageInfo, uint8_t **resultData, uint64_t &bufferSize, int &fd) +{ + int32_t pixelBytes = ImageUtils::GetPixelBytes(imageInfo.pixelFormat); + if (pixelBytes == 0) { + return ERR_IMAGE_CROP; + } + if (ImageUtils::CheckMulOverflow(imageInfo.size.width, imageInfo.size.height, pixelBytes)) { + IMAGE_LOGE("[PostProc]size.width:%{public}d, size.height:%{public}d is too large", + imageInfo.size.width, imageInfo.size.height); + return ERR_IMAGE_CROP; + } + bufferSize = static_cast(imageInfo.size.width) * imageInfo.size.height * pixelBytes; + IMAGE_LOGD("[PostProc]size.width:%{public}d, size.height:%{public}d, bufferSize:%{public}lld", + imageInfo.size.width, imageInfo.size.height, (long long)bufferSize); + if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) { + *resultData = AllocSharedMemory(imageInfo.size, bufferSize, fd); + if (*resultData == nullptr) { + IMAGE_LOGE("[PostProc]AllocSharedMemory failed"); + return ERR_IMAGE_CROP; + } + } else { + if (!AllocHeapBuffer(bufferSize, resultData)) { + return ERR_IMAGE_CROP; + } + } + return SUCCESS; +} + +bool PostProc::AllocHeapBuffer(uint64_t bufferSize, uint8_t **buffer) +{ + *buffer = static_cast(malloc(bufferSize)); + if (*buffer == nullptr) { + IMAGE_LOGE("[PostProc]alloc covert color buffersize[%{public}llu] failed.", + static_cast(bufferSize)); + return false; + } +#ifdef _WIN32 + memset(*buffer, 0, bufferSize); + return true; +#else + errno_t errRet = memset_s(*buffer, bufferSize, 0, bufferSize); + if (errRet != EOK) { + IMAGE_LOGE("[PostProc]memset convertData fail, errorCode = %{public}d", errRet); + ReleaseBuffer(AllocatorType::HEAP_ALLOC, 0, 0, buffer); + return false; + } + return true; +#endif +} + +uint8_t *PostProc::AllocSharedMemory(const Size &size, const uint64_t bufferSize, int &fd) +{ +#if defined(_WIN32) || defined(_APPLE) + return nullptr; +#else + fd = AshmemCreate("Parcel RawData", bufferSize); + if (fd < 0) { + IMAGE_LOGE("[PostProc]AllocSharedMemory fd error, bufferSize %{public}lld", (long long)bufferSize); + return nullptr; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + IMAGE_LOGE("[PostProc]AshmemSetProt error"); + ::close(fd); + return nullptr; + } + void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + IMAGE_LOGE("[PostProc]mmap error, errno: %{public}s, fd %{public}d, bufferSize %{public}lld", + strerror(errno), fd, (long long)bufferSize); + ::close(fd); + return nullptr; + } + return (uint8_t *)ptr; +#endif +} + +void PostProc::ReleaseBuffer(AllocatorType allocatorType, int fd, uint64_t dataSize, uint8_t **buffer) +{ +#if !defined(_WIN32) && !defined(_APPLE) + if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) { + if (*buffer != nullptr) { + ::munmap(*buffer, dataSize); + ::close(fd); + } + return; + } +#endif + + if (allocatorType == AllocatorType::HEAP_ALLOC) { + if (*buffer != nullptr) { + free(*buffer); + *buffer = nullptr; + } + return; + } +} + +uint32_t PostProc::NeedScanlineFilter(const Rect &cropRect, const Size &srcSize, const bool &hasPixelConvert) +{ + CropValue value = GetCropValue(cropRect, srcSize); + if (value == CropValue::NOCROP && !hasPixelConvert) { + IMAGE_LOGI("[PostProc]no need crop and pixel convert."); + return SUCCESS; + } else if (value == CropValue::INVALID) { + IMAGE_LOGE("[PostProc]invalid corp region, top:%{public}d, left:%{public}d, " + "width:%{public}d, height:%{public}d", + cropRect.top, cropRect.left, cropRect.width, cropRect.height); + return ERR_IMAGE_CROP; + } + return NEED_NEXT; +} + +void PostProc::ConvertPixelMapToPixmapInfo(PixelMap &pixelMap, PixmapInfo &pixmapInfo) +{ + pixmapInfo.imageInfo.size.width = pixelMap.GetWidth(); + pixmapInfo.imageInfo.size.height = pixelMap.GetHeight(); + pixmapInfo.imageInfo.pixelFormat = pixelMap.GetPixelFormat(); + pixmapInfo.imageInfo.colorSpace = pixelMap.GetColorSpace(); + pixmapInfo.imageInfo.alphaType = pixelMap.GetAlphaType(); + pixmapInfo.imageInfo.baseDensity = pixelMap.GetBaseDensity(); + pixmapInfo.data = const_cast(pixelMap.GetPixels()); + pixmapInfo.bufferSize = pixelMap.GetByteCount(); +} + +bool PostProc::RotatePixelMap(float rotateDegrees, PixelMap &pixelMap) +{ + BasicTransformer trans; + PixmapInfo input(false); + ConvertPixelMapToPixmapInfo(pixelMap, input); + // Default rotation at the center of the image, so divide 2 + trans.SetRotateParam(rotateDegrees, static_cast(input.imageInfo.size.width) * FHALF, + static_cast(input.imageInfo.size.height) * FHALF); + return Transform(trans, input, pixelMap); +} + +bool PostProc::ScalePixelMap(const Size &size, PixelMap &pixelMap) +{ + int32_t srcWidth = pixelMap.GetWidth(); + int32_t srcHeight = pixelMap.GetHeight(); + if (srcWidth <= 0 || srcHeight <= 0) { + IMAGE_LOGE("[PostProc]src width:%{public}d, height:%{public}d is invalid.", srcWidth, srcHeight); + return false; + } + float scaleX = static_cast(size.width) / static_cast(srcWidth); + float scaleY = static_cast(size.height) / static_cast(srcHeight); + return ScalePixelMap(scaleX, scaleY, pixelMap); +} + +bool PostProc::ScalePixelMap(float scaleX, float scaleY, PixelMap &pixelMap) +{ + // returns directly with a scale of 1.0 + if ((fabs(scaleX - 1.0f) < EPSILON) && (fabs(scaleY - 1.0f) < EPSILON)) { + return true; + } + BasicTransformer trans; + PixmapInfo input(false); + ConvertPixelMapToPixmapInfo(pixelMap, input); + + trans.SetScaleParam(scaleX, scaleY); + return Transform(trans, input, pixelMap); +} + +bool PostProc::Transform(BasicTransformer &trans, const PixmapInfo &input, PixelMap &pixelMap) +{ + PixmapInfo output(false); + uint32_t ret; + if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) { + typedef uint8_t *(*AllocMemory)(const Size &size, const uint64_t bufferSize, int &fd); + AllocMemory allcFunc = AllocSharedMemory; + ret = trans.TransformPixmap(input, output, allcFunc); + } else { + ret = trans.TransformPixmap(input, output); + } + if (ret != IMAGE_SUCCESS) { + output.Destroy(); + return false; + } + + if (pixelMap.SetImageInfo(output.imageInfo) != SUCCESS) { + output.Destroy(); + return false; + } + pixelMap.SetPixelsAddr(output.data, nullptr, output.bufferSize, decodeOpts_.allocatorType, nullptr); + return true; +} + +CropValue PostProc::GetCropValue(const Rect &rect, const Size &size) +{ + bool isSameSize = (rect.top == 0 && rect.left == 0 && rect.height == size.height && rect.width == size.width); + if (!IsHasCrop(rect) || isSameSize) { + return CropValue::NOCROP; + } + bool isValid = ((rect.top >= 0 && rect.width > 0 && rect.left >= 0 && rect.height > 0) && + (rect.top + rect.height <= size.height) && (rect.left + rect.width <= size.width)); + if (!isValid) { + return CropValue::INVALID; + } + return CropValue::VALID; +} + +bool PostProc::IsHasCrop(const Rect &rect) +{ + return (rect.top != 0 || rect.left != 0 || rect.width != 0 || rect.height != 0); +} + +bool PostProc::HasPixelConvert(const ImageInfo &srcImageInfo, ImageInfo &dstImageInfo) +{ + dstImageInfo.alphaType = ImageUtils::GetValidAlphaTypeByFormat(dstImageInfo.alphaType, dstImageInfo.pixelFormat); + return (dstImageInfo.pixelFormat != srcImageInfo.pixelFormat || dstImageInfo.alphaType != srcImageInfo.alphaType); +} + +void PostProc::SetScanlineCropAndConvert(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo, + ScanlineFilter &scanlineFilter, bool hasPixelConvert) +{ + if (hasPixelConvert) { + scanlineFilter.SetPixelConvert(srcImageInfo, dstImageInfo); + } + + Rect srcRect = cropRect; + if (IsHasCrop(cropRect)) { + dstImageInfo.size.width = cropRect.width; + dstImageInfo.size.height = cropRect.height; + } else { + srcRect = { 0, 0, srcImageInfo.size.width, srcImageInfo.size.height }; + dstImageInfo.size = srcImageInfo.size; + } + scanlineFilter.SetSrcRegion(srcRect); +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/converter/src/scan_line_filter.cpp b/frameworks/innerkitsimpl/converter/src/scan_line_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..021fbac9067467e155637016a85cea9bfa167f90 --- /dev/null +++ b/frameworks/innerkitsimpl/converter/src/scan_line_filter.cpp @@ -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. + */ + +#include "image_log.h" +#include "image_utils.h" +#include "media_errors.h" +#include "scan_line_filter.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace Media { +ScanlineFilter::ScanlineFilter(const PixelFormat &srcPixelFormat) : srcBpp_(ImageUtils::GetPixelBytes(srcPixelFormat)) +{} + +void ScanlineFilter::SetSrcPixelFormat(const PixelFormat &srcPixelFormat) +{ + srcBpp_ = ImageUtils::GetPixelBytes(srcPixelFormat); +} + +FilterRowType ScanlineFilter::GetFilterRowType(const int32_t rowNum) +{ + if (rowNum < srcRegion_.top || (rowNum - srcRegion_.top) > srcRegion_.height) { + return FilterRowType::NON_REFERENCE_ROW; + } + + if ((rowNum - srcRegion_.top) == srcRegion_.height) { + return FilterRowType::LAST_REFERENCE_ROW; + } + + return FilterRowType::NORMAL_REFERENCE_ROW; +} + +void ScanlineFilter::SetSrcRegion(const Rect ®ion) +{ + srcRegion_ = region; +} + +// outer need judgement the src and dst imageInfo pixelFormat and alphaType +void ScanlineFilter::SetPixelConvert(const ImageInfo &srcImageInfo, const ImageInfo &dstImageInfo) +{ + needPixelConvert_ = true; + pixelConverter_ = PixelConvert::Create(srcImageInfo, dstImageInfo); +} + +uint32_t ScanlineFilter::FilterLine(void *destRowPixels, uint32_t destRowBytes, const void *srcRowPixels) +{ + if (destRowPixels == nullptr || srcRowPixels == nullptr) { + IMAGE_LOGE("[ScanlineFilter]the src or dest pixel point is null."); + return ERR_IMAGE_CROP; + } + auto startPixel = static_cast(srcRowPixels) + srcRegion_.left * srcBpp_; + if (startPixel == nullptr) { + IMAGE_LOGE("[ScanlineFilter]the shift src pixel point is null."); + return ERR_IMAGE_CROP; + } + if (!needPixelConvert_) { + errno_t ret = memcpy_s(destRowPixels, destRowBytes, startPixel, srcRegion_.width * srcBpp_); + if (ret != 0) { + IMAGE_LOGE("[ScanlineFilter]memcpy failed,ret=%{public}d.", ret); + return ERR_IMAGE_CROP; + } + } else { + if (!ConvertPixels(destRowPixels, startPixel, srcRegion_.width)) { + IMAGE_LOGE("[ScanlineFilter]convert color failed."); + return ERR_IMAGE_COLOR_CONVERT; + } + } + return SUCCESS; +} + +bool ScanlineFilter::ConvertPixels(void *destRowPixels, const uint8_t *startPixel, uint32_t reqPixelNum) +{ + if (destRowPixels == nullptr || startPixel == nullptr) { + IMAGE_LOGE("[ScanlineFilter]convert color failed, the destRowPixels or startPixel is null."); + return false; + } + + if (pixelConverter_ == nullptr) { + IMAGE_LOGE("[ScanlineFilter]pixel converter is null"); + return false; + } + + pixelConverter_->Convert(destRowPixels, startPixel, reqPixelNum); + return true; +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/stream/include/buffer_packer_stream.h b/frameworks/innerkitsimpl/stream/include/buffer_packer_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..417c3a43232eb8778d2400f1ac3d4d716777875d --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/buffer_packer_stream.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BUFFER_PACKER_STREAM_H +#define BUFFER_PACKER_STREAM_H + +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "nocopyable.h" +#include "packer_stream.h" + +namespace OHOS { +namespace Media { +class BufferPackerStream : public PackerStream { +public: + BufferPackerStream(uint8_t *outputData, uint32_t maxSize); + ~BufferPackerStream() = default; + bool Write(const uint8_t *buffer, uint32_t size) override; + int64_t BytesWritten() override; + +private: + DISALLOW_COPY(BufferPackerStream); + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "BufferPackerStream" + }; + uint8_t *outputData_ = nullptr; + uint32_t maxSize_ = 0; + int64_t offset_ = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif // BUFFER_PACKER_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/buffer_source_stream.h b/frameworks/innerkitsimpl/stream/include/buffer_source_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..eb07d85f3e82bb35e91b8af97929f3737edb4570 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/buffer_source_stream.h @@ -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. + */ + +#ifndef BUFFER_SOURCE_STREAM_H +#define BUFFER_SOURCE_STREAM_H + +#include +#include +#include "image/input_data_stream.h" +#include "source_stream.h" + +namespace OHOS { +namespace Media { +class BufferSourceStream : public SourceStream { +public: + static std::unique_ptr CreateSourceStream(const uint8_t *data, uint32_t size); + ~BufferSourceStream(); + bool Read(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + bool Peek(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + uint32_t Tell() override; + bool Seek(uint32_t position) override; + size_t GetStreamSize() override; + uint8_t *GetDataPtr() override; + uint32_t GetStreamType() override; + +private: + BufferSourceStream(uint8_t *data, uint32_t size, uint32_t offset); + uint8_t *inputBuffer_ = nullptr; + size_t dataSize_ = 0; + size_t dataOffset_ = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif // BUFFER_SOURCE_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/file_packer_stream.h b/frameworks/innerkitsimpl/stream/include/file_packer_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..b0fd65ac28cb0ea8e5af30e6647c406cc39007c0 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/file_packer_stream.h @@ -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. + */ + +#ifndef FILE_PACKER_STREAM_H +#define FILE_PACKER_STREAM_H + +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "nocopyable.h" +#include "packer_stream.h" + +namespace OHOS { +namespace Media { +class FilePackerStream : public PackerStream { +public: + explicit FilePackerStream(const std::string &filePath); + ~FilePackerStream() override; + bool Write(const uint8_t *buffer, uint32_t size) override; + void Flush() override; + int64_t BytesWritten() override; + +private: + DISALLOW_COPY(FilePackerStream); + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "FilePackerStream" }; + FILE *file_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // FILE_PACKER_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/file_source_stream.h b/frameworks/innerkitsimpl/stream/include/file_source_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..dced8d8458eb079f73ab4bc251fa7e948d5c6594 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/file_source_stream.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILE_SOURCE_STREAM_H +#define FILE_SOURCE_STREAM_H + +#include +#include +#include +#include "image/input_data_stream.h" +#include "source_stream.h" + +namespace OHOS { +namespace Media { +class FileSourceStream : public SourceStream { +public: + static std::unique_ptr CreateSourceStream(const std::string &pathName); + ~FileSourceStream(); + + bool Read(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + bool Peek(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + uint32_t Tell() override; + bool Seek(uint32_t position) override; + size_t GetStreamSize() override; + uint8_t *GetDataPtr() override; + uint32_t GetStreamType() override; + +private: + DISALLOW_COPY_AND_MOVE(FileSourceStream); + FileSourceStream(std::FILE *file, size_t size, size_t offset, size_t original); + bool GetData(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize); + bool GetData(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData); + void ResetReadBuffer(); + std::FILE *filePtr_ = nullptr; + size_t fileSize_ = 0; + size_t fileOffset_ = 0; + size_t fileOriginalOffset_ = 0; + uint8_t *readBuffer_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // FILE_SOURCE_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/incremental_source_stream.h b/frameworks/innerkitsimpl/stream/include/incremental_source_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..e6af4523d217b96f20be0bbd773785cbbb5c68fc --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/incremental_source_stream.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCREMENTAL_SOURCE_STREAM_H +#define INCREMENTAL_SOURCE_STREAM_H + +#include +#include +#include +#include "image/input_data_stream.h" +#include "image_type.h" +#include "source_stream.h" + +namespace OHOS { +namespace Media { +class IncrementalSourceStream : public SourceStream { +public: + static std::unique_ptr CreateSourceStream(IncrementalMode mode); + ~IncrementalSourceStream() = default; + bool Read(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + bool Peek(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + uint32_t Tell() override; + bool Seek(uint32_t position) override; + + uint32_t UpdateData(const uint8_t *data, uint32_t size, bool isCompleted) override; + bool IsStreamCompleted() override; + size_t GetStreamSize() override; + +private: + explicit IncrementalSourceStream(IncrementalMode mode); + IncrementalMode incrementalMode_; + bool isFinalize_; + std::vector sourceData_; + size_t dataSize_ = 0; + size_t dataOffset_ = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif // ZINCREMENTAL_INPUT_STREAM_H diff --git a/frameworks/innerkitsimpl/stream/include/istream_source_stream.h b/frameworks/innerkitsimpl/stream/include/istream_source_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..68600073eabc4be7b3560b65f5e5c37db3cb651b --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/istream_source_stream.h @@ -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. + */ + +#ifndef ISTREAM_SOURCE_STREAM_H +#define ISTREAM_SOURCE_STREAM_H + +#include +#include +#include +#include "image/input_data_stream.h" +#include "source_stream.h" + +namespace OHOS { +namespace Media { +class IstreamSourceStream : public SourceStream { +public: + static std::unique_ptr CreateSourceStream(std::unique_ptr inputStream); + ~IstreamSourceStream(); + bool Read(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + bool Peek(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData) override; + bool Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) override; + uint32_t Tell() override; + bool Seek(uint32_t position) override; + size_t GetStreamSize() override; + uint8_t *GetDataPtr() override; + uint32_t GetStreamType() override; + +private: + DISALLOW_COPY_AND_MOVE(IstreamSourceStream); + IstreamSourceStream(std::unique_ptr inputStream, size_t size, size_t original, size_t offset); + bool GetData(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize); + bool GetData(uint32_t desiredSize, ImagePlugin::DataStreamBuffer &outData); + void ResetReadBuffer(); + std::unique_ptr inputStream_; + size_t streamSize_ = 0; + size_t streamOriginalOffset_ = 0; + size_t streamOffset_ = 0; + uint8_t *databuffer_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // ISTREAM_SOURCE_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/ostream_packer_stream.h b/frameworks/innerkitsimpl/stream/include/ostream_packer_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..1f799017f828d5abe611cccbc46e267fd8550370 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/ostream_packer_stream.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OSTREAM_PACKER_STREAM_H +#define OSTREAM_PACKER_STREAM_H + +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "nocopyable.h" +#include "packer_stream.h" + +namespace OHOS { +namespace Media { +class OstreamPackerStream : public PackerStream { +public: + explicit OstreamPackerStream(std::ostream &outputStream); + ~OstreamPackerStream() = default; + bool Write(const uint8_t *buffer, uint32_t size) override; + void Flush() override; + int64_t BytesWritten() override; + +private: + DISALLOW_COPY(OstreamPackerStream); + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "OstreamPackerStream" + }; + std::ostream *outputStream_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // OSTREAM_PACKER_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/packer_stream.h b/frameworks/innerkitsimpl/stream/include/packer_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..a8169488cdee786e379ae88bb0ef476ad8a1c99c --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/packer_stream.h @@ -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. + */ + +#ifndef PACKER_STREAM_H +#define PACKER_STREAM_H + +#include "image/output_data_stream.h" + +namespace OHOS { +namespace Media { +class PackerStream : public ImagePlugin::OutputDataStream { +public: + virtual int64_t BytesWritten() = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif // PACKER_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/include/source_stream.h b/frameworks/innerkitsimpl/stream/include/source_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..58ef70db2d4c2ab4e7b3b0ab17220400f02a38bf --- /dev/null +++ b/frameworks/innerkitsimpl/stream/include/source_stream.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOURCE_STREAM_H +#define SOURCE_STREAM_H + +#include +#include "image/input_data_stream.h" +#include "media_errors.h" + +namespace OHOS { +namespace Media { +class SourceStream : public ImagePlugin::InputDataStream { +public: + virtual uint32_t UpdateData(const uint8_t *data, uint32_t size, bool isCompleted) + { + return ERR_IMAGE_DATA_UNSUPPORT; + } +}; +} // namespace Media +} // namespace OHOS + +#endif // SOURCE_STREAM_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp b/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64f1e66f1d331e030ee2f0124555ce2848c54ebe --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp @@ -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. + */ + +#include "buffer_packer_stream.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +BufferPackerStream::BufferPackerStream(uint8_t *outputData, uint32_t maxSize) + : outputData_(outputData), maxSize_(maxSize) +{} + +bool BufferPackerStream::Write(const uint8_t *buffer, uint32_t size) +{ + if ((buffer == nullptr) || (size == 0)) { + HiLog::Error(LABEL, "input parameter invalid."); + return false; + } + if (outputData_ == nullptr) { + HiLog::Error(LABEL, "output stream is null."); + return false; + } + uint32_t leftSize = maxSize_ - offset_; + if (size > leftSize) { + HiLog::Error(LABEL, "write data:[%{public}lld] out of max size:[%{public}u].", + static_cast(size + offset_), maxSize_); + return false; + } + if (memcpy_s(outputData_ + offset_, leftSize, buffer, size) != EOK) { + HiLog::Error(LABEL, "memory copy failed."); + return false; + } + offset_ += size; + return true; +} + +int64_t BufferPackerStream::BytesWritten() +{ + return offset_; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/src/buffer_source_stream.cpp b/frameworks/innerkitsimpl/stream/src/buffer_source_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71cadaf80e37c97d15c393db45d1fb8d6b6b646d --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/buffer_source_stream.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "buffer_source_stream.h" + +#include +#include "image_log.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +using namespace ImagePlugin; + +BufferSourceStream::BufferSourceStream(uint8_t *data, uint32_t size, uint32_t offset) + : inputBuffer_(data), dataSize_(size), dataOffset_(offset) +{} + +BufferSourceStream::~BufferSourceStream() +{ + if (inputBuffer_ != nullptr) { + free(inputBuffer_); + inputBuffer_ = nullptr; + } +} + +std::unique_ptr BufferSourceStream::CreateSourceStream(const uint8_t *data, uint32_t size) +{ + if ((data == nullptr) || (size == 0)) { + IMAGE_LOGE("[BufferSourceStream]input the parameter exception."); + return nullptr; + } + uint8_t *dataCopy = static_cast(malloc(size)); + if (dataCopy == nullptr) { + IMAGE_LOGE("[BufferSourceStream]malloc the input data buffer fail."); + return nullptr; + } + errno_t ret = memcpy_s(dataCopy, size, data, size); + if (ret != 0) { + free(dataCopy); + dataCopy = nullptr; + IMAGE_LOGE("[BufferSourceStream]copy the input data fail, ret:%{public}d.", ret); + return nullptr; + } + return (unique_ptr(new BufferSourceStream(dataCopy, size, 0))); +} + +bool BufferSourceStream::Read(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (!Peek(desiredSize, outData)) { + IMAGE_LOGE("[BufferSourceStream]read fail."); + return false; + } + dataOffset_ += outData.dataSize; + return true; +} + +bool BufferSourceStream::Peek(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (desiredSize == 0) { + IMAGE_LOGE("[BufferSourceStream]input the parameter exception."); + return false; + } + if (dataSize_ == dataOffset_) { + IMAGE_LOGE("[BufferSourceStream]buffer read finish, offset:%{public}zu ,dataSize%{public}zu.", dataOffset_, + dataSize_); + return false; + } + outData.bufferSize = dataSize_ - dataOffset_; + if (desiredSize > dataSize_ - dataOffset_) { + desiredSize = dataSize_ - dataOffset_; + } + outData.dataSize = desiredSize; + outData.inputStreamBuffer = inputBuffer_ + dataOffset_; + IMAGE_LOGD("[BufferSourceStream]Peek end. desiredSize:%{public}d, offset:%{public}zu ,dataSize%{public}zu.", + desiredSize, dataOffset_, dataSize_); + return true; +} + +bool BufferSourceStream::Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (!Peek(desiredSize, outBuffer, bufferSize, readSize)) { + IMAGE_LOGE("[BufferSourceStream]read fail."); + return false; + } + dataOffset_ += readSize; + return true; +} + +bool BufferSourceStream::Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize) { + IMAGE_LOGE("[BufferSourceStream]input the parameter exception, desiredSize:%{public}u, bufferSize:%{public}u.", + desiredSize, bufferSize); + return false; + } + if (dataSize_ == dataOffset_) { + IMAGE_LOGE("[BufferSourceStream]buffer read finish, offset:%{public}zu ,dataSize%{public}zu.", dataOffset_, + dataSize_); + return false; + } + if (desiredSize > dataSize_ - dataOffset_) { + desiredSize = dataSize_ - dataOffset_; + } + errno_t ret = memcpy_s(outBuffer, bufferSize, inputBuffer_ + dataOffset_, desiredSize); + if (ret != 0) { + IMAGE_LOGE("[BufferSourceStream]copy data fail, ret:%{public}d, bufferSize:%{public}u, offset:%{public}zu,\ + desiredSize:%{public}u.", + ret, bufferSize, dataOffset_, desiredSize); + return false; + } + readSize = desiredSize; + return true; +} + +uint32_t BufferSourceStream::Tell() +{ + return dataOffset_; +} + +bool BufferSourceStream::Seek(uint32_t position) +{ + if (position > dataSize_) { + IMAGE_LOGE("[BufferSourceStream]Seek the position greater than the Data Size,position:%{public}u.", position); + return false; + } + dataOffset_ = position; + return true; +} + +size_t BufferSourceStream::GetStreamSize() +{ + return dataSize_; +} + +uint8_t *BufferSourceStream::GetDataPtr() +{ + return inputBuffer_; +} + +uint32_t BufferSourceStream::GetStreamType() +{ + return ImagePlugin::BUFFER_SOURCE_TYPE; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp b/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0aeb2a83972724436ea29e204503d624fcb14a8 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file_packer_stream.h" +#include +#include "directory_ex.h" +#include "image_utils.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +FilePackerStream::FilePackerStream(const std::string &filePath) +{ + std::string dirPath = ExtractFilePath(filePath); + std::string fileName = ExtractFileName(filePath); + std::string realPath; + if (!ImageUtils::PathToRealPath(dirPath, realPath)) { + file_ = nullptr; + HiLog::Error(LABEL, "convert to real path failed."); + return; + } + + if (!ForceCreateDirectory(realPath)) { + file_ = nullptr; + HiLog::Error(LABEL, "create directory failed."); + return; + } + + std::string fullPath = realPath + "/" + fileName; + file_ = fopen(fullPath.c_str(), "wb"); + if (file_ == nullptr) { + HiLog::Error(LABEL, "fopen file failed, error:%{public}d", errno); + return; + } +} + +FilePackerStream::~FilePackerStream() +{ + if (file_ != nullptr) { + fclose(file_); + } +} + +bool FilePackerStream::Write(const uint8_t *buffer, uint32_t size) +{ + if ((buffer == nullptr) || (size == 0)) { + HiLog::Error(LABEL, "input parameter invalid."); + return false; + } + if (file_ == nullptr) { + HiLog::Error(LABEL, "output file is null."); + return false; + } + if (fwrite(buffer, sizeof(uint8_t), size, file_) != size) { + HiLog::Error(LABEL, "write %{public}u bytes failed.", size); + fclose(file_); + file_ = nullptr; + return false; + } + return true; +} + +void FilePackerStream::Flush() +{ + if (file_ != nullptr) { + fflush(file_); + } +} + +int64_t FilePackerStream::BytesWritten() +{ + return (file_ != nullptr) ? ftell(file_) : 0; +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/stream/src/file_source_stream.cpp b/frameworks/innerkitsimpl/stream/src/file_source_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ffe15f051395ae04273d9232f87ea7c21b0af0e0 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/file_source_stream.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "directory_ex.h" +#include "file_source_stream.h" +#include "image_log.h" +#include "image_utils.h" +#include "media_errors.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +using namespace ImagePlugin; + +FileSourceStream::FileSourceStream(std::FILE *file, size_t size, size_t offset, size_t original) + : filePtr_(file), fileSize_(size), fileOffset_(offset), fileOriginalOffset_(original) +{} + +FileSourceStream::~FileSourceStream() +{ + fclose(filePtr_); + ResetReadBuffer(); +} + +unique_ptr FileSourceStream::CreateSourceStream(const string &pathName) +{ + string realPath; + if (!PathToRealPath(pathName, realPath)) { + IMAGE_LOGE("[FileSourceStream]input the file path exception."); + return nullptr; + } + size_t size = 0; + if (!ImageUtils::GetFileSize(realPath, size)) { + IMAGE_LOGE("[FileSourceStream]get the file size fail."); + return nullptr; + } + FILE *filePtr = fopen(realPath.c_str(), "rb"); + if (filePtr == nullptr) { + IMAGE_LOGE("[FileSourceStream]open file fail, error:%{public}s.", strerror(errno)); + return nullptr; + } + long offset = ftell(filePtr); + if (offset < 0) { + IMAGE_LOGE("[FileSourceStream]get the position fail."); + fclose(filePtr); + return nullptr; + } + return (unique_ptr(new FileSourceStream(filePtr, size, offset, offset))); +} + +bool FileSourceStream::Read(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (desiredSize == 0 || filePtr_ == nullptr) { + IMAGE_LOGE("[FileSourceStream]read stream input parameter exception."); + return false; + } + if (!GetData(desiredSize, outData)) { + IMAGE_LOGE("[FileSourceStream]read fail."); + return false; + } + fileOffset_ += outData.dataSize; + return true; +} + +bool FileSourceStream::Peek(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (desiredSize == 0 || filePtr_ == nullptr) { + IMAGE_LOGE("[FileSourceStream]peek stream input parameter exception."); + return false; + } + if (!GetData(desiredSize, outData)) { + IMAGE_LOGE("[FileSourceStream]peek fail."); + return false; + } + int ret = fseek(filePtr_, fileOffset_, SEEK_SET); + if (ret != 0) { + IMAGE_LOGE("[FileSourceStream]go to original position fail, ret:%{public}d.", ret); + return false; + } + return true; +} + +bool FileSourceStream::Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize || desiredSize > fileSize_) { + IMAGE_LOGE("[FileSourceStream]input parameter exception, desiredSize:%{public}u, bufferSize:%{public}u,\ + fileSize_:%{public}zu.", + desiredSize, bufferSize, fileSize_); + return false; + } + if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) { + IMAGE_LOGE("[FileSourceStream]read fail."); + return false; + } + fileOffset_ += readSize; + return true; +} + +bool FileSourceStream::Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize || desiredSize > fileSize_) { + IMAGE_LOGE("[FileSourceStream]input parameter exception, desiredSize:%{public}u, bufferSize:%{public}u,\ + fileSize_:%{public}zu.", + desiredSize, bufferSize, fileSize_); + return false; + } + if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) { + IMAGE_LOGE("[FileSourceStream]peek fail."); + return false; + } + int ret = fseek(filePtr_, fileOffset_, SEEK_SET); + if (ret != 0) { + IMAGE_LOGE("[FileSourceStream]go to original position fail, ret:%{public}d.", ret); + return false; + } + return true; +} + +bool FileSourceStream::Seek(uint32_t position) +{ + if (position > fileSize_) { + IMAGE_LOGE("[FileSourceStream]Seek the position greater than the file size, position:%{public}u.", position); + return false; + } + size_t targetPosition = position + fileOriginalOffset_; + fileOffset_ = ((targetPosition < fileSize_) ? targetPosition : fileSize_); + int ret = fseek(filePtr_, fileOffset_, SEEK_SET); + if (ret != 0) { + IMAGE_LOGE("[FileSourceStream]go to offset position fail, ret:%{public}d.", ret); + return false; + } + return true; +} + +uint32_t FileSourceStream::Tell() +{ + return fileOffset_; +} + +bool FileSourceStream::GetData(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (fileSize_ == fileOffset_) { + IMAGE_LOGE("[FileSourceStream]read finish, offset:%{public}zu ,dataSize%{public}zu.", fileOffset_, fileSize_); + return false; + } + if (desiredSize > (fileSize_ - fileOffset_)) { + desiredSize = fileSize_ - fileOffset_; + } + size_t bytesRead = fread(outBuffer, sizeof(outBuffer[0]), desiredSize, filePtr_); + if (bytesRead < desiredSize) { + IMAGE_LOGE("[FileSourceStream]read fail, bytesRead:%{public}zu", bytesRead); + return false; + } + readSize = desiredSize; + return true; +} + +bool FileSourceStream::GetData(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (fileSize_ == fileOffset_) { + IMAGE_LOGE("[FileSourceStream]read finish, offset:%{public}zu ,dataSize%{public}zu.", fileOffset_, fileSize_); + return false; + } + + ResetReadBuffer(); + readBuffer_ = static_cast(malloc(desiredSize)); + if (readBuffer_ == nullptr) { + IMAGE_LOGE("[FileSourceStream]malloc the desiredSize fail."); + return false; + } + outData.bufferSize = desiredSize; + if (desiredSize > (fileSize_ - fileOffset_)) { + desiredSize = fileSize_ - fileOffset_; + } + size_t bytesRead = fread(readBuffer_, sizeof(uint8_t), desiredSize, filePtr_); + if (bytesRead < desiredSize) { + IMAGE_LOGE("[FileSourceStream]read fail, bytesRead:%{public}zu", bytesRead); + return false; + } + outData.inputStreamBuffer = static_cast(readBuffer_); + outData.dataSize = desiredSize; + return true; +} + +size_t FileSourceStream::GetStreamSize() +{ + return fileSize_; +} + +uint8_t *FileSourceStream::GetDataPtr() +{ + return nullptr; +} + +uint32_t FileSourceStream::GetStreamType() +{ + return ImagePlugin::FILE_STREAM_TYPE; +} + +void FileSourceStream::ResetReadBuffer() +{ + if (readBuffer_ != nullptr) { + free(readBuffer_); + readBuffer_ = nullptr; + } +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/src/incremental_source_stream.cpp b/frameworks/innerkitsimpl/stream/src/incremental_source_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2f9f12f80d72b4a77f43474b8253de52eb9818d --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/incremental_source_stream.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "incremental_source_stream.h" + +#include +#include +#include "image_log.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +using namespace ImagePlugin; + +IncrementalSourceStream::IncrementalSourceStream(IncrementalMode mode) + : incrementalMode_(mode), isFinalize_(false), dataSize_(0), dataOffset_(0) +{} + +unique_ptr IncrementalSourceStream::CreateSourceStream(IncrementalMode mode) +{ + IMAGE_LOGD("[IncrementalSourceStream]mode:%{public}d.", mode); + return (unique_ptr(new IncrementalSourceStream(mode))); +} + +bool IncrementalSourceStream::Read(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (!Peek(desiredSize, outData)) { + IMAGE_LOGE("[IncrementalSourceStream]read fail."); + return false; + } + dataOffset_ += outData.dataSize; + return true; +} + +bool IncrementalSourceStream::Peek(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (desiredSize == 0) { + IMAGE_LOGE("[IncrementalSourceStream]input the parameter exception."); + return false; + } + if (sourceData_.empty() || dataSize_ == 0 || dataOffset_ >= dataSize_) { + IMAGE_LOGE("[IncrementalSourceStream]source data exception. dataSize_:%{public}zu, dataOffset_:%{public}zu.", + dataSize_, dataOffset_); + return false; + } + outData.bufferSize = dataSize_ - dataOffset_; + if (desiredSize > dataSize_ - dataOffset_) { + desiredSize = dataSize_ - dataOffset_; + } + outData.dataSize = desiredSize; + outData.inputStreamBuffer = sourceData_.data() + dataOffset_; + IMAGE_LOGD("[IncrementalSourceStream]Peek end. desiredSize:%{public}u, offset:%{public}zu, dataSize_:%{public}zu,\ + dataOffset_:%{public}zu.", + desiredSize, dataOffset_, dataSize_, dataOffset_); + return true; +} + +bool IncrementalSourceStream::Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (!Peek(desiredSize, outBuffer, bufferSize, readSize)) { + IMAGE_LOGE("[IncrementalSourceStream]read fail."); + return false; + } + dataOffset_ += readSize; + return true; +} + +bool IncrementalSourceStream::Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize) { + IMAGE_LOGE("[IncrementalSourceStream]input parameter exception, desiredSize:%{public}u, bufferSize:%{public}u.", + desiredSize, bufferSize); + return false; + } + if (sourceData_.empty() || dataSize_ == 0 || dataOffset_ >= dataSize_) { + IMAGE_LOGE("[IncrementalSourceStream]source data exception. dataSize_:%{public}zu, dataOffset_:%{public}zu.", + dataSize_, dataOffset_); + return false; + } + if (desiredSize > (dataSize_ - dataOffset_)) { + desiredSize = dataSize_ - dataOffset_; + } + errno_t ret = memcpy_s(outBuffer, bufferSize, sourceData_.data() + dataOffset_, desiredSize); + if (ret != 0) { + IMAGE_LOGE("[IncrementalSourceStream]copy data fail, ret:%{public}d, bufferSize:%{public}u, offset:%{public}zu,\ + desiredSize:%{public}u, dataSize:%{public}zu.", + ret, bufferSize, dataOffset_, desiredSize, dataSize_); + return false; + } + readSize = desiredSize; + return true; +} + +uint32_t IncrementalSourceStream::Tell() +{ + return dataOffset_; +} + +bool IncrementalSourceStream::Seek(uint32_t position) +{ + if (position >= dataSize_) { + IMAGE_LOGE("[IncrementalSourceStream]Seek the position greater than the Data Size."); + return false; + } + dataOffset_ = position; + return true; +} + +uint32_t IncrementalSourceStream::UpdateData(const uint8_t *data, uint32_t size, bool isCompleted) +{ + if (data == nullptr) { + IMAGE_LOGE("[IncrementalSourceStream]input the parameter exception."); + return ERR_IMAGE_DATA_ABNORMAL; + } + if (size == 0) { + IMAGE_LOGD("[IncrementalSourceStream]no need to update data."); + return SUCCESS; + } + if (incrementalMode_ == IncrementalMode::INCREMENTAL_DATA) { + vector newData; + newData.resize(size); + copy(data, data + size, newData.begin()); + sourceData_.resize(dataSize_ + size); + sourceData_.insert(sourceData_.begin() + dataSize_, newData.begin(), newData.end()); + dataSize_ += size; + isFinalize_ = isCompleted; + } else { + sourceData_.clear(); + sourceData_.resize(size); + dataSize_ = size; + copy(data, data + size, sourceData_.begin()); + isFinalize_ = true; + } + return SUCCESS; +} + +bool IncrementalSourceStream::IsStreamCompleted() +{ + return isFinalize_; +} + +size_t IncrementalSourceStream::GetStreamSize() +{ + return dataSize_; +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/stream/src/istream_source_stream.cpp b/frameworks/innerkitsimpl/stream/src/istream_source_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07eb5e11ee95d9e85f7cf26db88e00befb8c4fc5 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/istream_source_stream.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "istream_source_stream.h" +#include "image_log.h" +#include "image_utils.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +using namespace ImagePlugin; + +IstreamSourceStream::IstreamSourceStream(unique_ptr inputStream, size_t size, size_t original, size_t offset) + : inputStream_(move(inputStream)), streamSize_(size), streamOriginalOffset_(original), streamOffset_(offset) +{} + +IstreamSourceStream::~IstreamSourceStream() +{ + ResetReadBuffer(); +} + +std::unique_ptr IstreamSourceStream::CreateSourceStream(unique_ptr inputStream) +{ + if ((inputStream == nullptr) || (inputStream->rdbuf() == nullptr)) { + IMAGE_LOGE("[IstreamSourceStream]input parameter exception."); + return nullptr; + } + size_t streamSize = 0; + if (!ImageUtils::GetInputStreamSize(*(inputStream.get()), streamSize)) { + IMAGE_LOGE("[IstreamSourceStream]Get the input stream exception."); + return nullptr; + } + if (streamSize == 0) { + IMAGE_LOGE("[IstreamSourceStream]input stream size exception."); + return nullptr; + } + size_t original = inputStream->tellg(); + size_t offset = original; + return (unique_ptr(new IstreamSourceStream(move(inputStream), streamSize, original, offset))); +} + +bool IstreamSourceStream::Read(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (desiredSize == 0) { + IMAGE_LOGE("[IstreamSourceStream]read stream input parameter exception."); + return false; + } + if (!GetData(desiredSize, outData)) { + IMAGE_LOGE("[IstreamSourceStream]read fail."); + return false; + } + streamOffset_ += outData.dataSize; + return true; +} + +bool IstreamSourceStream::Peek(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (desiredSize == 0) { + IMAGE_LOGE("[IstreamSourceStream]peek stream input parameter exception."); + return false; + } + if (!GetData(desiredSize, outData)) { + IMAGE_LOGE("[IstreamSourceStream]peek fail."); + return false; + } + inputStream_->seekg(streamOffset_); + return true; +} + +bool IstreamSourceStream::Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize) { + IMAGE_LOGE("[IstreamSourceStream]input the parameter exception, desiredSize:%{public}d, bufferSize:%{public}d.", + desiredSize, bufferSize); + return false; + } + if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) { + IMAGE_LOGE("[IstreamSourceStream]read fail."); + return false; + } + streamOffset_ += readSize; + return true; +} + +bool IstreamSourceStream::Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize) { + IMAGE_LOGE("[IstreamSourceStream]input the parameter exception, desiredSize:%{public}d, bufferSize:%{public}d.", + desiredSize, bufferSize); + return false; + } + if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) { + IMAGE_LOGE("[IstreamSourceStream]peek fail."); + return false; + } + inputStream_->seekg(streamOffset_); + return true; +} + +bool IstreamSourceStream::Seek(uint32_t position) +{ + if (position > streamSize_) { + IMAGE_LOGE("[IstreamSourceStream]Seek the position error, position:%{public}u, streamSize_:%{public}zu.", + position, streamSize_); + return false; + } + size_t targetPosition = position + streamOriginalOffset_; + streamOffset_ = ((targetPosition < streamSize_) ? targetPosition : streamSize_); + inputStream_->seekg(streamOffset_); + return true; +} + +uint32_t IstreamSourceStream::Tell() +{ + return streamOffset_; +} + +bool IstreamSourceStream::GetData(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) +{ + if (streamSize_ == 0 || streamOffset_ >= streamSize_) { + IMAGE_LOGE("[IstreamSourceStream]get source data fail. streamSize:%{public}zu, streamOffset:%{public}zu.", + streamSize_, streamOffset_); + return false; + } + if (desiredSize > (streamSize_ - streamOffset_)) { + desiredSize = (streamSize_ - streamOffset_); + } + if (!inputStream_->read(reinterpret_cast(outBuffer), desiredSize)) { + IMAGE_LOGE("[IstreamSourceStream]read the inputstream fail."); + return false; + } + readSize = desiredSize; + return true; +} + +bool IstreamSourceStream::GetData(uint32_t desiredSize, DataStreamBuffer &outData) +{ + if (streamSize_ == 0 || streamOffset_ >= streamSize_) { + IMAGE_LOGE("[IstreamSourceStream]get source data fail. streamSize:%{public}zu, streamOffset:%{public}zu.", + streamSize_, streamOffset_); + return false; + } + ResetReadBuffer(); + databuffer_ = static_cast(malloc(desiredSize)); + if (databuffer_ == nullptr) { + IMAGE_LOGE("[IstreamSourceStream]malloc the output data buffer fail."); + return false; + } + outData.bufferSize = desiredSize; + if (desiredSize > (streamSize_ - streamOffset_)) { + desiredSize = (streamSize_ - streamOffset_); + } + inputStream_->seekg(streamOffset_); + if (!inputStream_->read(reinterpret_cast(databuffer_), desiredSize)) { + IMAGE_LOGE("[IstreamSourceStream]read the inputstream fail."); + return false; + } + outData.inputStreamBuffer = databuffer_; + outData.dataSize = desiredSize; + return true; +} + +size_t IstreamSourceStream::GetStreamSize() +{ + return streamSize_; +} + +uint8_t *IstreamSourceStream::GetDataPtr() +{ + return nullptr; +} + +uint32_t IstreamSourceStream::GetStreamType() +{ + return ImagePlugin::INPUT_STREAM_TYPE; +} + +void IstreamSourceStream::ResetReadBuffer() +{ + if (databuffer_ != nullptr) { + free(databuffer_); + databuffer_ = nullptr; + } +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp b/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..250b1d7390bf15c55bc94d3a80d05fed83d57b66 --- /dev/null +++ b/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ostream_packer_stream.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +OstreamPackerStream::OstreamPackerStream(std::ostream &outputStream) : outputStream_(&outputStream) {} + +bool OstreamPackerStream::Write(const uint8_t *buffer, uint32_t size) +{ + if ((buffer == nullptr) || (size == 0)) { + HiLog::Error(LABEL, "input parameter invalid."); + return false; + } + outputStream_->write(reinterpret_cast(buffer), size); + return true; +} + +void OstreamPackerStream::Flush() +{ + if (outputStream_ != nullptr) { + outputStream_->flush(); + } +} + +int64_t OstreamPackerStream::BytesWritten() +{ + return (outputStream_ != nullptr) ? static_cast(outputStream_->tellp()) : 0; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/.BUILD.gn.swp b/frameworks/innerkitsimpl/test/.BUILD.gn.swp new file mode 100644 index 0000000000000000000000000000000000000000..8d1fe6be7b7b174e1b482766490bf6013f20eadd Binary files /dev/null and b/frameworks/innerkitsimpl/test/.BUILD.gn.swp differ diff --git a/frameworks/innerkitsimpl/test/BUILD.gn b/frameworks/innerkitsimpl/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..35306a30446cabf7c1a288c675311dbe90cfe2a1 --- /dev/null +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -0,0 +1,170 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "multimedia_image/image_standard" + +ohos_unittest("imagepixelmaptest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/googletest/googletest/include", + "//utils/native/base/include", + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_pixel_map_test.cpp" ] + + deps = [ +# "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native:bitmapconverter", + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + ] + # external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_unittest("imagepixelmapparceltest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/googletest/googletest/include", + "//utils/native/base/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + ] + sources = [ "./unittest/image_pixel_map_parcel_test.cpp" ] + + deps = [ + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//foundation/multimedia/image_standard:image_framework", + ] + # external_deps = [ + # "bytrace_standard:bytrace_core", + # "hiviewdfx_hilog_native:libhilog", + # "ipc:ipc_core", + # "multimedia_image:libimage", + # ] +} + +ohos_unittest("imagesourcetest") { + DUAL_ADAPTER = true + module_out_path = module_output_path + + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/googletest/googletest/include", + "//utils/native/base/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + ] + sources = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_gif_test.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_jpeg_test.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_png_test.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_util.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_webp_test.cpp", + ] + if (DUAL_ADAPTER) { + sources += [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_bmp_test.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_raw_test.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_source_wbmp_test.cpp", + ] + } + + deps = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + ] + # external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + resource_config_file = + "//foundation/multimedia/image_standard/test/resource/image/ohos_test.xml" +} + +ohos_unittest("colorconvertertest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/googletest/googletest/include", + "//utils/native/base/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + ] + sources = [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/color_converter_test.cpp" ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + ] +# external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_unittest("transformtest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/googletest/googletest/include", + "//utils/native/base/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/test/unittest/image_transform_test.cpp" ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + ] +# external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +################################################ +group("unittest") { + testonly = true + deps = [ + ":colorconvertertest", + ":imagepixelmapparceltest", + ":imagepixelmaptest", + ":imagesourcetest", + ":transformtest", + ] +} +################################################ diff --git a/frameworks/innerkitsimpl/test/unittest/color_converter_test.cpp b/frameworks/innerkitsimpl/test/unittest/color_converter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02bff052ad1c0faeed0048f7b3b4c47699ddc7b8 --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/color_converter_test.cpp @@ -0,0 +1,743 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "media_errors.h" +#include "pixel_convert.h" +#include "securec.h" + +using namespace testing::ext; +using namespace OHOS::Media; +namespace OHOS { +namespace Multimedia { +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr bool IS_LITTLE_ENDIAN = true; +#else +constexpr bool IS_LITTLE_ENDIAN = false; +#endif +class ColorConverterTest : public testing::Test { +public: + ColorConverterTest(){}; + ~ColorConverterTest(){}; +}; + +/** + * @tc.name: ColorConverterTest001 + * @tc.desc: Create color space pointer, return nullptr. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest001, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. build success. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + EXPECT_NE(colorConverterPointer, nullptr); +} + +/** + * @tc.name: ColorConverterTest002 + * @tc.desc: RGB_565 to ARGB_8888. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest002, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + srcImageInfo.pixelFormat = PixelFormat::RGB_565; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + dstImageInfo.pixelFormat = PixelFormat::ARGB_8888; + // 1010 0000 0110 0100 + uint8_t source[2] = { 0xA0, 0x64 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x040314FF; + } else { + result[0] = 0xFF140304; + } + /** + * @tc.steps: step2. convert pixel. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 1); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest003 + * @tc.desc: RGB_565 to RGBA_8888. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest003, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + srcImageInfo.pixelFormat = PixelFormat::RGB_565; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + dstImageInfo.pixelFormat = PixelFormat::RGBA_8888; + uint8_t source[2] = { 0xA0, 0x64 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0xFF040314; + } else { + result[0] = 0x140304FF; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 1); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest004 + * @tc.desc: RGB_565 to BGRA_8888. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest004, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + srcImageInfo.pixelFormat = PixelFormat::RGB_565; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[2] = { 0xA0, 0x64 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0xFF140304; + } else { + result[0] = 0x040314FF; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 1); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest005 + * @tc.desc: ARGB_8888 to BGRA_8888 UNPREMUL to PREMUL. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest005, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x80010204; + result[1] = 0x40010102; + } else { + result[0] = 0x04020180; + result[1] = 0x02010140; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest006 + * @tc.desc: ARGB_8888 to BGRA_8888 UNPREMUL to UNPREMUL. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest006, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x80020408; + result[1] = 0x40020408; + } else { + result[0] = 0x08040280; + result[1] = 0x08040240; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest007 + * @tc.desc: ARGB_8888 to BGRA_8888 UNPREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest007, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0xFF020408; + result[1] = 0xFF020408; + } else { + result[0] = 0x080402FF; + result[1] = 0x080402FF; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest008 + * @tc.desc: ARGB_8888 to BGRA_8888 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest008, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0xFF040810; + result[1] = 0xFF081020; + } else { + result[0] = 0x100804FF; + result[1] = 0x201008FF; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest009 + * @tc.desc: ARGB_8888 to BGRA_8888 PREMUL to UNPREMUL. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest009, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x80040810; + result[1] = 0x40081020; + } else { + result[0] = 0x10080480; + result[1] = 0x20100840; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest010 + * @tc.desc: ARGB_8888 to BGRA_8888 PREMUL to PREMUL. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest010, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + dstImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x80020408; + result[1] = 0x40020408; + } else { + result[0] = 0x08040280; + result[1] = 0x08040240; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest011 + * @tc.desc: ARGB_8888 to RGB565 UNPREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest011, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint16_t destination[3] = { 0 }; + uint16_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x0820; + result[1] = 0x0820; + } else { + result[0] = 0x2008; + result[1] = 0x2008; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint16_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest012 + * @tc.desc: ARGB_8888 to RGB565 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest012, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint16_t destination[3] = { 0 }; + uint16_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x1040; + result[1] = 0x2081; + } else { + result[0] = 0x4010; + result[1] = 0x8120; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint16_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest013 + * @tc.desc: ARGB_8888 to BGRA_8888 UNPREMUL to PREMUL. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest013, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + srcImageInfo.pixelFormat = PixelFormat::RGB_565; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + EXPECT_EQ(colorConverterPointer, nullptr); +} + +/** + * @tc.name: ColorConverterTest014 + * @tc.desc: ARGB_8888 to RGBA_8888 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest014, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::RGBA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0xFF100804; + result[1] = 0xFF201008; + } else { + result[0] = 0x040810FF; + result[1] = 0x081020FF; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest015 + * @tc.desc: ARGB_8888 to RGBA_8888 PREMUL to UNPREMUL. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest015, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + dstImageInfo.pixelFormat = PixelFormat::RGBA_8888; + + uint8_t source[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x80100804; + result[1] = 0x40201008; + } else { + result[0] = 0x04081080; + result[1] = 0x08102040; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest016 + * @tc.desc: RGBA_8888 to ARGB_8888 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest016, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::RGBA_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + uint8_t source[8] = { 0x02, 0x04, 0x08, 0x80, 0x02, 0x04, 0x08, 0x40 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x100804FF; + result[1] = 0x201008FF; + } else { + result[0] = 0xFF040810; + result[1] = 0xFF081020; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest017 + * @tc.desc: RGBA_8888 to RGB_565 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest017, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::RGBA_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + + uint8_t source[8] = { 0x02, 0x04, 0x08, 0x80, 0x02, 0x04, 0x08, 0x40 }; + uint16_t destination[3] = { 0 }; + uint16_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x1040; + result[1] = 0x2081; + } else { + result[0] = 0x4010; + result[1] = 0x8120; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint16_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest018 + * @tc.desc: BGRA_8888 to ARGB_8888 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest018, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::ARGB_8888; + + uint8_t source[8] = { 0x02, 0x04, 0x08, 0x80, 0x02, 0x04, 0x08, 0x40 }; + uint32_t destination[3] = { 0 }; + uint32_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x040810FF; + result[1] = 0x081020FF; + } else { + result[0] = 0xFF100804; + result[1] = 0xFF201008; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint32_t)); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: ColorConverterTest019 + * @tc.desc: BGRA_8888 to RGB_565 PREMUL to OPAQUE. + * @tc.type: FUNC + */ +HWTEST_F(ColorConverterTest, ColorConverterTest019, TestSize.Level3) +{ + /** + * @tc.steps: step1. set parameters to build object. + * @tc.expected: step1. set parameters success. + */ + ImageInfo srcImageInfo; + srcImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + srcImageInfo.pixelFormat = PixelFormat::BGRA_8888; + + ImageInfo dstImageInfo; + dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + dstImageInfo.pixelFormat = PixelFormat::RGB_565; + + uint8_t source[8] = { 0x02, 0x04, 0x08, 0x80, 0x02, 0x04, 0x08, 0x40 }; + uint16_t destination[3] = { 0 }; + uint16_t result[3] = { 0 }; + if (IS_LITTLE_ENDIAN) { + result[0] = 0x0042; + result[1] = 0x0884; + } else { + result[0] = 0x4200; + result[1] = 0x8408; + } + /** + * @tc.steps: step2. build pixel convert object. + * @tc.expected: step2. The return value is the same as the result. + */ + std::unique_ptr colorConverterPointer = PixelConvert::Create(srcImageInfo, dstImageInfo); + colorConverterPointer->Convert(destination, source, 2); + int ret = memcmp(destination, result, 3 * sizeof(uint16_t)); + EXPECT_EQ(ret, 0); +} +} // namespace Multimedia +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/test/unittest/image_pixel_map_parcel_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_pixel_map_parcel_test.cpp new file mode 100755 index 0000000000000000000000000000000000000000..9970857abebf66eea743a0019c542337b2758429 --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_pixel_map_parcel_test.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "pixel_map.h" +#include "pixel_map_parcel.h" + +using namespace testing::ext; +using namespace OHOS::Media; + +namespace OHOS { +namespace Multimedia { + class ImagePixelMapParcelTest : public testing::Test { + public: + ImagePixelMapParcelTest(){}; + ~ImagePixelMapParcelTest(){}; + }; + + std::unique_ptr ConstructPixmap() + { + int32_t pixelMapWidth = 4; + int32_t pixelMapHeight = 3; + std::unique_ptr pixelMap = std::make_unique(); + ImageInfo info; + info.size.width = pixelMapWidth; + info.size.height = pixelMapHeight; + info.pixelFormat = PixelFormat::RGB_888; + info.colorSpace = ColorSpace::SRGB; + pixelMap->SetImageInfo(info); + + int32_t rowDataSize = pixelMapWidth; + uint32_t bufferSize = rowDataSize * pixelMapHeight; + void *buffer = malloc(bufferSize); + char *ch = (char *)buffer; + for (unsigned int i = 0; i < bufferSize; i++) { + *(ch++) = (char)i; + } + + pixelMap->SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + + return pixelMap; + } + /** + * @tc.name: ImagePixelMapParcel001 + * @tc.desc: test WriteToParcel + * @tc.type: FUNC + * @tc.require: AR000FTAMO + */ + HWTEST_F(ImagePixelMapParcelTest, ImagePixelMapParcel001, TestSize.Level3) + { + GTEST_LOG_(INFO) << "ImagePixelMapParcelTest: ImagePixelMapParcel001 start"; + + MessageParcel data; + + std::unique_ptr pixelmap = ConstructPixmap(); + + bool ret = PixelMapParcel::WriteToParcel(pixelmap.get(), data); + + EXPECT_EQ(true, ret); + + GTEST_LOG_(INFO) << "ImagePixelMapParcelTest: ImagePixelMapParcel001 end"; + } + + /** + * @tc.name: ImagePixelMapParcel002 + * @tc.desc: test CreateFromParcel + * @tc.type: FUNC + * @tc.require: AR000FTAMO + */ + HWTEST_F(ImagePixelMapParcelTest, ImagePixelMapParcel002, TestSize.Level3) + { + GTEST_LOG_(INFO) << "ImagePixelMapParcelTest: ImagePixelMapParcel002 start"; + + MessageParcel data; + + std::unique_ptr pixelmap1 = ConstructPixmap(); + + bool ret = PixelMapParcel::WriteToParcel(pixelmap1.get(), data); + + EXPECT_EQ(true, ret); + + std::unique_ptr pixelmap2 = PixelMapParcel::CreateFromParcel(data); + + EXPECT_EQ(pixelmap1->GetHeight(), pixelmap2->GetHeight()); + EXPECT_EQ(pixelmap1->GetWidth(), pixelmap2->GetWidth()); + EXPECT_EQ(pixelmap1->GetPixelFormat(), pixelmap2->GetPixelFormat()); + EXPECT_EQ(pixelmap1->GetColorSpace(), pixelmap2->GetColorSpace()); + + EXPECT_EQ(true, pixelmap1->IsSameImage(*pixelmap2)); + + GTEST_LOG_(INFO) << "ImagePixelMapParcelTest: ImagePixelMapParcel002 end"; + } +} // namespace Multimedia +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_pixel_map_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_pixel_map_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22e2d4f7e25f078ef0f4233f11eaa21a58b31dbc --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_pixel_map_test.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; + +namespace OHOS { +namespace Multimedia { +static constexpr int32_t PIXEL_MAP_TEST_WIDTH = 3; +static constexpr int32_t PIXEL_MAP_TEST_HEIGHT = 3; +static constexpr int32_t PIXEL_MAP_RGB565_BYTE = 2; +static constexpr int32_t PIXEL_MAP_RGB888_BYTE = 3; +static constexpr int32_t PIXEL_MAP_ARGB8888_BYTE = 4; + +class ImagePixelMapTest : public testing::Test { +public: + ImagePixelMapTest(){}; + ~ImagePixelMapTest(){}; +}; + +/** + * @tc.name: ImagePixelMap001 + * @tc.desc: ALPHA_8 pixel format pixel map operation + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap001, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap001 start"; + /** + * @tc.steps: step1. Set image info and alloc pixel map memory. + * @tc.expected: step1. The pixel map info is correct. + */ + PixelMap pixelMap; + ImageInfo info; + info.size.width = PIXEL_MAP_TEST_WIDTH; + info.size.height = PIXEL_MAP_TEST_HEIGHT; + info.pixelFormat = PixelFormat::ALPHA_8; + info.colorSpace = ColorSpace::SRGB; + pixelMap.SetImageInfo(info); + int32_t rowDataSize = (PIXEL_MAP_TEST_WIDTH + 3) / 4 * 4; + uint32_t bufferSize = rowDataSize * PIXEL_MAP_TEST_HEIGHT; + void *buffer = malloc(bufferSize); + EXPECT_NE(buffer, nullptr); + pixelMap.SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_NE(data, nullptr); + EXPECT_EQ(pixelMap.GetHeight(), PIXEL_MAP_TEST_HEIGHT); + EXPECT_EQ(pixelMap.GetWidth(), PIXEL_MAP_TEST_WIDTH); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::ALPHA_8); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetPixelBytes(), 1); + EXPECT_EQ(pixelMap.GetRowBytes(), rowDataSize); + EXPECT_EQ(pixelMap.GetByteCount(), PIXEL_MAP_TEST_HEIGHT * rowDataSize); + /** + * @tc.steps: step2. Get image info. + * @tc.expected: step2. The pixel map info is correct + */ + ImageInfo outInfo; + pixelMap.GetImageInfo(outInfo); + EXPECT_EQ(outInfo.size.width, info.size.width); + EXPECT_EQ(outInfo.size.height, info.size.height); + EXPECT_EQ(outInfo.pixelFormat, info.pixelFormat); + EXPECT_EQ(outInfo.colorSpace, info.colorSpace); + /** + * @tc.steps: step3. Set image color data and get image color value. + * @tc.expected: step3. The image color value is correct + */ + for (int32_t i = 0; i < rowDataSize * PIXEL_MAP_TEST_HEIGHT; i++) { + data[i] = i; + } + uint32_t color = 0; + EXPECT_NE(pixelMap.GetPixel8(1, 1), nullptr); + EXPECT_EQ(*pixelMap.GetPixel8(1, 1), 0x05); + EXPECT_EQ(pixelMap.GetARGB32Color(1, 1, color), true); + EXPECT_EQ(pixelMap.GetARGB32ColorA(color), 5); + EXPECT_EQ(pixelMap.GetARGB32ColorR(color), 0); + EXPECT_EQ(pixelMap.GetARGB32ColorG(color), 0); + EXPECT_EQ(pixelMap.GetARGB32ColorB(color), 0); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap001 end"; +} + +/** + * @tc.name: ImagePixelMap002 + * @tc.desc: RGB_565 pixel format pixel map operation + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap002, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap002 start"; + /** + * @tc.steps: step1. Set image info and alloc pixel map memory. + * @tc.expected: step1. The pixel map info is correct. + */ + PixelMap pixelMap; + int8_t bytesPerPixel = 2; + int8_t rowDataSize = PIXEL_MAP_TEST_WIDTH * bytesPerPixel; + ImageInfo info; + info.size.width = PIXEL_MAP_TEST_WIDTH; + info.size.height = PIXEL_MAP_TEST_HEIGHT; + info.pixelFormat = PixelFormat::RGB_565; + info.colorSpace = ColorSpace::SRGB; + pixelMap.SetImageInfo(info); + uint32_t bufferSize = rowDataSize * PIXEL_MAP_TEST_HEIGHT; + void *buffer = malloc(bufferSize); + EXPECT_NE(buffer, nullptr); + pixelMap.SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_NE(data, nullptr); + EXPECT_EQ(pixelMap.GetHeight(), PIXEL_MAP_TEST_HEIGHT); + EXPECT_EQ(pixelMap.GetWidth(), PIXEL_MAP_TEST_WIDTH); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::RGB_565); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetPixelBytes(), bytesPerPixel); + EXPECT_EQ(pixelMap.GetRowBytes(), rowDataSize); + EXPECT_EQ(pixelMap.GetByteCount(), PIXEL_MAP_TEST_HEIGHT * rowDataSize); + /** + * @tc.steps: step2. Set image color data and get image color value. + * @tc.expected: step2. The image color value is correct + */ + for (int32_t i = 0; i < PIXEL_MAP_TEST_WIDTH * PIXEL_MAP_RGB565_BYTE * PIXEL_MAP_TEST_HEIGHT; i++) { + data[i] = i; + } + EXPECT_NE(pixelMap.GetPixel16(1, 1), nullptr); + EXPECT_EQ(*pixelMap.GetPixel16(1, 1), 0x0908); + uint32_t color = 0; + uint32_t expect = 0xFF422008; + EXPECT_EQ(pixelMap.GetARGB32Color(1, 1, color), true); + EXPECT_EQ(color, expect); + // RGB565: binary: 0000100100001000 + // split to : 00001 001000 01000 + // | | | + // B G R + // transfer to RGB888: + // 1 8 8 + // multi 256(8bit length) + // 256*1/2^5 256*8/2^6 256*8/2^5 + // another method: + // (x<<3 | x>>2) (x<<2 | x>>4) + EXPECT_EQ(pixelMap.GetARGB32ColorA(color), 255); + EXPECT_EQ(pixelMap.GetARGB32ColorR(color), 66); // (8<<3 | 8 >> 2) + EXPECT_EQ(pixelMap.GetARGB32ColorG(color), 32); // (8<<2 | 8 >> 4) + EXPECT_EQ(pixelMap.GetARGB32ColorB(color), 8); // (1<<3 | 1 >> 2) + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap002 end"; +} + +/** + * @tc.name: ImagePixelMap003 + * @tc.desc: ARGB_8888 pixel format pixel map operation + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap003, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap003 start"; + /** + * @tc.steps: step1. Set image info and alloc pixel map memory. + * @tc.expected: step1. The pixel map info is correct. + */ + int8_t bytesPerPixel = 4; + int8_t rowDataSize = PIXEL_MAP_TEST_WIDTH * bytesPerPixel; + ImageInfo info; + info.size.width = PIXEL_MAP_TEST_WIDTH; + info.size.height = PIXEL_MAP_TEST_HEIGHT; + info.pixelFormat = PixelFormat::ARGB_8888; + info.colorSpace = ColorSpace::SRGB; + PixelMap pixelMap; + pixelMap.SetImageInfo(info); + uint32_t bufferSize = rowDataSize * PIXEL_MAP_TEST_HEIGHT; + void *buffer = malloc(bufferSize); + EXPECT_NE(buffer, nullptr); + pixelMap.SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_NE(data, nullptr); + EXPECT_EQ(pixelMap.GetHeight(), PIXEL_MAP_TEST_HEIGHT); + EXPECT_EQ(pixelMap.GetWidth(), PIXEL_MAP_TEST_WIDTH); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::ARGB_8888); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetPixelBytes(), bytesPerPixel); + EXPECT_EQ(pixelMap.GetRowBytes(), rowDataSize); + EXPECT_EQ(pixelMap.GetByteCount(), PIXEL_MAP_TEST_HEIGHT * rowDataSize); + /** + * @tc.steps: step2. Set image color data and get image color value. + * @tc.expected: step2. The image color value is correct + */ + for (int32_t i = 0; i < PIXEL_MAP_TEST_WIDTH * PIXEL_MAP_ARGB8888_BYTE * PIXEL_MAP_TEST_HEIGHT; i++) { + data[i] = i; + } + EXPECT_NE(pixelMap.GetPixel(1, 1), nullptr); + EXPECT_EQ(*pixelMap.GetPixel32(1, 1), static_cast(0x13121110)); + uint32_t color = 0; + EXPECT_EQ(pixelMap.GetARGB32Color(1, 1, color), true); + EXPECT_EQ(pixelMap.GetARGB32ColorA(color), 0x10); + EXPECT_EQ(pixelMap.GetARGB32ColorR(color), 0x11); + EXPECT_EQ(pixelMap.GetARGB32ColorG(color), 0x12); + EXPECT_EQ(pixelMap.GetARGB32ColorB(color), 0x13); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap003 end"; +} + +/** + * @tc.name: ImagePixelMap004 + * @tc.desc: Get pixel position out of image range + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap004, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap004 start"; + /** + * @tc.steps: step1. Set image info and alloc pixel map memory. + * @tc.expected: step1. The pixel map info is correct. + */ + PixelMap pixelMap; + int8_t bytesPerPixel = 4; + int8_t rowDataSize = PIXEL_MAP_TEST_WIDTH * bytesPerPixel; + ImageInfo info; + info.size.width = PIXEL_MAP_TEST_WIDTH; + info.size.height = PIXEL_MAP_TEST_HEIGHT; + info.pixelFormat = PixelFormat::ARGB_8888; + info.colorSpace = ColorSpace::SRGB; + pixelMap.SetImageInfo(info); + uint32_t bufferSize = rowDataSize * PIXEL_MAP_TEST_HEIGHT; + void *buffer = malloc(bufferSize); + EXPECT_NE(buffer, nullptr); + pixelMap.SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_NE(data, nullptr); + EXPECT_EQ(pixelMap.GetHeight(), PIXEL_MAP_TEST_HEIGHT); + EXPECT_EQ(pixelMap.GetWidth(), PIXEL_MAP_TEST_WIDTH); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::ARGB_8888); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetByteCount(), PIXEL_MAP_TEST_HEIGHT * rowDataSize); + /** + * @tc.steps: step2. Set image color data and get image color value. + * @tc.expected: step2. Get image color value failed, because of position out of image range. + */ + for (int32_t i = 0; i < PIXEL_MAP_TEST_WIDTH * PIXEL_MAP_ARGB8888_BYTE * PIXEL_MAP_TEST_HEIGHT; i++) { + data[i] = i; + } + EXPECT_EQ(pixelMap.GetPixel32(4, 4), nullptr); + EXPECT_EQ(pixelMap.GetPixel(-1, -1), nullptr); + uint32_t color = 0; + EXPECT_EQ(pixelMap.GetARGB32Color(4, 4, color), false); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap004 end"; +} + +/** + * @tc.name: ImagePixelMap005 + * @tc.desc: Set error image size + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap005, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap005 start"; + /** + * @tc.steps: step1. Set image error info include image height and width. + * @tc.expected: step1. The pixel map info is default value. + */ + PixelMap pixelMap; + ImageInfo info; + info.size.width = -10; + info.size.height = 10; + EXPECT_EQ(pixelMap.SetImageInfo(info), ERR_IMAGE_DATA_ABNORMAL); + EXPECT_EQ(pixelMap.GetHeight(), 0); + EXPECT_EQ(pixelMap.GetWidth(), 0); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::UNKNOWN); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetByteCount(), 0); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_EQ(data, nullptr); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap005 end"; +} + +/** + * @tc.name: ImagePixelMap006 + * @tc.desc: Set unknown pixel format and color space + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap006, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap006 start"; + /** + * @tc.steps: step1. Set image unknown pixel format and color space info. + * @tc.expected: step1. The pixel map info is default value. + */ + PixelMap pixelMap; + ImageInfo info; + info.size.width = 10; + info.size.height = 10; + EXPECT_EQ(pixelMap.SetImageInfo(info), ERR_IMAGE_DATA_UNSUPPORT); + EXPECT_EQ(pixelMap.GetHeight(), 0); + EXPECT_EQ(pixelMap.GetWidth(), 0); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::UNKNOWN); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetByteCount(), 0); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_EQ(data, nullptr); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap006 end"; +} + +/** + * @tc.name: ImagePixelMap007 + * @tc.desc: Set pixel map size out of max value + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap007, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap007 start"; + /** + * @tc.steps: step1. Set image size out of max value (500MB). + * @tc.expected: step1. The pixel map info is default value. + */ + PixelMap pixelMap; + ImageInfo info; + info.size.width = 500 * 1024; + info.size.height = 500 * 1024; + info.pixelFormat = PixelFormat::ARGB_8888; + info.colorSpace = ColorSpace::SRGB; + EXPECT_EQ(pixelMap.SetImageInfo(info), ERR_IMAGE_TOO_LARGE); + EXPECT_EQ(pixelMap.GetHeight(), 0); + EXPECT_EQ(pixelMap.GetWidth(), 0); + EXPECT_EQ(pixelMap.GetByteCount(), 0); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_EQ(data, nullptr); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap007 end"; +} + +/** + * @tc.name: ImagePixelMap008 + * @tc.desc: RGB_888 pixel format pixel map operation + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap008, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap008 start"; + /** + * @tc.steps: step1. Set image info and alloc pixel map memory. + * @tc.expected: step1. The pixel map info is correct. + */ + int8_t bytesPerPixel = 3; + int8_t rowDataSize = PIXEL_MAP_TEST_WIDTH * bytesPerPixel; + ImageInfo info; + info.size.width = PIXEL_MAP_TEST_WIDTH; + info.size.height = PIXEL_MAP_TEST_HEIGHT; + info.pixelFormat = PixelFormat::RGB_888; + info.colorSpace = ColorSpace::SRGB; + PixelMap pixelMap; + pixelMap.SetImageInfo(info); + uint32_t bufferSize = rowDataSize * PIXEL_MAP_TEST_HEIGHT; + void *buffer = malloc(bufferSize); + EXPECT_NE(buffer, nullptr); + pixelMap.SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); + uint8_t *data = const_cast(pixelMap.GetPixels()); + EXPECT_NE(data, nullptr); + EXPECT_EQ(pixelMap.GetHeight(), PIXEL_MAP_TEST_HEIGHT); + EXPECT_EQ(pixelMap.GetWidth(), PIXEL_MAP_TEST_WIDTH); + EXPECT_EQ(pixelMap.GetPixelFormat(), PixelFormat::RGB_888); + EXPECT_EQ(pixelMap.GetColorSpace(), ColorSpace::SRGB); + EXPECT_EQ(pixelMap.GetPixelBytes(), bytesPerPixel); + EXPECT_EQ(pixelMap.GetRowBytes(), rowDataSize); + EXPECT_EQ(pixelMap.GetByteCount(), PIXEL_MAP_TEST_HEIGHT * rowDataSize); + /** + * @tc.steps: step2. Set image color data and get image color value. + * @tc.expected: step2. The image color value is correct + */ + for (int32_t i = 0; i < PIXEL_MAP_TEST_WIDTH * PIXEL_MAP_RGB888_BYTE * PIXEL_MAP_TEST_HEIGHT; i++) { + data[i] = i; + } + EXPECT_NE(pixelMap.GetPixel(1, 1), nullptr); + uint32_t color = 0; + EXPECT_EQ(pixelMap.GetARGB32Color(1, 1, color), true); + EXPECT_EQ(pixelMap.GetARGB32ColorA(color), 255); + EXPECT_EQ(pixelMap.GetARGB32ColorR(color), 12); + EXPECT_EQ(pixelMap.GetARGB32ColorG(color), 13); + EXPECT_EQ(pixelMap.GetARGB32ColorB(color), 14); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap008 end"; +} + +/** + * @tc.name: ImagePixelMap009 + * @tc.desc: create pixelmap with wrong source and correct initialization options + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap009, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap009 start"; + /** + * @tc.steps: step1. set source pixelmap wrong and correct initialization options + * @tc.expected: step1. The new pixelmap is null. + */ + PixelMap srcPixelMap; + ImageInfo imageInfo; + srcPixelMap.SetImageInfo(imageInfo); + InitializationOptions opts; + opts.size.width = 200; + opts.size.height = 300; + opts.pixelFormat = PixelFormat::ARGB_8888; + opts.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + std::unique_ptr newPixelMap = PixelMap::Create(srcPixelMap, opts); + EXPECT_EQ(newPixelMap, nullptr); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap009 end"; +} +} // namespace Multimedia +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_bmp_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_bmp_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bfb0724fdc64ecf1f6cb039f09c94d4ae1184fb --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_bmp_test.cpp @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_type.h" +#include "image_utils.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static const std::string IMAGE_INPUT_BMP_PATH = "/sdcard/multimedia/image/test.bmp"; +static const std::string IMAGE_OUTPUT_BMP_FILE_PATH = "/data/test/test_bmp_file.jpg"; + +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap); +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize); + +class ImageSourceBmpTest : public testing::Test { +public: + ImageSourceBmpTest(){}; + ~ImageSourceBmpTest(){}; +}; + +/** + * @tc.name: BmpImageDecode001 + * @tc.desc: Decode bmp image from file source stream(default:RGBA_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/bmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options(RGBA_8888). + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: BmpImageDecode002 + * @tc.desc: Decode bmp image from file source stream(BGRA_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/bmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format BGRA_8888. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: BmpImageDecode003 + * @tc.desc: Decode bmp image from file source stream(RGB_565) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/bmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format RGB_565. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::RGB_565; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +/** + * @tc.name: BmpImageDecode004 + * @tc.desc: Decode bmp image from file source stream(ARGB_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/bmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format BGRA_8888. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: BmpImageDecode005 + * @tc.desc: Create image source by correct bmp file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and default format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get image info from input image. + * @tc.expected: step2. get image info success. + */ + ImageInfo imageInfo; + uint32_t ret = imageSource->GetImageInfo(0, imageInfo); + ASSERT_EQ(ret, SUCCESS); + ret = imageSource->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 472); + ASSERT_EQ(imageInfo.size.height, 75); +} + +/** + * @tc.name: BmpImageDecode006 + * @tc.desc: Create image source by correct bmp file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: BmpImageDecode007 + * @tc.desc: Create image source by wrong bmp file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by wrong bmp file path and default format hit. + * @tc.expected: step1. create image source error. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource("/data/jpeg/test.bmp", opts, errorCode); + ASSERT_EQ(errorCode, ERR_IMAGE_SOURCE_DATA); + ASSERT_EQ(imageSource.get(), nullptr); +} + +/** + * @tc.name: BmpImageDecode008 + * @tc.desc: Decode bmp image from buffer source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode008, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_BMP_PATH, bufferSize); + ASSERT_EQ(ret, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_BMP_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + + ImageInfo imageInfo; + pixelMap->GetImageInfo(imageInfo); + decodeOpts.CropRect = { imageInfo.size.width - 1, imageInfo.size.height - 1, 1, 1 }; + std::unique_ptr cropPixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(pixelMap.get(), nullptr); + cropPixelMap->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 1); + ASSERT_EQ(imageInfo.size.height, 1); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + ImagePacker imagePacker; + int64_t packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: BmpImageDecode009 + * @tc.desc: Decode bmp image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode009, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open(IMAGE_INPUT_BMP_PATH, std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: BmpImageDecode010 + * @tc.desc: Decode bmp image multiple times from one imageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode010, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by bmp file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_BMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap2 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_BMP_FILE_PATH, std::move(pixelMap2)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: BmpImageDecode011 + * @tc.desc: Decode wrong bmp image from one imageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceBmpTest, BmpImageDecode011, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit, modify data buffer to wrong + * bmp format. + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_BMP_PATH, bufferSize); + ASSERT_EQ(ret, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_BMP_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + buffer[0] = 43; // change one bit in buffer to wrong value. + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map failed, because bmp format error. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(errorCode, SUCCESS); + ASSERT_EQ(pixelMap.get(), nullptr); +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_gif_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_gif_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b3c0d45a34be6f621461518370ddc8f7dd888a2 --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_gif_test.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_type.h" +#include "image_utils.h" +#include "incremental_pixel_map.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL_TEST = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageSourceGifTest" +}; +static constexpr uint32_t DEFAULT_DELAY_UTIME = 10000; // 10 ms. + +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap); +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize); + +class ImageSourceGifTest : public testing::Test { +public: + ImageSourceGifTest(){}; + ~ImageSourceGifTest(){}; +}; + +/** + * @tc.name: GifImageDecode001 + * @tc.desc: Decode gif image from file source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/gif"; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/test.gif", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get the number of image. + * @tc.expected: step2. check the number of image equals the actual number. + */ + int32_t imageCount = imageSource->GetSourceInfo(errorCode).topLevelImageNum; + HiLog::Debug(LABEL_TEST, "image frame number:%{public}d", imageCount); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_EQ(1, imageCount); + /** + * @tc.steps: step3. decode image source to bitmap by default decode options + * @tc.expected: step3. decode image source to bitmap success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create bitmap code=%{public}d.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step4. get the image size. + * @tc.expected: step4. check the image size equals the actual size. + */ + EXPECT_EQ(198, pixelMap->GetWidth()); + EXPECT_EQ(202, pixelMap->GetHeight()); + /** + * @tc.steps: step5. get the the RGBA of the point. + * @tc.expected: step5. check the RGBA equals the actual RGBA. + */ + uint32_t color = 0; + uint32_t posX = 15; + uint32_t posY = 15; + pixelMap->GetARGB32Color(posX, posY, color); + uint8_t red = pixelMap->GetARGB32ColorR(color); + uint8_t green = pixelMap->GetARGB32ColorG(color); + uint8_t blue = pixelMap->GetARGB32ColorB(color); + uint8_t alpha = pixelMap->GetARGB32ColorA(color); + HiLog::Debug(LABEL_TEST, "point:[%u, %u] RGBA:[%u, %u, %u, %u]", posX, posY, red, green, blue, alpha); + + EXPECT_EQ(244, red); + EXPECT_EQ(63, green); + EXPECT_EQ(19, blue); + EXPECT_EQ(255, alpha); +} + +/** + * @tc.name: GifImageDecode002 + * @tc.desc: Create image source by correct gif file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/test.gif", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get the number of image, compatibility test. + * @tc.expected: step2. check the number of image equals the actual number. + */ + int32_t imageCount = imageSource->GetSourceInfo(errorCode).topLevelImageNum; + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_EQ(1, imageCount); +} + +/** + * @tc.name: GifImageDecode003 + * @tc.desc: Create image source by wrong file path and correct format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct png file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/gif"; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/gif/test.gif", opts, errorCode); + ASSERT_EQ(errorCode, ERR_IMAGE_SOURCE_DATA); + ASSERT_EQ(imageSource.get(), nullptr); +} + +/** + * @tc.name: GifImageDecode004 + * @tc.desc: Decode gif image from buffer source stream and pixel format ARGB. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize("/sdcard/multimedia/image/test.gif", bufferSize); + ASSERT_EQ(ret, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer("/sdcard/multimedia/image/test.gif", buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by pixel format BGRA. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create bitmap code=%{public}d.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step3. get the the ARGB of the point. + * @tc.expected: step3. check the ARGB equals the actual ARGB. + */ + uint32_t color = 0; + uint32_t posX = 15; + uint32_t posY = 15; + pixelMap->GetARGB32Color(posX, posY, color); + uint8_t alpha = pixelMap->GetARGB32ColorA(color); + uint8_t red = pixelMap->GetARGB32ColorR(color); + uint8_t green = pixelMap->GetARGB32ColorG(color); + uint8_t blue = pixelMap->GetARGB32ColorB(color); + HiLog::Debug(LABEL_TEST, "point:[%u, %u] ARGB:[%u, %u, %u, %u]", posX, posY, alpha, red, green, blue); + EXPECT_EQ(255, alpha); + EXPECT_EQ(244, red); + EXPECT_EQ(63, green); + EXPECT_EQ(19, blue); + free(buffer); +} + +/** + * @tc.name: GifImageDecode005 + * @tc.desc: Decode gif image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.gif", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step3. get the the RGBA of the point. + * @tc.expected: step3. check the RGBA equals the actual RGBA. + */ + uint32_t color = 0; + uint32_t posX = 15; + uint32_t posY = 15; + pixelMap->GetARGB32Color(posX, posY, color); + uint8_t red = pixelMap->GetARGB32ColorR(color); + uint8_t green = pixelMap->GetARGB32ColorG(color); + uint8_t blue = pixelMap->GetARGB32ColorB(color); + uint8_t alpha = pixelMap->GetARGB32ColorA(color); + HiLog::Debug(LABEL_TEST, "point:[%u, %u] RGBA:[%u, %u, %u, %u]", posX, posY, red, green, blue, alpha); + EXPECT_EQ(255, alpha); + EXPECT_EQ(244, red); + EXPECT_EQ(63, green); + EXPECT_EQ(19, blue); +} + +/** + * @tc.name: GifImageDecode006 + * @tc.desc: Decode moving gif image from file source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and correct format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/gif"; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/moving_test.gif", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get the number of image. + * @tc.expected: step2. check the number of image equals the actual number. + */ + int32_t imageCount = imageSource->GetSourceInfo(errorCode).topLevelImageNum; + HiLog::Debug(LABEL_TEST, "image frame number:%{public}d", imageCount); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_EQ(3, imageCount); + /** + * @tc.steps: step3. decode image source to bitmap by default decode options + * @tc.expected: step3. decode image source to bitmap success. + */ + DecodeOptions decodeOpts; + uint32_t color = 0; + uint32_t posX = 15; + uint32_t posY = 15; + + std::unique_ptr pixelMap; + for (int32_t i = 0; i < imageCount; i++) { + pixelMap = imageSource->CreatePixelMap(i, decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + if (i == 0) { + /** + * @tc.steps: step4. get the the RGBA of the point. + * @tc.expected: step4. check the RGBA equals the actual RGBA. + */ + pixelMap->GetARGB32Color(posX, posY, color); + uint8_t red = pixelMap->GetARGB32ColorR(color); + uint8_t green = pixelMap->GetARGB32ColorG(color); + uint8_t blue = pixelMap->GetARGB32ColorB(color); + uint8_t alpha = pixelMap->GetARGB32ColorA(color); + HiLog::Debug(LABEL_TEST, "point:[%u, %u] RGBA:[%u, %u, %u, %u]", posX, posY, red, green, blue, alpha); + EXPECT_EQ(255, alpha); + EXPECT_EQ(244, red); + EXPECT_EQ(63, green); + EXPECT_EQ(19, blue); + } + string fileName = "/data/test/test_moving_gif" + std::to_string(i) + ".jpg"; + int64_t packSize = PackImage(fileName, std::move(pixelMap)); + ASSERT_NE(0, packSize); + } +} + +/** + * @tc.name: GifImageDecode007 + * @tc.desc: Decode gif image from incremental source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceGifTest, GifImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize("/sdcard/multimedia/image/moving_test.gif", bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer("/sdcard/multimedia/image/moving_test.gif", buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = 10240; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + HiLog::Debug(LABEL_TEST, "updateOnceSize:%{public}u,updateSize:%{public}u,bufferSize:%{public}zu", + updateOnceSize, updateSize, bufferSize); + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + /** + * @tc.steps: step3. get the number of image. + * @tc.expected: step3. check the number of image equals the actual number. + */ + int32_t imageCount = imageSource->GetSourceInfo(errorCode).topLevelImageNum; + HiLog::Debug(LABEL_TEST, "image frame number:%{public}d", imageCount); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_EQ(3, imageCount); +} diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_jpeg_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_jpeg_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40f9c7b6178cd49e1aa73b723b9bccfdb74ca6ad --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_jpeg_test.cpp @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_type.h" +#include "image_utils.h" +#include "incremental_pixel_map.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL_TEST = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageSourceJpegTest" +}; +static constexpr uint32_t DEFAULT_DELAY_UTIME = 10000; // 10 ms. +static const std::string IMAGE_INPUT_JPEG_PATH = "/sdcard/multimedia/image/test.jpg"; +static const std::string IMAGE_INPUT_HW_JPEG_PATH = "/sdcard/multimedia/image/test_hw.jpg"; +static const std::string IMAGE_INPUT_EXIF_JPEG_PATH = "/sdcard/multimedia/image/test_exif.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_FILE_PATH = "/data/test/test_file.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_BUFFER_PATH = "/data/test/test_buffer.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_ISTREAM_PATH = "/data/test/test_istream.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_INC_PATH = "/data/test/test_inc.jpg"; +static const std::string IMAGE_OUTPUT_HW_JPEG_FILE_PATH = "/data/test/test_hw_file.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_FILE1_PATH = "/data/test/test_file1.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_FILE2_PATH = "/data/test/test_file2.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_INC1_PATH = "/data/test/test_inc1.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_ONETIME1_PATH = "/data/test/test_onetime1.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_INC2_PATH = "/data/test/test_inc2.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_ONETIME2_PATH = "/data/test/test_onetime2.jpg"; + +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap); +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize); + +class ImageSourceJpegTest : public testing::Test { +public: + ImageSourceJpegTest(){}; + ~ImageSourceJpegTest(){}; +}; + +/** + * @tc.name: JpegImageDecode001 + * @tc.desc: Decode jpeg image from file source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct jpeg file path and jpeg format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/jpeg"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_JPEG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get support decode image format. + * @tc.expected: step2. get support format info success. + */ + std::set formats; + uint32_t ret = imageSource->GetSupportedFormats(formats); + ASSERT_EQ(ret, SUCCESS); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options. + * @tc.expected: step3. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step4. get image source information. + * @tc.expected: step4. get image source information success and source state is parsed. + */ + SourceInfo sourceInfo = imageSource->GetSourceInfo(errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_EQ(sourceInfo.state, SourceInfoState::FILE_INFO_PARSED); + /** + * @tc.steps: step5. compress the pixel map to jpeg file. + * @tc.expected: step5. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: JpegImageDecode002 + * @tc.desc: Create image source by correct jpeg file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct jpeg file path and default format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_JPEG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get image info from input image. + * @tc.expected: step2. get image info success. + */ + ImageInfo imageInfo; + uint32_t ret = imageSource->GetImageInfo(0, imageInfo); + ASSERT_EQ(ret, SUCCESS); + ret = imageSource->GetImageInfo(imageInfo); + ASSERT_EQ(ret, SUCCESS); +} + +/** + * @tc.name: JpegImageDecode003 + * @tc.desc: Create image source by correct jpeg file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct jpeg file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_JPEG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: JpegImageDecode004 + * @tc.desc: Create image source by wrong jpeg file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by wrong jpeg file path and default format hit. + * @tc.expected: step1. create image source error. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource("/data/jpeg/test.jpg", opts, errorCode); + ASSERT_EQ(errorCode, ERR_IMAGE_SOURCE_DATA); + ASSERT_EQ(imageSource.get(), nullptr); +} + +/** + * @tc.name: JpegImageDecode005 + * @tc.desc: Decode jpeg image from buffer source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_JPEG_PATH, bufferSize); + ASSERT_EQ(ret, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_JPEG_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + + ImageInfo imageInfo; + pixelMap->GetImageInfo(imageInfo); + decodeOpts.CropRect = { imageInfo.size.width - 1, imageInfo.size.height - 1, 1, 1 }; + std::unique_ptr cropPixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(pixelMap.get(), nullptr); + cropPixelMap->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 1); + ASSERT_EQ(imageInfo.size.height, 1); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + ImagePacker imagePacker; + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_BUFFER_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: JpegImageDecode006 + * @tc.desc: Decode jpeg image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open(IMAGE_INPUT_JPEG_PATH, std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_ISTREAM_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: JpegImageDecode007 + * @tc.desc: Decode jpeg image from incremental source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize(IMAGE_INPUT_JPEG_PATH, bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer(IMAGE_INPUT_JPEG_PATH, buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_INC_PATH, std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: JpegImageDecode008 + * @tc.desc: Decode jpeg image multiple times from one ImageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode008, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by jpeg file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_JPEG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap2 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_FILE1_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_FILE2_PATH, std::move(pixelMap2)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: JpegImageDecode009 + * @tc.desc: Decode jpeg image by incremental mode and then decode again by one-time mode. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode009, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize(IMAGE_INPUT_JPEG_PATH, bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer(IMAGE_INPUT_JPEG_PATH, buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_INC1_PATH, std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_ONETIME1_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: JpegImageDecode010 + * @tc.desc: Decode jpeg image by one-time mode and then decode again by incremental mode. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageDecode010, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize(IMAGE_INPUT_JPEG_PATH, bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer(IMAGE_INPUT_JPEG_PATH, buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size. + * @tc.expected: step2. update success. + */ + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + + /** + * @tc.steps: step3. decode image source to pixel map by default decode options. + * @tc.expected: step3. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + + /** + * @tc.steps: step4. decode image source to pixel map by incremental mode again. + * @tc.expected: step4. decode image source to pixel map success. + */ + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_INC2_PATH, std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_ONETIME2_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: JpgImageCrop001 + * @tc.desc: Crop jpg image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpgImageCrop001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create jpg image source by istream source stream and default format hit + * @tc.expected: step1. create jpg image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.jpg", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. crop jpg image source to pixel map crop options + * @tc.expected: step2. crop jpg image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.CropRect.top = 3; + decodeOpts.CropRect.width = 100; + decodeOpts.CropRect.left = 3; + decodeOpts.CropRect.height = 200; + decodeOpts.desiredSize.width = 200; + decodeOpts.desiredSize.height = 400; + decodeOpts.rotateDegrees = 90; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create pixel map error code=%{public}u.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + EXPECT_EQ(200, pixelMap->GetWidth()); + EXPECT_EQ(400, pixelMap->GetHeight()); +} + +/** + * @tc.name: JpegImageHwDecode001 + * @tc.desc: Hardware decode jpeg image from file source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceJpegTest, JpegImageHwDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct jpeg file path and jpeg format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/jpeg"; + std::unique_ptr imageSource = + ImageSource::CreateImageSource(IMAGE_INPUT_HW_JPEG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create pixel map ret=%{public}u.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size equals to JPEG_PACK_SIZE. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_HW_JPEG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_png_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_png_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ef973f91a4ab992d1014db0bd48e2d805337c4e --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_png_test.cpp @@ -0,0 +1,606 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_type.h" +#include "image_utils.h" +#include "incremental_pixel_map.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL_TEST = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageSourcePngTest" +}; +static constexpr uint32_t DEFAULT_DELAY_UTIME = 10000; // 10 ms. + +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap); +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize); + +class ImageSourcePngTest : public testing::Test { +public: + ImageSourcePngTest(){}; + ~ImageSourcePngTest(){}; +}; + +/** + * @tc.name: PngImageDecode001 + * @tc.desc: Decode png image from file source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct png file path and png format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/test.png", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create pixel map error code=%{public}u.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step3. compress the pixel map to png file. + * @tc.expected: step3. pack pixel map success and the png compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/sdcard/multimedia/image/test_file.png", std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: PngImageDecode002 + * @tc.desc: Create image source by correct png file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct png file path and default format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/test.png", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: PngImageDecode003 + * @tc.desc: Create image source by correct png file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct png file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/test.png", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: PngImageDecode004 + * @tc.desc: Create image source by wrong png file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by wrong png file path and default format hit. + * @tc.expected: step1. create image source error. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/png/test.png", opts, errorCode); + ASSERT_EQ(errorCode, ERR_IMAGE_SOURCE_DATA); + ASSERT_EQ(imageSource.get(), nullptr); +} + +/** + * @tc.name: PngImageDecode005 + * @tc.desc: Decode png image from buffer source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize("/sdcard/multimedia/image/test.png", bufferSize); + ASSERT_EQ(ret, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer("/sdcard/multimedia/image/test.png", buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ImagePacker imagePacker; + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/sdcard/multimedia/image/test_file.jpg", std::move(pixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: PngImageDecode006 + * @tc.desc: Decode png image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.png", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create pixel map error code=%{public}u.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step3. compress the pixel map to png file. + * @tc.expected: step3. pack pixel map success and the png compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/data/test_istream.png", std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: PngImageDecode007 + * @tc.desc: Decode png image from incremental source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize("/sdcard/multimedia/image/test.png", bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer("/sdcard/multimedia/image/test.png", buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + HiLog::Debug(LABEL_TEST, "updateOnceSize:%{public}u,updateSize:%{public}u,bufferSize:%{public}zu", + updateOnceSize, updateSize, bufferSize); + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/sdcard/multimedia/image/test_file.jpg", std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: PngImageDecode008 + * @tc.desc: Decode png image multiple times from one ImageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode008, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by png file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = + ImageSource::CreateImageSource("/sdcard/multimedia/image/test.png", opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap2 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixlel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/sdcard/multimedia/image/test_png_file1.jpg", std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + packSize = PackImage("/sdcard/multimedia/image/test_png_file2.jpg", std::move(pixelMap2)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: PngImageDecode009 + * @tc.desc: Decode png image by incremental mode and then decode again by one-time mode. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode009, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize("/sdcard/multimedia/image/test.png", bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer("/sdcard/multimedia/image/test.png", buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack bitmap success and the jpeg compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/sdcard/multimedia/image/test_png_inc1.jpg", std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + packSize = PackImage("/sdcard/multimedia/image/test_png_onetime1.jpg", std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: PngImageDecode010 + * @tc.desc: Decode jpeg image by one-time mode and then decode again by incremental mode. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageDecode010, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize("/sdcard/multimedia/image/test.png", bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer("/sdcard/multimedia/image/test.png", buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size. + * @tc.expected: step2. update success. + */ + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + + /** + * @tc.steps: step3. decode image source to pixel map by default decode options. + * @tc.expected: step3. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + + /** + * @tc.steps: step4. decode image source to pixel map by incremental mode again. + * @tc.expected: step4. decode image source to pixel map success. + */ + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size equals to PNG_PACK_SIZE. + */ + int64_t packSize = PackImage("/sdcard/multimedia/image/test_png_inc2.jpg", std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + packSize = PackImage("/sdcard/multimedia/image/test_png_onetime2.jpg", std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: PngImageCrop001 + * @tc.desc: Crop png image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngImageCrop001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create png image source by istream source stream and default format hit + * @tc.expected: step1. create png image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.png", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. crop png image source to pixel map crop options + * @tc.expected: step2. crop png image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.CropRect.top = 3; + decodeOpts.CropRect.width = 200; + decodeOpts.CropRect.left = 3; + decodeOpts.CropRect.height = 40; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create pixel map error code=%{public}u.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + EXPECT_EQ(200, pixelMap->GetWidth()); + EXPECT_EQ(40, pixelMap->GetHeight()); +} +/** + * @tc.name: PngNinePatch001 + * @tc.desc: Decoding nine-patch picture + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngNinePatch001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create png image source by istream source stream and default format hit + * @tc.expected: step1. create png image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.9.png", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode png image source to pixel map + * @tc.expected: step2. decode png image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + + /** + * @tc.steps: step3. get png nine patch info + * @tc.expected: step3. get png nine patch info success. + */ + const NinePatchInfo &ninePatch = imageSource->GetNinePatchInfo(); + ASSERT_NE(ninePatch.ninePatch, nullptr); + ASSERT_EQ(static_cast(ninePatch.patchSize), 84); +} + +/** + * @tc.name: PngNinePatch002 + * @tc.desc: Decoding non-nine-patch picture + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngNinePatch002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create png image source by istream source stream and default format hit + * @tc.expected: step1. create png image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.png", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode png image source to pixel map + * @tc.expected: step2. decode png image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + + /** + * @tc.steps: step3. get png nine patch info + * @tc.expected: step3. get png nine patch info failed. + */ + const NinePatchInfo &ninePatch = imageSource->GetNinePatchInfo(); + ASSERT_EQ(ninePatch.ninePatch, nullptr); +} + +/** + * @tc.name: PngNinePatch003 + * @tc.desc: Decoding nine-patch picture with scale and pixelformat convert + * @tc.type: FUNC + */ +HWTEST_F(ImageSourcePngTest, PngNinePatch003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create png image source by istream source stream and default format hit + * @tc.expected: step1. create png image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test.9.png", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. scale and covert pixelformat png image source to pixel map + * @tc.expected: step2. scale and covert pixelformat png image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredSize = { 186, 160 }; + decodeOpts.desiredPixelFormat = PixelFormat::RGB_565; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + + /** + * @tc.steps: step3. get png nine patch info + * @tc.expected: step3. get png nine patch info success. + */ + const NinePatchInfo &ninePatch = imageSource->GetNinePatchInfo(); + ASSERT_NE(ninePatch.ninePatch, nullptr); + ASSERT_EQ(static_cast(ninePatch.patchSize), 84); +} diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_raw_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_raw_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b12ddca612699a50d509976b9754225ef5c493ae --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_raw_test.cpp @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "hilog/log.h" +#include "directory_ex.h" +#include "image_source_util.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_type.h" +#include "image_utils.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static const std::string IMAGE_INPUT_DNG_PATH = "/sdcard/multimedia/image/test.dng"; +static const std::string IMAGE_OUTPUT_DNG_FILE_PATH = "/data/test/test_raw_file.jpg"; + +class ImageSourceRawTest : public testing::Test { +public: + ImageSourceRawTest(){}; + ~ImageSourceRawTest(){}; +}; + +/** + * @tc.name: RawImageDecode001 + * @tc.desc: Decode raw image from file source stream(default:RGBA_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct raw file path and format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/x-raw"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options(RGBA_8888). + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: RawImageDecode002 + * @tc.desc: Decode raw image from file source stream(BGRA_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/raw"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format BGRA_8888. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: RawImageDecode003 + * @tc.desc: Decode raw image from file source stream(RGB_565) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/x-raw"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format RGB_565. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::RGB_565; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +/** + * @tc.name: RawImageDecode004 + * @tc.desc: Decode raw image from file source stream(ARGB_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/raw"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format BGRA_8888. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: RawImageDecode005 + * @tc.desc: Create raw source by correct file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and default format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get image info from input image. + * @tc.expected: step2. get image info success. + */ + ImageInfo imageInfo; + uint32_t ret = imageSource->GetImageInfo(0, imageInfo); + ASSERT_EQ(ret, SUCCESS); + ret = imageSource->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 5976); + ASSERT_EQ(imageInfo.size.height, 3992); +} + +/** + * @tc.name: RawImageDecode006 + * @tc.desc: Create image source by correct raw file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: RawImageDecode007 + * @tc.desc: Decode raw image from buffer source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_DNG_PATH, bufferSize); + ASSERT_EQ(ret, true); + auto *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_DNG_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + + ImageInfo imageInfo; + pixelMap->GetImageInfo(imageInfo); + decodeOpts.CropRect = { imageInfo.size.width - 1, imageInfo.size.height - 1, 1, 1 }; + std::unique_ptr cropPixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(pixelMap.get(), nullptr); + cropPixelMap->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 1); + ASSERT_EQ(imageInfo.size.height, 1); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and compare the jpeg compress file size. + */ + ImagePacker imagePacker; + int64_t packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: RawImageDecode008 + * @tc.desc: Decode raw image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode008, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open(IMAGE_INPUT_DNG_PATH, std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: RawImageDecode009 + * @tc.desc: Decode raw image multiple times from one imageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode009, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_DNG_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap2 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and compare the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_DNG_FILE_PATH, std::move(pixelMap2)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: RawImageDecode010 + * @tc.desc: Decode wrong raw image from one imageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceRawTest, RawImageDecode010, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit, modify data buffer to wrong + * format. + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_DNG_PATH, bufferSize); + ASSERT_EQ(ret, true); + auto *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_DNG_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + buffer[0] = 43; + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map failed, because format error. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(errorCode, SUCCESS); + ASSERT_EQ(pixelMap.get(), nullptr); +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_util.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0dec028ea2b9471fe4c5dee33c2c274ced5f4411 --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_util.cpp @@ -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. + */ + +#include "image_source_util.h" +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_type.h" +#include "image_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL_TEST = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageSourceUtil" }; +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap) +{ + ImagePacker imagePacker; + PackOption option; + option.format = "image/jpeg"; + option.quality = 100; + option.numberHint = 1; + std::set formats; + uint32_t ret = imagePacker.GetSupportedFormats(formats); + if (ret != SUCCESS) { + HiLog::Error(LABEL_TEST, "image packer get supported format failed, ret=%{public}u.", ret); + return 0; + } + imagePacker.StartPacking(filePath, option); + imagePacker.AddImage(*pixelMap); + int64_t packedSize = 0; + imagePacker.FinalizePacking(packedSize); + HiLog::Debug(LABEL_TEST, "packedSize=%{public}lld.", static_cast(packedSize)); + return packedSize; +} + +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize) +{ + std::string realPath; + if (!OHOS::PathToRealPath(filePath, realPath)) { + HiLog::Error(LABEL_TEST, "file path to real path failed, file path=%{public}s.", filePath.c_str()); + return false; + } + FILE *fp = fopen(realPath.c_str(), "rb"); + if (fp == nullptr) { + HiLog::Error(LABEL_TEST, "open file failed, real path=%{public}s.", realPath.c_str()); + return false; + } + fseek(fp, 0, SEEK_END); + size_t fileSize = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (bufferSize < fileSize) { + HiLog::Error(LABEL_TEST, "buffer size:(%{public}zu) is smaller than file size:(%{public}zu).", bufferSize, + fileSize); + fclose(fp); + return false; + } + size_t retSize = fread(buffer, 1, fileSize, fp); + if (retSize != fileSize) { + HiLog::Error(LABEL_TEST, "read file result size = %{public}zu, size = %{public}zu.", retSize, fileSize); + fclose(fp); + return false; + } + fclose(fp); + return true; +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_util.h b/frameworks/innerkitsimpl/test/unittest/image_source_util.h new file mode 100644 index 0000000000000000000000000000000000000000..abf59886889cb2e2b1571c95dec10a9885cc6105 --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_util.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef IMAGE_SOURCE_UTIL_H +#define IMAGE_SOURCE_UTIL_H +#include +#include "pixel_map.h" + +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap); +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize); + +#endif // IMAGE_SOURCE_UTIL_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_wbmp_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_wbmp_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..802a17b22e6612c8237233f93460db4c47170e3e --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_wbmp_test.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_source_util.h" +#include "image_type.h" +#include "image_utils.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static const std::string IMAGE_INPUT_WBMP_PATH = "/sdcard/multimedia/image/test.wbmp"; + +class ImageSourceWbmpTest : public testing::Test { +public: + ImageSourceWbmpTest(){}; + ~ImageSourceWbmpTest(){}; +}; + +/** + * @tc.name: WbmpImageDecode001 + * @tc.desc: Decode wbmp image from file source stream(default:RGBA_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct file path + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/vnd.wap.wbmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options(RGBA_8888). + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +/** + * @tc.name: WbmpImageDecode002 + * @tc.desc: Decode wbmp image from file source stream(BGRA_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/vnd.wap.wbmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format BGRA_8888. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +/** + * @tc.name: WbmpImageDecode003 + * @tc.desc: Decode wbmp image from file source stream(RGB_565) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/vnd.wap.wbmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format RGB_565. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::RGB_565; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +/** + * @tc.name: WbmpImageDecode004 + * @tc.desc: Decode wbmp image from file source stream(ARGB_8888) + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and bmp format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/vnd.wap.wbmp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map using pixel format BGRA_8888. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + ASSERT_EQ(pixelMap->GetAlphaType(), AlphaType::IMAGE_ALPHA_TYPE_OPAQUE); +} + +/** + * @tc.name: WbmpImageDecode005 + * @tc.desc: Create source by correct wbmp file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and default format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get image info from input image. + * @tc.expected: step2. get image info success. + */ + ImageInfo imageInfo; + uint32_t ret = imageSource->GetImageInfo(0, imageInfo); + ASSERT_EQ(ret, SUCCESS); + ret = imageSource->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 472); + ASSERT_EQ(imageInfo.size.height, 75); +} + +/** + * @tc.name: WbmpImageDecode006 + * @tc.desc: Create image source by correct wbmp file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct bmp file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: WbmpImageDecode007 + * @tc.desc: Decode wbmp image from buffer source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_WBMP_PATH, bufferSize); + ASSERT_EQ(ret, true); + auto *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_WBMP_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + + ImageInfo imageInfo; + pixelMap->GetImageInfo(imageInfo); + decodeOpts.CropRect = { imageInfo.size.width - 1, imageInfo.size.height - 1, 1, 1 }; + std::unique_ptr cropPixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(pixelMap.get(), nullptr); + cropPixelMap->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 1); + ASSERT_EQ(imageInfo.size.height, 1); +} + +/** + * @tc.name: WbmpImageDecode008 + * @tc.desc: Decode wbmp image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode008, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open(IMAGE_INPUT_WBMP_PATH, std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); +} + +/** + * @tc.name: WbmpImageDecode009 + * @tc.desc: Decode wbmp image multiple times from one imageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode009, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by bmp file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WBMP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap2 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); +} + +/** + * @tc.name: WbmpImageDecode010 + * @tc.desc: Decode wrong wbmp image from one imageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWbmpTest, WbmpImageDecode010, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit, modify data buffer to wrong + * format. + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_WBMP_PATH, bufferSize); + ASSERT_EQ(ret, true); + auto *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_WBMP_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + buffer[0] = 43; + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map failed, because bmp format error. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(errorCode, SUCCESS); + ASSERT_EQ(pixelMap.get(), nullptr); +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_source_webp_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_source_webp_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa1b8d0d8b9a291fa45db63c373d9bd1be14250b --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_source_webp_test.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "image_packer.h" +#include "image_source.h" +#include "image_type.h" +#include "image_utils.h" +#include "incremental_pixel_map.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL_TEST = { + LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageSourceWebpTest" +}; +static constexpr uint32_t DEFAULT_DELAY_UTIME = 10000; // 10 ms. +static const std::string IMAGE_INPUT_WEBP_PATH = "/sdcard/multimedia/image/test_large.webp"; +static const std::string IMAGE_INPUT_HW_JPEG_PATH = "/sdcard/multimedia/image/test_hw.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_FILE_PATH = "/data/test/test_webp_file.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_BUFFER_PATH = "/data/test/test_webp_buffer.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_ISTREAM_PATH = "/data/test/test_webp_istream.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_INC_PATH = "/data/test/test_webp_inc.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_FILE1_PATH = "/data/test/test_webp_file1.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_FILE2_PATH = "/data/test/test_webp_file2.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_INC1_PATH = "/data/test/test_webp_inc1.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_ONETIME1_PATH = "/data/test/test_webp_onetime1.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_INC2_PATH = "/data/test/test_webp_inc2.jpg"; +static const std::string IMAGE_OUTPUT_JPEG_MULTI_ONETIME2_PATH = "/data/test/test_webp_onetime2.jpg"; + +int64_t PackImage(const std::string &filePath, std::unique_ptr pixelMap); +bool ReadFileToBuffer(const std::string &filePath, uint8_t *buffer, size_t bufferSize); + +class ImageSourceWebpTest : public testing::Test { +public: + ImageSourceWebpTest(){}; + ~ImageSourceWebpTest(){}; +}; + +/** + * @tc.name: WebpImageDecode001 + * @tc.desc: Decode webp image from file source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct webp file path and jpeg format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/webp"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WEBP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get support decode image format. + * @tc.expected: step2. get support format info success. + */ + std::set formats; + uint32_t ret = imageSource->GetSupportedFormats(formats); + ASSERT_EQ(ret, SUCCESS); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options. + * @tc.expected: step3. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + /** + * @tc.steps: step4. get image source information. + * @tc.expected: step4. get image source information success and source state is parsed. + */ + SourceInfo sourceInfo = imageSource->GetSourceInfo(errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_EQ(sourceInfo.state, SourceInfoState::FILE_INFO_PARSED); + /** + * @tc.steps: step5. compress the pixel map to jpeg file. + * @tc.expected: step5. pack pixel map success and the jpeg compress file. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_FILE_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: WebpImageDecode002 + * @tc.desc: Create image source by correct webp file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode002, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct webp file path and default format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WEBP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. get image info from input image. + * @tc.expected: step2. get image info success. + */ + ImageInfo imageInfo; + uint32_t ret = imageSource->GetImageInfo(0, imageInfo); + ASSERT_EQ(ret, SUCCESS); + ret = imageSource->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 588); + ASSERT_EQ(imageInfo.size.height, 662); +} + +/** + * @tc.name: WebpImageDecode003 + * @tc.desc: Create image source by correct webp file path and wrong format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode003, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by correct webp file path and wrong format hit. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + opts.formatHint = "image/png"; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WEBP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); +} + +/** + * @tc.name: WebpImageDecode004 + * @tc.desc: Create image source by wrong webp file path and default format hit. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode004, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by wrong webp file path and default format hit. + * @tc.expected: step1. create image source error. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource("/data/jpeg/test.webp", opts, errorCode); + ASSERT_EQ(errorCode, ERR_IMAGE_SOURCE_DATA); + ASSERT_EQ(imageSource.get(), nullptr); +} + +/** + * @tc.name: WebpImageDecode005 + * @tc.desc: Decode webp image from buffer source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode005, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by buffer source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool ret = ImageUtils::GetFileSize(IMAGE_INPUT_WEBP_PATH, bufferSize); + ASSERT_EQ(ret, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + ret = ReadFileToBuffer(IMAGE_INPUT_WEBP_PATH, buffer, bufferSize); + ASSERT_EQ(ret, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(buffer, bufferSize, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + + ImageInfo imageInfo; + pixelMap->GetImageInfo(imageInfo); + decodeOpts.CropRect = { imageInfo.size.width - 1, imageInfo.size.height - 1, 1, 1 }; + std::unique_ptr cropPixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_NE(pixelMap.get(), nullptr); + cropPixelMap->GetImageInfo(imageInfo); + ASSERT_EQ(imageInfo.size.width, 1); + ASSERT_EQ(imageInfo.size.height, 1); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size. + */ + ImagePacker imagePacker; + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_BUFFER_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: WebpImageDecode006 + * @tc.desc: Decode webp image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode006, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by istream source stream and default format hit + * @tc.expected: step1. create image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open(IMAGE_INPUT_WEBP_PATH, std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_ISTREAM_PATH, std::move(pixelMap)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: WebpImageDecode007 + * @tc.desc: Decode webp image from incremental source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode007, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize(IMAGE_INPUT_WEBP_PATH, bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer(IMAGE_INPUT_WEBP_PATH, buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredSize.height = 1024; + decodeOpts.desiredSize.width = 512; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step3. compress the pixel map to jpeg file. + * @tc.expected: step3. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_INC_PATH, std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: WebpImageDecode008 + * @tc.desc: Decode webp image multiple times from one ImageSource + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode008, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by webp file path. + * @tc.expected: step1. create image source success. + */ + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(IMAGE_INPUT_WEBP_PATH, opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. decode image source to pixel map by default decode options. + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap2 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_FILE1_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_FILE2_PATH, std::move(pixelMap2)); + ASSERT_NE(packSize, 0); +} + +/** + * @tc.name: WebpImageDecode009 + * @tc.desc: Decode webp image by incremental mode and then decode again by one-time mode. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode009, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize(IMAGE_INPUT_WEBP_PATH, bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer(IMAGE_INPUT_WEBP_PATH, buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size and promote decode + * image to pixel map by default decode options + * @tc.expected: step2. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888; + decodeOpts.rotateDegrees = 180; + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint32_t updateSize = 0; + srand(time(nullptr)); + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + updateSize += updateOnceSize; + usleep(DEFAULT_DELAY_UTIME); + } + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step3. decode image source to pixel map by default decode options again. + * @tc.expected: step3. decode image source to pixel map success. + */ + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_INC1_PATH, std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_ONETIME1_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: WebpImageDecode010 + * @tc.desc: Decode webp image by one-time mode and then decode again by incremental mode. + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageDecode010, TestSize.Level3) +{ + /** + * @tc.steps: step1. create image source by incremental source stream and default format hit + * @tc.expected: step1. create image source success. + */ + size_t bufferSize = 0; + bool fileRet = ImageUtils::GetFileSize(IMAGE_INPUT_WEBP_PATH, bufferSize); + ASSERT_EQ(fileRet, true); + uint8_t *buffer = (uint8_t *)malloc(bufferSize); + ASSERT_NE(buffer, nullptr); + fileRet = ReadFileToBuffer(IMAGE_INPUT_WEBP_PATH, buffer, bufferSize); + ASSERT_EQ(fileRet, true); + uint32_t errorCode = 0; + IncrementalSourceOptions incOpts; + incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. update incremental stream every 10 ms with random data size. + * @tc.expected: step2. update success. + */ + uint32_t updateSize = 0; + bool isCompleted = false; + while (updateSize < bufferSize) { + uint32_t updateOnceSize = rand() % 1024; + if (updateSize + updateOnceSize > bufferSize) { + updateOnceSize = bufferSize - updateSize; + isCompleted = true; + } + uint32_t ret = imageSource->UpdateData(buffer + updateSize, updateOnceSize, isCompleted); + ASSERT_EQ(ret, SUCCESS); + updateSize += updateOnceSize; + } + + /** + * @tc.steps: step3. decode image source to pixel map by default decode options. + * @tc.expected: step3. decode image source to pixel map success. + */ + DecodeOptions decodeOpts; + std::unique_ptr pixelMap1 = imageSource->CreatePixelMap(decodeOpts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap1.get(), nullptr); + + /** + * @tc.steps: step4. decode image source to pixel map by incremental mode again. + * @tc.expected: step4. decode image source to pixel map success. + */ + std::unique_ptr incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode); + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + incPixelMap->DetachFromDecoding(); + IncrementalDecodingStatus status = incPixelMap->GetDecodingStatus(); + ASSERT_EQ(status.decodingProgress, 100); + /** + * @tc.steps: step4. compress the pixel map to jpeg file. + * @tc.expected: step4. pack pixel map success and the jpeg compress file size. + */ + int64_t packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_INC2_PATH, std::move(incPixelMap)); + ASSERT_NE(packSize, 0); + packSize = PackImage(IMAGE_OUTPUT_JPEG_MULTI_ONETIME2_PATH, std::move(pixelMap1)); + ASSERT_NE(packSize, 0); + free(buffer); +} + +/** + * @tc.name: WebpImageCrop001 + * @tc.desc: Crop webp image from istream source stream + * @tc.type: FUNC + */ +HWTEST_F(ImageSourceWebpTest, WebpImageCrop001, TestSize.Level3) +{ + /** + * @tc.steps: step1. create webp image source by istream source stream and default format hit + * @tc.expected: step1. create webp image source success. + */ + std::unique_ptr fs = std::make_unique(); + fs->open("/sdcard/multimedia/image/test_large.webp", std::fstream::binary | std::fstream::in); + bool isOpen = fs->is_open(); + ASSERT_EQ(isOpen, true); + uint32_t errorCode = 0; + SourceOptions opts; + std::unique_ptr imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(imageSource.get(), nullptr); + /** + * @tc.steps: step2. crop jpg image source to pixel map crop options + * @tc.expected: step2. crop jpg image source to pixel map success. + */ + DecodeOptions decodeOpts; + decodeOpts.CropRect.top = 3; + decodeOpts.CropRect.width = 151; + decodeOpts.CropRect.left = 3; + decodeOpts.CropRect.height = 183; + decodeOpts.desiredSize.width = 200; + decodeOpts.desiredSize.height = 300; + decodeOpts.rotateDegrees = 90; + std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode); + HiLog::Debug(LABEL_TEST, "create pixel map error code=%{public}u.", errorCode); + ASSERT_EQ(errorCode, SUCCESS); + ASSERT_NE(pixelMap.get(), nullptr); + EXPECT_EQ(200, pixelMap->GetWidth()); + EXPECT_EQ(300, pixelMap->GetHeight()); +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/unittest/image_transform_test.cpp b/frameworks/innerkitsimpl/test/unittest/image_transform_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f872a838b3f49fafccbeda0531781ecbb64025bd --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_transform_test.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "basic_transformer.h" +#include "securec.h" + +using namespace testing::ext; +using namespace OHOS::Media; +namespace OHOS { +namespace Multimedia { +class ImageTransformTest : public testing::Test { +public: + ImageTransformTest(){}; + ~ImageTransformTest(){}; +}; + +/* +|255,255,0,0 0,0,0,0 255,0,255,0| +|0,0,0,0 0,0,0,0 0,0,0,0| +|0,0,0,0 0,0,0,0 0,0,0,0| +|255,0,0,255 0,0,0,0 255,163,213,234| + */ +void ConstructPixmapInfo(PixmapInfo &pixmapInfo) +{ + pixmapInfo.imageInfo.size.width = 3; + pixmapInfo.imageInfo.size.height = 4; + pixmapInfo.imageInfo.pixelFormat = PixelFormat::ARGB_8888; + pixmapInfo.imageInfo.colorSpace = ColorSpace::SRGB; + int32_t width = 3; + int32_t height = 4; + pixmapInfo.data = new uint8_t[width * height * 4]; + + if (pixmapInfo.data == nullptr) { + return; + } + pixmapInfo.bufferSize = width * height * 4; + if (memset_s(pixmapInfo.data, sizeof(width * height * 4), 0, sizeof(width * height * 4)) != EOK) { + ASSERT_NE(*pixmapInfo.data, 0); + } + for (int32_t i = 0; i < width * height; ++i) { + int rb = i * 4; + // the 0th item set red + if (i == 0) { + *(pixmapInfo.data + rb) = 255; + *(pixmapInfo.data + rb + 1) = 255; + } + // the 2th item set green + if (i == 2) { + *(pixmapInfo.data + rb) = 255; + *(pixmapInfo.data + rb + 2) = 255; + } + + // the 9th item set blue + if (i == 9) { + *(pixmapInfo.data + rb) = 255; + *(pixmapInfo.data + rb + 3) = 255; + } + + // the 11th item rand + if (i == 11) { + *(pixmapInfo.data + rb) = 255; + *(pixmapInfo.data + rb + 1) = 163; + *(pixmapInfo.data + rb + 2) = 213; + *(pixmapInfo.data + rb + 3) = 234; + } + } +} + +/** + * @tc.name: ImageTransformTest001 + * @tc.desc: the pixmap info scale 2.0f. + * @tc.type: FUNC + */ +HWTEST_F(ImageTransformTest, ImageTransformTest001, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageTransformTest: ImageTransform001_Scale2 start"; + + PixmapInfo inPutInfo; + ConstructPixmapInfo(inPutInfo); + + /** + * @tc.steps: step1. construct pixel map info. + * @tc.expected: step1. expect the pixel map width and height. + */ + PixmapInfo outPutInfo(inPutInfo); + BasicTransformer trans; + trans.SetScaleParam(2.0f, 2.0f); + trans.TransformPixmap(inPutInfo, outPutInfo); + + ASSERT_NE(outPutInfo.data, nullptr); + EXPECT_EQ(outPutInfo.imageInfo.size.width, 6); + EXPECT_EQ(outPutInfo.imageInfo.size.height, 8); + EXPECT_EQ(outPutInfo.bufferSize, (uint32_t)(6 * 8 * 4)); + + /** + * @tc.steps: step2. scale 2 times. + * @tc.expected: step2. expect four corner values. + */ + for (int32_t i = 0; i < 6 * 8; ++i) { + int rb = i * 4; + // after scale 2.0, the 0th item change to 0th item + if (i == 0) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 1)), 255); + } + + // after scale 2.0, the 2th item change to 5th item + if (i == 5) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 2)), 255); + } + + // after scale 2.0, the 9th item change to 42th item + if (i == 42) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 3)), 255); + } + + // after scale 2.0, the 11th item change to 47th item + if (i == 47) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 1)), 163); + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 2)), 213); + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 3)), 234); + } + } + if (inPutInfo.data != nullptr) { + free(inPutInfo.data); + inPutInfo.data = nullptr; + } + if (outPutInfo.data != nullptr) { + free(outPutInfo.data); + outPutInfo.data = nullptr; + } + GTEST_LOG_(INFO) << "ImageTransformTest: ImageTransform001_Scale2 end"; +} + +/** + * @tc.name: ImageTransformTest002 + * @tc.desc: the pixmap info rotate 90 at the center point. + * @tc.type: FUNC + */ +HWTEST_F(ImageTransformTest, ImageTransformTest002, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageTransformTest: ImageTransform002_Rotate90 start"; + + PixmapInfo inPutInfo; + ConstructPixmapInfo(inPutInfo); + + /** + * @tc.steps: step1. construct pixel map info. + * @tc.expected: step1. expect the pixel map width and height. + */ + PixmapInfo outPutInfo(inPutInfo); + BasicTransformer trans; + trans.SetRotateParam(90, (float)(inPutInfo.imageInfo.size.width / 2), (float)(inPutInfo.imageInfo.size.height / 2)); + trans.TransformPixmap(inPutInfo, outPutInfo); + + ASSERT_NE(outPutInfo.data, nullptr); + EXPECT_EQ(outPutInfo.imageInfo.size.width, 4); + EXPECT_EQ(outPutInfo.imageInfo.size.height, 3); + EXPECT_EQ(outPutInfo.bufferSize, (uint32_t)(4 * 3 * 4)); + + /** + * @tc.steps: step2. rotate 90. + * @tc.expected: step2. expect four corner values. + */ + for (int32_t i = 0; i < 4 * 3; ++i) { + int rb = i * 4; + // after rotate 90, the 0th change to 9th + if (i == 0) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 3)), 255); + } + + // after rotate 90, the 3th item change to 0th item + if (i == 3) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 1)), 255); + } + + // after rotate 90, the 11th item change to 2th item + if (i == 11) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 2)), 255); + } + } + if (inPutInfo.data != nullptr) { + free(inPutInfo.data); + inPutInfo.data = nullptr; + } + if (outPutInfo.data != nullptr) { + free(outPutInfo.data); + outPutInfo.data = nullptr; + } + GTEST_LOG_(INFO) << "ImageTransforTest: ImageTransfor002_Rotate90 end"; +} + +/** + * @tc.name: ImageTransformTest003 + * @tc.desc: the pixmap info rotate 180 at the center point. + * @tc.type: FUNC + */ +HWTEST_F(ImageTransformTest, ImageTransformTest003, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImageTransformTest: ImageTransform003_Rotate180 start"; + + /** + * @tc.steps: step1. construct pixel map info. + * @tc.expected: step1. expect the pixel map width and height. + */ + PixmapInfo inPutInfo; + ConstructPixmapInfo(inPutInfo); + + PixmapInfo outPutInfo(inPutInfo); + BasicTransformer trans; + trans.SetRotateParam(180, (float)(inPutInfo.imageInfo.size.width / 2), + (float)(inPutInfo.imageInfo.size.height / 2)); + trans.TransformPixmap(inPutInfo, outPutInfo); + + ASSERT_NE(outPutInfo.data, nullptr); + EXPECT_EQ(outPutInfo.imageInfo.size.width, 3); + EXPECT_EQ(outPutInfo.imageInfo.size.height, 4); + EXPECT_EQ(outPutInfo.bufferSize, (uint32_t)(3 * 4 * 4)); + + /** + * @tc.steps: step2. rotate 180. + * @tc.expected: step2. expect four corner values. + */ + for (int32_t i = 0; i < 3 * 4; ++i) { + int rb = i * 4; + // after rotate 180, the 0th change to 11th + if (i == 0) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 1)), 163); + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 2)), 213); + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 3)), 234); + } + + // after rotate 180, the 2th item change to 9th item + if (i == 2) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 3)), 255); + } + + // after rotate 180, the 9th item change to 2th item + if (i == 9) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 2)), 255); + } + + // after rotate 180, the 11th item change to 0th item + if (i == 11) { + EXPECT_EQ((int32_t)(*(outPutInfo.data + rb + 1)), 255); + } + } + if (inPutInfo.data != nullptr) { + free(inPutInfo.data); + inPutInfo.data = nullptr; + } + if (outPutInfo.data != nullptr) { + free(outPutInfo.data); + outPutInfo.data = nullptr; + } + GTEST_LOG_(INFO) << "ImageTransformTest: ImageTransform003_Rotate180 end"; +} +} // namespace Multimedia +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/utils/BUILD.gn b/frameworks/innerkitsimpl/utils/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..93da1ccfd8c00cac349ed4178207bcaa0f51da9f --- /dev/null +++ b/frameworks/innerkitsimpl/utils/BUILD.gn @@ -0,0 +1,113 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("image_utils") { + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//utils/native/base/include", + "//foundation/multimedia/utils/lite/interfaces/kits", + "//foundation/communication/ipc/utils/include", + ] + + sources = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/src/image_trace.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/src/image_utils.cpp", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + sources -= [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/src/image_trace.cpp" ] + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + sources -= [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/src/image_trace.cpp" ] + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + defines = [ "DUAL_ADAPTER" ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + external_deps = [ + "bytrace_standard:bytrace_core", + "hiviewdfx_hilog_native:libhilog", + ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_static_library("image_utils_static") { + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//utils/native/base/include", + ] + + sources = [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/src/image_utils.cpp" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + sources += [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/src/image_trace.cpp" ] + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + external_deps = [ + "bytrace_standard:bytrace_core", + "hiviewdfx_hilog_native:libhilog", + ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/frameworks/innerkitsimpl/utils/include/image_format.h b/frameworks/innerkitsimpl/utils/include/image_format.h new file mode 100644 index 0000000000000000000000000000000000000000..cc3ee124153986e6c64c48123b862444cd027a2b --- /dev/null +++ b/frameworks/innerkitsimpl/utils/include/image_format.h @@ -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. + */ + +#ifndef IMAGE_FORMAT_H +#define IMAGE_FORMAT_H + +namespace OHOS { +namespace Media { +enum class ImageFormat { UNKNOWN = 0, NV21 = 1, YUV420_888 = 2, JPEG = 3, RAW10 = 4, RAW16 = 5, H264 = 6, H265 = 7 }; + +enum class ComponentType { + UNKNOWN = 0, + YUV_Y = 1, + YUV_U = 2, + YUV_V = 3, + JPEG = 4, + RAW10 = 5, + RAW16 = 6, + H264 = 7, + H265 = 8 +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_FORMAT_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/utils/include/image_log.h b/frameworks/innerkitsimpl/utils/include/image_log.h new file mode 100644 index 0000000000000000000000000000000000000000..45fb80908561414087aaaa49b718f6e33844d860 --- /dev/null +++ b/frameworks/innerkitsimpl/utils/include/image_log.h @@ -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. + */ + +#ifndef IMAGE_LOG_H +#define IMAGE_LOG_H + +#include "hilog/log.h" +#include "log_tags.h" + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageCode" }; + +#define IMAGE_LOGF(...) (void)OHOS::HiviewDFX::HiLog::Fatal(LABEL, __VA_ARGS__) +#define IMAGE_LOGE(...) (void)OHOS::HiviewDFX::HiLog::Error(LABEL, __VA_ARGS__) +#define IMAGE_LOGW(...) (void)OHOS::HiviewDFX::HiLog::Warn(LABEL, __VA_ARGS__) +#define IMAGE_LOGI(...) (void)OHOS::HiviewDFX::HiLog::Info(LABEL, __VA_ARGS__) +#define IMAGE_LOGD(...) (void)OHOS::HiviewDFX::HiLog::Debug(LABEL, __VA_ARGS__) + +#endif // IMAGE_LOG_H diff --git a/frameworks/innerkitsimpl/utils/include/image_trace.h b/frameworks/innerkitsimpl/utils/include/image_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..9a0196d846870dc2f2ad69f9ef50f10d8c0a37f3 --- /dev/null +++ b/frameworks/innerkitsimpl/utils/include/image_trace.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_TRACE_H +#define IMAGE_TRACE_H + +#include + +namespace OHOS { +namespace Media { +class ImageTrace { +public: + explicit ImageTrace(const std::string &title); + explicit ImageTrace(const char *fmt, ...); + ~ImageTrace(); + +private: + std::string title_; +}; +} // namespace Media +} // namespace OHOS +#endif // IMAGE_TRACE_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/utils/include/image_utils.h b/frameworks/innerkitsimpl/utils/include/image_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ed94d6ac3160e5cfdf2f77e409d8794e0ff2b42b --- /dev/null +++ b/frameworks/innerkitsimpl/utils/include/image_utils.h @@ -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. + */ + +#ifndef IMAGE_UTILS_H +#define IMAGE_UTILS_H + +#include +#include +#include +#include "image_type.h" +#include "plugin_server.h" + +namespace OHOS { +namespace Media { +const std::string IMAGE_ENCODE_FORMAT = "encodeFormat"; + +class ImageUtils { +public: + static bool GetFileSize(const std::string &pathName, size_t &size); + static bool GetInputStreamSize(std::istream &inputStream, size_t &size); + static int32_t GetPixelBytes(const PixelFormat &pixelFormat); + static bool PathToRealPath(const std::string &path, std::string &realPath); + static bool FloatCompareZero(float src); + static AlphaType GetValidAlphaTypeByFormat(const AlphaType &dstType, const PixelFormat &format); + static bool IsValidImageInfo(const ImageInfo &info); + static MultimediaPlugin::PluginServer& GetPluginServer(); + static bool CheckMulOverflow(int32_t width, int32_t bytesPerPixel); + static bool CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel); + +private: + static uint32_t RegisterPluginServer(); +}; +} // namespace Media +} // namespace OHOS +#endif // IMAGE_UTILS_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/utils/src/image_trace.cpp b/frameworks/innerkitsimpl/utils/src/image_trace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59bd3d30503af178251636d58b6c3510315be11d --- /dev/null +++ b/frameworks/innerkitsimpl/utils/src/image_trace.cpp @@ -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. + */ +#include "image_trace.h" +#include "bytrace.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +static constexpr int32_t FORMAT_BUF_SIZE = 128; + +ImageTrace::ImageTrace(const std::string &title) : title_(title) +{ + StartTrace(BYTRACE_TAG_ZIMAGE, title); +} + +ImageTrace::~ImageTrace() +{ + FinishTrace(BYTRACE_TAG_ZIMAGE, title_); +} + +ImageTrace::ImageTrace(const char *fmt, ...) +{ + if (fmt == nullptr) { + title_ = "ImageTraceFmt Param invalid"; + } else { + char buf[FORMAT_BUF_SIZE] = { 0 }; + va_list args; + va_start(args, fmt); + int32_t ret = vsprintf_s(buf, FORMAT_BUF_SIZE, fmt, args); + va_end(args); + if (ret != -1) { + title_ = buf; + } else { + title_ = "ImageTraceFmt Format Error"; + } + } + StartTrace(BYTRACE_TAG_ZIMAGE, title_); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/utils/src/image_utils.cpp b/frameworks/innerkitsimpl/utils/src/image_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1e5da791dbade49c47636aa01b26f85f2525565 --- /dev/null +++ b/frameworks/innerkitsimpl/utils/src/image_utils.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_utils.h" +#include +#include +#include "image_log.h" +#include "media_errors.h" +#include "plugin_server.h" +#ifdef _WIN32 +#include +#endif + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; +using namespace std; +using namespace MultimediaPlugin; + +constexpr int32_t ALPHA8_BYTES = 1; +constexpr int32_t RGB565_BYTES = 2; +constexpr int32_t RGB888_BYTES = 3; +constexpr int32_t ARGB8888_BYTES = 4; +constexpr int32_t RGBA_F16_BYTES = 8; +constexpr int32_t NV21_BYTES = 2; // Each pixel is sorted on 3/2 bytes. +constexpr float EPSILON = 1e-6; +constexpr int MAX_DIMENSION = INT32_MAX >> 2; +static bool g_pluginRegistered = false; + +bool ImageUtils::GetFileSize(const string &pathName, size_t &size) +{ + if (pathName.empty()) { + IMAGE_LOGE("[ImageUtil]input parameter exception."); + return false; + } + struct stat statbuf; + int ret = stat(pathName.c_str(), &statbuf); + if (ret != 0) { + IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d.", ret); + return false; + } + size = statbuf.st_size; + return true; +} + +bool ImageUtils::GetInputStreamSize(istream &inputStream, size_t &size) +{ + if (inputStream.rdbuf() == nullptr) { + IMAGE_LOGE("[ImageUtil]input parameter exception."); + return false; + } + size_t original = inputStream.tellg(); + inputStream.seekg(0, ios_base::end); + size = inputStream.tellg(); + inputStream.seekg(original); + return true; +} + +int32_t ImageUtils::GetPixelBytes(const PixelFormat &pixelFormat) +{ + int pixelBytes = 0; + switch (pixelFormat) { + case PixelFormat::ARGB_8888: + case PixelFormat::BGRA_8888: + case PixelFormat::RGBA_8888: + case PixelFormat::CMYK: + pixelBytes = ARGB8888_BYTES; + break; + case PixelFormat::ALPHA_8: + pixelBytes = ALPHA8_BYTES; + break; + case PixelFormat::RGB_888: + pixelBytes = RGB888_BYTES; + break; + case PixelFormat::RGB_565: + pixelBytes = RGB565_BYTES; + break; + case PixelFormat::RGBA_F16: + pixelBytes = RGBA_F16_BYTES; + break; + case PixelFormat::NV21: + case PixelFormat::NV12: + pixelBytes = NV21_BYTES; // perl pixel 1.5 Bytes but return int so return 2 + break; + default: + IMAGE_LOGE("[ImageUtil]get pixel bytes failed, pixelFormat:%{public}d.", static_cast(pixelFormat)); + break; + } + return pixelBytes; +} + +uint32_t ImageUtils::RegisterPluginServer() +{ +#ifdef _WIN32 + vector pluginPaths = { "" }; +#elif defined(_APPLE) + vector pluginPaths = { "./" }; +#else + vector pluginPaths = { "/system/etc/multimediaplugin/image" }; +#endif + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + uint32_t result = pluginServer.Register(std::move(pluginPaths)); + if (result != SUCCESS) { + IMAGE_LOGE("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result); + } else { + g_pluginRegistered = true; + IMAGE_LOGI("[ImageUtil]success to register plugin server"); + } + return result; +} + +PluginServer& ImageUtils::GetPluginServer() +{ + if (!g_pluginRegistered) { + uint32_t result = RegisterPluginServer(); + if (result != SUCCESS) { + IMAGE_LOGI("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result); + } + } + return DelayedRefSingleton::GetInstance(); +} + +bool ImageUtils::PathToRealPath(const string &path, string &realPath) +{ + if (path.empty()) { + IMAGE_LOGE("path is empty!"); + return false; + } + + if ((path.length() >= PATH_MAX)) { + IMAGE_LOGE("path len is error, the len is: [%{public}lu]", static_cast(path.length())); + return false; + } + + char tmpPath[PATH_MAX] = { 0 }; + +#ifdef _WIN32 + if (_fullpath(tmpPath, path.c_str(), path.length()) == nullptr) { + IMAGE_LOGW("path to _fullpath error"); + } +#else + if (realpath(path.c_str(), tmpPath) == nullptr) { + IMAGE_LOGE("path to realpath is nullptr"); + return false; + } +#endif + + realPath = tmpPath; + return true; +} + +bool ImageUtils::FloatCompareZero(float src) +{ + return fabs(src - 0) < EPSILON; +} + +AlphaType ImageUtils::GetValidAlphaTypeByFormat(const AlphaType &dstType, const PixelFormat &format) +{ + switch (format) { + case PixelFormat::RGBA_8888: + case PixelFormat::BGRA_8888: + case PixelFormat::ARGB_8888: + case PixelFormat::RGBA_F16: { + break; + } + case PixelFormat::ALPHA_8: { + if (dstType != AlphaType::IMAGE_ALPHA_TYPE_PREMUL) { + return AlphaType::IMAGE_ALPHA_TYPE_PREMUL; + } + break; + } + case PixelFormat::RGB_888: + case PixelFormat::RGB_565: { + if (dstType != AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) { + return AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + } + break; + } + case PixelFormat::NV21: + case PixelFormat::NV12: + case PixelFormat::CMYK: + default: { + HiLog::Error(LABEL, "GetValidAlphaTypeByFormat unsupport the format(%{public}d).", format); + return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; + } + } + return dstType; +} + +bool ImageUtils::IsValidImageInfo(const ImageInfo &info) +{ + if (info.size.width <= 0 || info.size.height <= 0 || info.size.width > MAX_DIMENSION || + info.size.height > MAX_DIMENSION) { + HiLog::Error(LABEL, "width(%{public}d) or height(%{public}d) is invalid.", info.size.width, info.size.height); + return false; + } + if (info.pixelFormat == PixelFormat::UNKNOWN || info.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) { + HiLog::Error(LABEL, "check pixelformat and alphatype is invalid."); + return false; + } + return true; +} + +bool ImageUtils::CheckMulOverflow(int32_t width, int32_t bytesPerPixel) +{ + if (width == 0 || bytesPerPixel == 0) { + HiLog::Error(LABEL, "para is 0"); + return true; + } + int64_t rowSize = static_cast(width) * bytesPerPixel; + if ((rowSize / width) != bytesPerPixel) { + HiLog::Error(LABEL, "width * bytesPerPixel overflow!"); + return true; + } + return false; +} + +bool ImageUtils::CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel) +{ + if (width == 0 || height == 0 || bytesPerPixel == 0) { + HiLog::Error(LABEL, "para is 0"); + return true; + } + int64_t rectSize = static_cast(width) * height; + if ((rectSize / width) != height) { + HiLog::Error(LABEL, "width * height overflow!"); + return true; + } + int64_t bufferSize = rectSize * bytesPerPixel; + if ((bufferSize / bytesPerPixel) != rectSize) { + HiLog::Error(LABEL, "bytesPerPixel overflow!"); + return true; + } + return false; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/jni/common/include/ohos_image_jni_utils.h b/frameworks/jni/common/include/ohos_image_jni_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..41700b506240ddf77eee0cfc290583e576c6cfa4 --- /dev/null +++ b/frameworks/jni/common/include/ohos_image_jni_utils.h @@ -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. + */ + +#ifndef OHOS_IMAGE_JNI_UTILS_H +#define OHOS_IMAGE_JNI_UTILS_H + +#include +#include "hilog/log.h" +#include "image_type.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "pixel_map.h" + +namespace OHOS { +namespace Media { +bool GetFieldId(JNIEnv *env, const std::string &className, const std::string ¶m, const std::string ¶mType, + jfieldID &fieldId); +bool GetFieldId(JNIEnv *env, jobject inObj, const std::string ¶m, const std::string ¶mType, jfieldID &fieldId); +bool GetObjectField(JNIEnv *env, jobject inObj, const std::string ¶m, const std::string ¶mType, + jobject &result); +bool GetFieldLongValue(JNIEnv *env, jobject inObj, const std::string ¶m, int64_t &result); +bool GetFieldIntValue(JNIEnv *env, jobject inObj, const std::string ¶m, int32_t &result); +bool GetFieldStringValue(JNIEnv *env, jobject inObj, const std::string ¶m, std::string &result); +bool GetFieldBooleanValue(JNIEnv *env, jobject inObj, const std::string ¶m, bool &result); +bool GetIntValByMethod(JNIEnv *env, jobject inObj, const std::string &methodName, int32_t &value); +bool GetSize(JNIEnv *env, jobject sizeObj, Size &size); +bool GetRect(JNIEnv *env, jobject rectObj, Rect &rect); +bool GetBufferPointer(JNIEnv *env, jobject jbuffer, jlong &pointer); +bool ThrowException(JNIEnv *env, const char *className, const char *msg); +bool ThrowImageException(JNIEnv *env, const char *msg); +bool ThrowIllegalArgumentException(JNIEnv *env, const char *msg); +bool ThrowIllegalStateException(JNIEnv *env, const char *msg); +void ThrowExceptionByErrorCode(JNIEnv *env, uint32_t errorCode); +} // namespace Media +} // namespace OHOS + +#endif // OHOS_IMAGE_JNI_UTILS_H diff --git a/frameworks/jni/common/src/ohos_image_jni_utils.cpp b/frameworks/jni/common/src/ohos_image_jni_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb60b725a3e09a7ae16a67ac67e9a3c549a1aef7 --- /dev/null +++ b/frameworks/jni/common/src/ohos_image_jni_utils.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ohos_image_jni_utils.h" + +#include +#include +#include "media_errors.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::HiviewDFX; + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "Image_Jni_Utils" }; +const std::map CODE_TO_EXCEPTION = { + { ERR_IMAGE_UNKNOWN_FORMAT, "ohos/media/image/SourceDataMalformedException" }, + { ERR_IMAGE_SOURCE_DATA_INCOMPLETE, "ohos/media/image/SourceDataIncompleteException" }, + { ERR_IMAGE_DECODE_FAILED, "ohos/media/image/SourceDataMalformedException" }, +#if defined(_WIN32) || defined(_APPLE) + { ERR_IMAGE_PLUGIN_CREATE_FAILED, "ohos/media/image/SourceDataMalformedException" }, +#endif +}; +const std::map CODE_TO_MESSAGE = { + { ERR_IMAGE_UNKNOWN_FORMAT, "image source data error or unknown format" }, + { ERR_IMAGE_SOURCE_DATA_INCOMPLETE, "image source data incomplete" }, + { ERR_IMAGE_DECODE_FAILED, "image decode failed" }, +#if defined(_WIN32) || defined(_APPLE) + { ERR_IMAGE_PLUGIN_CREATE_FAILED, "create plugin failed" }, +#endif +}; +} // namespace + +bool GetFieldId(JNIEnv *env, const std::string &className, const std::string ¶m, const std::string ¶mType, + jfieldID &fieldId) +{ + if (className.empty() || param.empty() || paramType.empty()) { + HiLog::Error(LABEL, "GetFieldId params invalid"); + return false; + } + + jclass clazz = env->FindClass(className.c_str()); + if (clazz == nullptr) { + HiLog::Error(LABEL, "GetFieldId fail, class: %{public}s not found", className.c_str()); + return false; + } + + fieldId = env->GetFieldID(clazz, param.c_str(), paramType.c_str()); + env->DeleteLocalRef(clazz); + if (fieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldId fail, param %{public}s %{public}s not found", param.c_str(), paramType.c_str()); + return false; + } + return true; +} + +bool GetFieldId(JNIEnv *env, jobject inObj, const std::string ¶m, const std::string ¶mType, jfieldID &fieldId) +{ + if (inObj == nullptr || param.empty() || paramType.empty()) { + HiLog::Error(LABEL, "GetJField params invalid"); + return false; + } + + jclass clazz = env->GetObjectClass(inObj); + if (clazz == nullptr) { + HiLog::Error(LABEL, "GetJField fail, inObj not found class"); + return false; + } + + fieldId = env->GetFieldID(clazz, param.c_str(), paramType.c_str()); + env->DeleteLocalRef(clazz); + if (fieldId == nullptr) { + HiLog::Error(LABEL, "GetJField fail, param %{public}s %{public}s not found", param.c_str(), paramType.c_str()); + return false; + } + return true; +} + +bool GetObjectField(JNIEnv *env, jobject inObj, const std::string ¶m, const std::string ¶mType, jobject &result) +{ + jfieldID fieldId; + if (GetFieldId(env, inObj, param, paramType, fieldId)) { + result = env->GetObjectField(inObj, fieldId); + return true; + } + return false; +} + +bool GetFieldLongValue(JNIEnv *env, jobject inObj, const std::string ¶m, int64_t &result) +{ + jfieldID fieldId; + if (GetFieldId(env, inObj, param, "J", fieldId)) { + result = env->GetLongField(inObj, fieldId); + return true; + } + return false; +} + +bool GetFieldIntValue(JNIEnv *env, jobject inObj, const std::string ¶m, int32_t &result) +{ + jfieldID fieldId; + if (GetFieldId(env, inObj, param, "I", fieldId)) { + result = env->GetIntField(inObj, fieldId); + return true; + } + return false; +} + +bool GetFieldStringValue(JNIEnv *env, jobject inObj, const std::string ¶m, std::string &result) +{ + jfieldID fieldId; + if (GetFieldId(env, inObj, param, "L/java/lang/String;", fieldId)) { + jstring strObj = reinterpret_cast(env->GetObjectField(inObj, fieldId)); + const char *strChars = env->GetStringUTFChars(strObj, nullptr); + if (strChars != nullptr) { + result = strChars; + env->ReleaseStringUTFChars(strObj, strChars); + } + return true; + } + return false; +} + +bool GetFieldBooleanValue(JNIEnv *env, jobject inObj, const std::string ¶m, bool &result) +{ + jfieldID fieldId; + if (GetFieldId(env, inObj, param, "Z", fieldId)) { + result = env->GetBooleanField(inObj, fieldId); + return true; + } + return false; +} + +bool GetSize(JNIEnv *env, jobject sizeObj, Size &size) +{ + if (sizeObj != nullptr) { + if (!GetFieldIntValue(env, sizeObj, "width", size.width) || + !GetFieldIntValue(env, sizeObj, "height", size.height)) { + HiLog::Error(LABEL, "get size value fail"); + return false; + } + } + HiLog::Debug(LABEL, "size width:%{public}d, height:%{public}d", size.width, size.height); + return true; +} + +bool GetRect(JNIEnv *env, jobject rectObj, Rect &rect) +{ + if (rectObj != nullptr) { + if (!GetFieldIntValue(env, rectObj, "minX", rect.left) || !GetFieldIntValue(env, rectObj, "minY", rect.top) || + !GetFieldIntValue(env, rectObj, "width", rect.width) || + !GetFieldIntValue(env, rectObj, "height", rect.height)) { + HiLog::Error(LABEL, "get rect value fail"); + return false; + } + } + HiLog::Debug(LABEL, "rect:[%{public}d, %{public}d, %{public}d, %{public}d]", rect.left, rect.top, rect.width, + rect.height); + return true; +} + +bool GetIntValByMethod(JNIEnv *env, jobject inObj, const std::string &methodName, int32_t &value) +{ + if (inObj == nullptr || methodName.empty()) { + HiLog::Error(LABEL, "GetIntValByMethod params invalid"); + return false; + } + jclass clazz = env->GetObjectClass(inObj); + if (clazz == nullptr) { + HiLog::Error(LABEL, "GetIntValByMethod fail, inObj not found class"); + return false; + } + jmethodID zMethodId = env->GetMethodID(clazz, methodName.c_str(), "()I"); + env->DeleteLocalRef(clazz); + if (zMethodId == nullptr) { + HiLog::Error(LABEL, "GetIntValByMethod fail, method: %{public}s not found.", methodName.c_str()); + return false; + } + value = env->CallIntMethod(inObj, zMethodId); + return true; +} + +bool GetBufferPointer(JNIEnv *env, jobject jbuffer, jlong &pointer) +{ + if (!GetFieldLongValue(env, jbuffer, "address", pointer)) { + HiLog::Error(LABEL, "GetNioBufferPointer get baseAddress fail."); + return false; + } + if (pointer != 0) { + int pos = 0; + if (!GetFieldIntValue(env, jbuffer, "position", pos)) { + HiLog::Error(LABEL, "GetNioBufferPointer get position fail."); + return false; + } + int shift = 0; + if (!GetFieldIntValue(env, jbuffer, "_elementSizeShift", shift)) { + HiLog::Error(LABEL, "GetNioBufferPointer get shift fail."); + return false; + } + pointer += static_cast(pos) << static_cast(shift); + } + return true; +} + +bool ThrowException(JNIEnv *env, const char *className, const char *msg) +{ + if ((className == nullptr) || (msg == nullptr)) { + HiLog::Error(LABEL, "ThrownException param invalid"); + return false; + } + jclass exceptionClass = env->FindClass(className); + if (exceptionClass == nullptr) { + HiLog::Error(LABEL, "FindClass(%{public}s) fail", className); + return false; + } + jint ret = env->ThrowNew(exceptionClass, msg); + env->DeleteLocalRef(exceptionClass); + return ret == 0; +} + +bool ThrowImageException(JNIEnv *env, const char *msg) +{ + return ThrowException(env, "ohos/media/image/ImageException", msg); +} + +bool ThrowIllegalArgumentException(JNIEnv *env, const char *msg) +{ + return ThrowException(env, "java/lang/IllegalArgumentException", msg); +} + +bool ThrowIllegalStateException(JNIEnv *env, const char *msg) +{ + return ThrowException(env, "java/lang/IllegalStateException", msg); +} + +bool ErrorCodeToException(JNIEnv *env, uint32_t errorCode, std::string &exception) +{ + auto iter = CODE_TO_EXCEPTION.find(errorCode); + if (iter == CODE_TO_EXCEPTION.end()) { + HiLog::Error(LABEL, "can not find error code in exception map"); + return false; + } + + exception = iter->second; + return true; +} + +bool ErrorCodeToMessage(JNIEnv *env, uint32_t errorCode, std::string &msg) +{ + auto iter = CODE_TO_MESSAGE.find(errorCode); + if (iter == CODE_TO_MESSAGE.end()) { + HiLog::Error(LABEL, "can not find error code in message map"); + return false; + } + + msg = iter->second; + return true; +} + +void ThrowExceptionByErrorCode(JNIEnv *env, uint32_t errorCode) +{ + if (errorCode == SUCCESS) { + HiLog::Debug(LABEL, "operation is success, no need to throw exception"); + return; + } + std::string exception; + if (!ErrorCodeToException(env, errorCode, exception)) { + HiLog::Error(LABEL, "can not find exception by error code"); + return; + } + + std::string msg; + if (!ErrorCodeToMessage(env, errorCode, msg)) { + HiLog::Error(LABEL, "can not find error msg by error code"); + return; + } + + if (!ThrowException(env, exception.c_str(), msg.c_str())) { + HiLog::Error(LABEL, "throw exception failed, exception:%{public}s, msg:%{public}s", exception.c_str(), + msg.c_str()); + return; + } + + HiLog::Debug(LABEL, "throw exception success, exception:%{public}s, msg:%{public}s", exception.c_str(), + msg.c_str()); +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/jni/imagepacker/BUILD.gn b/frameworks/jni/imagepacker/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a730314e856ca5d03f981e7a2733d030c7196ab5 --- /dev/null +++ b/frameworks/jni/imagepacker/BUILD.gn @@ -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("//build/ohos.gni") + +config("image_packer_jni_config") { + visibility = [ ":*" ] + include_dirs = [ + "//utils/native/base/include", + "//utils/jni/jnikit/include", + "//foundation/multimedia/image/frameworks/innerkitsimpl/codec/include", + "//foundation/multimedia/image/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/image/frameworks/innerkitsimpl/stream/include", + "//foundation/multimedia/image/interfaces/innerkits/include", + "//foundation/multimedia/image/plugins/manager/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image/frameworks/jni/common/include", + ] +} + +group("g_image_packer_jni") { + deps = [ ":image_packer_jni" ] +} + +ohos_shared_library("image_packer_jni") { + sources = [ + "//foundation/multimedia/image/frameworks/jni/common/src/ohos_image_jni_utils.cpp", + "src/ohos_image_ImagePacker.cpp", + ] + + configs = [ ":image_packer_jni_config" ] + + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image", + "//foundation/multimedia/image/plugins/manager:pluginmanager", + "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + + external_deps = [ "hilog:libhilog" ] + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/frameworks/jni/imagepacker/src/ohos_image_ImagePacker.cpp b/frameworks/jni/imagepacker/src/ohos_image_ImagePacker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddb9af00788af62cbb89c674dd42c5a1196c840e --- /dev/null +++ b/frameworks/jni/imagepacker/src/ohos_image_ImagePacker.cpp @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "ohos_image_jni_utils.h" +#include "hilog/log.h" +#include "image_packer_ex.h" +#include "image_source.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map_manager.h" + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImagePacker_JNI" }; +static std::mutex g_imageMutex; + +jobject ohos_media_image_ImagePacker_nativeCreateImagePacker(JNIEnv *env, jobject thiz) +{ + HiLog::Debug(LABEL, "nativeCreateImagePacker"); + std::lock_guard lg(g_imageMutex); + + jclass imageClazz = env->FindClass("ohos/media/image/ImagePacker"); + if (imageClazz == nullptr) { + HiLog::Error(LABEL, "find ImagePacker class fail"); + return nullptr; + } + + jmethodID constructorMethodID = env->GetMethodID(imageClazz, "", "(J)V"); + if (constructorMethodID == nullptr) { + HiLog::Error(LABEL, "find constructorMethod fail"); + env->DeleteLocalRef(imageClazz); + return nullptr; + } + + ImagePackerEx *imagePacker = new (std::nothrow) ImagePackerEx(); + if (imagePacker == nullptr) { + HiLog::Error(LABEL, "ImagePacker is nullptr"); + env->DeleteLocalRef(imageClazz); + return nullptr; + } + + jobject newImagePacker = env->NewObject(imageClazz, constructorMethodID, reinterpret_cast(imagePacker)); + env->DeleteLocalRef(imageClazz); + return newImagePacker; +} + +void ohos_media_image_ImagePacker_nativeRelease(JNIEnv *env, jobject thiz, jlong nativePtr) +{ + HiLog::Debug(LABEL, "nativeRelease begin"); + ImagePackerEx *imagePacker = reinterpret_cast(nativePtr); + if (imagePacker != nullptr) { + delete imagePacker; + imagePacker = nullptr; + } + HiLog::Debug(LABEL, "nativeRelease end"); +} + +static jobject ohos_media_image_ImagePacker_nativeGetSupportedFormats(JNIEnv *env, jobject thiz) +{ + std::set formats; + if (ImagePacker::GetSupportedFormats(formats) != SUCCESS) { + HiLog::Error(LABEL, "GetSupportedFormats is fail."); + return nullptr; + } + + jclass listClazz = env->FindClass("java/util/HashSet"); + if (listClazz == nullptr) { + HiLog::Error(LABEL, "HashSet class not find!"); + return nullptr; + } + + jmethodID listInit = env->GetMethodID(listClazz, "", "()V"); + if (listInit == nullptr) { + HiLog::Error(LABEL, "listInit not find!"); + env->DeleteLocalRef(listClazz); + return nullptr; + } + + jobject listObj = env->NewObject(listClazz, listInit, ""); + if (listObj == nullptr) { + HiLog::Error(LABEL, "listObj not find!"); + env->DeleteLocalRef(listClazz); + return nullptr; + } + jmethodID listAdd = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z"); + env->DeleteLocalRef(listClazz); + if (listAdd == nullptr) { + HiLog::Error(LABEL, "listInit not find!"); + env->DeleteLocalRef(listObj); + return nullptr; + } + std::set::iterator iter = formats.begin(); + while (iter != formats.end()) { + env->CallBooleanMethod(listObj, listAdd, env->NewStringUTF((*iter).c_str())); + ++iter; + } + return listObj; +} + +bool SetPackOption(JNIEnv *env, jobject option, PackOption &packOption) +{ + jclass packOptionClazz = env->GetObjectClass(option); + if (packOptionClazz == nullptr) { + HiLog::Error(LABEL, "packOptionClazz is null."); + return false; + } + jfieldID formatFileId = env->GetFieldID(packOptionClazz, "format", "Ljava/lang/String;"); + jfieldID qualityFileId = env->GetFieldID(packOptionClazz, "quality", "I"); + jfieldID numberHintFileId = env->GetFieldID(packOptionClazz, "numberHint", "I"); + env->DeleteLocalRef(packOptionClazz); + if (formatFileId == nullptr) { + HiLog::Error(LABEL, "formatFileId is null."); + return false; + } + if (qualityFileId == nullptr) { + HiLog::Error(LABEL, "qualityFileId is null."); + return false; + } + if (numberHintFileId == nullptr) { + HiLog::Error(LABEL, "numberHintFileId is null."); + return false; + } + jstring format = reinterpret_cast(env->GetObjectField(option, formatFileId)); + if (format == nullptr) { + HiLog::Error(LABEL, "nativeStartPacking format is null."); + return false; + } + const char *formatStr = env->GetStringUTFChars(format, nullptr); + if (formatStr == nullptr) { + HiLog::Error(LABEL, "format is invalid"); + return false; + } + packOption.format = formatStr; + packOption.quality = env->GetIntField(option, qualityFileId); + packOption.numberHint = env->GetIntField(option, numberHintFileId); + env->ReleaseStringUTFChars(format, formatStr); + return true; +} + +jint ohos_media_image_ImagePacker_nativeStartPackingByArray(JNIEnv *env, jobject thiz, jlong nativePtr, + jbyteArray data, jint offset, jobject option) +{ + if ((data == nullptr) || (option == nullptr)) { + HiLog::Error(LABEL, "nativeStartPackingByArray parameter is illegal."); + return ERR_IMAGE_INVALID_PARAMETER; + } + jsize size = env->GetArrayLength(data); + if (size == 0) { + HiLog::Error(LABEL, "nativeStartPackingByArray data size is zero."); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (offset < 0 || size - offset < 0) { + HiLog::Error(LABEL, "nativeStartPackingByArray offset %{public}d and size %{public}d invalid", offset, size); + return ERR_IMAGE_INVALID_PARAMETER; + } + + PackOption packOption; + if (!SetPackOption(env, option, packOption)) { + return ERR_IMAGE_INVALID_PARAMETER; + } + + ImagePackerEx *imgPacker = reinterpret_cast(nativePtr); + if (imgPacker == nullptr) { + HiLog::Error(LABEL, "nativeStartPackingByArray get image packer native obj is null."); + return ERR_IMAGE_INIT_ABNORMAL; + } + jbyte *dataBuf = env->GetByteArrayElements(data, nullptr); + jint errCode = imgPacker->StartPacking(reinterpret_cast(dataBuf) + offset, size - offset, packOption); + env->ReleaseByteArrayElements(data, dataBuf, 0); // Release dataBuf + return errCode; +} + +class OutputStreamWrapper : public PackerStream { +public: + OutputStreamWrapper(JNIEnv *env, jobject outputStream, jbyteArray buffer, jmethodID writeMethodId, + jmethodID flushMethodId) + : env_(env), + outputStream_(env->NewGlobalRef(outputStream)), + buffer_(reinterpret_cast(env->NewGlobalRef(buffer))), + bufferSize_(env->GetArrayLength(buffer)), + writeMethodId_(writeMethodId), + flushMethodId_(flushMethodId), + bytesWritten_(0) + {} + + ~OutputStreamWrapper() + { + if (outputStream_ != nullptr) { + env_->DeleteGlobalRef(outputStream_); + } + + if (buffer_ != nullptr) { + env_->DeleteGlobalRef(buffer_); + } + } + + virtual int64_t BytesWritten() + { + return bytesWritten_; + } + + virtual bool Write(const uint8_t *buffer, uint32_t size) + { + if (outputStream_ == nullptr || buffer_ == nullptr) { + HiLog::Error(LABEL, "Write outputStream or buffer is null, check constructor firstly."); + return false; + } + + int64_t wSize = size; + while (wSize > 0) { + jint needSize; + if (wSize > bufferSize_) { + needSize = bufferSize_; + } else { + needSize = static_cast(wSize); + } + + env_->SetByteArrayRegion(buffer_, 0, needSize, reinterpret_cast(buffer)); + if (env_->ExceptionCheck()) { + env_->ExceptionClear(); + HiLog::Error(LABEL, "set byte array elements throw exception"); + return false; + } + + env_->CallVoidMethod(outputStream_, writeMethodId_, buffer_, 0, needSize); + if (env_->ExceptionCheck()) { + env_->ExceptionClear(); + HiLog::Error(LABEL, "write throw exception."); + return false; + } + + buffer += needSize; + wSize -= needSize; + bytesWritten_ += needSize; + } + return true; + } + + virtual void Flush() + { + if (outputStream_ == nullptr) { + HiLog::Error(LABEL, "Flush outputStream is null, check constructor firstly."); + return; + } + env_->CallVoidMethod(outputStream_, flushMethodId_); + } + +private: + JNIEnv *env_; + jobject outputStream_; + jbyteArray buffer_; + jint bufferSize_; + jmethodID writeMethodId_; + jmethodID flushMethodId_; + int64_t bytesWritten_; +}; + +jint ohos_media_image_ImagePacker_nativeStartPackingByStream(JNIEnv *env, jobject thiz, jlong nativePtr, + jobject outputStream, jobject option, + jbyteArray tmpBuffer) +{ + if ((outputStream == nullptr) || (option == nullptr) || tmpBuffer == nullptr) { + HiLog::Error(LABEL, "nativeStartPackingByStream parameter is illegal."); + return ERR_IMAGE_INVALID_PARAMETER; + } + + PackOption packOption; + if (!SetPackOption(env, option, packOption)) { + return ERR_IMAGE_INVALID_PARAMETER; + } + + ImagePackerEx *imgPacker = reinterpret_cast(nativePtr); + if (imgPacker == nullptr) { + HiLog::Error(LABEL, "nativeStartPackingByStream get image packer native obj is null."); + return ERR_IMAGE_INIT_ABNORMAL; + } + + jclass outputStreamClazz = env->GetObjectClass(outputStream); + if (outputStreamClazz == nullptr) { + HiLog::Error(LABEL, "nativeStartPackingByStream class(java/io/OutputStream) not found."); + return ERR_IMAGE_INVALID_PARAMETER; + } + + jmethodID writeMethodId = env->GetMethodID(outputStreamClazz, "write", "([BII)V"); + jmethodID flushMethodId = env->GetMethodID(outputStreamClazz, "flush", "()V"); + env->DeleteLocalRef(outputStreamClazz); + if (writeMethodId == nullptr || flushMethodId == nullptr) { + HiLog::Error(LABEL, "nativeStartPackingByStream java/io/OutputStream write or flush method not found."); + return ERR_IMAGE_INVALID_PARAMETER; + } + + // ImagePacker manage the outputWrapper lifecycle + PackerStream *outputWrapper = + new (std::nothrow) OutputStreamWrapper(env, outputStream, tmpBuffer, writeMethodId, flushMethodId); + if (outputWrapper == nullptr) { + HiLog::Error(LABEL, "nativeStartPackingByStream by outputStream, new bytearray fail."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + return imgPacker->StartPacking(*outputWrapper, packOption); +} + +jint ohos_media_image_ImagePacker_nativeAddImage(JNIEnv *env, jobject thiz, jlong nativePtr, jobject pixelmap) +{ + if (pixelmap == nullptr) { + HiLog::Error(LABEL, "nativeAddImage parameter is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + jclass pixelMapClazz = env->GetObjectClass(pixelmap); + if (pixelMapClazz == nullptr) { + HiLog::Error(LABEL, "GetNativePixelMap, PixelMap class not found."); + return ERR_IMAGE_INVALID_PARAMETER; + } + jfieldID pixelMapFileId = env->GetFieldID(pixelMapClazz, "nativeImagePixelMap", "J"); + env->DeleteLocalRef(pixelMapClazz); + if (pixelMapFileId == nullptr) { + HiLog::Error(LABEL, "get nativeImagePixelMap error."); + return ERR_IMAGE_INVALID_PARAMETER; + } + jlong pixelMapPtr = env->GetLongField(pixelmap, pixelMapFileId); + PixelMapManager *pixelMapManager = reinterpret_cast(pixelMapPtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "GetNativePixelMap pixel map is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + ImagePackerEx *imgPacker = reinterpret_cast(nativePtr); + if (imgPacker == nullptr) { + HiLog::Error(LABEL, "get image packer native obj is null."); + return ERR_IMAGE_INIT_ABNORMAL; + } + return imgPacker->AddImage(pixelMapManager->GetPixelMap()); +} + +jint ohos_media_image_ImagePacker_nativeAddIndexImageFormSource(JNIEnv *env, jobject thiz, jlong nativePtr, + jobject source, jint index) +{ + jclass sourceClazz = env->GetObjectClass(source); + if (sourceClazz == nullptr) { + HiLog::Error(LABEL, "sourceClazz is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + jfieldID sourceFileId = env->GetFieldID(sourceClazz, "nativeImageSource", "J"); + if (sourceFileId == nullptr) { + HiLog::Error(LABEL, "sourceFileId is null."); + env->DeleteLocalRef(sourceClazz); + return ERR_IMAGE_INVALID_PARAMETER; + } + env->DeleteLocalRef(sourceClazz); + jlong sourcePtr = env->GetLongField(source, sourceFileId); + ImageSource *imgSource = reinterpret_cast(sourcePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "get image source native obj is null."); + return ERR_IMAGE_INIT_ABNORMAL; + } + ImagePackerEx *imgPacker = reinterpret_cast(nativePtr); + if (imgPacker == nullptr) { + HiLog::Error(LABEL, "get image packer native obj is null."); + return ERR_IMAGE_INIT_ABNORMAL; + } + return imgPacker->AddImage(*imgSource, index); +} + +jint ohos_media_image_ImagePacker_nativeAddImageFormSource(JNIEnv *env, jobject thiz, jlong nativePtr, + jobject source) +{ + return ohos_media_image_ImagePacker_nativeAddIndexImageFormSource(env, thiz, nativePtr, source, 0); +} + +jlong ohos_media_image_ImagePacker_nativeFinalizePacking(JNIEnv *env, jobject thiz, jlong nativePtr) +{ + ImagePackerEx *imgPacker = reinterpret_cast(nativePtr); + if (imgPacker == nullptr) { + HiLog::Error(LABEL, "get image packer native obj is null."); + return -1L; + } + int64_t bytes = 0; + uint32_t errorCode = imgPacker->FinalizePacking(bytes); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "FinalizePacking fail: %{public}u.", errorCode); + return -1L; + } + HiLog::Debug(LABEL, "FinalizePacking write %{public}lld bytes.", static_cast(bytes)); + jlong ret{ bytes }; + return ret; +} + +static const JNINativeMethod METHODS[] = { + { "nativeGetSupportedFormats", "()Ljava/util/HashSet;", + reinterpret_cast(ohos_media_image_ImagePacker_nativeGetSupportedFormats) }, + { "nativeStartPacking", "(J[BILohos/media/image/ImagePacker$PackingOptions;)I", + reinterpret_cast(ohos_media_image_ImagePacker_nativeStartPackingByArray) }, + { "nativeStartPacking", "(JLjava/io/OutputStream;Lohos/media/image/ImagePacker$PackingOptions;[B)I", + reinterpret_cast(ohos_media_image_ImagePacker_nativeStartPackingByStream) }, + { "nativeAddImage", "(JLohos/media/image/PixelMap;)I", + reinterpret_cast(ohos_media_image_ImagePacker_nativeAddImage) }, + { "nativeAddImage", "(JLohos/media/image/ImageSource;)I", + reinterpret_cast(ohos_media_image_ImagePacker_nativeAddImageFormSource) }, + { "nativeAddImage", "(JLohos/media/image/ImageSource;I)I", + reinterpret_cast(ohos_media_image_ImagePacker_nativeAddIndexImageFormSource) }, + { "nativeFinalizePacking", "(J)J", + reinterpret_cast(ohos_media_image_ImagePacker_nativeFinalizePacking) }, + { "nativeCreateImagePacker", "()Lohos/media/image/ImagePacker;", + reinterpret_cast(ohos_media_image_ImagePacker_nativeCreateImagePacker) }, + { "nativeRelease", "(J)V", reinterpret_cast(ohos_media_image_ImagePacker_nativeRelease) }, +}; + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + HiLog::Debug(LABEL, "JNI_OnLoad begin"); + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + HiLog::Error(LABEL, "JNI_OnLoad: GetEnv failed"); + return ERROR; + } + int ret = JkitRegisterNativeMethods(env, "ohos/media/image/ImagePacker", METHODS, ARRCOUNT(METHODS)); + if (ret == JNI_ERR) { + HiLog::Error(LABEL, "JkitRegisterNativeMethods failed, ret=%{public}d", ret); + return ERROR; + } + Jkit::nativeInit(vm); + HiLog::Debug(LABEL, "JNI_OnLoad end"); + return JNI_VERSION_1_4; +} diff --git a/frameworks/jni/imagereceiver/BUILD.gn b/frameworks/jni/imagereceiver/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7ff4b2200f54d8bb1076f74a106f7efba1beffd5 --- /dev/null +++ b/frameworks/jni/imagereceiver/BUILD.gn @@ -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("//build/ohos.gni") + +config("imagereceiver_jni_config") { + visibility = [ ":*" ] + include_dirs = [ + "//utils/native/base/include", + "//utils/jni/jnikit/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image/interfaces/innerkits/include", + ] +} + +ohos_shared_library("imagereceiver_jni") { + sources = [ "src/ohos_image_ImageReceiver.cpp" ] + + configs = [ ":imagereceiver_jni_config" ] + + deps = [ + "//foundation/multimedia/image/adapter/frameworks/receiver:imagereceiver_adapter", + "//foundation/multimedia/image/interfaces/innerkits:image", + "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + + external_deps = [ "hilog:libhilog" ] + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/frameworks/jni/imagereceiver/src/ohos_image_ImageReceiver.cpp b/frameworks/jni/imagereceiver/src/ohos_image_ImageReceiver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6d8f9b00f2d5fa270c36bee90e55651dfdecbc9 --- /dev/null +++ b/frameworks/jni/imagereceiver/src/ohos_image_ImageReceiver.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_receiver_adapter.h" + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageReceiver_JNI" }; + +void ohos_media_image_ImageReceiver_nativeInit(JNIEnv *env, jobject thiz, jobject weakThiz, jint width, + jint height, jint format, jint capacity, jlong usage) +{ + HiLog::Debug(LABEL, "nativeInit begin."); + ImageReceiverAdapter::InitImageReceiverContext(env, thiz, weakThiz, width, height, format, capacity, usage); + HiLog::Debug(LABEL, "nativeInit end."); +} + +jboolean ohos_media_image_ImageReceiver_nativeReadNext(JNIEnv *env, jobject thiz, jobject image) +{ + HiLog::Debug(LABEL, "nativeReadNext begin."); + jboolean result = ImageReceiverAdapter::ReadNextImage(env, thiz, image); + HiLog::Debug(LABEL, "nativeReadNext end."); + return result; +} + +void ohos_media_image_ImageReceiver_nativeReleaseFreeBuffers(JNIEnv *env, jobject thiz) +{ + HiLog::Debug(LABEL, "nativeReleaseFreeBuffers begin."); + ImageReceiverAdapter::ReleaseFreeBuffers(env, thiz); + HiLog::Debug(LABEL, "nativeReleaseFreeBuffers end."); +} + +void ohos_media_image_ImageReceiver_nativeRelease(JNIEnv *env, jobject thiz) +{ + HiLog::Debug(LABEL, "nativeRelease begin."); + ImageReceiverAdapter::ReleaseReceiver(env, thiz); + HiLog::Debug(LABEL, "nativeRelease end."); +} + +void ohos_media_image_ImageReceiver_nativeCacheClass(JNIEnv *env, jclass clazz) +{ + HiLog::Debug(LABEL, "ImageReceiver nativeCacheClass begin."); + ImageReceiverAdapter::CacheActiveClass(env, clazz); + HiLog::Debug(LABEL, "ImageReceiver nativeCacheClass end."); +} + +jobject ohos_media_image_ImageReceiver_nativeGetReceiverSurface(JNIEnv *env, jobject thiz) +{ + HiLog::Debug(LABEL, "nativeGetReceiverSurface begin."); + jobject result = ImageReceiverAdapter::GetSurface(env, thiz); + ImageReceiverUtils::LogWhenNull(result, "get native surface is null."); + HiLog::Debug(LABEL, "nativeGetReceiverSurface end."); + return result; +} + +jint ohos_media_image_Image_nativeGetFormat(JNIEnv *env, jobject thiz, jint receiverFormat) +{ + HiLog::Debug(LABEL, "nativeGetFormat begin."); + jint result = ImageReceiverAdapter::GetFormat(env, thiz, receiverFormat); + HiLog::Debug(LABEL, "nativeGetFormat end."); + return result; +} + +jobject ohos_media_image_Image_nativeGetSize(JNIEnv *env, jclass thiz) +{ + HiLog::Debug(LABEL, "nativeGetSize begin."); + Size size = ImageReceiverAdapter::GetSize(env, thiz); + jclass sizeClazz = env->FindClass("ohos/media/image/common/Size"); + if (ImageReceiverUtils::LogWhenNull(sizeClazz, "can't find Size class.")) { + return nullptr; + } + jmethodID sizeConstructor = env->GetMethodID(sizeClazz, "", "(II)V"); + if (ImageReceiverUtils::LogWhenNull(sizeConstructor, "can't find sizeConstructor.")) { + env->DeleteLocalRef(sizeClazz); + return nullptr; + } + jobject sizeObj = env->NewObject(sizeClazz, sizeConstructor, size.width, size.width); + env->DeleteLocalRef(sizeClazz); + HiLog::Debug(LABEL, "nativeGetSize end."); + return sizeObj; +} + +jobjectArray ohos_media_image_Image_nativeGetComponents(JNIEnv *env, jobject thiz, jint componentNum, + jint receiverFormat) +{ + HiLog::Debug(LABEL, "nativeGetComponents begin."); + jobjectArray result = ImageReceiverAdapter::GetComponents(env, thiz, componentNum, receiverFormat); + HiLog::Debug(LABEL, "nativeGetComponents end."); + return result; +} + +void ohos_media_image_Image_nativeReleaseImage(JNIEnv *env, jobject thiz, jobject imageReceiver) +{ + HiLog::Debug(LABEL, "nativeReleaseImage begin."); + ImageReceiverAdapter::ReleaseImage(env, thiz, imageReceiver); + HiLog::Debug(LABEL, "nativeReleaseImage end."); +} + +static const JNINativeMethod RECEIVER_METHODS[] = { + { "nativeInit", "(Ljava/lang/Object;IIIIJ)V", + reinterpret_cast(ohos_media_image_ImageReceiver_nativeInit) }, + { "nativeReadNext", "(Lohos/media/image/Image;)Z", + reinterpret_cast(ohos_media_image_ImageReceiver_nativeReadNext) }, + { "nativeRelease", "()V", reinterpret_cast(ohos_media_image_ImageReceiver_nativeRelease) }, + { "nativeReleaseFreeBuffers", "()V", + reinterpret_cast(ohos_media_image_ImageReceiver_nativeReleaseFreeBuffers) }, + { "nativeCacheClass", "()V", reinterpret_cast(ohos_media_image_ImageReceiver_nativeCacheClass) }, + { "nativeGetReceiverSurface", "()Lohos/agp/graphics/Surface;", + reinterpret_cast(ohos_media_image_ImageReceiver_nativeGetReceiverSurface) } +}; + +static const JNINativeMethod IMAGE_METHODS[] = { + { "nativeGetFormat", "(I)I", reinterpret_cast(ohos_media_image_Image_nativeGetFormat) }, + { "nativeGetSize", "()Lohos/media/image/common/Size;", + reinterpret_cast(ohos_media_image_Image_nativeGetSize) }, + { "nativeGetComponents", "(II)[Lohos/media/image/Image$Component;", + reinterpret_cast(ohos_media_image_Image_nativeGetComponents) }, + { "nativeReleaseImage", "(Lohos/media/image/ImageReceiver;)V", + reinterpret_cast(ohos_media_image_Image_nativeReleaseImage) }, +}; + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + HiLog::Debug(LABEL, "JNI_OnLoad begin"); + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + HiLog::Error(LABEL, "JNI_OnLoad: GetEnv failed"); + return ERROR; + } + + int32_t receiveRet = JkitRegisterNativeMethods(env, "ohos/media/image/ImageReceiver", RECEIVER_METHODS, + ARRCOUNT(RECEIVER_METHODS)); + int32_t imageRet = + JkitRegisterNativeMethods(env, "ohos/media/image/Image", IMAGE_METHODS, ARRCOUNT(IMAGE_METHODS)); + if (receiveRet == JNI_ERR || imageRet == JNI_ERR) { + HiLog::Error(LABEL, "JkitRegisterNativeMethods failed, receiveRet = %{public}d, imageRet = %{public}d", + receiveRet, imageRet); + return ERROR; + } + Jkit::nativeInit(vm); + HiLog::Debug(LABEL, "JNI_OnLoad end"); + return JNI_VERSION_1_4; +} \ No newline at end of file diff --git a/frameworks/jni/imagesource/BUILD.gn b/frameworks/jni/imagesource/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..6343e00694f9aac2727444c60e3011e4e9c71778 --- /dev/null +++ b/frameworks/jni/imagesource/BUILD.gn @@ -0,0 +1,89 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image/ide/image_decode_config.gni") + +config("image_source_jni_config") { + visibility = [ ":*" ] + include_dirs = [ + "//utils/jni/jnikit/include", + "//foundation/multimedia/image/frameworks/innerkitsimpl/codec/include", + "//foundation/multimedia/image/interfaces/innerkits/include", + "//foundation/multimedia/image/plugins/manager/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image/frameworks/jni/common/include", + "//foundation/multimedia/image/frameworks/jni/imagesource/include", + ] + if (use_mingw_win) { + include_dirs += [ + "//foundation/multimedia/image/mock/native/include", + #"//foundation/multimedia/image/mock/native/include/secure", + ] + } else if (use_clang_mac) { + include_dirs += [ + "//foundation/multimedia/image/mock/native/include", + "//utils/native/base/include", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + } +} + +group("g_image_source_jni") { + deps = [ ":image_source_jni" ] +} + +ohos_shared_library("image_source_jni") { + sources = [ + "//foundation/multimedia/image/frameworks/jni/common/src/ohos_image_jni_utils.cpp", + "src/jni_decode_event_listener.cpp", + "src/ohos_image_ImageSource.cpp", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + configs = [ ":image_source_jni_config" ] + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image_static", + "//foundation/multimedia/image/mock/native:log_mock_static", + "//foundation/multimedia/image/plugins/manager:pluginmanager_static", + "//utils/jni:utils_jnikit_win", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + configs = [ ":image_source_jni_config" ] + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image_static", + "//foundation/multimedia/image/mock/native:log_mock_static", + "//foundation/multimedia/image/plugins/manager:pluginmanager_static", + "//utils/jni:utils_jnikit_mac", + "//utils/native/base:utilsecurec", + ] + } else { + configs = [ ":image_source_jni_config" ] + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image", + "//foundation/multimedia/image/plugins/manager:pluginmanager", + "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + external_deps = [ + "hicollie:libhicollie", + "hilog:libhilog", + ] + } + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/frameworks/jni/imagesource/include/jni_decode_event_listener.h b/frameworks/jni/imagesource/include/jni_decode_event_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..0194cf2cc0a7ec021e6578b9647a9bec4d8e6c4a --- /dev/null +++ b/frameworks/jni/imagesource/include/jni_decode_event_listener.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef JNI_DECODE_EVENT_LISTENER_H +#define JNI_DECODE_EVENT_LISTENER_H + +#include +#include + +class JniDecodeEventListener : public OHOS::Media::DecodeListener { +public: + JniDecodeEventListener(JNIEnv* env, jobject thiz, jmethodID postEventFromNative); + ~JniDecodeEventListener(); + virtual void OnEvent(int event); + +private: + JNIEnv* getJNIEnv(); + JavaVM* mJavaVM; + jobject mObject; // ref to ImageSource Java object to call on + jmethodID mPostEventFromNative; // postEventFromNative method ID. +}; + +#endif // JNI_DECODE_EVENT_LISTENER_H diff --git a/frameworks/jni/imagesource/src/jni_decode_event_listener.cpp b/frameworks/jni/imagesource/src/jni_decode_event_listener.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbacfc19e19405492f599e12d606670392c81038 --- /dev/null +++ b/frameworks/jni/imagesource/src/jni_decode_event_listener.cpp @@ -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. + */ + + +#include "jni_decode_event_listener.h" +#include "ohos_image_jni_utils.h" +#include "hilog/log.h" + +using namespace OHOS::HiviewDFX; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "JniDecodeEventListener" }; + +JniDecodeEventListener::JniDecodeEventListener(JNIEnv* env, jobject thiz, jmethodID postEventFromNative) +{ + HiLog::Debug(LABEL, "%{public}s", __FUNCTION__); + + env->GetJavaVM(&mJavaVM); + + // We use a weak reference so the ImageSource object can be garbage collected. + // The reference is only used as a proxy for callbacks. + mObject = env->NewGlobalRef(thiz); + + mPostEventFromNative = postEventFromNative; +} + +JNIEnv* JniDecodeEventListener::getJNIEnv() +{ + JNIEnv* env = nullptr; + mJavaVM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4); + return env; +} + +JniDecodeEventListener::~JniDecodeEventListener() +{ + HiLog::Debug(LABEL, "%{public}s", __FUNCTION__); + + // remove global references + JNIEnv *env = getJNIEnv(); + if (env == nullptr) { + return; + } + env->DeleteGlobalRef(mObject); +} + +void JniDecodeEventListener::OnEvent(int event) +{ + JNIEnv *env = getJNIEnv(); + if (env == nullptr) { + HiLog::Error(LABEL, "env is null"); + return; + } + + HiLog::Debug(LABEL, "%{public}s event %{public}d", __FUNCTION__, event); + if (mPostEventFromNative == nullptr) { + HiLog::Error(LABEL, "JniDecodeEventListener: mPostEventFromNative is null."); + return; + } + + env->CallVoidMethod(mObject, mPostEventFromNative, mObject, jint(event)); + if (env->ExceptionCheck()) { + HiLog::Error(LABEL, "An exception occurred while notifying an event."); + env->ExceptionClear(); + } +} diff --git a/frameworks/jni/imagesource/src/ohos_image_ImageSource.cpp b/frameworks/jni/imagesource/src/ohos_image_ImageSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d357ef2c3a032cc21beafc9402b9f9adc150ac94 --- /dev/null +++ b/frameworks/jni/imagesource/src/ohos_image_ImageSource.cpp @@ -0,0 +1,1186 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "ohos_image_jni_utils.h" +#include "hilog/log.h" +#include "image_source.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map_manager.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif +#include "jni_decode_event_listener.h" +#ifdef _WIN32 +#include +#endif +#if !defined(_WIN32) && !defined(_APPLE) +#include "xcollie/xcollie.h" +#endif + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImageSource_JNI" }; +static jclass g_imageSourceClass; +static jmethodID g_imageSourceConstructMethodId; +static jmethodID g_imageSourcePostFromNativeMethodId; +static std::unique_ptr g_decodeEventListener; +static jclass g_pixelMapClass; +static jmethodID g_pixelMapCtorMethodId; +static jmethodID g_setBaseDensityMethodId; +static jclass g_allocatorClass; +static jclass g_pixelFormatClass; +static jclass g_colorSpaceClass; + +// DecodingOptions fields +static jfieldID g_optionsFitDensityFieldId; +static jfieldID g_optionsAllocatorFieldId; +static jfieldID g_optionsRectFieldId; +static jfieldID g_optionsSizeFieldId; +static jfieldID g_optionsRotateDegreesFieldId; +static jfieldID g_optionsSampleSizeFieldId; +static jfieldID g_optionsPixelFormatFieldId; +static jfieldID g_optionsColorSpaceFieldId; +static jfieldID g_optionsAllowPartialImageFieldId; +static jfieldID g_optionsEditableFieldId; + +static inline void PixelFormatToNative(PixelFormat &pixelFormat) +{ + if (pixelFormat == PixelFormat::ARGB_8888) { + pixelFormat = PixelFormat::RGBA_8888; + } +} + +static bool InitImageSource(JNIEnv *env) +{ + jclass imageClazz = env->FindClass("ohos/media/image/ImageSource"); + if (imageClazz == nullptr) { + HiLog::Error(LABEL, "find ImageSource class fail"); + return false; + } + g_imageSourceClass = static_cast(env->NewGlobalRef(imageClazz)); + g_imageSourceConstructMethodId = env->GetMethodID(g_imageSourceClass, "", "(J)V"); + g_imageSourcePostFromNativeMethodId = env->GetMethodID(g_imageSourceClass, "postEventFromNative", + "(Lohos/media/image/ImageSource;I)V"); + env->DeleteLocalRef(imageClazz); + return true; +} + +static bool CheckInitDecodeOption2(JNIEnv *env, jclass decodOptionClazz) +{ + if (decodOptionClazz == nullptr) { + HiLog::Error(LABEL, "find DecodeOption class fail"); + return false; + } + g_optionsPixelFormatFieldId = env->GetFieldID(decodOptionClazz, "desiredPixelFormat", + "Lohos/media/image/common/PixelFormat;"); + if (g_optionsPixelFormatFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID desiredPixelFormat not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + return true; +} + +static bool InitPixelMap(JNIEnv *env) +{ + jclass pixelMapClazz = env->FindClass("ohos/media/image/PixelMap"); + if (pixelMapClazz == nullptr) { + HiLog::Error(LABEL, "CreatePixelmap fail, not found PixelMap class."); + return false; + } + g_pixelMapClass = static_cast(env->NewGlobalRef(pixelMapClazz)); + g_pixelMapCtorMethodId = env->GetMethodID(pixelMapClazz, "", "(JJ[B)V"); + if (g_pixelMapCtorMethodId == nullptr) { + env->DeleteLocalRef(pixelMapClazz); + HiLog::Error(LABEL, "InitPixelMapId fail, PixelMap construction method not found."); + return false; + } + g_setBaseDensityMethodId = env->GetMethodID(pixelMapClazz, "setBaseDensity", "(I)V"); + if (g_setBaseDensityMethodId == nullptr) { + env->DeleteLocalRef(pixelMapClazz); + HiLog::Error(LABEL, "InitPixelMapId fail, PixelMap setBaseDensity method not found."); + return false; + } + env->DeleteLocalRef(pixelMapClazz); + return true; +} + +static bool InitDecodeOption(JNIEnv *env) +{ + jclass decodOptionClazz = env->FindClass("ohos/media/image/ImageSource$DecodingOptions"); + if (decodOptionClazz == nullptr) { + HiLog::Error(LABEL, "find DecodeOption class fail"); + return false; + } + g_optionsFitDensityFieldId = env->GetFieldID(decodOptionClazz, "fitDensity", "I"); + if (g_optionsFitDensityFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID fail, fitDensity not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsAllocatorFieldId = env->GetFieldID(decodOptionClazz, "allocator", + "Lohos/media/image/common/AllocatorType;"); + if (g_optionsAllocatorFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID allocator not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsRectFieldId = env->GetFieldID(decodOptionClazz, "desiredRegion", + "Lohos/media/image/common/Rect;"); + if (g_optionsRectFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID fail, fitDensity not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsSizeFieldId = env->GetFieldID(decodOptionClazz, "desiredSize", + "Lohos/media/image/common/Size;"); + if (g_optionsSizeFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID fail, fitDensity not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsRotateDegreesFieldId = env->GetFieldID(decodOptionClazz, "rotateDegrees", "F"); + if (g_optionsRotateDegreesFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID fail, rotateDegrees not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsSampleSizeFieldId = env->GetFieldID(decodOptionClazz, "sampleSize", "I"); + if (g_optionsSampleSizeFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID fail, sampleSize not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + env->DeleteLocalRef(decodOptionClazz); + return true; +} + +static bool InitDecodeOption2(JNIEnv *env) +{ + jclass decodOptionClazz = env->FindClass("ohos/media/image/ImageSource$DecodingOptions"); + if (CheckInitDecodeOption2(env, decodOptionClazz) != true) { + return false; + } + g_optionsColorSpaceFieldId = env->GetFieldID(decodOptionClazz, "desiredColorSpace", + "Lohos/media/image/common/ColorSpace;"); + if (g_optionsColorSpaceFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID allocator not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsAllowPartialImageFieldId = env->GetFieldID(decodOptionClazz, "allowPartialImage", "Z"); + if (g_optionsAllowPartialImageFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID allowPartialImage not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + g_optionsEditableFieldId = env->GetFieldID(decodOptionClazz, "editable", "Z"); + if (g_optionsEditableFieldId == nullptr) { + HiLog::Error(LABEL, "GetFieldID editable not found."); + env->DeleteLocalRef(decodOptionClazz); + return false; + } + jclass allocatorClazz = env->FindClass("ohos/media/image/common/AllocatorType"); + if (allocatorClazz == nullptr) { + HiLog::Error(LABEL, "FindClass AllocatorType not found."); + return false; + } + g_allocatorClass = static_cast(env->NewGlobalRef(allocatorClazz)); + env->DeleteLocalRef(allocatorClazz); + jclass pixelFormatClazz = env->FindClass("ohos/media/image/common/PixelFormat"); + if (pixelFormatClazz == nullptr) { + HiLog::Error(LABEL, "FindClass PixelFormat not found."); + return false; + } + g_pixelFormatClass = static_cast(env->NewGlobalRef(pixelFormatClazz)); + env->DeleteLocalRef(pixelFormatClazz); + jclass colorClazz = env->FindClass("ohos/media/image/common/ColorSpace"); + if (colorClazz == nullptr) { + HiLog::Error(LABEL, "FindClass ColorSpace not found."); + return false; + } + g_colorSpaceClass = static_cast(env->NewGlobalRef(colorClazz)); + env->DeleteLocalRef(colorClazz); + env->DeleteLocalRef(decodOptionClazz); + return true; +} + +void ohos_media_image_ImageSource_nativeInit(JNIEnv *env, jclass thiz) +{ + HiLog::Debug(LABEL, "nativeInit begin"); + if (!InitImageSource(env)) { + HiLog::Error(LABEL, "nativeInit InitImageSource failed"); + return; + } + if (!InitPixelMap(env)) { + HiLog::Error(LABEL, "nativeInit InitPixelMap failed"); + return; + } + if (!InitDecodeOption(env)) { + HiLog::Error(LABEL, "nativeInit InitDecodeOption failed"); + return; + } + if (!InitDecodeOption2(env)) { + HiLog::Error(LABEL, "nativeInit InitDecodeOption2 failed"); + return; + } + HiLog::Debug(LABEL, "nativeInit end"); +} + +jobject GetObject(JNIEnv *env, jobject inObj, const std::string &className, const std::string ¶, + const std::string &type) +{ + if (inObj == nullptr) { + HiLog::Error(LABEL, "GetObject para obj is null."); + return nullptr; + } + jfieldID zFieldId; + bool isSuccess = GetFieldId(env, className, para, type, zFieldId); + if (!isSuccess) { + HiLog::Error(LABEL, "GetObject fail, para: %{public}s, type: %{public}s not found.", para.c_str(), + type.c_str()); + return nullptr; + } + if (zFieldId == nullptr) { + HiLog::Error(LABEL, "zFieldId is null."); + return nullptr; + } + jobject outValue = env->GetObjectField(inObj, zFieldId); + return outValue; +} + +bool GetIntValue(JNIEnv *env, jobject inObj, const std::string &className, const std::string ¶, jint &value) +{ + if (inObj == nullptr) { + HiLog::Error(LABEL, "GetIntValue para obj is null."); + return false; + } + jfieldID zFieldId; + bool isSuccess = GetFieldId(env, className, para, "I", zFieldId); + if (!isSuccess) { + HiLog::Error(LABEL, "GetIntValue fail, para: %{public}s.", para.c_str()); + return false; + } + value = env->GetIntField(inObj, zFieldId); + return true; +} + +bool GetStringValue(JNIEnv *env, jobject inObj, const std::string &className, const std::string ¶, jstring &value) +{ + if (inObj == nullptr) { + HiLog::Error(LABEL, "GetStringValue para obj is null."); + return false; + } + jfieldID zFieldId; + bool isSuccess = GetFieldId(env, className, para, "L/java/lang/String;", zFieldId); + if (!isSuccess) { + HiLog::Error(LABEL, "GetStringValue fail, para: %{public}s.", para.c_str()); + return false; + } + if (zFieldId == nullptr) { + HiLog::Error(LABEL, "GetStringValue fail, zMethodId is null"); + return false; + } + value = reinterpret_cast(env->GetObjectField(inObj, zFieldId)); + return true; +} + +bool ReadInputStreamToBytesArray(JNIEnv *env, jobject inObj, jbyteArray buf, jint &value) +{ + if (inObj == nullptr) { + HiLog::Error(LABEL, "ReadInputStreamToBytesArray : obj is null."); + return false; + } + + if (buf == nullptr) { + HiLog::Error(LABEL, "ReadInputStreamToBytesArray : buf is null."); + return false; + } + + jclass zClazz = env->GetObjectClass(inObj); + if (zClazz == nullptr) { + HiLog::Error(LABEL, "ReadInputStreamToBytesArray class(java/io/InputStream) not found."); + return false; + } + jmethodID zMethodId = env->GetMethodID(zClazz, "read", "([B)I"); + env->DeleteLocalRef(zClazz); + if (zMethodId == nullptr) { + HiLog::Error(LABEL, "ReadInputStreamToBytesArray fail, method: read not found."); + return false; + } + value = env->CallIntMethod(inObj, zMethodId, buf); + return true; +} + +static jobject ohos_media_image_ImageSource_nativeGetSupportedFormats(JNIEnv *env, jobject thiz) +{ + std::set formats; + if (ImageSource::GetSupportedFormats(formats) != SUCCESS) { + HiLog::Error(LABEL, "GetSupportedFormats is fail."); + return nullptr; + } + + jclass listClazz = env->FindClass("java/util/HashSet"); + if (listClazz == nullptr) { + HiLog::Error(LABEL, "nativeGetSupportedFormats HashSet class not find!"); + return nullptr; + } + + jmethodID listInit = env->GetMethodID(listClazz, "", "()V"); + jmethodID listAdd = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z"); + if ((listInit == nullptr) || (listAdd == nullptr)) { + HiLog::Error(LABEL, "nativeGetSupportedFormats mehtoid id is null"); + env->DeleteLocalRef(listClazz); + return nullptr; + } + + jobject listObj = env->NewObject(listClazz, listInit, ""); + env->DeleteLocalRef(listClazz); + if (listObj == nullptr) { + HiLog::Error(LABEL, "nativeGetSupportedFormats listObj is null"); + return nullptr; + } + + std::set::iterator iter = formats.begin(); + while (iter != formats.end()) { + env->CallBooleanMethod(listObj, listAdd, env->NewStringUTF((*iter).c_str())); + ++iter; + } + return listObj; +} + +void ohos_media_image_ImageSource_nativeSetDecodeEventListener(JNIEnv *env, jobject thiz, + jobject sourceObj, jlong nativePtr) +{ + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeSetDecodeEventListener, get image source fail."); + return; + } + + if (g_decodeEventListener != nullptr) { + g_decodeEventListener.reset(); + } + + // init listener + g_decodeEventListener = std::make_unique(env, + sourceObj, g_imageSourcePostFromNativeMethodId); + imgSource->AddDecodeListener(g_decodeEventListener.release()); + HiLog::Debug(LABEL, "nativeSetDecodeEventListener end"); +} + +void ohos_media_image_ImageSource_nativeRelease(JNIEnv *env, jobject thiz, jlong nativePtr) +{ + HiLog::Debug(LABEL, "nativeRelease begin"); + ImageSource *imageSource = reinterpret_cast(nativePtr); + if (imageSource != nullptr) { + HiLog::Error(LABEL, "do release ImageSource pointer."); + if (g_decodeEventListener != nullptr) { + imageSource->RemoveDecodeListener(g_decodeEventListener.release()); + g_decodeEventListener.reset(); + } + delete imageSource; + } + HiLog::Debug(LABEL, "nativeRelease end"); +} + +bool ConvertSourceOptions(JNIEnv *env, jobject opts, SourceOptions &sourceOpts) +{ + if (opts == nullptr) { + HiLog::Debug(LABEL, "ConvertSourceOptions source opts is null, use default option"); + return true; + } + + jclass optClazz = env->GetObjectClass(opts); + if (optClazz == nullptr) { + HiLog::Error(LABEL, "ConvertSourceOptions by path, optClazz is null"); + return false; + } + jfieldID formatFileId = env->GetFieldID(optClazz, "formatHint", "Ljava/lang/String;"); + jfieldID baseDensityFileId = env->GetFieldID(optClazz, "baseDensity", "I"); + env->DeleteLocalRef(optClazz); + if (formatFileId == nullptr) { + HiLog::Error(LABEL, "ConvertSourceOptions by path, formatFileId is null."); + return false; + } + if (baseDensityFileId == nullptr) { + HiLog::Error(LABEL, "ConvertSourceOptions by path, baseDensityFileId is null."); + return false; + } + + jobject formatValue = env->GetObjectField(opts, formatFileId); + jstring formatHint = reinterpret_cast(formatValue); + const char *formatHintChars = env->GetStringUTFChars(formatHint, nullptr); + // formatHint is optional + if (formatHintChars != nullptr) { + sourceOpts.formatHint = formatHintChars; + env->ReleaseStringUTFChars(formatHint, formatHintChars); // Release formatHintChars + env->DeleteLocalRef(formatValue); + } + + jint baseDensityValue = env->GetIntField(opts, baseDensityFileId); + sourceOpts.baseDensity = baseDensityValue; + return true; +} + +jobject ohos_media_image_ImageSource_nativeCreateImageSourceFromFilePath(JNIEnv *env, jobject thiz, + jstring pathName, jobject opts) +{ + if (pathName == nullptr) { + HiLog::Error(LABEL, "createImageSource by path, pathName is null."); + return nullptr; + } + + SourceOptions sourceOpt; + if (!ConvertSourceOptions(env, opts, sourceOpt)) { + HiLog::Error(LABEL, "createImageSource ConvertSourceOptions fail.ed"); + return nullptr; + } + + const char *fileChars = env->GetStringUTFChars(pathName, nullptr); + if (fileChars == nullptr) { + HiLog::Error(LABEL, "createImageSource by path, get parameter str fail."); + return nullptr; + } + + uint32_t errCode = ERROR; + std::unique_ptr imageSource = ImageSource::CreateImageSource(fileChars, sourceOpt, errCode); + env->ReleaseStringUTFChars(pathName, fileChars); // Release fileChars + if (imageSource == nullptr) { + HiLog::Error(LABEL, "createImageSource by path, create image source fail."); + return nullptr; + } + return env->NewObject(g_imageSourceClass, g_imageSourceConstructMethodId, + reinterpret_cast(imageSource.release())); +} + +std::unique_ptr ConvertInputStreamToStringStream(JNIEnv *env, jobject inputStream) +{ + constexpr jsize buffSize = 4096; + jbyteArray inputBuf = env->NewByteArray(buffSize); + if (inputBuf == nullptr) { + HiLog::Error(LABEL, "createImageSource by InputStream, new bytearray fail."); + return nullptr; + } + + jbyte *outBuf = static_cast(malloc(buffSize)); + if (outBuf == nullptr) { + env->DeleteLocalRef(inputBuf); + HiLog::Error(LABEL, "createImageSource by InputStream, malloc fail."); + return nullptr; + } + std::unique_ptr dataStream = std::make_unique(); + if (dataStream == nullptr) { + HiLog::Error(LABEL, "createImageSource by InputStream, new fail."); + env->DeleteLocalRef(inputBuf); + free(outBuf); + outBuf = nullptr; + return nullptr; + } +#if !defined(_WIN32) && !defined(_APPLE) + constexpr int timeoutSeconds = 4; + // set XCollie timer, baseline: 5ms each 1M + int xCollieTimerid = OHOS::HiviewDFX::XCollie::GetInstance().SetTimer("ImageSourceTimer", timeoutSeconds, + nullptr, nullptr, OHOS::HiviewDFX::XCOLLIE_FLAG_LOG | OHOS::HiviewDFX::XCOLLIE_FLAG_RECOVERY); +#endif + jint bytes = 0; + while (bytes != -1) { + if (!ReadInputStreamToBytesArray(env, inputStream, inputBuf, bytes)) { + HiLog::Error(LABEL, "createImageSource: get input data fail."); + env->DeleteLocalRef(inputBuf); + free(outBuf); + outBuf = nullptr; + return nullptr; + } + + if (bytes == -1) { + break; + } + env->GetByteArrayRegion(inputBuf, 0, bytes, outBuf); + dataStream->write(reinterpret_cast(outBuf), bytes); + } + env->DeleteLocalRef(inputBuf); + free(outBuf); + outBuf = nullptr; +#if !defined(_WIN32) && !defined(_APPLE) + // cancel XCollie timer + OHOS::HiviewDFX::XCollie::GetInstance().CancelTimer(xCollieTimerid); +#endif + HiLog::Debug(LABEL, "ConvertInputStreamToStringStream: done."); + return dataStream; +} + +jobject ohos_media_image_ImageSource_nativeCreateImageSourceFromInputStream(JNIEnv *env, jobject thiz, + jobject inputStream, jobject opts) +{ + if (inputStream == nullptr) { + HiLog::Error(LABEL, "createImageSource by inputStream, param is null."); + return nullptr; + } + + SourceOptions sourceOpt; + if (!ConvertSourceOptions(env, opts, sourceOpt)) { + HiLog::Error(LABEL, "createImageSource ConvertSourceOptions fail.ed"); + return nullptr; + } + + std::unique_ptr dataStream = ConvertInputStreamToStringStream(env, inputStream); + if (dataStream == nullptr) { + HiLog::Error(LABEL, "ConvertInputStreamToStringStream fail."); + return nullptr; + } + uint32_t errCode = ERROR; + std::unique_ptr imageSource = + ImageSource::CreateImageSource(std::move(dataStream), sourceOpt, errCode); + if (imageSource == nullptr) { + HiLog::Error(LABEL, "createImageSource by inputStream, create image source fail."); + return nullptr; + } + return env->NewObject(g_imageSourceClass, g_imageSourceConstructMethodId, + reinterpret_cast(imageSource.release())); +} + +jobject ohos_media_image_ImageSource_nativeCreateImageSourceFromByteArray(JNIEnv *env, jobject thiz, + jbyteArray data, jint offset, + jint length, jobject opts) +{ + if (data == nullptr) { + HiLog::Error(LABEL, "createImageSource by data, data is null."); + return nullptr; + } + + SourceOptions sourceOpt; + if (!ConvertSourceOptions(env, opts, sourceOpt)) { + HiLog::Error(LABEL, "createImageSource ConvertSourceOptions fail.ed"); + return nullptr; + } + + jbyte *dataBuf = env->GetByteArrayElements(data, nullptr); + if (dataBuf == nullptr) { + HiLog::Error(LABEL, "createImageSource by data, get parameter str fail."); + return nullptr; + } + uint32_t errCode = ERROR; + std::unique_ptr imageSource = + ImageSource::CreateImageSource(reinterpret_cast(dataBuf) + offset, length, sourceOpt, errCode); + env->ReleaseByteArrayElements(data, dataBuf, 0); // Release dataBuf + if (imageSource == nullptr) { + HiLog::Error(LABEL, "createImageSource by byte array, create image source fail."); + return nullptr; + } + return env->NewObject(g_imageSourceClass, g_imageSourceConstructMethodId, + reinterpret_cast(imageSource.release())); +} + +bool SetIncrementalSourceOpts(JNIEnv *env, jobject opts, IncrementalSourceOptions &increSourceOpts) +{ + if (opts == nullptr) { + HiLog::Debug(LABEL, "SetIncrementalSourceOpts use default options"); + return true; + } + + jobject sourceOpts = GetObject(env, opts, "ohos/media/image/ImageSource$IncrementalSourceOptions", "opts", + "Lohos/media/image/ImageSource$SourceOptions;"); + if (sourceOpts != nullptr) { + jclass optClazz = env->GetObjectClass(sourceOpts); + if (optClazz == nullptr) { + env->DeleteLocalRef(sourceOpts); + return false; + } + jfieldID formatFileId = env->GetFieldID(optClazz, "formatHint", "Ljava/lang/String;"); + env->DeleteLocalRef(optClazz); + if (formatFileId == nullptr) { + env->DeleteLocalRef(sourceOpts); + return false; + } + jstring format = reinterpret_cast(env->GetObjectField(sourceOpts, formatFileId)); + env->DeleteLocalRef(sourceOpts); + const char *formatHintChars = env->GetStringUTFChars(format, nullptr); + if (formatHintChars != nullptr) { + increSourceOpts.sourceOptions.formatHint = formatHintChars; + env->ReleaseStringUTFChars(format, formatHintChars); // Release formatHintChars + env->DeleteLocalRef(format); + } + } + + jobject updateModeObj = GetObject(env, opts, "ohos/media/image/ImageSource$IncrementalSourceOptions", "mode", + "Lohos/media/image/ImageSource$UpdateMode;"); + if (updateModeObj != nullptr) { + jclass updateModeClazz = env->FindClass("ohos/media/image/ImageSource$UpdateMode"); + if (updateModeClazz == nullptr) { + env->DeleteLocalRef(updateModeObj); + return false; + } + jmethodID getUpdateModeMID = env->GetMethodID(updateModeClazz, "getValue", "()I"); + if (getUpdateModeMID == nullptr) { + env->DeleteLocalRef(updateModeObj); + env->DeleteLocalRef(updateModeClazz); + return false; + } + jint incrementalMode = env->CallIntMethod(updateModeObj, getUpdateModeMID); + increSourceOpts.incrementalMode = static_cast(incrementalMode); + env->DeleteLocalRef(updateModeObj); + env->DeleteLocalRef(updateModeClazz); + } + return true; +} + +jobject ohos_media_image_ImageSource_nativeCreateIncrementalImageSource(JNIEnv *env, jobject thiz, jobject opts) +{ + IncrementalSourceOptions increSourceOpts; + if (!SetIncrementalSourceOpts(env, opts, increSourceOpts)) { + HiLog::Error(LABEL, "createIncrementalImageSource : incremental opts para invalid."); + return nullptr; + } + uint32_t errCode = ERROR; + std::unique_ptr imageSource = ImageSource::CreateIncrementalImageSource(increSourceOpts, errCode); + if (imageSource == nullptr) { + HiLog::Error(LABEL, "createIncrementalImageSource, create image source fail."); + return nullptr; + } + return env->NewObject(g_imageSourceClass, g_imageSourceConstructMethodId, + reinterpret_cast(imageSource.release())); +} + +jint ohos_media_image_ImageSource_nativeUpdateData(JNIEnv *env, jobject thiz, jlong nativePtr, jbyteArray data, + jint offset, jint size, jboolean isCompleted) +{ + if (data == nullptr) { + HiLog::Error(LABEL, "nativeUpdateData data is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeUpdateData, get image source fail."); + return ERR_IMAGE_INIT_ABNORMAL; + } + jbyte *dataBuf = env->GetByteArrayElements(data, nullptr); + jint errCode = imgSource->UpdateData(reinterpret_cast(dataBuf) + offset, size, isCompleted); + env->ReleaseByteArrayElements(data, dataBuf, 0); // Release dataBuf + return errCode; +} + +bool InitDecOptRect(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + jobject rectObj = env->GetObjectField(opts, g_optionsRectFieldId); + jint left = 0; + jint top = 0; + jint rectWidth = 0; + jint rectHeight = 0; + if (rectObj != nullptr) { + if (!GetIntValue(env, rectObj, "ohos/media/image/common/Rect", "minX", left) || + !GetIntValue(env, rectObj, "ohos/media/image/common/Rect", "minY", top) || + !GetIntValue(env, rectObj, "ohos/media/image/common/Rect", "width", rectWidth) || + !GetIntValue(env, rectObj, "ohos/media/image/common/Rect", "height", rectHeight)) { + HiLog::Error(LABEL, "InitDecOptRect: get rect value fail."); + env->DeleteLocalRef(rectObj); + return false; + } + } + decodeOpts.CropRect.left = left; + decodeOpts.CropRect.top = top; + decodeOpts.CropRect.width = rectWidth; + decodeOpts.CropRect.height = rectHeight; + + HiLog::Debug(LABEL, + "InitDecOptRect, desiredRegion minX:%{public}d, minY:%{public}d, width:%{public}d, height:%{public}d", + left, top, rectWidth, rectHeight); + if (rectObj != nullptr) { + env->DeleteLocalRef(rectObj); + } + return true; +} + +bool InitDecOptSize(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + jobject desSizeObj = env->GetObjectField(opts, g_optionsSizeFieldId); + jint width = 0; + jint height = 0; + if (desSizeObj != nullptr) { + if (!GetIntValue(env, desSizeObj, "ohos/media/image/common/Size", "width", width) || + !GetIntValue(env, desSizeObj, "ohos/media/image/common/Size", "height", height)) { + HiLog::Error(LABEL, "InitDecOptSize: get size value fail."); + env->DeleteLocalRef(desSizeObj); + return false; + } + } + decodeOpts.desiredSize.width = width; + decodeOpts.desiredSize.height = height; + HiLog::Debug(LABEL, "InitDecOptSize, desiredSize width:%{public}d, height:%{public}d", width, height); + if (desSizeObj != nullptr) { + env->DeleteLocalRef(desSizeObj); + } + return true; +} + +bool InitDecOptPixelFormat(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + // desiredPixelFormat + jmethodID zMethodId = env->GetMethodID(g_pixelFormatClass, "getValue", "()I"); + if (zMethodId == nullptr) { + HiLog::Error(LABEL, "GetMethodID fail, method: getValue not found."); + return false; + } + jobject pixelFormat = env->GetObjectField(opts, g_optionsPixelFormatFieldId); + decodeOpts.desiredPixelFormat = static_cast(env->CallIntMethod(pixelFormat, zMethodId)); + env->DeleteLocalRef(pixelFormat); + return true; +} + +bool InitDecOptColor(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + // desiredColorSpace + jmethodID zMethodId = env->GetMethodID(g_colorSpaceClass, "getValue", "()I"); + if (zMethodId == nullptr) { + HiLog::Error(LABEL, "GetMethodID fail, method: getValue not found."); + return false; + } + jobject color = env->GetObjectField(opts, g_optionsColorSpaceFieldId); + decodeOpts.desiredColorSpace = static_cast(env->CallIntMethod(color, zMethodId)); + env->DeleteLocalRef(color); + return true; +} + +bool InitDecOptAllocatorType(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + // allocator + jmethodID zMethodId = env->GetMethodID(g_allocatorClass, "getValue", "()I"); + if (zMethodId == nullptr) { + HiLog::Error(LABEL, "GetMethodID fail, method: getValue not found."); + return false; + } + jobject allocator = env->GetObjectField(opts, g_optionsAllocatorFieldId); + decodeOpts.allocatorType = static_cast(env->CallIntMethod(allocator, zMethodId)); + env->DeleteLocalRef(allocator); + return true; +} + +bool InitDecOpts(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + // fitDensity + decodeOpts.fitDensity = env->GetIntField(opts, g_optionsFitDensityFieldId); + // rotateDegrees + decodeOpts.rotateDegrees = env->GetFloatField(opts, g_optionsRotateDegreesFieldId); + // sampleSize + decodeOpts.sampleSize = env->GetIntField(opts, g_optionsSampleSizeFieldId); + // allowPartialImage + decodeOpts.allowPartialImage = env->GetBooleanField(opts, g_optionsAllowPartialImageFieldId); + // editable + decodeOpts.editable = env->GetBooleanField(opts, g_optionsEditableFieldId); + return true; +} + +bool ConvertDecodingOptions(JNIEnv *env, jobject opts, DecodeOptions &decodeOpts) +{ + if (opts == nullptr) { + HiLog::Debug(LABEL, "ConvertDecodingOptions use default options"); + return true; + } + + if (!InitDecOpts(env, opts, decodeOpts) || + !InitDecOptRect(env, opts, decodeOpts) || !InitDecOptSize(env, opts, decodeOpts) || + !InitDecOptPixelFormat(env, opts, decodeOpts) || !InitDecOptColor(env, opts, decodeOpts) || + !InitDecOptAllocatorType(env, opts, decodeOpts)) { + HiLog::Error(LABEL, "ConvertDecodingOptions : convert para fail"); + return false; + } + + return true; +} + +bool GetNinePatchChunk(JNIEnv *env, const NinePatchInfo &ninePatchInfo, jbyteArray &ninePatchChunk) +{ + if (ninePatchInfo.ninePatch != nullptr && ninePatchInfo.patchSize != 0) { + ninePatchChunk = env->NewByteArray(ninePatchInfo.patchSize); + if (ninePatchChunk == nullptr) { + return false; + } + + jbyte *array = reinterpret_cast(env->GetPrimitiveArrayCritical(ninePatchChunk, nullptr)); + if (array == nullptr) { + HiLog::Error(LABEL, "array is null"); + env->DeleteLocalRef(ninePatchChunk); + return false; + } + errno_t ret = memcpy_s(array, ninePatchInfo.patchSize, ninePatchInfo.ninePatch, ninePatchInfo.patchSize); + if (ret != 0) { + HiLog::Error(LABEL, "mempcy nine patch info failed, error is %{public}d.", ret); + env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); + env->DeleteLocalRef(ninePatchChunk); + return false; + } + env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); + } + return true; +} + +jobject ohos_media_image_ImageSource_nativeCreatePixelmap(JNIEnv *env, jobject thiz, jobject sourceObj, + jlong nativePtr, jint index, jobject opts) +{ + DecodeOptions decodeOpts; + if (!ConvertDecodingOptions(env, opts, decodeOpts)) { + HiLog::Error(LABEL, "CreatePixelmap : deopt para is invalid."); + return nullptr; + } + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "CreatePixelmap, get image source fail."); + return nullptr; + } + PixelFormatToNative(decodeOpts.desiredPixelFormat); + uint32_t err = 0; + jlong nativePixelMapPtr; + jlong nativeBytes; + jbyteArray ninePatchChunk = nullptr; + jint baseDensity = 0; + if (imgSource->IsIncrementalSource()) { + std::unique_ptr incPixelMap = imgSource->CreateIncrementalPixelMap(index, decodeOpts, err); + if (err != SUCCESS) { + HiLog::Error(LABEL, "CreateIncrementalPixelMap fail, error is %{public}d.", err); + return nullptr; + } + uint8_t decodeProgress = 0; + incPixelMap->PromoteDecoding(decodeProgress); + incPixelMap->DetachFromDecoding(); + nativeBytes = static_cast(incPixelMap->GetByteCount()); + PixelMapManager *pixelMapManager = new (std::nothrow) PixelMapManager(incPixelMap.release()); + if (pixelMapManager == nullptr) { + HiLog::Error(LABEL, "new pixelMapManager failed."); + return nullptr; + } + nativePixelMapPtr = reinterpret_cast(pixelMapManager); + } else { + std::unique_ptr pixelMap = imgSource->CreatePixelMap(index, decodeOpts, err); + if (err != SUCCESS) { + HiLog::Error(LABEL, "CreatePixelmap fail, error is %{public}d.", err); + ThrowExceptionByErrorCode(env, err); + return nullptr; + } + const NinePatchInfo &ninePatchInfo = imgSource->GetNinePatchInfo(); + if (!GetNinePatchChunk(env, ninePatchInfo, ninePatchChunk)) { + HiLog::Error(LABEL, "get nine patch chunk failed."); + return nullptr; + } + nativeBytes = static_cast(pixelMap->GetByteCount()); + baseDensity = static_cast(pixelMap->GetBaseDensity()); + PixelMapManager *pixelMapManager = new (std::nothrow) PixelMapManager(pixelMap.release()); + if (pixelMapManager == nullptr) { + HiLog::Error(LABEL, "new pixelMapManager failed."); + env->DeleteLocalRef(ninePatchChunk); + return nullptr; + } + nativePixelMapPtr = reinterpret_cast(pixelMapManager); + } + jobject pixelMapObj = env->NewObject(g_pixelMapClass, g_pixelMapCtorMethodId, + nativePixelMapPtr, nativeBytes, ninePatchChunk); + if (pixelMapObj != nullptr && baseDensity > 0) { + env->CallVoidMethod(pixelMapObj, g_setBaseDensityMethodId, baseDensity); + } + return pixelMapObj; +} + +jobject ohos_media_image_ImageSource_nativeCreateIncrementalPixelmap(JNIEnv *env, jobject thiz, jlong nativePtr, + jint index, jobject opts) +{ + DecodeOptions decodeOpts; + if (!ConvertDecodingOptions(env, opts, decodeOpts)) { + HiLog::Error(LABEL, "nativeCreateIncrementalPixelmap : deopt para is invalid."); + return nullptr; + } + + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeCreateIncrementalPixelmap, get image source fail."); + return nullptr; + } + + jclass pixelMapClazz = env->FindClass("ohos/media/image/IncrementalPixelMap"); + if (pixelMapClazz == nullptr) { + HiLog::Error(LABEL, "nativeCreateIncrementalPixelmap fail, not found IncrementalPixelMap class."); + return nullptr; + } + jmethodID pixelMapConstrocMID = env->GetMethodID(pixelMapClazz, "", "(J)V"); + if (pixelMapConstrocMID == nullptr) { + env->DeleteLocalRef(pixelMapClazz); + HiLog::Error(LABEL, "nativeCreateIncrementalPixelmap fail, PixelMap construction method not found."); + return nullptr; + } + + uint32_t err = 0; + PixelFormatToNative(decodeOpts.desiredPixelFormat); + std::unique_ptr incPixelMap = imgSource->CreateIncrementalPixelMap(index, decodeOpts, err); + if (err != SUCCESS) { + HiLog::Error(LABEL, "CreateIncrementalPixelMap fail, error is %{public}u.", err); + env->DeleteLocalRef(pixelMapClazz); + return nullptr; + } + + jlong nativeBytes = static_cast(incPixelMap->GetByteCount()); + return env->NewObject(pixelMapClazz, pixelMapConstrocMID, reinterpret_cast(incPixelMap.release()), + nativeBytes); +} + +jobject ConstructSize(JNIEnv *env, Size &size) +{ + jclass sizeClazz = env->FindClass("ohos/media/image/common/Size"); + if (sizeClazz == nullptr) { + HiLog::Error(LABEL, "ConstructSize, Size class not found ."); + return nullptr; + } + + jmethodID sizeConstrocMID = env->GetMethodID(sizeClazz, "", "(II)V"); + if (sizeConstrocMID == nullptr) { + HiLog::Error(LABEL, "ConstructSize, sizeConstrocMID is null."); + env->DeleteLocalRef(sizeClazz); + return nullptr; + } + + return env->NewObject(sizeClazz, sizeConstrocMID, size.width, size.height); +} + +jobject ConstructImageInfo(JNIEnv *env, ImageInfo &imgInfo) +{ + jclass imageInfoClazz = env->FindClass("ohos/media/image/common/ImageInfo"); + if (imageInfoClazz == nullptr) { + HiLog::Error(LABEL, "ConstructImageInfo, ImageInfo class not found ."); + return nullptr; + } + jmethodID imgInfoMID = env->GetMethodID(imageInfoClazz, "", "()V"); + if (imgInfoMID == nullptr) { + env->DeleteLocalRef(imageInfoClazz); + return nullptr; + } + jobject imgInfoObj = env->NewObject(imageInfoClazz, imgInfoMID); + if (imgInfoObj == nullptr) { + HiLog::Error(LABEL, "ConstructImageInfo, imgInfoObj is null."); + env->DeleteLocalRef(imageInfoClazz); + return nullptr; + } + + jobject sizeObj = ConstructSize(env, imgInfo.size); + if (sizeObj == nullptr) { + HiLog::Error(LABEL, "ConstructImageInfo, sizeObj is null."); + env->DeleteLocalRef(imageInfoClazz); + env->DeleteLocalRef(imgInfoObj); + return nullptr; + } + jfieldID sizeFileID = env->GetFieldID(imageInfoClazz, "size", "Lohos/media/image/common/Size;"); + if (sizeFileID == nullptr) { + env->DeleteLocalRef(imageInfoClazz); + env->DeleteLocalRef(imgInfoObj); + return nullptr; + } + env->SetObjectField(imgInfoObj, sizeFileID, sizeObj); + + jmethodID setPixelFormatID = env->GetMethodID(imageInfoClazz, "setPixelFormat", "(I)V"); + if (setPixelFormatID == nullptr) { + env->DeleteLocalRef(imageInfoClazz); + env->DeleteLocalRef(imgInfoObj); + return nullptr; + } + env->CallVoidMethod(imgInfoObj, setPixelFormatID, jint(imgInfo.pixelFormat)); + + jmethodID setColorSpaceID = env->GetMethodID(imageInfoClazz, "setColorSpace", "(I)V"); + if (setColorSpaceID == nullptr) { + env->DeleteLocalRef(imageInfoClazz); + env->DeleteLocalRef(imgInfoObj); + return nullptr; + } + env->CallVoidMethod(imgInfoObj, setColorSpaceID, jint(imgInfo.colorSpace)); + + env->DeleteLocalRef(imageInfoClazz); + + return imgInfoObj; +} + +jobject ohos_media_image_ImageSource_nativeGetImageInfo(JNIEnv *env, jobject thiz, jlong nativePtr, jint index) +{ + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeGetImageInfo imgSource pointer is null."); + return nullptr; + } + ImageInfo imgInfo; + uint32_t err = imgSource->GetImageInfo(index, imgInfo); + if (err != SUCCESS) { + HiLog::Error(LABEL, "nativeGetImageInfo fail, ret:%{public}u.", err); + return nullptr; + } + + return ConstructImageInfo(env, imgInfo); +} + +jobject ConstructSourceInfo(JNIEnv *env, SourceInfo &sourceInfo) +{ + jclass sourceInfoClazz = env->FindClass("ohos/media/image/ImageSource$SourceInfo"); + if (sourceInfoClazz == nullptr) { + HiLog::Error(LABEL, "ConstructSourceInfo, SourceInfo class not found ."); + return nullptr; + } + jmethodID sourceInfoConstrocMID = env->GetMethodID(sourceInfoClazz, "", "()V"); + if (sourceInfoConstrocMID == nullptr) { + HiLog::Error(LABEL, "ConstructSourceInfo, sourceInfoConstrocMID is null."); + env->DeleteLocalRef(sourceInfoClazz); + return nullptr; + } + jobject sourceInfoObj = env->NewObject(sourceInfoClazz, sourceInfoConstrocMID); + if (sourceInfoObj == nullptr) { + HiLog::Error(LABEL, "ConstructSourceInfo, sourceInfoObj is null."); + env->DeleteLocalRef(sourceInfoClazz); + return nullptr; + } + + jfieldID topLevelImageNumFileID = env->GetFieldID(sourceInfoClazz, "topLevelImageNum", "I"); + jfieldID encodedFormatFileID = env->GetFieldID(sourceInfoClazz, "encodedFormat", "Ljava/lang/String;"); + if ((topLevelImageNumFileID == nullptr) || (encodedFormatFileID == nullptr)) { + HiLog::Error(LABEL, "ConstructSourceInfo, fieldID is null."); + env->DeleteLocalRef(sourceInfoClazz); + env->DeleteLocalRef(sourceInfoObj); + return nullptr; + } + + jstring encodedFormat = env->NewStringUTF((sourceInfo.encodedFormat).c_str()); + env->SetIntField(sourceInfoObj, topLevelImageNumFileID, sourceInfo.topLevelImageNum); + env->SetObjectField(sourceInfoObj, encodedFormatFileID, encodedFormat); + env->DeleteLocalRef(sourceInfoClazz); + + return sourceInfoObj; +} + +jobject ohos_media_image_ImageSource_nativeGetSourceInfo(JNIEnv *env, jobject thiz, jlong nativePtr) +{ + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeGetImageInfo imgSource pointer is null."); + return nullptr; + } + uint32_t err = 0; + SourceInfo sourceInfo = imgSource->GetSourceInfo(err); + if (err != SUCCESS) { + HiLog::Error(LABEL, "nativeGetImageInfo fail, ret:%{public}u.", err); + return nullptr; + } + + return ConstructSourceInfo(env, sourceInfo); +} + +void ohos_media_image_ImageSource_nativeSetMemoryUsagePreference(JNIEnv *env, jobject thiz, + jlong nativePtr, jobject preference) +{ + if (preference == nullptr) { + HiLog::Error(LABEL, "GetObject preference obj is null, use default preference"); + return; + } + jclass preferenceClazz = env->GetObjectClass(preference); + if (preferenceClazz == nullptr) { + HiLog::Error(LABEL, "SetMemoryUsagePreference: preferenceClazz is null."); + return; + } + jmethodID preferenceValueId = env->GetMethodID(preferenceClazz, "getValue", "()I"); + if (preferenceValueId == nullptr) { + HiLog::Error(LABEL, "SetMemoryUsagePreference: preferenceValueId is null."); + return; + } + MemoryUsagePreference nativePreference = + static_cast(env->CallIntMethod(preference,preferenceValueId)); + + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeSetMemoryUsagePreference imgSource pointer is null."); + return; + } + imgSource->SetMemoryUsagePreference(nativePreference); +} + +jint ohos_media_image_ImageSource_nativeGetImagePropertyInt(JNIEnv *env, jobject thiz, jlong nativePtr, jint index, + jstring key, jint defaultValue) +{ + ImageSource *imgSource = reinterpret_cast(nativePtr); + if (imgSource == nullptr) { + HiLog::Error(LABEL, "nativeGetImageInfo imgSource pointer is null."); + return defaultValue; + } + const char *keyChars = env->GetStringUTFChars(key, nullptr); + HiLog::Error(LABEL, "enter GetImageProperty key:%{public}s", keyChars); + int32_t value; + uint32_t errorCode = imgSource->GetImagePropertyInt(index, keyChars, value); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "GetImageProperty fail, ret:%{public}u.", errorCode); + env->ReleaseStringUTFChars(key, keyChars); + return defaultValue; + } + + env->ReleaseStringUTFChars(key, keyChars); + HiLog::Error(LABEL, "GetImageProperty key:%{public}s, value:%{public}d.", keyChars, value); + return value; +} + +static const JNINativeMethod METHODS[] = { + { "nativeSetDecodeEventListener", "(Lohos/media/image/ImageSource;J)V", + reinterpret_cast(ohos_media_image_ImageSource_nativeSetDecodeEventListener) }, + { "nativeGetSupportedFormats", "()Ljava/util/HashSet;", + reinterpret_cast(ohos_media_image_ImageSource_nativeGetSupportedFormats) }, + { "nativeCreateImageSource", + "(Ljava/lang/String;Lohos/media/image/ImageSource$SourceOptions;)Lohos/media/image/ImageSource;", + reinterpret_cast(ohos_media_image_ImageSource_nativeCreateImageSourceFromFilePath) }, + { "nativeCreateImageSource", + "(Ljava/io/InputStream;Lohos/media/image/ImageSource$SourceOptions;)Lohos/media/image/ImageSource;", + reinterpret_cast(ohos_media_image_ImageSource_nativeCreateImageSourceFromInputStream) }, + { "nativeCreateImageSource", + "([BIILohos/media/image/ImageSource$SourceOptions;)Lohos/media/image/ImageSource;", + reinterpret_cast(ohos_media_image_ImageSource_nativeCreateImageSourceFromByteArray) }, + { "nativeCreateIncrementalImageSource", + "(Lohos/media/image/ImageSource$IncrementalSourceOptions;)Lohos/media/image/ImageSource;", + reinterpret_cast(ohos_media_image_ImageSource_nativeCreateIncrementalImageSource) }, + { "nativeUpdateData", "(J[BIIZ)I", reinterpret_cast(ohos_media_image_ImageSource_nativeUpdateData) }, + { "nativeCreatePixelmap", + "(Lohos/media/image/ImageSource;JILohos/media/image/ImageSource$DecodingOptions;)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_ImageSource_nativeCreatePixelmap) }, + { "nativeGetImageInfo", "(JI)Lohos/media/image/common/ImageInfo;", + reinterpret_cast(ohos_media_image_ImageSource_nativeGetImageInfo) }, + { "nativeGetSourceInfo", "(J)Lohos/media/image/ImageSource$SourceInfo;", + reinterpret_cast(ohos_media_image_ImageSource_nativeGetSourceInfo) }, + { "nativeGetImagePropertyInt", "(JILjava/lang/String;I)I", + reinterpret_cast(ohos_media_image_ImageSource_nativeGetImagePropertyInt) }, + { "nativeInit", "()V", reinterpret_cast(ohos_media_image_ImageSource_nativeInit) }, + { "nativeRelease", "(J)V", reinterpret_cast(ohos_media_image_ImageSource_nativeRelease) }, + { "nativeSetMemoryUsagePreference", "(JLohos/media/image/common/MemoryUsagePreference;)V", + reinterpret_cast(ohos_media_image_ImageSource_nativeSetMemoryUsagePreference) }, +}; + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + HiLog::Debug(LABEL, "JNI_OnLoad begin"); + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + HiLog::Error(LABEL, "JNI_OnLoad: GetEnv failed"); + return ERROR; + } + int ret = JkitRegisterNativeMethods(env, "ohos/media/image/ImageSource", METHODS, ARRCOUNT(METHODS)); + if (ret == JNI_ERR) { + HiLog::Error(LABEL, "JkitRegisterNativeMethods failed, ret=%{public}d", ret); + return ERROR; + } + Jkit::nativeInit(vm); + HiLog::Debug(LABEL, "JNI_OnLoad end"); + return JNI_VERSION_1_4; +} diff --git a/frameworks/jni/incrementalpixelmap/BUILD.gn b/frameworks/jni/incrementalpixelmap/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..da09c8593684e4ac1e78fecd2ebcf2bb776d7569 --- /dev/null +++ b/frameworks/jni/incrementalpixelmap/BUILD.gn @@ -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("//build/ohos.gni") +import("//foundation/multimedia/image/ide/image_decode_config.gni") + +config("incremental_pixelmap_jni_config") { + visibility = [ ":*" ] + include_dirs = [ + "//utils/jni/jnikit/include", + "//foundation/multimedia/image/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image/adapter/frameworks/bitmapconverter/native/include", + ] + + if (use_mingw_win) { + include_dirs += [ "//foundation/multimedia/image/mock/native/include" ] + } else if (use_clang_mac) { + include_dirs += [ "//foundation/multimedia/image/mock/native/include" ] + } else { + include_dirs += [ "//utils/native/base/include" ] + } +} + +group("g_incremental_pixelmap_jni") { + deps = [ ":incremental_pixelmap_jni" ] +} + +ohos_shared_library("incremental_pixelmap_jni") { + sources = [ "src/ohos_image_IncrementalPixelmap.cpp" ] + + configs = [ ":incremental_pixelmap_jni_config" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image_static", + "//foundation/multimedia/image/mock/native:log_mock_static", + "//foundation/multimedia/image/mock/native:utils_mock_static", + "//utils/jni:utils_jnikit_win", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image_static", + "//foundation/multimedia/image/mock/native:log_mock_static", + "//foundation/multimedia/image/mock/native:utils_mock_static", + "//utils/jni:utils_jnikit_mac", + ] + } else { + deps = [ + "//foundation/multimedia/image/interfaces/innerkits:image", + "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + external_deps = [ "hilog:libhilog" ] + } + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/frameworks/jni/incrementalpixelmap/src/ohos_image_IncrementalPixelmap.cpp b/frameworks/jni/incrementalpixelmap/src/ohos_image_IncrementalPixelmap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2af101b44cb2c51d80c49ec519e46b81c9ae1499 --- /dev/null +++ b/frameworks/jni/incrementalpixelmap/src/ohos_image_IncrementalPixelmap.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "hilog/log.h" +#include "image_type.h" +#include "incremental_pixel_map.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" +#include "pixel_map.h" +#if !defined(_WIN32) && !defined(_APPLE) +#include "parcel.h" +#endif +#ifndef _WIN32 +#include "securec.h" +#endif + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, + "IncrementalPixelMap_JNI" }; + +jint ohos_media_image_IncrementalPixelMap_nativePromoteDecoding(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + IncrementalPixelMap *incrementalPixelMap = reinterpret_cast(nativePtr); + if (incrementalPixelMap == nullptr) { + HiLog::Error(LABEL, "nativePromoteDecoding incremental pixelmap pointer is null."); + return -1; + } + + uint8_t decodeProgress = 0; + uint32_t ret = incrementalPixelMap->PromoteDecoding(decodeProgress); + if ((ret != SUCCESS) && (ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE)) { + HiLog::Error(LABEL, "nativePromoteDecoding PromoteDecoding fail,ret=%{public}u.", ret); + return ret; + } + + return decodeProgress; +} + +void ohos_media_image_IncrementalPixelMap_nativeDetachFromDecoding(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + IncrementalPixelMap *incrementalPixelMap = reinterpret_cast(nativePtr); + if (incrementalPixelMap == nullptr) { + HiLog::Error(LABEL, "nativeDetachFromDecoding incremental pixelmap pointer is null."); + return; + } + + incrementalPixelMap->DetachFromDecoding(); +} + +void ohos_media_image_IncrementalPixelMap_nativeRelease(JNIEnv *env, jobject thiz, jlong nativePtr) +{ + HiLog::Debug(LABEL, "nativeRelease begin"); + IncrementalPixelMap *incrementalPixelMap = reinterpret_cast(nativePtr); + if (incrementalPixelMap != nullptr) { + HiLog::Debug(LABEL, "do release incremental pixel map"); + delete incrementalPixelMap; + incrementalPixelMap = nullptr; + } + HiLog::Debug(LABEL, "nativeRelease end"); +} + +static const JNINativeMethod METHODS[] = { + { "nativePromoteDecoding", "(J)I", + reinterpret_cast(ohos_media_image_IncrementalPixelMap_nativePromoteDecoding) }, + { "nativeDetachFromDecoding", "(J)V", + reinterpret_cast(ohos_media_image_IncrementalPixelMap_nativeDetachFromDecoding) }, + { "nativeRelease", "(J)V", reinterpret_cast(ohos_media_image_IncrementalPixelMap_nativeRelease) }, +}; + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + HiLog::Debug(LABEL, "JNI_OnLoad begin"); + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + HiLog::Error(LABEL, "JNI_OnLoad: GetEnv failed"); + return ERROR; + } + int32_t ret = + JkitRegisterNativeMethods(env, "ohos/media/image/IncrementalPixelMap", METHODS, ARRCOUNT(METHODS)); + if (ret == JNI_ERR) { + HiLog::Error(LABEL, "JkitRegisterNativeMethods failed, ret=%{public}d", ret); + return ERROR; + } + Jkit::nativeInit(vm); + HiLog::Debug(LABEL, "JNI_OnLoad end"); + return JNI_VERSION_1_4; +} diff --git a/frameworks/jni/pixelmap/BUILD.gn b/frameworks/jni/pixelmap/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..4a52129618c27c8230b6a7d6ee6a25b036f1096e --- /dev/null +++ b/frameworks/jni/pixelmap/BUILD.gn @@ -0,0 +1,114 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +config("pixelmap_jni_config") { + visibility = [ ":*" ] + include_dirs = [ + "//utils/jni/jnikit/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/interfaces/kits/native/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native/include", + "//utils/jni/common/include", + "//foundation/multimedia/image_standard/frameworks/jni/common/include", + "//foundation/multimedia/image_standard/frameworks/jni/pixelmap/include", + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/include", + ] + + if (use_mingw_win) { + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + # "//foundation/multimedia/image_standard/mock/native/include/secure", + ] + } else if (use_clang_mac) { + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + ] + } else { + include_dirs += [ + "//sdk/aosp-arm64/communication/ipc_core/include/", + "//utils/native/base/include", + ] + } +} + +group("g_pixelmap_jni") { + deps = [ ":pixelmap_jni" ] +} + +ohos_shared_library("pixelmap_jni") { + if (use_mingw_win) { + defines = image_decode_windows_defines + sources = [ + "//foundation/multimedia/image_standard/frameworks/jni/common/src/ohos_image_jni_utils.cpp", + "src/ohos_image_pixelmap.cpp", + ] + + configs = [ ":pixelmap_jni_config" ] + + deps = [ + # "//foundation/multimedia/image/adapter/frameworks/bitmapconverter/native:static_bitmapconverter", + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter_static", + "//foundation/multimedia/image_standard/interfaces/innerkits:image_static", + + # "//foundation/multimedia/image/mock/native:utils_mock_static", + "//utils/jni:utils_jnikit_win", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + + sources = [ + "//foundation/multimedia/image_standard/frameworks/jni/common/src/ohos_image_jni_utils.cpp", + "src/ohos_image_pixelmap.cpp", + ] + + configs = [ ":pixelmap_jni_config" ] + + deps = [ + # "//foundation/multimedia/image/adapter/frameworks/bitmapconverter/native:static_bitmapconverter", + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter_static", + "//foundation/multimedia/image_standard/interfaces/innerkits:image_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//utils/jni:utils_jnikit_mac", + "//utils/native/base:utilsecurec", + ] + } else { + sources = [ + "//foundation/multimedia/image_standard/frameworks/jni/common/src/ohos_image_jni_utils.cpp", + "src/ohos_image_pixelmap.cpp", + ] + + configs = [ ":pixelmap_jni_config" ] + + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/bitmapconverter/native:bitmapconverter", + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter", + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//utils/jni:utils_jni", + "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + + external_deps = [ + "hilog:libhilog", + "ipc:ipc_core", + ] + } + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/frameworks/jni/pixelmap/include/ohos_image_pixelmap.h b/frameworks/jni/pixelmap/include/ohos_image_pixelmap.h new file mode 100644 index 0000000000000000000000000000000000000000..505d211a81fc54f2d48335ac1735c3d620b0d51a --- /dev/null +++ b/frameworks/jni/pixelmap/include/ohos_image_pixelmap.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_IMAGE_PIXELMAP_H +#define OHOS_IMAGE_PIXELMAP_H +#include "image_pixel_map.h" +#include "jkit_utils.h" +#include "pixel_map.h" + +namespace OHOS { +namespace Media { +void ohos_media_image_GetImageInfo(JNIEnv *env, jobject pixelMapObject, OhosPixelMapInfo &info); +void *ohos_media_image_AccessPixels(JNIEnv *env, jobject pixelMapObject); +bool ohos_media_image_UnAccessPixels(JNIEnv *env, jobject pixelMapObject); +} // namespace Media +} // namespace OHOS +#endif // OHOS_IMAGE_PIXELMAP_H diff --git a/frameworks/jni/pixelmap/src/ohos_image_pixelmap.cpp b/frameworks/jni/pixelmap/src/ohos_image_pixelmap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5956b2188bfd8487fa38a109597fb166d665a344 --- /dev/null +++ b/frameworks/jni/pixelmap/src/ohos_image_pixelmap.cpp @@ -0,0 +1,988 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ohos_image_pixelmap.h" +#include +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "media_errors.h" +#include "message_parcel.h" +#include "ohos_image_jni_utils.h" +#include "ohos_utils_parcel.h" +#include "parcel.h" +#include "pixel_map.h" +#include "pixel_map_jni_utils.h" +#include "pixel_map_manager.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif +#ifdef _WIN32 +#include +#include +#endif + +#if !defined(_WIN32) && !defined(_APPLE) +#include +#include "ashmem.h" +#include "image_bitmap_converter.h" +#endif + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +namespace { +constexpr int32_t PIXEL_MAP_INFO_MAX_LENGTH = 128; +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelMap_JNI" }; +jclass g_pixelMapClz; +jmethodID g_pixelMapConstructorMethodId; +jfieldID g_nativePixelMapFieldId; + +// java default byte order is big endian, native is little endian, here implements type convert +void PixelFormatToNative(PixelFormat &pixelFormat) +{ + if (pixelFormat == PixelFormat::ARGB_8888) { + pixelFormat = PixelFormat::RGBA_8888; + } +} + +void PixelFormatToKits(PixelFormat &pixelFormat) +{ + if (pixelFormat == PixelFormat::RGBA_8888) { + pixelFormat = PixelFormat::ARGB_8888; + } +} + +jobject MakeImageInfoObj(JNIEnv *env) +{ + jclass imageInfoClazz = env->FindClass("ohos/media/image/common/ImageInfo"); + if (imageInfoClazz == nullptr) { + HiLog::Error(LABEL, "MakeImageInfoObj, ImageInfo class not found ."); + return nullptr; + } + jmethodID imgInfoMID = env->GetMethodID(imageInfoClazz, "", "()V"); + if (imgInfoMID == nullptr) { + HiLog::Error(LABEL, "MakeImageInfoObj, imgInfoMID is null."); + env->DeleteLocalRef(imageInfoClazz); + return nullptr; + } + return env->NewObject(imageInfoClazz, imgInfoMID); +} + +jobject MakeSizeObj(JNIEnv *env, Size &size) +{ + jclass sizeClazz = env->FindClass("ohos/media/image/common/Size"); + if (sizeClazz == nullptr) { + HiLog::Error(LABEL, "MakeSizeObj, Size class not found ."); + return nullptr; + } + + jmethodID sizeConstrocMID = env->GetMethodID(sizeClazz, "", "(II)V"); + if (sizeConstrocMID == nullptr) { + HiLog::Error(LABEL, "MakeSizeObj, sizeConstrocMID is null."); + env->DeleteLocalRef(sizeClazz); + return nullptr; + } + + return env->NewObject(sizeClazz, sizeConstrocMID, size.width, size.height); +} + +jobject ohos_media_image_PixelMap_nativeGetImageInfo(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native pointer is null"); + return nullptr; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + ImageInfo imgInfo; + pixelMap.GetImageInfo(imgInfo); + jclass imageInfoClazz = env->FindClass("ohos/media/image/common/ImageInfo"); + if (imageInfoClazz == nullptr) { + HiLog::Error(LABEL, "can't find ImageInfo class"); + return nullptr; + } + jfieldID sizeFileID = env->GetFieldID(imageInfoClazz, "size", "Lohos/media/image/common/Size;"); + jmethodID setPixelFormatID = env->GetMethodID(imageInfoClazz, "setPixelFormat", "(I)V"); + jmethodID setColorSpaceID = env->GetMethodID(imageInfoClazz, "setColorSpace", "(I)V"); + jmethodID setAlphaTypeID = env->GetMethodID(imageInfoClazz, "setAlphaType", "(I)V"); + env->DeleteLocalRef(imageInfoClazz); + if (sizeFileID == nullptr || setPixelFormatID == nullptr || setColorSpaceID == nullptr || + setAlphaTypeID == nullptr) { + HiLog::Error(LABEL, "imageinfo attributes is invalid"); + return nullptr; + } + + jobject imgInfoObj = MakeImageInfoObj(env); + if (imgInfoObj == nullptr) { + HiLog::Error(LABEL, "nativeGetImageInfo obj is null."); + return nullptr; + } + PixelFormatToKits(imgInfo.pixelFormat); + env->CallVoidMethod(imgInfoObj, setPixelFormatID, jint(imgInfo.pixelFormat)); + env->CallVoidMethod(imgInfoObj, setColorSpaceID, jint(imgInfo.colorSpace)); + env->CallVoidMethod(imgInfoObj, setAlphaTypeID, jint(imgInfo.alphaType)); + + jobject sizeObj = MakeSizeObj(env, imgInfo.size); + if (sizeObj == nullptr) { + HiLog::Error(LABEL, "nativeGetImageInfo size obj is null."); + env->DeleteLocalRef(imgInfoObj); + return nullptr; + } + env->SetObjectField(imgInfoObj, sizeFileID, sizeObj); + env->DeleteLocalRef(sizeObj); + return imgInfoObj; +} + +void ohos_media_image_PixelMap_nativeRelease(JNIEnv *env, jobject thiz, jlong nativePtr, jlong nativeRes) +{ + HiLog::Debug(LABEL, "nativeRelease begin"); + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native pointer is null"); + return; + } + pixelMapManager->FreePixels(); + env->DeleteGlobalRef(reinterpret_cast(nativeRes)); + HiLog::Debug(LABEL, "nativeRelease end"); +} + +jboolean ohos_media_image_PixelMap_nativeWriteToParcel(JNIEnv *env, jobject thiz, jlong nativePtr, jobject parcel) +{ + if (parcel == NULL) { + HiLog::Error(LABEL, "writeToParcel null parcel."); + return false; + } + + jclass zParcelClazz = env->GetObjectClass(parcel); + jfieldID zNativeHandleField = env->GetFieldID(zParcelClazz, "nativeHandle", "J"); + env->DeleteLocalRef(zParcelClazz); + if (zNativeHandleField == nullptr) { + HiLog::Error(LABEL, "zNativeHandleField is invalid"); + return false; + } + + jlong zParcelNative = env->GetLongField(parcel, zNativeHandleField); + auto nativeParcel = reinterpret_cast(zParcelNative); + + if (nativeParcel == nullptr) { + HiLog::Error(LABEL, "get native parcel failed."); + return false; + } + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "write to parcel failed, pixel map pointer is null."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + int32_t bufferSize = pixelMap.GetByteCount(); + if (static_cast(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH) > nativeParcel->GetDataCapacity() && + !nativeParcel->SetDataCapacity(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH)) { + HiLog::Error(LABEL, "set parcel max capacity:[%{public}d] failed.", bufferSize + PIXEL_MAP_INFO_MAX_LENGTH); + return false; + } + if (!nativeParcel->WriteInt32(pixelMap.GetWidth())) { + HiLog::Error(LABEL, "write pixel map width:[%{public}d] to parcel failed.", pixelMap.GetWidth()); + return false; + } + if (!nativeParcel->WriteInt32(pixelMap.GetHeight())) { + HiLog::Error(LABEL, "write pixel map height:[%{public}d] to parcel failed.", pixelMap.GetHeight()); + return false; + } + if (!nativeParcel->WriteInt32(static_cast(pixelMap.GetPixelFormat()))) { + HiLog::Error(LABEL, "write pixel map pixel format:[%{public}d] to parcel failed.", pixelMap.GetPixelFormat()); + return false; + } + if (!nativeParcel->WriteInt32(static_cast(pixelMap.GetColorSpace()))) { + HiLog::Error(LABEL, "write pixel map color space:[%{public}d] to parcel failed.", pixelMap.GetColorSpace()); + return false; + } + if (!nativeParcel->WriteInt32(static_cast(pixelMap.GetAlphaType()))) { + HiLog::Error(LABEL, "write pixel map alpha type:[%{public}d] to parcel failed.", pixelMap.GetAlphaType()); + return false; + } + if (!nativeParcel->WriteInt32(pixelMap.GetBaseDensity())) { + HiLog::Error(LABEL, "write pixel map base density:[%{public}d] to parcel failed.", pixelMap.GetBaseDensity()); + return false; + } + if (!nativeParcel->WriteInt32(bufferSize)) { + HiLog::Error(LABEL, "write pixel map buffer size:[%{public}d] to parcel failed.", bufferSize); + return false; + } + if (!nativeParcel->WriteInt32(static_cast(pixelMap.GetAllocatorType()))) { + HiLog::Error(LABEL, "write pixel map allocator type:[%{public}d] to parcel failed.", pixelMap.GetAllocatorType()); + return false; + } + if (pixelMap.GetAllocatorType() == AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int *fd = static_cast(pixelMap.GetFd()); + if (*fd < 0) { + HiLog::Error(LABEL, "write pixel map failed, fd < 0."); + return false; + } + if (!nativeParcel->WriteFileDescriptor(*fd)) { + HiLog::Error(LABEL, "write pixel map fd:[%{public}d] to parcel failed.", *fd); + return false; + } +#endif + } else { + const uint8_t *addr = pixelMap.GetPixels(); + if (addr == nullptr) { + HiLog::Error(LABEL, "write to parcel failed, pixel memory is null."); + return false; + } + if (!nativeParcel->WriteBuffer(addr, bufferSize)) { + HiLog::Error(LABEL, "write pixel map buffer to parcel failed."); + return false; + } + } + return true; +} + +jobject CreatePixelMapObject(JNIEnv *env, PixelMapManager *pixelMapManager) +{ + return env->NewObject(g_pixelMapClz, g_pixelMapConstructorMethodId, reinterpret_cast(pixelMapManager), + static_cast(pixelMapManager->GetByteCount())); +} + +void ReleaseMemory(OHOS::Media::AllocatorType allocType, void *addr, int fd, uint32_t size, void *base) +{ + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int *fdAddr = static_cast(addr); + if (base != nullptr) { + ::munmap(base, size); + base = nullptr; + } + if (fdAddr != nullptr) { + ::close(*fdAddr); + delete fdAddr; + } +#endif + } else if (allocType == AllocatorType::HEAP_ALLOC) { + if (base != nullptr) { + free(base); + } + } +} + +jobject ohos_media_image_PixelMap_nativeCreateFromParcel(JNIEnv *env, jobject thiz, jobject parcel) +{ + HiLog::Debug(LABEL, "nativeCreateFromParcel."); + if (parcel == NULL) { + HiLog::Error(LABEL, "writeToParcel null parcel."); + return nullptr; + } + jclass zParcelClazz = env->GetObjectClass(parcel); + jfieldID zNativeHandleField = env->GetFieldID(zParcelClazz, "nativeHandle", "J"); + env->DeleteLocalRef(zParcelClazz); + if (zNativeHandleField == nullptr) { + HiLog::Error(LABEL, "zNativeHandleField is invalid"); + return nullptr; + } + + jlong zParcelNative = env->GetLongField(parcel, zNativeHandleField); + auto nativeParcel = reinterpret_cast(zParcelNative); + + if (nativeParcel == nullptr) { + HiLog::Error(LABEL, "get native parcel failed."); + return nullptr; + } + ImageInfo imgInfo; + imgInfo.size.width = nativeParcel->ReadInt32(); + imgInfo.size.height = nativeParcel->ReadInt32(); + imgInfo.pixelFormat = static_cast(nativeParcel->ReadInt32()); + imgInfo.colorSpace = static_cast(nativeParcel->ReadInt32()); + imgInfo.alphaType = static_cast(nativeParcel->ReadInt32()); + imgInfo.baseDensity = nativeParcel->ReadInt32(); + int32_t bufferSize = nativeParcel->ReadInt32(); + AllocatorType allocType = static_cast(nativeParcel->ReadInt32()); + uint8_t *base = nullptr; + int fd = 0; + void *context = nullptr; + if (allocType == AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + fd = nativeParcel->ReadFileDescriptor(); + if (fd < 0) { + HiLog::Error(LABEL, "fd < 0"); + return nullptr; + } + HiLog::Debug(LABEL, "ReadFileDescriptor fd %{public}d.", fd); + void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + HiLog::Error(LABEL, "shared memory map failed"); + return nullptr; + } + context = new int32_t(); + if (context == nullptr) { + HiLog::Error(LABEL, "alloc sizeof(fd) size:[%{public}zu] error.", sizeof(fd)); + ::munmap(ptr, bufferSize); + ::close(fd); + return nullptr; + } + *static_cast(context) = fd; + base = static_cast(ptr); +#endif + } else { + const uint8_t *addr = nativeParcel->ReadBuffer(bufferSize); + if (addr == nullptr) { + HiLog::Error(LABEL, "read buffer from parcel failed, read buffer addr is null"); + return nullptr; + } + base = static_cast(malloc(bufferSize)); + if (base == nullptr) { + HiLog::Error(LABEL, "alloc output pixel memory size:[%{public}d] error.", bufferSize); + return nullptr; + } + if (memcpy_s(base, bufferSize, addr, bufferSize) != 0) { + free(base); + base = nullptr; + HiLog::Error(LABEL, "memcpy pixel data size:[%{public}d] error.", bufferSize); + return nullptr; + } + } + std::unique_ptr pixelMap = std::make_unique(); + if (pixelMap.get() == nullptr) { + ReleaseMemory(allocType, context, fd, bufferSize, base); + HiLog::Error(LABEL, "create pixel map failed, malloc error."); + return nullptr; + } + uint32_t ret = pixelMap->SetImageInfo(imgInfo); + if (ret != SUCCESS) { + ReleaseMemory(allocType, context, fd, bufferSize, base); + HiLog::Error(LABEL, "create pixel map from parcel failed, set image info error."); + return nullptr; + } + pixelMap->SetPixelsAddr(base, context, bufferSize, allocType, nullptr); + PixelMapManager *pixelMapManager = new (std::nothrow) PixelMapManager(pixelMap.release()); + if (pixelMapManager == nullptr) { + ReleaseMemory(allocType, context, fd, bufferSize, base); + HiLog::Error(LABEL, "new pixelMap manager failed."); + return nullptr; + } + return CreatePixelMapObject(env, pixelMapManager); +} + +jobject ohos_media_image_PixelMap_nativeCreateByColors(JNIEnv *env, jclass thiz, jintArray colors, jint offset, + jint stride, jint width, jint height, jint pixelFormat, + jint alphaType, jboolean editable) +{ + if (colors == nullptr) { + HiLog::Error(LABEL, "CreatePixelmap : colors is null."); + return nullptr; + } + uint64_t arrayLength = env->GetArrayLength(colors); + uint32_t *array = reinterpret_cast(env->GetIntArrayElements(colors, nullptr)); + uint32_t colorLength = static_cast(arrayLength); + + InitializationOptions initializationOpts; + initializationOpts.size.width = width; + initializationOpts.size.height = height; + initializationOpts.pixelFormat = static_cast(pixelFormat); + PixelFormatToNative(initializationOpts.pixelFormat); + initializationOpts.alphaType = static_cast(alphaType); + initializationOpts.editable = editable; + + std::unique_ptr pixelMap = PixelMap::Create(array, colorLength, offset, stride, initializationOpts); + env->ReleaseIntArrayElements(colors, reinterpret_cast(array), JNI_ABORT); + if (pixelMap == nullptr) { + return nullptr; + } + PixelMapManager *pixelMapManager = new (std::nothrow) PixelMapManager(pixelMap.release()); + if (pixelMapManager == nullptr) { + return nullptr; + } + return CreatePixelMapObject(env, pixelMapManager); +} + +jobject ohos_media_image_PixelMap_nativeCreateByOptions(JNIEnv *env, jclass thiz, jint width, jint height, + jint pixelFormat, jint alphaType, jboolean editable) +{ + InitializationOptions initializationOpts; + initializationOpts.size.width = width; + initializationOpts.size.height = height; + initializationOpts.pixelFormat = static_cast(pixelFormat); + PixelFormatToNative(initializationOpts.pixelFormat); + initializationOpts.alphaType = static_cast(alphaType); + initializationOpts.editable = editable; + + std::unique_ptr pixelMap = PixelMap::Create(initializationOpts); + if (pixelMap == nullptr) { + return nullptr; + } + PixelMapManager *pixelMapManager = new (std::nothrow) PixelMapManager(pixelMap.release()); + if (pixelMapManager == nullptr) { + return nullptr; + } + return CreatePixelMapObject(env, pixelMapManager); +} + +jobject ohos_media_image_PixelMap_nativeCreateBySource(JNIEnv *env, jclass thiz, jobject srcPixelMap, jint rectX, + jint rectY, jint rectWidth, jint rectHeight, jint width, + jint height, jint pixelFormat, jint alphaType, + jint scaleMode, jboolean useSourceIfMatch, + jboolean editable) +{ + if (srcPixelMap == nullptr) { + HiLog::Error(LABEL, "source pixelMap jobject is null"); + return nullptr; + } + PixelMapManager *pixelMapManager = + reinterpret_cast(env->GetLongField(srcPixelMap, g_nativePixelMapFieldId)); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "source native pixelMap is null"); + return nullptr; + } + PixelMap &source = pixelMapManager->GetPixelMap(); + Rect rect; + rect.left = rectX; + rect.top = rectY; + rect.width = rectWidth; + rect.height = rectHeight; + + InitializationOptions initializationOpts; + initializationOpts.size.width = width; + initializationOpts.size.height = height; + initializationOpts.pixelFormat = static_cast(pixelFormat); + PixelFormatToNative(initializationOpts.pixelFormat); + initializationOpts.alphaType = static_cast(alphaType); + initializationOpts.scaleMode = static_cast(scaleMode); + initializationOpts.useSourceIfMatch = useSourceIfMatch; + initializationOpts.editable = editable; + + std::unique_ptr pixelMap = PixelMap::Create(source, rect, initializationOpts); + if (pixelMap == nullptr) { + return nullptr; + } + if (pixelMap->IsSourceAsResponse()) { + pixelMap.release(); + return srcPixelMap; + } + PixelMapManager *newPixelMapManager = new (std::nothrow) PixelMapManager(pixelMap.release()); + if (newPixelMapManager == nullptr) { + return nullptr; + } + return CreatePixelMapObject(env, newPixelMapManager); +} + +jint ohos_media_image_PixelMap_nativeGetBytesNumberPerRow(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native GetBytesNumberPerRow, pixelMap is null."); + return ERR_MEDIA_INVALID_VALUE; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + return static_cast(pixelMap.GetRowBytes()); +} + +jlong ohos_media_image_PixelMap_nativeGetBytesNumber(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native GetBytesNumber, pixelMap is null."); + return ERR_MEDIA_INVALID_VALUE; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + return pixelMap.GetByteCount(); +} + +jlong ohos_media_image_PixelMap_nativeGetPixelBytesCapacity(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native GetPixelBytesCapacity, pixelMap is null."); + return ERR_MEDIA_INVALID_VALUE; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + return pixelMap.GetCapacity(); +} + +jboolean ohos_media_image_PixelMap_nativeIsEditable(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native IsEditable, pixelMap is null."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + return pixelMap.IsEditable(); +} + +jboolean ohos_media_image_PixelMap_nativeIsSameImage(JNIEnv *env, jclass thiz, jlong nativePtr, + jlong otherNativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + PixelMapManager *other = reinterpret_cast(otherNativePtr); + if (pixelMapManager == nullptr || other == nullptr || pixelMapManager->Invalid() || other->Invalid()) { + HiLog::Error(LABEL, "native IsSameImage, curPixelMap or otherPixelMap is null."); + return false; + } + PixelMap &curPixelMap = pixelMapManager->GetPixelMap(); + return curPixelMap.IsSameImage(other->GetPixelMap()); +} + +jint ohos_media_image_PixelMap_nativeReadPixel(JNIEnv *env, jclass thiz, jlong nativePtr, jint x, jint y) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native read pixel by pos, pixelMap is null."); + ThrowIllegalStateException(env, "native read pixel by pos, pixelMap is null"); + return ERR_MEDIA_INVALID_VALUE; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + Position pos{ x, y }; + uint32_t dst = 0; + uint32_t ret = pixelMap.ReadPixel(pos, dst); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "native read pixel by pos, ReadPixel fail.ret=%{public}u", ret); + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native read pixel by pos, invalid input parameters"); + return ERR_MEDIA_INVALID_VALUE; + } + ThrowIllegalStateException(env, "native read pixel by pos, some error occurred in pixelmap"); + return ERR_MEDIA_INVALID_VALUE; + } + return static_cast(dst); +} + +jboolean ohos_media_image_PixelMap_nativeReadPixelsToIntArray(JNIEnv *env, jclass thiz, jlong nativePtr, + jintArray nativePixels, jint nativeOffset, + jint nativeStride, jint x, jint y, jint width, + jint height) +{ + if (nativePixels == nullptr) { + HiLog::Error(LABEL, "native read pixels by rect, nativePixels is null."); + return false; + } + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native read pixels by rect, pixelMap is null."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + Rect srcRegion{ x, y, width, height }; + jint *dst = env->GetIntArrayElements(nativePixels, nullptr); + if (dst == nullptr) { + HiLog::Error(LABEL, "native read pixels by rect GetIntArrayElements return dst is null."); + return false; + } + uint64_t dstLen = static_cast(env->GetArrayLength(nativePixels)) * 4; // jintArray is 4 bytes + uint32_t dstRowBytes = static_cast(nativeStride) * 4; // "4" is pixel format size. + uint32_t offset = static_cast(nativeOffset) * 4; // shift as bytes count, need need multiply 4 + uint32_t ret = pixelMap.ReadPixels(dstLen, offset, dstRowBytes, srcRegion, reinterpret_cast(dst)); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native read pixel by rect, invalid input parameters"); + } + HiLog::Error(LABEL, "native read pixels by rect, ReadPixels fail, ret=%{public}u", ret); + env->ReleaseIntArrayElements(nativePixels, dst, 0); + return false; + } + env->ReleaseIntArrayElements(nativePixels, dst, 0); + return true; +} + +void *GetBufferAddress(JNIEnv *env, jobject jbuffer) +{ + jlong pointer = 0L; + if (!GetBufferPointer(env, jbuffer, pointer)) { + HiLog::Error(LABEL, "GetBufferAddress call GetNioBufferPointer fail."); + return nullptr; + } + jarray array = nullptr; + void *elements = nullptr; + void *dstAddress = nullptr; + if (pointer != 0L) { + // Buffer is backed by a direct buffer. + dstAddress = reinterpret_cast(pointer); + } else { + // Buffer is backed by a managed array. + jint byteOffset = 0; + if (!PixelMapJniUtilsAdapter::GetBufferBaseArrayOffset(env, jbuffer, byteOffset)) { + HiLog::Error(LABEL, "GetBufferAddress call GetNioBufferBaseArrayOffset fail."); + return nullptr; + } + array = PixelMapJniUtilsAdapter::GetBufferBaseArray(env, jbuffer); + if (array == nullptr) { + HiLog::Error(LABEL, "GetBufferAddress call GetNioBufferBaseArray fail."); + return nullptr; + } + elements = env->GetPrimitiveArrayCritical(array, nullptr); + dstAddress = reinterpret_cast(reinterpret_cast(elements) + byteOffset); + env->ReleasePrimitiveArrayCritical(array, elements, 0); + } + return dstAddress; +} + +jboolean ohos_media_image_PixelMap_nativeReadPixelsToBuffer(JNIEnv *env, jclass thiz, jlong nativePtr, + jobject nioBuffer, jlong nioBufferSize) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (nioBuffer == nullptr || pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native read pixels to buffer, nioBuffer or pixelMap is null."); + return false; + } + void *dstAddress = GetBufferAddress(env, nioBuffer); + if (dstAddress == nullptr) { + HiLog::Error(LABEL, "native read pixels to buffer, dstAddress is null."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + uint32_t ret = pixelMap.ReadPixels(nioBufferSize, static_cast(dstAddress)); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native read pixel to buffer, invalid input parameters"); + } + HiLog::Error(LABEL, "native read pixels to buffer, ReadPixels fail, ret=%{public}u", ret); + return false; + } + return true; +} + +jboolean ohos_media_image_PixelMap_nativeResetConfig(JNIEnv *env, jclass thiz, jlong nativePtr, jint width, + jint height, jint nativePixelFormat) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr) { + HiLog::Error(LABEL, "nativeResetConfig input parameters invalid."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + Size size{ width, height }; + uint32_t ret = pixelMap.ResetConfig(size, static_cast(nativePixelFormat)); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native reset config, invalid input parameters"); + } + HiLog::Error(LABEL, "nativeResetConfig to call ResetConfig fail,ret=%{public}u", ret); + return false; + } + return true; +} + +jboolean ohos_media_image_PixelMap_nativeSetAlphaType(JNIEnv *env, jclass thiz, jlong nativePtr, + jint nativeAlphaType) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "nativeSetAlphaType input parameters invalid."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + if (!pixelMap.SetAlphaType(static_cast(nativeAlphaType))) { + HiLog::Error(LABEL, "nativeSetAlphaType call SetAlphaType to set PixelNap AlphaType fail."); + return false; + } + return true; +} + +jboolean ohos_media_image_PixelMap_nativeWritePixel(JNIEnv *env, jclass thiz, jlong nativePtr, jint x, jint y, + jint nativeColor) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native write pixel by pos input parameters invalid."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + Position pos{ x, y }; + uint32_t ret = pixelMap.WritePixel(pos, static_cast(nativeColor)); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native write pixel by pos, invalid input parameters"); + } + HiLog::Error(LABEL, "native write pixel by pos call WritePixel func fail, ret=%{public}d", ret); + return false; + } + return true; +} + +jboolean ohos_media_image_PixelMap_nativeWritePixelsByIntArray(JNIEnv *env, jclass thiz, jlong nativePtr, + jintArray nativePixels, jint nativeOffset, + jint nativeStride, jint x, jint y, jint width, + jint height) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (nativePixels == nullptr || pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native write pixel by rect input parameters is invalid."); + return false; + } + Rect dstRegion{ x, y, width, height }; + jint *srcPixels = env->GetIntArrayElements(nativePixels, nullptr); + if (srcPixels == nullptr) { + HiLog::Error(LABEL, "native write pixel by rect call GetIntArrayElements is null."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + uint64_t srcPixelsLen = static_cast(env->GetArrayLength(nativePixels)) * 4; // jintArray is 4 bytes + uint32_t rowDataSize = static_cast(nativeStride) * 4; // jintArray is 4 bytes + uint32_t offset = static_cast(nativeOffset) * 4; // shift as bytes count, need need multiply 4 + uint32_t ret = + pixelMap.WritePixels(reinterpret_cast(srcPixels), srcPixelsLen, offset, rowDataSize, dstRegion); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native write pixel by rect, invalid input parameters"); + } + HiLog::Error(LABEL, "native write pixel by rect call WritePixels fail, ret=%{public}u", ret); + env->ReleaseIntArrayElements(nativePixels, srcPixels, 0); + return false; + } + env->ReleaseIntArrayElements(nativePixels, srcPixels, 0); + return true; +} + +jboolean ohos_media_image_PixelMap_nativeWritePixelsFromBuffer(JNIEnv *env, jclass thiz, jlong nativePtr, + jobject nativeBuffer, jlong nativeBufferSize) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (nativeBuffer == nullptr || pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native write pixel by buffer input parameters is invalid."); + return false; + } + void *srcAddress = GetBufferAddress(env, nativeBuffer); + if (srcAddress == nullptr) { + HiLog::Error(LABEL, "native write pixel by buffer srcAddress is null."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + uint32_t ret = pixelMap.WritePixels(static_cast(srcAddress), nativeBufferSize); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_INVALID_PARAMETER) { + ThrowIllegalArgumentException(env, "native write pixel from buffer, invalid input parameters"); + } + HiLog::Error(LABEL, "native write pixel by buffer failed,ret=%{public}u.", ret); + return false; + } + + return true; +} + +jboolean ohos_media_image_PixelMap_nativeWritePixelsFromInt(JNIEnv *env, jclass thiz, jlong nativePtr, + jint nativeColor) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native erase by color input parameters is invalid."); + return false; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + if (!pixelMap.WritePixels(nativeColor)) { + HiLog::Error(LABEL, "native erase by color call WritePixels return fail."); + return false; + } + return true; +} + +#if !defined(_WIN32) && !defined(_APPLE) +jobject ohos_media_image_PixelMap_nativeCreateFromAlpha(JNIEnv *env, jclass thiz, jlong nativePtr) +{ + PixelMapManager *pixelMapManager = reinterpret_cast(nativePtr); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "native CreateFromAlpha input parameters is invalid."); + return nullptr; + } + PixelMap &pixelMapSrc = pixelMapManager->GetPixelMap(); + PixelMap *pixelMapRet = ImageBitmapConverter::createFromAlpha(&pixelMapSrc); + + if (pixelMapRet == nullptr) { + HiLog::Error(LABEL, "native CreateFromAlpha get alpha pixelmap failed."); + } + + PixelMapManager *newPixelMapManager = new (std::nothrow) PixelMapManager(pixelMapRet); + if (newPixelMapManager == nullptr) { + HiLog::Error(LABEL, "native CreateFromAlpha create pixelmapmanager failed."); + return nullptr; + } + return CreatePixelMapObject(env, newPixelMapManager); +} +#endif + +void FreePixelMap(PixelMapManager *manager) +{ + if (manager != nullptr) { + delete manager; + } +} + +jlong ohos_media_image_PixelMap_nativeGetFreeFunction(JNIEnv *env, jclass thiz) +{ + return static_cast(reinterpret_cast(&FreePixelMap)); +} + +const JNINativeMethod METHODS[] = { + { "nativeGetImageInfo", "(J)Lohos/media/image/common/ImageInfo;", + reinterpret_cast(ohos_media_image_PixelMap_nativeGetImageInfo) }, + { "nativeRelease", "(JJ)V", reinterpret_cast(ohos_media_image_PixelMap_nativeRelease) }, + { "nativeWriteToParcel", "(JLohos/utils/Parcel;)Z", + reinterpret_cast(ohos_media_image_PixelMap_nativeWriteToParcel) }, + { "nativeCreateFromParcel", "(Lohos/utils/Parcel;)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_PixelMap_nativeCreateFromParcel) }, + { "nativeCreate", "([IIIIIIIZ)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_PixelMap_nativeCreateByColors) }, + { "nativeCreate", "(IIIIZ)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_PixelMap_nativeCreateByOptions) }, + { "nativeCreate", "(Lohos/media/image/PixelMap;IIIIIIIIIZZ)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_PixelMap_nativeCreateBySource) }, + { "nativeGetBytesNumberPerRow", "(J)I", + reinterpret_cast(ohos_media_image_PixelMap_nativeGetBytesNumberPerRow) }, + { "nativeGetBytesNumber", "(J)J", reinterpret_cast(ohos_media_image_PixelMap_nativeGetBytesNumber) }, + { "nativeGetPixelBytesCapacity", "(J)J", + reinterpret_cast(ohos_media_image_PixelMap_nativeGetPixelBytesCapacity) }, + { "nativeIsEditable", "(J)Z", reinterpret_cast(ohos_media_image_PixelMap_nativeIsEditable) }, + { "nativeIsSameImage", "(JJ)Z", reinterpret_cast(ohos_media_image_PixelMap_nativeIsSameImage) }, + { "nativeReadPixel", "(JII)I", reinterpret_cast(ohos_media_image_PixelMap_nativeReadPixel) }, + { "nativeReadPixels", "(J[IIIIIII)Z", + reinterpret_cast(ohos_media_image_PixelMap_nativeReadPixelsToIntArray) }, + { "nativeReadPixels", "(JLjava/nio/Buffer;J)Z", + reinterpret_cast(ohos_media_image_PixelMap_nativeReadPixelsToBuffer) }, + { "nativeResetConfig", "(JIII)Z", reinterpret_cast(ohos_media_image_PixelMap_nativeResetConfig) }, + { "nativeSetAlphaType", "(JI)Z", reinterpret_cast(ohos_media_image_PixelMap_nativeSetAlphaType) }, + { "nativeWritePixel", "(JIII)Z", reinterpret_cast(ohos_media_image_PixelMap_nativeWritePixel) }, + { "nativeWritePixels", "(J[IIIIIII)Z", + reinterpret_cast(ohos_media_image_PixelMap_nativeWritePixelsByIntArray) }, + { "nativeWritePixels", "(JLjava/nio/Buffer;J)Z", + reinterpret_cast(ohos_media_image_PixelMap_nativeWritePixelsFromBuffer) }, + { "nativeWritePixels", "(JI)Z", reinterpret_cast(ohos_media_image_PixelMap_nativeWritePixelsFromInt) }, + { "nativeGetFreeFunction", "()J", reinterpret_cast(ohos_media_image_PixelMap_nativeGetFreeFunction) }, +#if !defined(_WIN32) && !defined(_APPLE) + { "nativeCreateFromAlpha", "(J)Lohos/media/image/PixelMap;", + reinterpret_cast(ohos_media_image_PixelMap_nativeCreateFromAlpha) }, +#endif +}; + +jint RegisterGlobalCache(JNIEnv *env) +{ + if (env != nullptr) { + jobject pixelMapClz = env->FindClass("ohos/media/image/PixelMap"); + if (pixelMapClz == nullptr) { + HiLog::Error(LABEL, "find pixel map class failed."); + return ERROR; + } + g_pixelMapClz = static_cast(env->NewGlobalRef(pixelMapClz)); + if (g_pixelMapClz == nullptr) { + HiLog::Error(LABEL, "register global pixelMap clz failed."); + return ERROR; + } + g_pixelMapConstructorMethodId = env->GetMethodID(g_pixelMapClz, "", "(JJ)V"); + if (g_pixelMapConstructorMethodId == nullptr) { + HiLog::Error(LABEL, "get pixelmap constructor method Id failed."); + return ERROR; + } + g_nativePixelMapFieldId = env->GetFieldID(g_pixelMapClz, "nativeImagePixelMap", "J"); + if (g_nativePixelMapFieldId == nullptr) { + HiLog::Error(LABEL, "get native pixelmap fieldId failed."); + return ERROR; + } + return SUCCESS; + } + return ERROR; +} +} // namespace + +namespace OHOS { +namespace Media { +void ohos_media_image_GetImageInfo(JNIEnv *env, jobject pixelMapObject, OhosPixelMapInfo &info) +{ + PixelMapManager *pixelMapManager = + reinterpret_cast(env->GetLongField(pixelMapObject, g_nativePixelMapFieldId)); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "getImageInfo:source native pixelMap is null"); + return; + } + PixelMap &pixelMap = pixelMapManager->GetPixelMap(); + info.width = pixelMap.GetWidth(); + info.height = pixelMap.GetHeight(); + info.rowSize = pixelMap.GetRowBytes(); + PixelFormat pixelFormat = pixelMap.GetPixelFormat(); + HiLog::Error(LABEL, "getImageInfo:format:%{public}d", pixelFormat); + switch (pixelFormat) { + case PixelFormat::RGBA_8888: + info.pixelFormat = OHOS_PIXEL_MAP_FORMAT_RGBA_8888; + break; + case PixelFormat::RGB_565: + info.pixelFormat = OHOS_PIXEL_MAP_FORMAT_RGB_565; + break; + default: + info.pixelFormat = OHOS_PIXEL_MAP_FORMAT_NONE; + break; + } +} + +void *ohos_media_image_AccessPixels(JNIEnv *env, jobject pixelMapObject) +{ + if (pixelMapObject == nullptr) { + HiLog::Error(LABEL, "accessPixels:pixelMapObject is null"); + return nullptr; + } + + PixelMapManager *pixelMapManager = + reinterpret_cast(env->GetLongField(pixelMapObject, g_nativePixelMapFieldId)); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "accessPixels:source native pixelMap is null"); + return nullptr; + } + + pixelMapManager->Ref(); + return pixelMapManager->GetPixelMap().GetWritablePixels(); +} + +bool ohos_media_image_UnAccessPixels(JNIEnv *env, jobject pixelMapObject) +{ + if (pixelMapObject == nullptr) { + HiLog::Error(LABEL, "unAccessPixels:pixelMapObject is null"); + return false; + } + PixelMapManager *pixelMapManager = + reinterpret_cast(env->GetLongField(pixelMapObject, g_nativePixelMapFieldId)); + if (pixelMapManager == nullptr || pixelMapManager->Invalid()) { + HiLog::Error(LABEL, "unAccessPixels::source native pixelMap is null"); + return false; + } + if (pixelMapManager->GetPixelMap().GetSptrRefCount() == 0) { + HiLog::Error(LABEL, "unAccessPixels::native ptr ref count is zero"); + return false; + } + pixelMapManager->UnRef(); + return true; +} +} // namespace Media +} // namespace OHOS + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + HiLog::Debug(LABEL, "JNI_OnLoad begin"); + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + HiLog::Error(LABEL, "JNI_OnLoad: GetEnv failed"); + return ERROR; + } + int ret = JkitRegisterNativeMethods(env, "ohos/media/image/PixelMap", METHODS, ARRCOUNT(METHODS)); + if (ret == JNI_ERR) { + HiLog::Error(LABEL, "JkitRegisterNativeMethods failed, ret=%{public}d", ret); + return ERROR; + } + Jkit::nativeInit(vm); + HiLog::Debug(LABEL, "JNI_OnLoad end"); + + if (RegisterGlobalCache(env) == ERROR) { + HiLog::Error(LABEL, "register global cache failed."); + return ERROR; + } + return JNI_VERSION_1_4; +} diff --git a/ide/BUILD.gn b/ide/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2e825ab94387cb52d27a3035f30d4bd2ca17b6a3 --- /dev/null +++ b/ide/BUILD.gn @@ -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("//build/config/ohos/rules.gni") +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +group("image_decode_only") { + if (host_os == "mac") { + deps = [ + "//foundation/multimedia/image_standard/frameworks/jni/imagesource:image_source_jni(${mac_buildtool})", + "//foundation/multimedia/image_standard/frameworks/jni/incrementalpixelmap:incremental_pixelmap_jni(${mac_buildtool})", + "//foundation/multimedia/image_standard/frameworks/jni/pixelmap:pixelmap_jni(${mac_buildtool})", + "//foundation/multimedia/image_standard/interfaces/innerkits:image(${mac_buildtool})", + "//foundation/multimedia/image_standard/plugins/common/libs:multimediaplugin(${mac_buildtool})", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager(${mac_buildtool})", + ] + } else { + deps = [ + "//foundation/multimedia/image_standard/frameworks/jni/imagesource:image_source_jni(${windows_buildtool})", + "//foundation/multimedia/image_standard/frameworks/jni/incrementalpixelmap:incremental_pixelmap_jni(${windows_buildtool})", + "//foundation/multimedia/image_standard/frameworks/jni/pixelmap:pixelmap_jni(${windows_buildtool})", + "//foundation/multimedia/image_standard/interfaces/innerkits:image(${windows_buildtool})", + "//foundation/multimedia/image_standard/plugins/common/libs:multimediaplugin(${windows_buildtool})", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager(${windows_buildtool})", + ] + } +} + +#ohos_combine_jars("image_decode_only_java") { +# deps = [ +# "//foundation/multimedia/image_standard/interfaces/kits/java:image_decode_java", +# "//foundation/multimedia/image_standard/mock/java/src/ohos:mock_java", +# ] +# subsystem_name = "multimedia" +#} + +config("media_config") { + defines = [] + if (current_cpu == "arm64" || (current_cpu == "arm" && arm_use_neon)) { + defines += [ "USE_NEON" ] + } +} diff --git a/ide/image_decode_config.gni b/ide/image_decode_config.gni new file mode 100644 index 0000000000000000000000000000000000000000..4f32884bf1486b969b5a9fd4320a2ca0f8cb9c77 --- /dev/null +++ b/ide/image_decode_config.gni @@ -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. + +# source code for Windows. +use_mingw_win = "${current_os}_${current_cpu}" == "mingw_x86_64" +use_clang_mac = "${current_os}_${current_cpu}" == "mac_x64" + +# Toolchain +windows_buildtool = "//build/toolchain/mingw:mingw_x86_64" +mac_buildtool = "//build/toolchain/mac:clang_x64" + +# Defines +image_decode_windows_defines = [ "_WIN32" ] +image_decode_mac_defines = [ "_APPLE" ] diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..10a4f7b16cf9e315409e0b20553a4318a5c79385 --- /dev/null +++ b/interfaces/innerkits/BUILD.gn @@ -0,0 +1,224 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +config("image_external_config") { + include_dirs = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//utils/jni/jnikit/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + if (use_mingw_win) { + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + } else if (use_clang_mac) { + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + } else { + include_dirs += [ + "//utils/native/base/include", + "//third_party/libpng", + "//third_party/libjpeg-turbo", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + } +} + +ohos_shared_library("image") { + public_configs = [ ":image_external_config" ] + + sources = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_source.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/common/src/incremental_pixel_map.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/common/src/pixel_map.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/common/src/pixel_map_parcel.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/matrix.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/post_proc.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/scan_line_filter.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/incremental_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/istream_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + sources -= [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp", + ] + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter_static", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + sources -= [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp", + ] + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter_static", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + defines = [ "DUAL_ADAPTER" ] + DUAL_ADAPTER = true + + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { +# aosp_deps = [ +# "shared_library:libjpeg", +# "shared_library:libpng", +# ] + } else { + deps += [ + "//third_party/libjpeg-turbo:libjpeg-turbo", + "//third_party/libpng:libpng", + ] + } + external_deps = [ +# "bytrace:bytrace_core", +# "hilog:libhilog", + "bytrace_standard:bytrace_core", + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + + ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_static_library("image_static") { + public_configs = [ ":image_external_config" ] + + sources = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_source.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/common/src/incremental_pixel_map.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/common/src/pixel_map.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/basic_transformer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/matrix.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/post_proc.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/converter/src/scan_line_filter.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/incremental_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/istream_source_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + sources -= [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp", + ] + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter_static", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + sources -= [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/codec/src/image_packer_ex.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/buffer_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/file_packer_stream.cpp", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/stream/src/ostream_packer_stream.cpp", + ] + + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter_static", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//utils/native/base:utilsecurec", + ] + } else { + defines = [ "DUAL_ADAPTER" ] + DUAL_ADAPTER = true + + deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/pixelconverter:pixelconvertadapter", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { +# aosp_deps = [ +# "shared_library:libjpeg", +# "shared_library:libpng", +# ] + } else { + deps += [ + "//third_party/libjpeg-turbo:libjpeg-turbo", + "//third_party/libpng:libpng", + ] + } +# external_deps = [ +# "bytrace:bytrace_core", +# "hilog:libhilog", +# ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/interfaces/innerkits/include/decode_listener.h b/interfaces/innerkits/include/decode_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..93cda60e69428311f34b04a2cabfeec62c0ae96b --- /dev/null +++ b/interfaces/innerkits/include/decode_listener.h @@ -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. + */ + +#ifndef DECODE_LISTENER_H +#define DECODE_LISTENER_H + +namespace OHOS { +namespace Media { +class DecodeListener { +public: + DecodeListener() = default; + virtual ~DecodeListener() = default; + virtual void OnEvent(int event) = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif // DECODE_LISTENER_H \ No newline at end of file diff --git a/interfaces/innerkits/include/image_native_interface_utils.h b/interfaces/innerkits/include/image_native_interface_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..2f6f0fe224b8526c7e9d2710d18369caca607bce --- /dev/null +++ b/interfaces/innerkits/include/image_native_interface_utils.h @@ -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. + */ + +#ifndef IMAGE_NATIVE_INTERFACE_UTILS_H +#define IMAGE_NATIVE_INTERFACE_UTILS_H + +#include "pixel_map.h" +#include "jkit_utils.h" + +namespace OHOS { +namespace Media { +PixelMap *GetNativePixelMap(JNIEnv *env, jobject pixelMapObj); +jobject GetNativeBitmap(JNIEnv *env, jobject pixelMapObj); +jobject GetShellPixelMap(JNIEnv *env, jobject bitmapObj); +void PixelMapWriteToParcel(JNIEnv *env, jobject pixelMapObj, jobject parcel); +} // namespace Media +} // namespace OHOS +#endif // IMAGE_NATIVE_INTERFACE_UTILS_H diff --git a/interfaces/innerkits/include/image_packer.h b/interfaces/innerkits/include/image_packer.h new file mode 100644 index 0000000000000000000000000000000000000000..4154b63bfca74d40a2e924fa46aa2cec7edeed40 --- /dev/null +++ b/interfaces/innerkits/include/image_packer.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_PACKER_H +#define IMAGE_PACKER_H + +#include +#include "image_source.h" +#include "image_type.h" +#include "nocopyable.h" +#include "pixel_map.h" + +namespace OHOS { +namespace MultimediaPlugin { +class PluginServer; +} // namespace MultimediaPlugin +} // namespace OHOS + +namespace OHOS { +namespace ImagePlugin { +struct PlEncodeOptions; +class AbsImageEncoder; +} // namespace ImagePlugin +} // namespace OHOS + +namespace OHOS { +namespace Media { +struct PackOption { + /** + * Specify the file format of the output image. + */ + std::string format; + /** + * Hint to the compression quality, 0-100. + * Larger values indicate higher image quality but usually take up larger sizes. + */ + uint8_t quality = 100; + + /** + * Hint to how many images will be packed into the image file. + */ + uint32_t numberHint = 1; +}; + +class PackerStream; + +class ImagePacker { +public: + ImagePacker(); + ~ImagePacker(); + static uint32_t GetSupportedFormats(std::set &formats); + uint32_t StartPacking(uint8_t *data, uint32_t maxSize, const PackOption &option); + uint32_t StartPacking(const std::string &filePath, const PackOption &option); + uint32_t StartPacking(std::ostream &outputStream, const PackOption &option); + uint32_t AddImage(PixelMap &pixelMap); + uint32_t AddImage(ImageSource &source); + uint32_t AddImage(ImageSource &source, uint32_t index); + uint32_t FinalizePacking(); + uint32_t FinalizePacking(int64_t &packedSize); + +protected: + uint32_t StartPackingAdapter(PackerStream &outputStream, const PackOption &option); + +private: + DISALLOW_COPY_AND_MOVE(ImagePacker); + static void CopyOptionsToPlugin(const PackOption &opts, ImagePlugin::PlEncodeOptions &plOpts); + uint32_t StartPackingImpl(const PackOption &option); + bool GetEncoderPlugin(const PackOption &option); + void FreeOldPackerStream(); + bool IsPackOptionValid(const PackOption &option); + static MultimediaPlugin::PluginServer &pluginServer_; + std::unique_ptr packerStream_; + std::unique_ptr encoder_; + std::unique_ptr pixelMap_; // inner imagesource create, our manage the lifecycle +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_PACKER_H \ No newline at end of file diff --git a/interfaces/innerkits/include/image_source.h b/interfaces/innerkits/include/image_source.h new file mode 100644 index 0000000000000000000000000000000000000000..74195469120d406dd03dceaccfd76bb00124b39c --- /dev/null +++ b/interfaces/innerkits/include/image_source.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_SOURCE_H +#define IMAGE_SOURCE_H + +#include +#include +#include +#include +#include +#include + +#include "decode_listener.h" +#include "image_type.h" +#include "incremental_pixel_map.h" +#include "peer_listener.h" +#include "pixel_map.h" + +namespace OHOS { +namespace MultimediaPlugin { +constexpr float EPSILON = 1e-6; + +class PluginServer; +} // namespace MultimediaPlugin +} // namespace OHOS + +namespace OHOS { +namespace ImagePlugin { +class AbsImageFormatAgent; +class AbsImageDecoder; +struct PixelDecodeOptions; +struct PlImageInfo; +} // namespace ImagePlugin +} // namespace OHOS + +namespace OHOS { +namespace Media { +struct SourceOptions { + std::string formatHint; + int32_t baseDensity = 0; +}; + +struct IncrementalSourceOptions { + SourceOptions sourceOptions; + IncrementalMode incrementalMode = IncrementalMode::FULL_DATA; +}; + +struct NinePatchInfo { + void *ninePatch = nullptr; + size_t patchSize = 0; +}; + +enum class DecodeEvent : int32_t { + EVENT_COMPLETE_DECODE = 0, + EVENT_PARTIAL_DECODE = 1, + EVENT_HEADER_DECODE = 2, + EVENT_LAST = 3 +}; + +enum class ImageDecodingState : int32_t { + UNRESOLVED = 0, + BASE_INFO_ERROR = 1, + BASE_INFO_PARSED = 2, + IMAGE_DECODING = 3, + IMAGE_ERROR = 4, + PARTIAL_IMAGE = 5, + IMAGE_DECODED = 6 +}; + +enum class SourceDecodingState : int32_t { + UNRESOLVED = 0, + SOURCE_ERROR = 1, + UNKNOWN_FORMAT = 2, + FORMAT_RECOGNIZED = 3, + UNSUPPORTED_FORMAT = 4, + FILE_INFO_ERROR = 5, + FILE_INFO_DECODED = 6, + IMAGE_DECODING = 7, + ALL_IMAGES_ERROR = 8 +}; + +enum class SourceInfoState : int32_t { + SOURCE_ERROR = 0, + SOURCE_INCOMPLETE = 1, + UNKNOWN_FORMAT = 2, + UNSUPPORTED_FORMAT = 3, + FILE_INFO_ERROR = 4, + FILE_INFO_PARSED = 5 +}; + +struct ImageDecodingStatus { + ImageInfo imageInfo; + ImageDecodingState imageState = ImageDecodingState::UNRESOLVED; +}; + +struct SourceInfo { + int32_t baseDensity = 0; + uint32_t topLevelImageNum = 0; + std::string encodedFormat; + SourceInfoState state = SourceInfoState::SOURCE_ERROR; +}; + +struct IncrementalDecodingContext { + std::unique_ptr decoder; + ImageDecodingState IncrementalState = ImageDecodingState::UNRESOLVED; + uint8_t decodingProgress = 0; +}; + +class SourceStream; + +class ImageSource { +public: + ~ImageSource(); + NATIVEEXPORT static uint32_t GetSupportedFormats(std::set &formats); + NATIVEEXPORT static std::unique_ptr CreateImageSource(std::unique_ptr is, + const SourceOptions &opts, uint32_t &errorCode); + NATIVEEXPORT static std::unique_ptr CreateImageSource(const uint8_t *data, uint32_t size, + const SourceOptions &opts, uint32_t &errorCode); + NATIVEEXPORT static std::unique_ptr CreateImageSource(const std::string &pathName, + const SourceOptions &opts, uint32_t &errorCode); + NATIVEEXPORT static std::unique_ptr CreateIncrementalImageSource(const IncrementalSourceOptions &opts, + uint32_t &errorCode); + + NATIVEEXPORT std::unique_ptr CreatePixelMap(const DecodeOptions &opts, uint32_t &errorCode) + { + return CreatePixelMap(0, opts, errorCode); + } + NATIVEEXPORT std::unique_ptr CreatePixelMap(uint32_t index, const DecodeOptions &opts, + uint32_t &errorCode); + NATIVEEXPORT std::unique_ptr CreateIncrementalPixelMap(uint32_t index, + const DecodeOptions &opts, + uint32_t &errorCode); + // for incremental source. + NATIVEEXPORT uint32_t UpdateData(const uint8_t *data, uint32_t size, bool isCompleted); + // for obtaining basic image information without decoding image data. + NATIVEEXPORT uint32_t GetImageInfo(ImageInfo &imageInfo) + { + return GetImageInfo(0, imageInfo); + } + NATIVEEXPORT uint32_t GetImageInfo(uint32_t index, ImageInfo &imageInfo); + NATIVEEXPORT const SourceInfo &GetSourceInfo(uint32_t &errorCode); + NATIVEEXPORT void RegisterListener(PeerListener *listener); + NATIVEEXPORT void UnRegisterListener(PeerListener *listener); + NATIVEEXPORT DecodeEvent GetDecodeEvent(); + NATIVEEXPORT void AddDecodeListener(DecodeListener *listener); + NATIVEEXPORT void RemoveDecodeListener(DecodeListener *listener); + NATIVEEXPORT bool IsIncrementalSource(); + NATIVEEXPORT uint32_t GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value); + NATIVEEXPORT const NinePatchInfo &GetNinePatchInfo() const; + NATIVEEXPORT void SetMemoryUsagePreference(const MemoryUsagePreference preference); + NATIVEEXPORT MemoryUsagePreference GetMemoryUsagePreference(); + +private: + DISALLOW_COPY_AND_MOVE(ImageSource); + using FormatAgentMap = std::map; + using ImageStatusMap = std::map; + using IncrementalRecordMap = std::map; + ImageSource(std::unique_ptr &&stream, const SourceOptions &opts); + uint32_t CheckEncodedFormat(ImagePlugin::AbsImageFormatAgent &agent); + static FormatAgentMap InitClass(); + uint32_t GetEncodedFormat(const std::string &formatHint, std::string &format); + uint32_t DecodeImageInfo(uint32_t index, ImageStatusMap::iterator &iter); + uint32_t DecodeSourceInfo(bool isAcquiredImageNum); + uint32_t InitMainDecoder(); + ImagePlugin::AbsImageDecoder *CreateDecoder(uint32_t &errorCode); + void CopyOptionsToPlugin(const DecodeOptions &opts, ImagePlugin::PixelDecodeOptions &plOpts); + void CopyOptionsToProcOpts(const DecodeOptions &opts, DecodeOptions &procOpts, PixelMap &pixelMap); + uint32_t CheckFormatHint(const std::string &formatHint, FormatAgentMap::iterator &formatIter); + uint32_t GetSourceInfo(); + uint32_t OnSourceRecognized(bool isAcquiredImageNum); + uint32_t OnSourceUnresolved(); + uint32_t SetDecodeOptions(std::unique_ptr &decoder, uint32_t index, + const DecodeOptions &opts, ImagePlugin::PlImageInfo &plInfo); + uint32_t UpdatePixelMapInfo(const DecodeOptions &opts, ImagePlugin::PlImageInfo &plInfo, PixelMap &pixelMap); + // declare friend class, only IncrementalPixelMap can call PromoteDecoding function. + friend class IncrementalPixelMap; + uint32_t PromoteDecoding(uint32_t index, const DecodeOptions &opts, PixelMap &pixelMap, ImageDecodingState &state, + uint8_t &decodeProgress); + void DetachIncrementalDecoding(PixelMap &pixelMap); + ImageStatusMap::iterator GetValidImageStatus(uint32_t index, uint32_t &errorCode); + uint32_t AddIncrementalContext(PixelMap &pixelMap, IncrementalRecordMap::iterator &iterator); + uint32_t DoIncrementalDecoding(uint32_t index, const DecodeOptions &opts, PixelMap &pixelMap, + IncrementalDecodingContext &recordContext); + void SetIncrementalSource(const bool isIncrementalSource); + bool IsStreamCompleted(); + FinalOutputStep GetFinalOutputStep(const DecodeOptions &opts, PixelMap &pixelMap, bool hasNinePatch); + bool HasDensityChange(const DecodeOptions &opts, ImageInfo &srcImageInfo, bool hasNinePatch); + bool ImageSizeChange(int32_t width, int32_t height, int32_t desiredWidth, int32_t desiredHeight); + bool ImageConverChange(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo); + void Reset(); + + const std::string NINE_PATCH = "ninepatch"; + const std::string SKIA_DECODER = "SKIA_DECODER"; + static MultimediaPlugin::PluginServer &pluginServer_; + static FormatAgentMap formatAgentMap_; + std::unique_ptr sourceStreamPtr_; + SourceDecodingState decodeState_ = SourceDecodingState::UNRESOLVED; + SourceInfo sourceInfo_; + NinePatchInfo ninePatchInfo_; + ImageStatusMap imageStatusMap_; + IncrementalRecordMap incDecodingMap_; + // The main decoder is responsible for ordinary decoding (non-Incremental decoding), + // as well as decoding SourceInfo and ImageInfo. + std::unique_ptr mainDecoder_; + DecodeOptions opts_; + std::set listeners_; + DecodeEvent decodeEvent_ = DecodeEvent::EVENT_COMPLETE_DECODE; + std::map decodeEventMap_; + std::set decodeListeners_; + std::mutex listenerMutex_; + std::mutex decodingMutex_; + bool isIncrementalSource_ = false; + bool isIncrementalCompleted_ = false; + MemoryUsagePreference preference_ = MemoryUsagePreference::DEFAULT; +}; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_SOURCE_H diff --git a/interfaces/innerkits/include/image_type.h b/interfaces/innerkits/include/image_type.h new file mode 100644 index 0000000000000000000000000000000000000000..36c71c2433e47cf61e8c6865653c6ecb99b6613f --- /dev/null +++ b/interfaces/innerkits/include/image_type.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_TYPE_H +#define IMAGE_TYPE_H + +#include + +namespace OHOS { +namespace Media { +#ifdef _WIN32 +#define NATIVEEXPORT __declspec(dllexport) +#else +#define NATIVEEXPORT +#endif + +enum class AllocatorType : int32_t { + // keep same with java AllocatorType + DEFAULT = 0, + HEAP_ALLOC = 1, + SHARE_MEM_ALLOC = 2, + CUSTOM_ALLOC = 3, // external +}; + +enum class ColorSpace : int32_t { + // unknown color space. + UNKNOWN = 0, + + // based on SMPTE RP 431-2-2007 & IEC 61966-2.1:1999. + DISPLAY_P3 = 1, + + // standard Red Green Blue based on IEC 61966-2.1:1999. + SRGB = 2, + + // SRGB with a linear transfer function based on IEC 61966-2.1:1999. + LINEAR_SRGB = 3, + + // based on IEC 61966-2-2:2003. + EXTENDED_SRGB = 4, + + // based on IEC 61966-2-2:2003. + LINEAR_EXTENDED_SRGB = 5, + + // based on standard illuminant D50 as the white point. + GENERIC_XYZ = 6, + + // based on CIE XYZ D50 as the profile conversion space. + GENERIC_LAB = 7, + + // based on SMPTE ST 2065-1:2012. + ACES = 8, + + // based on Academy S-2014-004. + ACES_CG = 9, + + // based on Adobe RGB (1998). + ADOBE_RGB_1998 = 10, + + // based on SMPTE RP 431-2-2007. + DCI_P3 = 11, + + // based on Rec. ITU-R BT.709-5. + ITU_709 = 12, + + // based on Rec. ITU-R BT.2020-1. + ITU_2020 = 13, + + // based on ROMM RGB ISO 22028-2:2013. + ROMM_RGB = 14, + + // based on 1953 standard. + NTSC_1953 = 15, + + // based on SMPTE C. + SMPTE_C = 16, +}; + +enum class EncodedFormat : int32_t { + UNKNOWN = 0, + JPEG = 1, + PNG = 2, + GIF = 3, + HEIF = 4, +}; + +enum class PixelFormat : int32_t { + UNKNOWN = 0, + ARGB_8888 = 1, // Each pixel is stored on 4 bytes. + RGB_565 = 2, // Each pixel is stored on 2 bytes + RGBA_8888 = 3, + BGRA_8888 = 4, + RGB_888 = 5, + ALPHA_8 = 6, + RGBA_F16 = 7, + NV21 = 8, // Each pixel is sotred on 3/2 bytes. + NV12 = 9, + CMYK = 10, +}; + +enum class AlphaType : int32_t { + IMAGE_ALPHA_TYPE_UNKNOWN = 0, + IMAGE_ALPHA_TYPE_OPAQUE = 1, // image pixels are stored as opaque. + IMAGE_ALPHA_TYPE_PREMUL = 2, // image have alpha component, and all pixels have premultiplied by alpha value. + IMAGE_ALPHA_TYPE_UNPREMUL = 3, // image have alpha component, and all pixels stored without premultiply alpha value. +}; + +enum class MemoryUsagePreference : int32_t { + DEFAULT = 0, + LOW_RAM = 1, // low memory +}; + +enum class FinalOutputStep : int32_t { + NO_CHANGE = 0, + CONVERT_CHANGE = 1, + ROTATE_CHANGE = 2, + SIZE_CHANGE = 3, + DENSITY_CHANGE = 4 +}; + +struct Position { + int32_t x = 0; + int32_t y = 0; +}; + +struct Rect { + int32_t left = 0; + int32_t top = 0; + int32_t width = 0; + int32_t height = 0; +}; + +struct Size { + int32_t width = 0; + int32_t height = 0; +}; + +struct ImageInfo { + Size size; + PixelFormat pixelFormat = PixelFormat::UNKNOWN; + ColorSpace colorSpace = ColorSpace::SRGB; + AlphaType alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; + int32_t baseDensity = 0; +}; + +struct DecodeOptions { + int32_t fitDensity = 0; + Rect CropRect; + Size desiredSize; + float rotateDegrees = 0; + static constexpr uint32_t DEFAULT_SAMPLE_SIZE = 1; + uint32_t sampleSize = DEFAULT_SAMPLE_SIZE; + PixelFormat desiredPixelFormat = PixelFormat::UNKNOWN; + AllocatorType allocatorType = AllocatorType::HEAP_ALLOC; + ColorSpace desiredColorSpace = ColorSpace::SRGB; + bool allowPartialImage = true; + bool editable = false; + MemoryUsagePreference preference = MemoryUsagePreference::DEFAULT; +}; + +enum class ScaleMode : int32_t { + FIT_TARGET_SIZE = 0, + CENTER_CROP = 1, +}; + +enum class IncrementalMode { FULL_DATA = 0, INCREMENTAL_DATA = 1 }; +} // namespace Media +} // namespace OHOS + +#endif // IMAGE_TYPE_H diff --git a/interfaces/innerkits/include/incremental_pixel_map.h b/interfaces/innerkits/include/incremental_pixel_map.h new file mode 100644 index 0000000000000000000000000000000000000000..ea0e2a76bd573d2f911bebd73ae31b64b8ef62ba --- /dev/null +++ b/interfaces/innerkits/include/incremental_pixel_map.h @@ -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. + */ + +#ifndef INCREMENTAL_PIXEL_MAP_H +#define INCREMENTAL_PIXEL_MAP_H + +#include "nocopyable.h" +#include "image_type.h" +#include "pixel_map.h" +#include "peer_listener.h" + +namespace OHOS { +namespace Media { +class ImageSource; + +enum class IncrementalDecodingState : int32_t { + UNRESOLVED = 0, + BASE_INFO_ERROR = 1, + BASE_INFO_PARSED = 2, + IMAGE_DECODING = 3, + IMAGE_ERROR = 4, + PARTIAL_IMAGE = 5, + IMAGE_DECODED = 6 +}; + +struct IncrementalDecodingStatus { + static constexpr uint8_t FULL_PROGRESS = 100; + IncrementalDecodingState state = IncrementalDecodingState::UNRESOLVED; + uint32_t errorDetail = 0; + uint8_t decodingProgress = 0; +}; + +class IncrementalPixelMap : public PixelMap, public PeerListener { +public: + IncrementalPixelMap() = delete; + ~IncrementalPixelMap(); + uint32_t PromoteDecoding(uint8_t &decodeProgress); + void DetachFromDecoding(); + const IncrementalDecodingStatus &GetDecodingStatus(); + +private: + // declare friend class, only ImageSource can create IncrementalPixelMap object. + friend class ImageSource; + DISALLOW_COPY_AND_MOVE(IncrementalPixelMap); + IncrementalPixelMap(uint32_t index, const DecodeOptions opts, ImageSource *imageSource); + void OnPeerDestory() override; + void DetachSource(); + IncrementalDecodingStatus decodingStatus_; + uint32_t index_ = 0; + DecodeOptions opts_; + ImageSource *imageSource_ = nullptr; +}; +} // namespace Media +} // namespace OHOS + +#endif // INCREMENTAL_PIXEL_MAP_H \ No newline at end of file diff --git a/interfaces/innerkits/include/log_tags.h b/interfaces/innerkits/include/log_tags.h new file mode 100644 index 0000000000000000000000000000000000000000..15d8ff7e7a9c34c1558b2e990414df5ca5aa64bc --- /dev/null +++ b/interfaces/innerkits/include/log_tags.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOG_TAGS_H +#define LOG_TAGS_H + +const unsigned int LOG_TAG_DOMAIN_ID_MEDIA = 0xD002B01; +const unsigned int LOG_TAG_DOMAIN_ID_CAMERA = 0xD002B02; +const unsigned int LOG_TAG_DOMAIN_ID_PLUGIN = 0xD002B03; +const unsigned int LOG_TAG_DOMAIN_ID_DATA_TUNNEL = 0xD002B04; +const unsigned int LOG_TAG_DOMAIN_ID_IMAGE = 0xD002B05; +const unsigned int LOG_TAG_DOMAIN_ID_AUDIO = 0xD002B06; +const unsigned int LOG_TAG_DOMAIN_ID_RADIO = 0xD002B07; + +#endif diff --git a/interfaces/innerkits/include/media_errors.h b/interfaces/innerkits/include/media_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..1699dc731963e7ecdb63a9219ddbd1b358259db0 --- /dev/null +++ b/interfaces/innerkits/include/media_errors.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEDIA_ERRORS_H +#define MEDIA_ERRORS_H + +#include +#include "errors.h" +#include "modules.h" + +namespace OHOS { +namespace Media { +constexpr int32_t BASE_MEDIA_ERR_OFFSET = ErrCodeOffset(SUBSYS_MULTIMEDIA, MODULE_MEDIA); + +/* Media defined errors */ +const int32_t ERR_MEDIA_INVALID_VALUE = -1; // invalid size +const uint32_t SUCCESS = 0; // Operation success +const uint32_t ERROR = BASE_MEDIA_ERR_OFFSET; // Operation failed +const uint32_t ERR_IPC = BASE_MEDIA_ERR_OFFSET + 1; // ipc error +const uint32_t ERR_SHAMEM_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 2; // sharememory error +const uint32_t ERR_SHAMEM_DATA_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 3; // sharememory error +const uint32_t ERR_IMAGE_DECODE_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 4; // image decode error +const uint32_t ERR_IMAGE_DATA_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 5; // image input data error +const uint32_t ERR_IMAGE_MALLOC_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 6; // image malloc error +const uint32_t ERR_IMAGE_DATA_UNSUPPORT = BASE_MEDIA_ERR_OFFSET + 7; // image type unsupported +const uint32_t ERR_IMAGE_INIT_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 8; // image init error +const uint32_t ERR_IMAGE_GET_DATA_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 9; // image get data error +const uint32_t ERR_IMAGE_TOO_LARGE = BASE_MEDIA_ERR_OFFSET + 10; // image data too large +const uint32_t ERR_IMAGE_TRANSFORM = BASE_MEDIA_ERR_OFFSET + 11; // image transform error +const uint32_t ERR_IMAGE_COLOR_CONVERT = BASE_MEDIA_ERR_OFFSET + 12; // image color convert error +const uint32_t ERR_IMAGE_CROP = BASE_MEDIA_ERR_OFFSET + 13; // crop error +const uint32_t ERR_IMAGE_SOURCE_DATA = BASE_MEDIA_ERR_OFFSET + 14; // image source data error +const uint32_t ERR_IMAGE_SOURCE_DATA_INCOMPLETE = BASE_MEDIA_ERR_OFFSET + 15; // image source data incomplete +const uint32_t ERR_IMAGE_MISMATCHED_FORMAT = BASE_MEDIA_ERR_OFFSET + 16; // image mismatched format +const uint32_t ERR_IMAGE_UNKNOWN_FORMAT = BASE_MEDIA_ERR_OFFSET + 17; // image unknown format +const uint32_t ERR_IMAGE_SOURCE_UNRESOLVED = BASE_MEDIA_ERR_OFFSET + 18; // image source unresolved +const uint32_t ERR_IMAGE_INVALID_PARAMETER = BASE_MEDIA_ERR_OFFSET + 19; // image invalid parameter +const uint32_t ERR_IMAGE_DECODE_FAILED = BASE_MEDIA_ERR_OFFSET + 20; // decode fail +const uint32_t ERR_IMAGE_PLUGIN_REGISTER_FAILED = BASE_MEDIA_ERR_OFFSET + 21; // register plugin fail +const uint32_t ERR_IMAGE_PLUGIN_CREATE_FAILED = BASE_MEDIA_ERR_OFFSET + 22; // create plugin fail +const uint32_t ERR_IMAGE_ENCODE_FAILED = BASE_MEDIA_ERR_OFFSET + 23; // image encode fail +const uint32_t ERR_IMAGE_ADD_PIXEL_MAP_FAILED = BASE_MEDIA_ERR_OFFSET + 24; // image add pixel map fail +const uint32_t ERR_IMAGE_HW_DECODE_UNSUPPORT = BASE_MEDIA_ERR_OFFSET + 25; // image hardware decode unsupported +const uint32_t ERR_IMAGE_DECODE_HEAD_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 26; // image decode head error +const uint32_t ERR_IMAGE_DECODE_EXIF_UNSUPPORT = BASE_MEDIA_ERR_OFFSET + 27; // image decode exif unsupport +const uint32_t ERR_IMAGE_PROPERTY_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 28; // image property not exist +// The error code is occupied by media, the image starts from 150 +const uint32_t ERR_IMAGE_READ_PIXELMAP_FAILED = BASE_MEDIA_ERR_OFFSET + 150; // read pixelmap failed +const uint32_t ERR_IMAGE_WRITE_PIXELMAP_FAILED = BASE_MEDIA_ERR_OFFSET + 151; // write pixelmap failed +const uint32_t ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY = BASE_MEDIA_ERR_OFFSET + 152; // pixelmap not allow modify +const uint32_t ERR_IMAGE_CONFIG_FAILED = BASE_MEDIA_ERR_OFFSET + 153; // config error + +const int32_t ERR_MEDIA_DATA_UNSUPPORT = BASE_MEDIA_ERR_OFFSET + 30; // media type unsupported +const int32_t ERR_MEDIA_TOO_LARGE = BASE_MEDIA_ERR_OFFSET + 31; // media data too large +const int32_t ERR_MEDIA_MALLOC_FAILED = BASE_MEDIA_ERR_OFFSET + 32; // media malloc memory failed +const int32_t ERR_MEDIA_END_OF_STREAM = BASE_MEDIA_ERR_OFFSET + 33; // media end of stream error +const int32_t ERR_MEDIA_IO_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 34; // media io error +const int32_t ERR_MEDIA_MALFORMED = BASE_MEDIA_ERR_OFFSET + 35; // media malformed error +const int32_t ERR_MEDIA_BUFFER_TOO_SMALL = BASE_MEDIA_ERR_OFFSET + 36; // media buffer too small error +const int32_t ERR_MEDIA_OUT_OF_RANGE = BASE_MEDIA_ERR_OFFSET + 37; // media out of range error +const int32_t ERR_MEDIA_STATUS_ABNORMAL = BASE_MEDIA_ERR_OFFSET + 38; // media status abnormal error +const int32_t ERR_MEDIA_VALUE_INVALID = BASE_MEDIA_ERR_OFFSET + 39; // media value invalid +const int32_t ERR_MEDIA_NULL_POINTER = BASE_MEDIA_ERR_OFFSET + 40; // media error operation +const int32_t ERR_MEDIA_INVALID_OPERATION = BASE_MEDIA_ERR_OFFSET + 41; // media invalid operation +const int32_t ERR_PLAYER_NOT_INIT = BASE_MEDIA_ERR_OFFSET + 42; // media init error +const int32_t ERR_MEDIA_EARLY_PREPARE = BASE_MEDIA_ERR_OFFSET + 43; // media early prepare +const int32_t ERR_MEDIA_SEEK_ERR = BASE_MEDIA_ERR_OFFSET + 44; // media rewind error +const int32_t ERR_MEDIA_PERMISSION_DENIED = BASE_MEDIA_ERR_OFFSET + 45; // media permission denied +const int32_t ERR_MEDIA_DEAD_OBJECT = BASE_MEDIA_ERR_OFFSET + 46; // media dead object +const int32_t ERR_MEDIA_TIMED_OUT = BASE_MEDIA_ERR_OFFSET + 47; // media time out +const int32_t ERR_MEDIA_TRACK_NOT_ALL_SUPPORTED = BASE_MEDIA_ERR_OFFSET + 48; // media track subset support +const int32_t ERR_RECORDER_ADAPTER_INIT_FAILED = BASE_MEDIA_ERR_OFFSET + 49; // media recorder adapter init failed +const int32_t ERR_MEDIA_WRITE_PARCEL_FAIL = BASE_MEDIA_ERR_OFFSET + 50; // write parcel failed +const int32_t ERR_MEDIA_READ_PARCEL_FAIL = BASE_MEDIA_ERR_OFFSET + 51; // read parcel failed +const int32_t ERR_MEDIA_NO_AVAIL_BUFFER = BASE_MEDIA_ERR_OFFSET + 52; // read parcel failed +const int32_t ERR_MEDIA_INVALID_PARAM = BASE_MEDIA_ERR_OFFSET + 53; // media function found invalid param +const int32_t ERR_MEDIA_CODEC_ADAPTER_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 54; // media zcodec adapter not init +const int32_t ERR_MEDIA_CREATE_CODEC_ADAPTER_FAILED = BASE_MEDIA_ERR_OFFSET + 55; // media create zcodec adapter failed +const int32_t ERR_MEDIA_CODEC_ADAPTER_NOT_INIT = BASE_MEDIA_ERR_OFFSET + 56; // media adapter inner not init +const int32_t ERR_MEDIA_ZCODEC_CREATE_FAILED = BASE_MEDIA_ERR_OFFSET + 57; // media adapter inner not init +const int32_t ERR_MEDIA_ZCODEC_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 58; // media zcodec not exist +const int32_t ERR_MEDIA_JNI_CLASS_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 59; // media jni class not found +const int32_t ERR_MEDIA_JNI_METHOD_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 60; // media jni method not found +const int32_t ERR_MEDIA_JNI_NEW_OBJ_FAILED = BASE_MEDIA_ERR_OFFSET + 61; // media jni obj new failed +const int32_t ERR_MEDIA_JNI_COMMON_ERROR = BASE_MEDIA_ERR_OFFSET + 62; // media jni normal error +const int32_t ERR_MEDIA_DISTRIBUTE_NOT_SUPPORT = BASE_MEDIA_ERR_OFFSET + 63; // media distribute not support +const int32_t ERR_MEDIA_SOURCE_NOT_SET = BASE_MEDIA_ERR_OFFSET + 64; // media source not set +const int32_t ERR_MEDIA_RTSP_ADAPTER_NOT_INIT = BASE_MEDIA_ERR_OFFSET + 65; // media rtsp adapter not init +const int32_t ERR_MEDIA_RTSP_ADAPTER_NOT_EXIST = BASE_MEDIA_ERR_OFFSET + 66; // media rtsp adapter not exist +const int32_t ERR_MEDIA_RTSP_SURFACE_UNSUPPORT = BASE_MEDIA_ERR_OFFSET + 67; // media rtsp surface not support +const int32_t ERR_MEDIA_RTSP_CAPTURE_NOT_INIT = BASE_MEDIA_ERR_OFFSET + 68; // media rtsp capture init error +const int32_t ERR_MEDIA_RTSP_SOURCE_URL_INVALID = BASE_MEDIA_ERR_OFFSET + 69; // media rtsp source url invalid +const int32_t ERR_MEDIA_RTSP_VIDEO_TRACK_NOT_FOUND = BASE_MEDIA_ERR_OFFSET + 70; // media rtsp can't find video track +const int32_t ERR_MEDIA_RTSP_CAMERA_NUM_REACH_MAX = BASE_MEDIA_ERR_OFFSET + 71; // rtsp camera num reach to max num +const int32_t ERR_MEDIA_SET_VOLUME = BASE_MEDIA_ERR_OFFSET + 72; // media set volume error +const int32_t ERR_MEDIA_NUMBER_OVERFLOW = BASE_MEDIA_ERR_OFFSET + 73; // media number operation overflow +const int32_t ERR_MEDIA_DIS_PLAYER_UNSUPPORTED = BASE_MEDIA_ERR_OFFSET + 74; // media distribute player unsupporteded + +const int32_t ERR_MEDIA_UNKNOWN = BASE_MEDIA_ERR_OFFSET + 200; // media unknown error + +} // namespace Media +} // namespace OHOS +#endif // MEDIA_ERRORS_H diff --git a/interfaces/innerkits/include/modules.h b/interfaces/innerkits/include/modules.h new file mode 100644 index 0000000000000000000000000000000000000000..880672d3aff81e743aac76e5224ac0225c19f21d --- /dev/null +++ b/interfaces/innerkits/include/modules.h @@ -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. + */ +#ifndef MODULES_H +#define MODULES_H + +const int MODULE_AUDIO = 0; +const int MODULE_MEDIA = 1; +const int MODULE_CAMERA = 2; +const int MODULE_PLUGIN = 3; +const int MODULE_DATA_TUNNEL = 4; + +#endif diff --git a/interfaces/innerkits/include/peer_listener.h b/interfaces/innerkits/include/peer_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..17ff8e5f9d7e2168d0fa60ffd490507a90699106 --- /dev/null +++ b/interfaces/innerkits/include/peer_listener.h @@ -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. + */ + +#ifndef PEER_LISTENER_H +#define PEER_LISTENER_H + +namespace OHOS { +namespace Media { +class PeerListener { +public: + PeerListener() = default; + virtual ~PeerListener() = default; + virtual void OnPeerDestory() = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif // PEER_LISTENER_H \ No newline at end of file diff --git a/interfaces/innerkits/include/pixel_map.h b/interfaces/innerkits/include/pixel_map.h new file mode 100644 index 0000000000000000000000000000000000000000..687a4e7bf2646a428ac27febc45448e9abe90ec7 --- /dev/null +++ b/interfaces/innerkits/include/pixel_map.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PIXEL_MAP_H +#define PIXEL_MAP_H + +#include +#include "image_type.h" +#include "refbase.h" +#include "parcel.h" + +namespace OHOS { +namespace Media { +using TransColorProc = bool (*)(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); +using CustomFreePixelMap = void (*)(void *addr, void *context, uint32_t size); + +struct InitializationOptions { + Size size; + PixelFormat pixelFormat = PixelFormat::UNKNOWN; + AlphaType alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; + ScaleMode scaleMode = ScaleMode::FIT_TARGET_SIZE; + bool editable = false; + bool useSourceIfMatch = false; +}; + +// Build ARGB_8888 pixel value +constexpr uint8_t ARGB_MASK = 0xFF; +constexpr uint8_t ARGB_A_SHIFT = 24; +constexpr uint8_t ARGB_R_SHIFT = 16; +constexpr uint8_t ARGB_G_SHIFT = 8; +constexpr uint8_t ARGB_B_SHIFT = 0; +// Define pixel map malloc max size 600MB +constexpr int32_t PIXEL_MAP_MAX_RAM_SIZE = 600 * 1024 * 1024; + +class PixelMap : public Parcelable { +public: + PixelMap() = default; + virtual ~PixelMap(); + NATIVEEXPORT static std::unique_ptr Create(const uint32_t *colors, uint32_t colorLength, + const InitializationOptions &opts); + NATIVEEXPORT static std::unique_ptr Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, + int32_t stride, const InitializationOptions &opts); + NATIVEEXPORT static std::unique_ptr Create(const InitializationOptions &opts); + NATIVEEXPORT static std::unique_ptr Create(PixelMap &source, const InitializationOptions &opts); + NATIVEEXPORT static std::unique_ptr Create(PixelMap &source, const Rect &srcRect, + const InitializationOptions &opts); + NATIVEEXPORT uint32_t SetImageInfo(ImageInfo &info); + NATIVEEXPORT uint32_t SetImageInfo(ImageInfo &info, bool isReused); + NATIVEEXPORT const uint8_t *GetPixel(int32_t x, int32_t y); + NATIVEEXPORT const uint8_t *GetPixel8(int32_t x, int32_t y); + NATIVEEXPORT const uint16_t *GetPixel16(int32_t x, int32_t y); + NATIVEEXPORT const uint32_t *GetPixel32(int32_t x, int32_t y); + NATIVEEXPORT bool GetARGB32Color(int32_t x, int32_t y, uint32_t &color); + NATIVEEXPORT void SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, + CustomFreePixelMap func); + NATIVEEXPORT int32_t GetPixelBytes(); + NATIVEEXPORT int32_t GetRowBytes(); + NATIVEEXPORT int32_t GetByteCount(); + NATIVEEXPORT int32_t GetWidth(); + NATIVEEXPORT int32_t GetHeight(); + NATIVEEXPORT int32_t GetBaseDensity(); + NATIVEEXPORT void GetImageInfo(ImageInfo &imageInfo); + NATIVEEXPORT PixelFormat GetPixelFormat(); + NATIVEEXPORT ColorSpace GetColorSpace(); + NATIVEEXPORT AlphaType GetAlphaType(); + NATIVEEXPORT const uint8_t *GetPixels(); + NATIVEEXPORT uint8_t GetARGB32ColorA(uint32_t color); + NATIVEEXPORT uint8_t GetARGB32ColorR(uint32_t color); + NATIVEEXPORT uint8_t GetARGB32ColorG(uint32_t color); + NATIVEEXPORT uint8_t GetARGB32ColorB(uint32_t color); + // Config the pixel map parameter + NATIVEEXPORT bool IsSameImage(const PixelMap &other); + NATIVEEXPORT uint32_t ReadPixels(const uint64_t &bufferSize, const uint32_t &offset, const uint32_t &stride, + const Rect ®ion, uint8_t *dst); + NATIVEEXPORT uint32_t ReadPixels(const uint64_t &bufferSize, uint8_t *dst); + NATIVEEXPORT uint32_t ReadPixel(const Position &pos, uint32_t &dst); + NATIVEEXPORT uint32_t ResetConfig(const Size &size, const PixelFormat &format); + NATIVEEXPORT bool SetAlphaType(const AlphaType &alphaType); + NATIVEEXPORT uint32_t WritePixel(const Position &pos, const uint32_t &color); + NATIVEEXPORT uint32_t WritePixels(const uint8_t *source, const uint64_t &bufferSize, const uint32_t &offset, + const uint32_t &stride, const Rect ®ion); + NATIVEEXPORT uint32_t WritePixels(const uint8_t *source, const uint64_t &bufferSize); + NATIVEEXPORT bool WritePixels(const uint32_t &color); + NATIVEEXPORT void FreePixelMap(); + NATIVEEXPORT AllocatorType GetAllocatorType(); + NATIVEEXPORT void *GetFd() const; + + NATIVEEXPORT uint32_t GetCapacity() + { + return pixelsSize_; + } + + NATIVEEXPORT bool IsEditable() + { + return editable_; + } + + // judgement whether create pixelmap use source as result + NATIVEEXPORT bool IsSourceAsResponse() + { + return useSourceAsResponse_; + } + + NATIVEEXPORT void *GetWritablePixels() const + { + return static_cast(data_); + } + + NATIVEEXPORT bool Marshalling(Parcel &data) const override; + NATIVEEXPORT static PixelMap *Unmarshalling(Parcel &data); +private: + friend class ImageSource; + static bool ALPHA8ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); + static bool RGB565ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); + static bool ARGB8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); + static bool RGBA8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); + static bool BGRA8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); + static bool RGB888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount); + static bool CheckParams(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t stride, + const InitializationOptions &opts); + static void UpdatePixelsAlpha(const AlphaType &alphaType, const PixelFormat &pixelFormat, uint8_t *dstPixels, + PixelMap dstPixelMap); + static void InitDstImageInfo(const InitializationOptions &opts, const ImageInfo &srcImageInfo, + ImageInfo &dstImageInfo); + static bool CopyPixelMap(PixelMap &source, PixelMap &dstPixelMap); + static bool SourceCropAndConvert(PixelMap &source, const ImageInfo &srcImageInfo, const ImageInfo &dstImageInfo, + const Rect &srcRect, PixelMap &dstPixelMap); + static bool IsSameSize(const Size &src, const Size &dst); + static bool ScalePixelMap(const Size &targetSize, const Size &dstSize, const ScaleMode &scaleMode, + PixelMap &dstPixelMap); + bool GetPixelFormatDetail(const PixelFormat format); + bool CheckPixelsInput(const uint8_t *dst, const uint64_t &bufferSize, const uint32_t &offset, + const uint32_t &stride, const Rect ®ion); + void ReleaseSharedMemory(void *addr, void *context, uint32_t size); + void SetEditable(bool editable) + { + editable_ = editable; + } + + void ResetPixelMap() + { + rowDataSize_ = 0; + pixelBytes_ = 0; + colorProc_ = nullptr; + } + + bool CheckValidParam(int32_t x, int32_t y) + { + return (data_ == nullptr) || (x >= imageInfo_.size.width) || (x < 0) || (y >= imageInfo_.size.height) || + (y < 0) || (pixelsSize_ < static_cast(rowDataSize_) * imageInfo_.size.height) + ? false + : true; + } + bool WriteFileDescriptor(Parcel &data, int fd) const; + static int ReadFileDescriptor(Parcel &data); + + uint8_t *data_ = nullptr; + // this info SHOULD be the final info for decoded pixelmap, not the original image info + ImageInfo imageInfo_; + int32_t rowDataSize_ = 0; + int32_t pixelBytes_ = 0; + TransColorProc colorProc_ = nullptr; + void *context_ = nullptr; + CustomFreePixelMap custFreePixelMap_ = nullptr; + AllocatorType allocatorType_ = AllocatorType::HEAP_ALLOC; + uint32_t pixelsSize_ = 0; + bool editable_ = false; + bool useSourceAsResponse_ = false; +}; +} // namespace Media +} // namespace OHOS + +#endif // PIXEL_MAP_H diff --git a/interfaces/innerkits/include/pixel_map_manager.h b/interfaces/innerkits/include/pixel_map_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..bd5cf5196c0f976ee263bbf35e250eae24c1c6ce --- /dev/null +++ b/interfaces/innerkits/include/pixel_map_manager.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PIXEL_MAP_MANAGER_H +#define PIXEL_MAP_MANAGER_H + +#include "pixel_map.h" + +namespace OHOS { +namespace Media { +class PixelMapManager { +public: + explicit PixelMapManager(PixelMap *pixelMap) : pixelMap_(pixelMap) + {} + + void FreePixels() + { + pixelMap_.clear(); + } + + bool Invalid() + { + return pixelMap_ == nullptr; + } + + PixelMap &GetPixelMap() + { + return *pixelMap_; + } + + int32_t GetByteCount() + { + return pixelMap_->GetByteCount(); + } + + void Ref() + { + pixelMap_->IncStrongRef(nullptr); + } + + void UnRef() + { + pixelMap_->DecStrongRef(nullptr); + } + + ~PixelMapManager() + {} + +private: + ::OHOS::sptr pixelMap_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // PIXEL_MAP_MANAGER_H diff --git a/interfaces/innerkits/include/pixel_map_parcel.h b/interfaces/innerkits/include/pixel_map_parcel.h new file mode 100755 index 0000000000000000000000000000000000000000..450a343ade940de16afcc76b40a7240d41196dfe --- /dev/null +++ b/interfaces/innerkits/include/pixel_map_parcel.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PIXEL_MAP_PARCEL_H +#define PIXEL_MAP_PARCEL_H + +#include "message_parcel.h" +#include "pixel_map.h" + +namespace OHOS { +namespace Media { +class PixelMapParcel { +public: + static std::unique_ptr CreateFromParcel(OHOS::MessageParcel& data); + static bool WriteToParcel(PixelMap* pixelMap, OHOS::MessageParcel& data); + +private: + static void ReleaseMemory(AllocatorType allocType, void *addr, void *context, uint32_t size); +}; +} // namespace Media +} // namespace OHOS + +#endif // PIXEL_MAP_PARCEL_H diff --git a/interfaces/kits/java/BUILD.gn b/interfaces/kits/java/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..15e1c501b05728a26fe226b969915fb1ab855a01 --- /dev/null +++ b/interfaces/kits/java/BUILD.gn @@ -0,0 +1,159 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/ohos/rules.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +java_library("image_java") { + java_files = [ + "src/ohos/media/image_standard/PixelMap.java", + "src/ohos/media/image_standard/ImageSource.java", + "src/ohos/media/image_standard/ImagePacker.java", + "src/ohos/media/image_standard/package-info.java", + "src/ohos/media/image_standard/common/AllocatorType.java", + "src/ohos/media/image_standard/common/AlphaType.java", + "src/ohos/media/image_standard/common/ColorSpace.java", + "src/ohos/media/image_standard/common/DecodeEvent.java", + "src/ohos/media/image_standard/common/ImageInfo.java", + "src/ohos/media/image_standard/common/MemoryUsagePreference.java", + "src/ohos/media/image_standard/common/PixelFormat.java", + "src/ohos/media/image_standard/common/Position.java", + "src/ohos/media/image_standard/common/Rect.java", + "src/ohos/media/image_standard/common/ScaleMode.java", + "src/ohos/media/image_standard/common/Size.java", + "src/ohos/media/image_standard/common/PropertyKey.java", + "src/ohos/media/image_standard/common/ImageFormat.java", + "src/ohos/media/image_standard/common/package-info.java", + "src/ohos/media/image_standard/common/Filter.java", + "src/ohos/media/image_standard/PropertyFilter.java", + "src/ohos/media/image_standard/ImageException.java", + "src/ohos/media/image_standard/DataSourceUnavailableException.java", + "src/ohos/media/image_standard/SourceDataIncompleteException.java", + "src/ohos/media/image_standard/SourceDataMalformedException.java", + "src/ohos/media/image_standard/ExifUtils.java", + ] + + classpath_deps = [ + "//foundation/multimedia/image_standard/adapter/frameworks/exif:image_exifadapter_java", + "//foundation/multimedia/utils/java:multimedia_utils_java", + "//utils/java:utils_java", + ] + external_deps = [ + "resmgr:kits_java", + "startup:syspara_java", + "utils:utils_java", + ] + part_name = "multimedia_image" +} + +ohos_maple_java("image_maple_java") { + deps = [ + ":image_java", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + ] + + external_deps = [ + "hilog:hilog_maple_java", + "startup:syspara_maple_java", + "utils:utils_maple_java", + ] + + subsystem_name = "multimedia" +} + +java_library("image_decode_java") { + java_files = [ + "src/ohos/media/image_standard/common/AllocatorType.java", + "src/ohos/media/image_standard/common/AlphaType.java", + "src/ohos/media/image_standard/common/ColorSpace.java", + "src/ohos/media/image_standard/common/DecodeEvent.java", + "src/ohos/media/image_standard/common/ImageInfo.java", + "src/ohos/media/image_standard/common/MemoryUsagePreference.java", + "src/ohos/media/image_standard/common/PixelFormat.java", + "src/ohos/media/image_standard/common/Position.java", + "src/ohos/media/image_standard/common/Rect.java", + "src/ohos/media/image_standard/common/ScaleMode.java", + "src/ohos/media/image_standard/common/Size.java", + "src/ohos/media/image_standard/common/PropertyKey.java", + "src/ohos/media/image_standard/common/ImageFormat.java", + "src/ohos/media/image_standard/common/package-info.java", + "src/ohos/media/image_standard/common/Filter.java", + "src/ohos/media/image_standard/ImageException.java", + "src/ohos/media/image_standard/DataSourceUnavailableException.java", + "src/ohos/media/image_standard/SourceDataIncompleteException.java", + "src/ohos/media/image_standard/SourceDataMalformedException.java", + "src/ohos/media/image_standard/ImageSource.java", + "src/ohos/media/image_standard/PixelMap.java", + "//foundation/multimedia/image_standard/mock/java/src/ohos/media/image/ExifUtils.java", + "//foundation/multimedia/image_standard/mock/java/src/ohos/media/image/Image.java", + "//foundation/multimedia/image_standard/mock/java/src/ohos/media/image/ImagePacker.java", + "//foundation/multimedia/image_standard/mock/java/src/ohos/media/image/ImageReceiver.java", + "//foundation/multimedia/image_standard/mock/java/src/ohos/media/image/exifadapter/ExifAdapter.java", + ] + + external_deps = [ + "appexecfwk:eventhandler_java", + "graphic:agp_java", + "utils:utils_java", + ] + + classpath_deps = [ + "//foundation/multimedia/image_standard/mock/java/src/ohos:mock_java", + "//foundation/multimedia/utils/java:multimedia_utils_java", + "//utils/java:utils_java", + ] + + part_name = "multimedia_image" +} + +ohos_maple_java("image_decode_maple_java") { + deps = [ ":image_decode_java" ] + + subsystem_name = "multimedia" +} + +java_library("image_receiver_java") { + java_files = [ + "src/ohos/media/image_standard/common/Rect.java", + "src/ohos/media/image_standard/common/Size.java", + "src/ohos/media/image_standard/Image.java", + "src/ohos/media/image_standard/ImageReceiver.java", + "src/ohos/media/image_standard/common/ImageFormat.java", + ] + + classpath_deps = [ + "//foundation/multimedia/utils/java:multimedia_utils_java", + "//utils/java:utils_java", + ] + + external_deps = [ + "appexecfwk:eventhandler_java", + "graphic:agp_java", + ] + part_name = "multimedia_image" +} + +ohos_maple_java("image_receiver_maple_java") { + deps = [ + ":image_receiver_java", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + ] + + external_deps = [ + "appexecfwk:eventhandler_java_maple", + "graphic:agp_maple_java", + "hilog:hilog_maple_java", + ] + + subsystem_name = "multimedia" +} diff --git a/interfaces/kits/java/src/ohos/media/image/DataSourceUnavailableException.java b/interfaces/kits/java/src/ohos/media/image/DataSourceUnavailableException.java new file mode 100644 index 0000000000000000000000000000000000000000..2dd3e0263f4f844b2718c29e435573f5bcdd5f00 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/DataSourceUnavailableException.java @@ -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. + */ + +package ohos.media.image; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Provides the exception for image source error. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class DataSourceUnavailableException extends ImageException { + private static final long serialVersionUID = -8211123830794624112L; + + /** + * A constructor used to create an {@code DataSourceUnavailableException} instance based on the exception message. + * + * @param msg Indicates the string representation of the exception message. + * @since 3 + */ + public DataSourceUnavailableException(String msg) { + super(msg); + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/ExifUtils.java b/interfaces/kits/java/src/ohos/media/image/ExifUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..0fe0efe1e8cf3fc1845a6a9055dde84a0d82805f --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/ExifUtils.java @@ -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. + */ + +package ohos.media.image; + +import ohos.media.image.common.PropertyKey; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.utils.Pair; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Provides methods to obtain a combination of Exchangeable Image File Format (Exif) properties, such as the longitude, + * latitude, and altitude. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 4 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class ExifUtils { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ExifUtils.class); + + private static final double MINUTES = 60.0; + + private static final double SECONDS = 3600.0; + + private static final int DEFAULT_VALUE = -1; + + private static final String RATIONAL_SEPARATOR = "/"; + + /** + * Obtains longitude and latitude information about the image in its Exif property. + * + * @param imageSource Indicates the image data source. + * @return Returns the {@code Pair} object containing the longitude and latitude information if the information + * exists; returns {@code null} otherwise. The {@code f} member of {@code Pair} indicates the latitude, and {@code + * s} indicates the longitude. + * @throws IllegalStateException Throws this exception if native resources associated with {@code imageSource} have + * been released. + * @throws IllegalArgumentException Throws this exception if {@code imageSource} is null. + * @since 4 + */ + public static Pair getLatLong(ImageSource imageSource) { + if (imageSource == null) { + throw new IllegalArgumentException("imageSource is null"); + } + + String latitudeValue = imageSource.getImagePropertyString(PropertyKey.Exif.GPS_LATITUDE); + String latitudeRef = imageSource.getImagePropertyString(PropertyKey.Exif.GPS_LATITUDE_REF); + String longitudeValue = imageSource.getImagePropertyString(PropertyKey.Exif.GPS_LONGITUDE); + String longitudeRef = imageSource.getImagePropertyString(PropertyKey.Exif.GPS_LONGITUDE_REF); + if (latitudeValue != null && latitudeRef != null && longitudeValue != null && longitudeRef != null) { + try { + float latitude = convertRationalToFloat(latitudeValue, latitudeRef); + float longitude = convertRationalToFloat(longitudeValue, longitudeRef); + return Pair.create(latitude, longitude); + } catch (IllegalArgumentException e) { + return null; + } + } + + return null; + } + + /** + * Obtains altitude information about the image in its Exif property. + * + * @param imageSource Indicates the image data source. + * @param defaultValue Indicates the custom default value of the property. + * @return Returns the altitude information if it exists; returns the custom default value otherwise. + * @throws IllegalStateException Throws this exception if native resources associated with {@code imageSource} have + * been released. + * @throws IllegalArgumentException Throws this exception if {@code imageSource} is null. + * @since 4 + */ + public static double getAltitude(ImageSource imageSource, double defaultValue) { + if (imageSource == null) { + throw new IllegalArgumentException("imageSource is null"); + } + + double altitude = imageSource.getImagePropertyDouble(PropertyKey.Exif.GPS_ALTITUDE, DEFAULT_VALUE); + int ref = imageSource.getImagePropertyInt(PropertyKey.Exif.GPS_ALTITUDE_REF, DEFAULT_VALUE); + + if (altitude >= 0 && ref >= 0) { + return altitude * ((ref == 1) ? DEFAULT_VALUE : 1); + } else { + return defaultValue; + } + } + + private static double checkDivisor(double num1, double num2) { + if (Math.abs(num2 - 0.0f) < 0.000001f) { + throw new NumberFormatException(); + } + return num1 / num2; + } + + private static float convertRationalToFloat(String rationalNum, String ref) { + try { + String[] components = rationalNum.split(","); + if (components.length < 3) { + throw new IllegalArgumentException("parameter is invalid"); + } + + String[] rationalParts; + rationalParts = components[0].split(RATIONAL_SEPARATOR); + double degrees = checkDivisor(Double.parseDouble(rationalParts[0].trim()), + Double.parseDouble(rationalParts[1].trim())); + + rationalParts = components[1].split(RATIONAL_SEPARATOR); + double minutes = checkDivisor(Double.parseDouble(rationalParts[0].trim()), + Double.parseDouble(rationalParts[1].trim())); + + rationalParts = components[2].split(RATIONAL_SEPARATOR); + double seconds = checkDivisor(Double.parseDouble(rationalParts[0].trim()), + Double.parseDouble(rationalParts[1].trim())); + + double result = degrees + (minutes / MINUTES) + (seconds / SECONDS); + if ("S".equals(ref) || "W".equals(ref)) { + return (float) -result; + } + return (float) result; + } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/Image.java b/interfaces/kits/java/src/ohos/media/image/Image.java new file mode 100644 index 0000000000000000000000000000000000000000..833213fa2f9752b6e489ff588d017a5a8988d7d8 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/Image.java @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + + +/** + * Provides basic image operations, including obtaining image information, and reading and writing image data. + * + *

An {@code Image} object can be generated by an {@link ImageReceiver} object. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class Image { + private static final Logger LOGGER = LoggerFactory.getImageLogger(Image.class); + + /** + * Image availability status + */ + private volatile boolean isImageValid = false; + + /** + * Timestamp in nanosecond + */ + private long timestamp = 0L; + + /** + * Clip rectangle + */ + private Rect clipRect; + + /** + * Color components + */ + private Component[] components; + + /** + * Image Receiver + */ + private ImageReceiver imageReceiver; + + /** + * Native used,tracing native object + */ + private long nativeBuffer; + + /** + * Constructor + * + * @param imageReceiver The image receiver. + */ + Image(ImageReceiver imageReceiver) { + if (imageReceiver == null) { + LOGGER.error("imageReceiver is null."); + throw new IllegalArgumentException("imageReceiver is null."); + } + this.imageReceiver = imageReceiver; + } + + /** + * Set the image status. + * + * @param isImageValid The image status. + */ + void setImageStatus(boolean isImageValid) { + this.isImageValid = isImageValid; + } + + /** + * Get the image status. + * + * @return The image status. + */ + boolean getImageStatus() { + return isImageValid; + } + + /** + * Obtains the image format. + * + * @return Returns the image format, which is defined by {@link ImageFormat}. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public int getFormat() { + checkImageIsValid(); + return nativeGetFormat(imageReceiver.getImageFormat()); + } + + /** + * Obtains the image size. + * + * @return Returns the image size, which is specified by a {@link Size} object. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public Size getImageSize() { + checkImageIsValid(); + // JPEG/H264/H265 size is come from ImageReceiver + int format = getFormat(); + if (format == ImageFormat.JPEG || format == ImageFormat.H264 || format == ImageFormat.H265) { + return imageReceiver.getImageSize(); + } + return nativeGetSize(); + } + + /** + * Obtains the image timestamp, in nanoseconds. + * + * @return Returns the timestamp. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public long getTimestamp() { + checkImageIsValid(); + return timestamp; + } + + /** + * Obtains the cropped area of an image. + * + * @return Returns the cropped area, which is specified by a {@link Rect} object. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public Rect getClipRect() { + checkImageIsValid(); + if (clipRect == null) { + Size imageSize = getImageSize(); + return new Rect(0, 0, imageSize.width, imageSize.height); + } else { + return new Rect(clipRect); + } + } + + /** + * Sets the image area to crop. + * + *

If the area exceeds the image size or is outside of the image, the cropping will not be operated. + * + * @param clipRect Indicates the image area to crop, which is specified by a {@link Rect} object. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public void setClipRect(Rect clipRect) { + checkImageIsValid(); + if (clipRect != null) { + Rect clipRectCopy = new Rect(clipRect); + Size imageSize = getImageSize(); + if (!clipRectCopy.cropRect(0, 0, imageSize.width, imageSize.height)) { + clipRectCopy.setEmpty(); + } + this.clipRect = clipRectCopy; + } else { + this.clipRect = clipRect; + } + } + + /** + * Releases native resources associated with the image. + * + *

After the image data is released, any image operation will not be supported. + * + * @since 1 + */ + public void release() { + if (!isImageValid) { + return; + } + // image need to know who produce it + nativeReleaseImage(imageReceiver); + isImageValid = false; + if (components != null) { + for (Component component : components) { + component.release(); + } + } + components = null; + } + + @Override + protected void finalize() throws Throwable { + try { + release(); + } finally { + super.finalize(); + } + } + + /** + * Obtains the color component based on a specified component type. + * + * @param componentType Indicates a color component type, which is specified by {@link ImageFormat.ComponentType}. + * @return Returns the image color component if obtained; returns {@code null} if the image does not + * have the type of color component. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public Component getComponent(ImageFormat.ComponentType componentType) { + checkImageIsValid(); + if (componentType == null) { + LOGGER.error("component type is null."); + return null; + } + if (components == null) { + initComponents(); + } + if (components != null) { + for (Component component : components) { + if (componentType == component.componentType) { + return component; + } + } + } + LOGGER.error("component type %{public}s mismatch native acquire.", componentType); + return null; + } + + /** + * Get all component data from native. + * + * @throws IllegalStateException Error when image is invalid. + */ + private void initComponents() { + checkImageIsValid(); + int format = imageReceiver.getImageFormat(); + components = nativeGetComponents(ImageFormat.getComponentNumber(format), format); + } + + /** + * Check image is valid. + * + * @throws IllegalStateException Error when image is invalid. + */ + private void checkImageIsValid() { + if (!isImageValid) { + throw new IllegalStateException("image state is invalid"); + } + } + + /** + * Describes image color components. + * + *

This class provides methods for obtaining image color component attributes, + * and reading and writing color component data. + * + * @since 1 + */ + public static class Component { + /** + * Describes results of color component–related operations. + * + * @since 1 + */ + public static final class OperationResult { + /** + * Indicates that the color component–related operation is successful. + * + * @since 1 + */ + public static final int SUCCESS = 0; + + /** + * Indicates that the color component–related operation fails. + * + * @since 1 + */ + public static final int FAILURE = -1; + + /** + * Indicates that the operation is not supported because the specified color component has been released. + * + * @since 1 + */ + public static final int RELEASED = -2; + + private OperationResult() {} + } + + /** + * Byte unsigned mask. + */ + private static final int UNSIGNED_BYTE_MASK = 0xFF; + + /** + * Indicates the color component type defined in {@link ImageFormat.ComponentType}. + * + * @since 1 + */ + public final ImageFormat.ComponentType componentType; + + /** + * Indicates the distance in bytes between adjacent pixel rows. + * + * @since 1 + */ + public final int rowStride; + + /** + * Indicates the distance in bytes between adjacent pixels in a row. + * + * @since 1 + */ + public final int pixelStride; + + /** + * Buffer of image data. + */ + private ByteBuffer byteBuffer; + + /** + * Default constructor, be created by native. + * + * @param componentType ComponentType value {@link ImageFormat.ComponentType}. + * @param rowStride Distance of adjacent row pixels. + * @param pixelStride Distance of adjacent pixels. + * @param byteBuffer Buffer of image data. + */ + private Component(int componentType, int rowStride, int pixelStride, ByteBuffer byteBuffer) { + this.componentType = ImageFormat.ComponentType.valueOf(componentType); + this.rowStride = rowStride; + this.pixelStride = pixelStride; + this.byteBuffer = byteBuffer; + // Set the byteBuffer order in native order, otherwise the default order is BIG_ENDIAN + this.byteBuffer.order(ByteOrder.nativeOrder()); + } + + /** + * Reads color component data of one byte. + * + * @return Returns the data if the reading is successful; returns {@link OperationResult#FAILURE} + * constant if the reading fails; returns the {@link OperationResult#RELEASED} constant if the + * image or component data is released. + * @since 1 + */ + public int read() { + try { + checkParameterIsValid(); + return (byteBuffer.get() & UNSIGNED_BYTE_MASK); + } catch (IllegalStateException e) { + LOGGER.error("component has been released."); + return OperationResult.RELEASED; + } catch (BufferUnderflowException e) { + LOGGER.error("read byte occurs exception."); + return OperationResult.FAILURE; + } + } + + /** + * Reads color component data of multiple consecutive bytes. + * + * @param dstArray Indicates an array to store the data. + * @return Returns the {@link OperationResult#SUCCESS} constant if the reading is successful; + * returns the {@link OperationResult#FAILURE} constant if the reading fails; returns the + * {@link OperationResult#RELEASED} constant if the image or component data is released. + * @since 1 + */ + public int read(byte[] dstArray) { + try { + checkParameterIsValid(); + byteBuffer.get(dstArray); + return OperationResult.SUCCESS; + } catch (IllegalStateException e) { + LOGGER.error("component has been released."); + return OperationResult.RELEASED; + } catch (BufferUnderflowException e) { + LOGGER.error("read bulk byte occurs exception."); + return OperationResult.FAILURE; + } + } + + /** + * Reads color component data of multiple consecutive bytes and write the data in an + * array with specified offsets and length. + * + * @param dstArray Indicates an array to store the data. + * @param offset Indicates where to write the data in the target array. + * @param length Indicates the maximum length allowed to write data into the target array. + * @return Returns the {@link OperationResult#SUCCESS} constant if the reading is successful; + * returns the {@link OperationResult#FAILURE} constant if the reading fails; returns the + * {@link OperationResult#RELEASED} constant if the image or component data is released. + * @since 1 + */ + public int read(byte[] dstArray, int offset, int length) { + try { + checkParameterIsValid(); + byteBuffer.get(dstArray, offset, length); + return OperationResult.SUCCESS; + } catch (IllegalStateException e) { + LOGGER.error("component has been released."); + return OperationResult.RELEASED; + } catch (BufferUnderflowException | IndexOutOfBoundsException e) { + LOGGER.error("read bulk byte occurs exception."); + return OperationResult.FAILURE; + } + } + + /** + * Obtains the position of the current color component data to read. + * + * @return Returns the position of the current color component data if obtained; returns the + * {@link OperationResult#RELEASED} if the image or component data is released. + * @since 1 + */ + public int tell() { + try { + checkParameterIsValid(); + return byteBuffer.position(); + } catch (IllegalStateException e) { + LOGGER.error("tell position occurs exception."); + return OperationResult.RELEASED; + } + } + + /** + * Sets a position of the current color component data to read. + * + * @param newPosition Indicates a new position of the current color component data to read. + * @return Returns the {@link OperationResult#SUCCESS} constant if the reading position is set; + * returns the {@link OperationResult#FAILURE} constant if the setting fails; returns the + * {@link OperationResult#RELEASED} constant if the image or component data is released. + * @since 1 + */ + public int seek(int newPosition) { + try { + checkParameterIsValid(); + byteBuffer.position(newPosition); + return OperationResult.SUCCESS; + } catch (IllegalStateException e) { + LOGGER.error("component has been released."); + return OperationResult.RELEASED; + } catch (IllegalArgumentException e) { + LOGGER.error("seek position occurs exception."); + return OperationResult.FAILURE; + } + } + + /** + * Obtains the remaining data size (in bytes) of the color component. + * + * @return Returns the bytes of the remaining data if obtained; returns the {@link OperationResult#RELEASED} + * if the image or component data is released. + * @since 1 + */ + public int remaining() { + try { + checkParameterIsValid(); + return byteBuffer.remaining(); + } catch (IllegalStateException e) { + LOGGER.error("component has been released."); + return OperationResult.RELEASED; + } + } + + /** + * Obtains the {@link java.nio.ByteBuffer} object of the current color component. Note that the object directly + * maps to the native resource buffer. After the receiver or image resource is released, the object should + * not be used to read or write data. + * + * @return Returns the {@link java.nio.ByteBuffer} object of the current color component. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public ByteBuffer getBuffer() { + checkParameterIsValid(); + return byteBuffer; + } + + /** + * Releases native resources associated with the color component. + * + *

After this method is called, color component-related operations will no longer be supported. + * + * @since 1 + */ + public void release() { + if (byteBuffer == null) { + return; + } + if (byteBuffer.isDirect()) { + reflectFreeDirectBuffer(byteBuffer); + } + byteBuffer = null; + } + + private void checkParameterIsValid() { + if (byteBuffer == null) { + throw new IllegalStateException("image or buffer is invalid"); + } + } + + /** + * Reflect invoke NioUtils freeDirectBuffer method. + * + * @param byteBuffer DirectByteBuffer object. + */ + private void reflectFreeDirectBuffer(ByteBuffer byteBuffer) { + try { + Class nioUtilsClz = Class.forName("java.nio.NioUtils"); + Method freeBufferMethod = nioUtilsClz.getMethod("freeDirectBuffer", java.nio.ByteBuffer.class); + freeBufferMethod.invoke(null, byteBuffer); + } catch (IllegalAccessException | ClassNotFoundException | InvocationTargetException + | NoSuchMethodException e) { + LOGGER.error("reflect free direct buffer error %{public}s", e.getMessage()); + } + } + } + + private synchronized native int nativeGetFormat(int receiverFormat); + + private synchronized native Size nativeGetSize(); + + private synchronized native Component[] nativeGetComponents(int componentNumber, int receiverFormat); + + private synchronized native void nativeReleaseImage(ImageReceiver imageReceiver); +} diff --git a/interfaces/kits/java/src/ohos/media/image/ImageException.java b/interfaces/kits/java/src/ohos/media/image/ImageException.java new file mode 100644 index 0000000000000000000000000000000000000000..c9fb155aceb895012b09f4a173ed90a7bd20e910 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/ImageException.java @@ -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. + */ + +package ohos.media.image; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Parent class for the image module exception. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class ImageException extends RuntimeException { + private static final long serialVersionUID = 6953810857206391682L; + + /** + * A constructor used to create an {@code ImageException} instance based on the exception message. + * + * @param msg Indicates the string representation of the exception message. + * @since 3 + */ + public ImageException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/interfaces/kits/java/src/ohos/media/image/ImagePacker.java b/interfaces/kits/java/src/ohos/media/image/ImagePacker.java new file mode 100644 index 0000000000000000000000000000000000000000..8a9a788eb422b1d9ba0cbd18994ed17d23463aae --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/ImagePacker.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.io.OutputStream; +import java.util.HashSet; + +/** + * Represents the image packer that packs compressed images into files or other objects. + * + *

You can call {@code create} to create an image packer, {@code initializePacking} to set packing options, + * {@code addImage} to add image data to be packed, and {@code finalizePacking} to complete packing and output the + * target object. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class ImagePacker { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImagePacker.class); + + /** + * Success state by image packer native interface return. + */ + private static final int SUCCESS = 0; + + private static final long FAILED = -1L; + + private static final int BUFFER_SIZE = 4096; + + static { + LOGGER.debug("Begin loading image_packer_jni library"); + try { + System.loadLibrary("image_packer_jni.z"); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary image_packer_jni.z fail"); + } + } + + /** + * Accessed by native methods, save object address + */ + private long nativeImagePacker; + + /** + * native used, write tmp buffer + */ + private byte[] nativeBuffer = new byte[BUFFER_SIZE]; + + /** + * Private constructor called by JNI. + * + * @param nativePtr the native object point. + */ + private ImagePacker(long nativePtr) { + nativeImagePacker = nativePtr; + } + + /** + * Creates an {@code ImagePacker} instance. + * + * @return Returns the {@code ImagePacker} instance if created; returns {@code null} if an exception occurs. + * @since 3 + */ + public static ImagePacker create() { + return nativeCreateImagePacker(); + } + + /** + * Obtains the supported output image formats for packing. + * + * @return Returns the set of supported output image formats, which are represented by MIME type strings, for + * example, {@code image/jpeg}. Currently, only the JPEG format is supported. + * @since 3 + */ + public static HashSet getSupportedFormats() { + return nativeGetSupportedFormats(); + } + + /** + * Describes options for compressing and packing. + * + *

The options include the output file format, compression quality, and other parameters. + * + * @since 3 + */ + public static class PackingOptions { + /** + * Indicates the output image format represented by an MIME type string. {@code image/jpeg} is supported. + * + * @since 3 + */ + public String format = "image/jpeg"; + + /** + * Indicates the image compression quality. The value ranges from 0 to 100. A larger value indicates better + * image quality but larger space occupied. + * + * @since 3 + */ + public int quality = 100; + + /** + * Indicates the prompt of the number of images to be packed. + * + * @since 3 + */ + public int numberHint = 1; + } + + /** + * Initializes the packing task that outputs the result to a byte array. + * + * @param data Indicates the byte array containing the packed images. + * @param opts Indicates the packing options. + * @return Returns {@code true} if the packing task is successfully initialized; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean initializePacking(byte[] data, PackingOptions opts) { + if (data == null) { + throw new IllegalArgumentException("data is null"); + } + + PackingOptions packingOptions = (opts == null) ? new PackingOptions() : opts; + if (!isPackerOptionValid(packingOptions.format, packingOptions.quality)) { + return false; + } + return initializePacking(data, 0, packingOptions); + } + + /** + * Initializes the packing task that outputs the result to a byte array at a specific offset. + * + * @param data Indicates the byte array containing the packed images. + * @param offset Indicates the data array offset into which the compressed image data will be written. + * @param opts Indicates the packing options. + * @return Returns {@code true} if the packing task is successfully initialized; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean initializePacking(byte[] data, int offset, PackingOptions opts) { + if (data == null) { + throw new IllegalArgumentException("data is null"); + } + if ((offset < 0) || (offset >= data.length)) { + throw new IndexOutOfBoundsException("offset is invalid"); + } + + PackingOptions packingOptions = (opts == null) ? new PackingOptions() : opts; + if (!isPackerOptionValid(packingOptions.format, packingOptions.quality)) { + return false; + } + int ret = nativeStartPacking(nativeImagePacker, data, offset, packingOptions); + if (ret != SUCCESS) { + LOGGER.error("startPacking failed to data array,error code is %{public}d", ret); + return false; + } + return true; + } + + /** + * Initializes the packing task that outputs the result to a {@code OutputStream} object. + * + * @param outputStream Indicates the output stream of the packed images. + * @param opts Indicates the packing options. + * @return Returns {@code true} if the packing task is successfully initialized; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean initializePacking(OutputStream outputStream, PackingOptions opts) { + if (outputStream == null) { + throw new IllegalArgumentException("outputStream is null"); + } + + PackingOptions packingOptions = (opts == null) ? new PackingOptions() : opts; + if (!isPackerOptionValid(packingOptions.format, packingOptions.quality)) { + return false; + } + // caller manage the outputStream life circle, here we don't care about + int ret = nativeStartPacking(nativeImagePacker, outputStream, packingOptions, nativeBuffer); + if (ret != SUCCESS) { + LOGGER.error("startPacking failed to outputStream, error code is %{public}d", ret); + return false; + } + return true; + } + + /** + * Adds a {@link PixelMap} to the image packer. + * + *

This method adds only one {@link PixelMap} object at a time. + * + * @param pixelmap Indicates the {@link PixelMap} to be packed. + * @return Returns {@code true} if the pixel map is added; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean addImage(PixelMap pixelmap) { + if (pixelmap == null) { + throw new IllegalArgumentException("pixelmap is null"); + } + int ret = nativeAddImage(nativeImagePacker, pixelmap); + if (ret != SUCCESS) { + LOGGER.error("addImage failed, error code is %{public}d", ret); + return false; + } + return true; + } + + /** + * Adds the image in an {@link ImageSource} to the image packer. + * + *

If the {@link ImageSource} contains multiple images, only the first image will be added. + * + * @param source Indicates the {@code ImageSource}. + * @return Returns {@code true} if the image is added; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean addImage(ImageSource source) { + if (source == null) { + throw new IllegalArgumentException("source is null"); + } + int ret = nativeAddImage(nativeImagePacker, source); + if (ret != SUCCESS) { + LOGGER.error("addImage failed from image source, error code is %{public}d", ret); + return false; + } + return true; + } + + /** + * Adds a specified image in an {@link ImageSource} to the image packer. + * + *

You can use an index to specify the image to be added. + * + * @param source Indicates the {@code ImageSource}. + * @param index Indicates the index of the target image in the {@code ImageSource}. The value starts from 0. + * @return Returns {@code true} if the specified image is added; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean addImage(ImageSource source, int index) { + if (source == null) { + throw new IllegalArgumentException("source is null"); + } + if (index < 0) { + throw new IllegalArgumentException("index must not be negative"); + } + int ret = nativeAddImage(nativeImagePacker, source, index); + if (ret != SUCCESS) { + LOGGER.error("addImage failed from index image source, error code is %{public}d, index is %{public}d", ret, + index); + return false; + } + return true; + } + + /** + * Completes the image packing. + * + *

Calling this method will inform the {@code ImagePacker} that all the required image data has been + * added for packing and the {@code ImagePacker} will pack the data into the specified object. + * + * @return Returns the output data size (in bytes) if the operation is successful; returns {@code -1} otherwise. + * @since 3 + */ + public long finalizePacking() { + long ret = nativeFinalizePacking(nativeImagePacker); + if (ret < 0) { + LOGGER.error("finalizePacking failed, error code is %{public}d.", ret); + return FAILED; + } + return ret; + } + + /** + * Releases native resources associated with the {@code ImagePacker} object. + * + * @since 3 + */ + public void release() { + if (!isReleased()) { + nativeRelease(nativeImagePacker); + nativeImagePacker = 0L; + } + } + + @Override + protected void finalize() throws Throwable { + release(); + super.finalize(); + } + + /** + * Checks whether native resources have been released. + * + * @return Returns {@code true} if the resources are released; returns {@code false} otherwise. + * @since 1 + */ + private boolean isReleased() { + return nativeImagePacker == 0; + } + + private boolean isPackerOptionValid(String format, int quality) { + if (format == null || format.isEmpty() || quality < 0 || quality > 100) { + LOGGER.error("PackingOptions invalid %{public}s, %{public}d", format, quality); + return false; + } + return true; + } + + private static native ImagePacker nativeCreateImagePacker(); + + private static native HashSet nativeGetSupportedFormats(); + + private native void nativeRelease(long nativePtr); + + private native int nativeStartPacking(long nativePtr, byte[] data, int offset, PackingOptions opts); + + private native int nativeStartPacking(long nativePtr, OutputStream outputStream, PackingOptions opts, + byte[] nativeBuffer); + + private native int nativeAddImage(long nativePtr, PixelMap pixelmap); + + private native int nativeAddImage(long nativePtr, ImageSource source); + + private native int nativeAddImage(long nativePtr, ImageSource source, int index); + + private native long nativeFinalizePacking(long nativePtr); +} diff --git a/interfaces/kits/java/src/ohos/media/image/ImageReceiver.java b/interfaces/kits/java/src/ohos/media/image/ImageReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..66603c209dc9715b03de60f42616a0c96b559369 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/ImageReceiver.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.agp.graphics.Surface; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Set; + +/** + * Describes an image receiver that connects to an image output device and + * provides a buffer queue to receive image data. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class ImageReceiver { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageReceiver.class); + private static final String HANDLER_NAME = "nativeEventHandler"; + private static final long USAGE_CPU_READ_OFTEN = 3L; // native hardware setting + private static final int MIN_POSITIVE = 1; + private final int width; + private final int height; + private final int format; + private final int capacity; + private final Object receiverLock = new Object(); + private volatile boolean isReceiverValid = false; // receiver availability status + private volatile IImageArrivalListener arrivalListener; // native callback listener + private final Set images = new HashSet<>(); // image release when free receiver + private long nativeContext; // native used,tracing native object + private final Surface surface; + private volatile EventHandler handler; + + static { + LOGGER.debug("Begin loading imagereceiver_jni library."); + try { + System.loadLibrary("imagereceiver_jni.z"); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary imagereceiver_jni.z fail"); + } + nativeCacheClass(); // native cache some field + } + + /** + * Creates an {@link ImageReceiver} instance based on a specified image width, height, format, + * and the buffer queue capacity. + * + * @param width Indicates the image width. + * @param height Indicates the image height. + * @param format Indicates the image format, which is defined by {@link ImageFormat}. + * @param capacity Indicates the maximum buffer capacity of the image receiver. The value must be greater than 0. + * @return Returns the {@link ImageReceiver} object. + * @throws IllegalArgumentException Throws this exception if a parameter is incorrect. + * @throws IllegalStateException Throws this exception if the operation is not supported in the current state, + * for example, if native resources fail to be applied for the receiver. + * @since 1 + */ + public static ImageReceiver create(int width, int height, int format, int capacity) { + return new ImageReceiver(width, height, format, capacity, USAGE_CPU_READ_OFTEN); + } + + /** + * Constructor implement. + * + * @param width The width in pixels of the image. + * @param height The height in pixels of the image. + * @param format The format of image, which is one of values from {@link ImageFormat}. + * @param capacity The maximum number of images cached by ImageReceiver, must be larger than 0. + * @param usage The intended usage of the image. + * @throws IllegalArgumentException when width, height or imageCount not valid. + * @throws IllegalStateException Error when native create failed. + */ + private ImageReceiver(int width, int height, int format, int capacity, long usage) { + if (width < MIN_POSITIVE || height < MIN_POSITIVE) { + LOGGER.error("The image size:[%{public}d, %{public}d] must be positive.", width, height); + throw new IllegalArgumentException("The image size must be positive."); + } + if (capacity < MIN_POSITIVE) { + LOGGER.error("The image capacity %{public}d must be larger than zero.", capacity); + throw new IllegalArgumentException("The image capacity must be larger than zero."); + } + // ImageReceiver can't support NV21 format + if (format == ImageFormat.NV21) { + LOGGER.error("NV21 format is not supported."); + throw new IllegalArgumentException("NV21 format is not supported."); + } + this.width = width; + this.height = height; + this.format = format; + this.capacity = capacity; + nativeInit(new WeakReference<>(this), width, height, format, capacity, usage); + surface = nativeGetReceiverSurface(); + isReceiverValid = true; + } + + /** + * Obtains the receiver surface of the image receiver. + * + * @return Returns a {@link Surface} object of the image receiver. + * @since 3 + */ + public Surface getRecevingSurface() { + return surface; + } + + /** + * Obtains the image size. + * + * @return Returns the image size specified in a {@link Size} object. + * @since 1 + */ + public Size getImageSize() { + return new Size(width, height); + } + + /** + * Obtains the maximum buffer capacity of the image receiver. + * + * @return Returns the buffer size of the image receiver. + * @since 1 + */ + public int getCapacity() { + return capacity; + } + + /** + * Obtains the image format. + * + * @return Returns the image format, which is defined by {@link ImageFormat}. + * @since 1 + */ + public int getImageFormat() { + return format; + } + + /** + * Reads the latest image data from the buffer queue and clears earlier images from the queue. + * + * @return Returns the latest image data if obtained; returns {@code null} otherwise. + * @throws IllegalStateException Throws this exception if the operation is not supported in the current state, + * for example, if native resources associated with the receiver are released. + * @since 1 + */ + public Image readLatestImage() { + Image image = readNextImage(); + if (image == null) { + return null; + } + + while (true) { + Image nextImage = readNextImage(); + if (nextImage == null) { + return image; + } + image.release(); + synchronized (receiverLock) { + images.remove(image); + } + image = nextImage; + } + } + + /** + * Reads the next image from the buffer queue. + * + * @return Returns next image data if obtained; returns {@code null} otherwise. + * @throws IllegalStateException Throws this exception if the operation is not supported in the current state, + * for example, if native resources associated with the receiver are released. + * @since 1 + */ + public Image readNextImage() { + Image image = null; + synchronized(receiverLock) { + if (isReceiverValid) { + image = new Image(this); + boolean hasNext = nativeReadNext(image); + if (!hasNext) { + LOGGER.error("get image from native response empty."); + return null; + } + image.setImageStatus(true); + images.add(image); + } + } + return image; + } + + /** + * Releases native resources associated with the image receiver, including the surface and obtained images. + * + * @since 1 + */ + public void release() { + setImageArrivalListener(null); + synchronized (receiverLock) { + isReceiverValid = false; + for (Image image : images) { + if (image.getImageStatus()) { + image.release(); + } + } + images.clear(); + nativeRelease(); + } + } + + @Override + protected void finalize() throws Throwable { + try { + release(); + } finally { + super.finalize(); + } + } + + /** + * Native call back when an Event happens. + * + * @param objectRef ImageReceiver reference form native. + */ + private static void onEventFromNative(Object objectRef) { + if (objectRef instanceof WeakReference) { + @SuppressWarnings("unchecked") + WeakReference weakRef = (WeakReference)objectRef; + final ImageReceiver imageReceiver = weakRef.get(); + if (imageReceiver == null) { + LOGGER.error("native transmit image receiver is null."); + return; + } + final EventHandler handler = imageReceiver.handler; + if (handler == null) { + LOGGER.error("event handler is null, set image arrival listener firstly."); + return; + } + final IImageArrivalListener listener = imageReceiver.arrivalListener; + final boolean receiverValid = imageReceiver.isReceiverValid; + handler.postTask(new Runnable() { + @Override + public void run() { + if (listener != null && receiverValid) { + listener.onImageArrival(imageReceiver); + } + } + }); + } else { + LOGGER.error("can't cast object to weak reference."); + } + } + + /** + * Sets the image listener which will be called when new image data is received. + * + * @param listener Indicates the image listener, which is defined by {@link IImageArrivalListener}. + * @since 1 + */ + public void setImageArrivalListener(IImageArrivalListener listener) { + if (listener == null) { + arrivalListener = null; + if (handler == null) { + return; + } + handler.removeAllEvent(); + handler = null; + } else { + arrivalListener = listener; + if (handler == null) { + handler = new EventHandler(EventRunner.create(HANDLER_NAME)); + } + } + } + + /** + * Callback interface used when new image data is received. + * + * @since 1 + */ + public interface IImageArrivalListener { + /** + * Called when new image data is received. + * + * @param imageReceiver Indicates an {@link ImageReceiver} object. + * @since 1 + */ + void onImageArrival(ImageReceiver imageReceiver); + } + + private synchronized native void nativeInit(Object weakThiz, int width, int height, int format, int capacity, + long consumerUsage); + + private synchronized native boolean nativeReadNext(Image image); + + private synchronized native void nativeRelease(); + + private synchronized native void nativeReleaseFreeBuffers(); + + private synchronized native Surface nativeGetReceiverSurface(); + + private static native void nativeCacheClass(); +} diff --git a/interfaces/kits/java/src/ohos/media/image/ImageSource.java b/interfaces/kits/java/src/ohos/media/image/ImageSource.java new file mode 100644 index 0000000000000000000000000000000000000000..25974678dd8993867c9ec4aa7f890758f287b3ea --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/ImageSource.java @@ -0,0 +1,1283 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.image.common.AllocatorType; +import ohos.media.image.common.ColorSpace; +import ohos.media.image.common.DecodeEvent; +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.ImageInfo; +import ohos.media.image.common.MemoryUsagePreference; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.PropertyKey; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.media.image.exifadapter.ExifAdapter; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.media.utils.trace.Tracer; +import ohos.media.utils.trace.TracerFactory; +import ohos.global.resource.RawFileDescriptor; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.concurrent.Callable; +import java.util.Locale; + +/** + * Describes image data sources used to share source data in a series of operations, such as image decoding. + * + *

Applications can use this class to decode image. + *

Create an {@code ImageSource} by calling {@code create}. Obtain basic image information by + * calling {@code getImageInfo}. Decode images by calling {@code createPixelMap}. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class ImageSource { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageSource.class); + + private static final Tracer TRACER = TracerFactory.getImageTracer(); + + /** + * Success state by image source native interface return. + */ + private static final int SUCCESS = 0; + + private static SourceOptions inputOpts; + + private static long fileSize; + + private volatile ExifAdapter exifAdapter; + + /** + * Saved data source, maybe ByteArrayDataSource, or InputStreamDataSource, or FileDataSource, or + * FileDescriptorDataSource. + */ + private Object imgDataSource; + + /** + * Accessed by native methods + */ + private long nativeImageSource; + + private DecodeEventListener decodeEventListener; + + private final Object exifLock = new Object(); + + /** + * Describes the update mode of the image data source. + * + *

There are two modes: full data update and incremental data update. + * + * @since 1 + */ + public enum UpdateMode { + /** + * Indicates that all the accumulated obtained data is input to update the source. + */ + FULL_DATA(0), + /** + * Indicates that only incremental data is input to update the source. + */ + INCREMENTAL_DATA(1); + + private final int updateMode; + + UpdateMode(int mode) { + updateMode = mode; + } + + /** + * Obtains an enum value. + * + * @return Returns the enum value. + * @since 1 + */ + public int getValue() { + return updateMode; + } + } + + /** + * Describes image data source options, including the image format represented as {@code image/png}, for example. + * + * @since 1 + */ + public static class SourceOptions { + /** + * Indicates an optional prompt about the image format, which is represented by an MIME type string. Proper + * configuration improves the decoding efficiency. + * + * @since 1 + */ + public String formatHint = ""; + + /** + * Indicates the pixel density of the source image. + * + * @since 4 + */ + public int baseDensity = 0; + } + + /** + * Describes options of the incremental data source. + * + *

The options include image data source options provided by {@link SourceOptions} + * and the data update mode defined by {@link UpdateMode}. + * + * @since 1 + */ + public static class IncrementalSourceOptions { + /** + * Indicates image data source options defined by {@link SourceOptions}. + * + * @since 1 + */ + public SourceOptions opts; + + /** + * Indicates the data update mode defined by {@link UpdateMode}. + * + * @since 1 + */ + public UpdateMode mode = UpdateMode.FULL_DATA; + } + + /** + * Provides image decoding options. + * + *

The options include the pixel format, color space, + * and parameters for cropping, scaling, and rotating an image. + * + * @since 1 + */ + public static class DecodingOptions { + /** + * Indicates the default sampling size. + * + * @since 1 + */ + public static final int DEFAULT_SAMPLE_SIZE = 1; + + /** + * Indicates the pixel density of the decoded image. + * + * @since 4 + */ + public int fitDensity = 0; + + /** + * Indicates the memory allocation type for decoded image data. + * + * @since 4 + */ + public AllocatorType allocator = AllocatorType.DEFAULT; + + /** + * Indicates an image area to be decoded. + *

If area decoding is not supported, the entire image is decoded and then cropped with a rectangle. + * The area to be decoded is specified based on the original image instead of an edited image. + * + * @since 1 + */ + public Rect desiredRegion; + + /** + * Indicates the expected output size. + *

If the opted size is different from the original image size, the image is output + * after being scaled up or down. If both {@code sampleSize} and this option are set, this option prevails. This + * variable specifies the final size of an output image. If this variable, {@code desiredRegion}, and {@code + * rotateDegrees} are all set, the expected image area will be decoded, rotated, and then scaled to the expected + * size. + * + * @since 1 + */ + public Size desiredSize; + + /** + * Indicates the rotation angle, ranging from 0 to 360. An image is rotated clockwise with the original image + * center as the rotation center. + * + * @since 1 + */ + public float rotateDegrees = 0; + + /** + * Indicates the sampling size based on which an image is scaled down. For example, if the value is 2, both the + * width and height of the image are scaled down to half of the original. The value must be an integer, 1 or + * greater. + * + * @since 1 + */ + public int sampleSize = DEFAULT_SAMPLE_SIZE; + + /** + * Indicates the pixel format of a decoded image, which is defined by {@link PixelFormat}. + *

If this format is supported, the decoder will decode the image to the target format. + * Otherwise, the decoder will select the most suitable format for the image. + * + * @since 1 + */ + public PixelFormat desiredPixelFormat = PixelFormat.UNKNOWN; + + /** + * Indicates the color space of a decoded image, which is defined by {@link ColorSpace}. + *

If this color space is supported, the decoder will decode the image to one with this color space. + * Otherwise, the decoder will select the most suitable color space for the image. + * + * @since 1 + */ + public ColorSpace desiredColorSpace = ColorSpace.SRGB; + + /** + * Indicates whether to allow partial image decoding. + *

When this option is set to {@code false} and an incomplete image is partially decoded, the decoding + * fails. + * + * @since 1 + */ + public boolean allowPartialImage = true; + + /** + * Specifies whether pixel values of the pixel map to be decoded can be edited. Value {@code true} means that + * the values can be edited, and {@code false} means the opposite. The default value is {@code false}. + * + * @since 4 + */ + public boolean editable = false; + } + + /** + * Describes image source information, including the image quantity and file format. + * + * @since 1 + */ + public static class SourceInfo { + /** + * Indicates the number of top-level images contained in the source. + * + * @since 1 + */ + public int topLevelImageNum = 0; + + /** + * Indicates the image format represented by an MIME type string, for example, {@code image/png}. + * + * @since 1 + */ + public String encodedFormat; + } + + /** + * Data file path of encoded image data. + * + * @since 3 + */ + private static class FilePathDataSource { + private final String filePath; + + FilePathDataSource(String filePath) { + this.filePath = filePath; + } + } + + /** + * Data byte array of encoded image data. + * + * @since 1 + */ + private static class ByteArrayDataSource { + private final byte[] data; + + private final int offset; + + private final int length; + + ByteArrayDataSource(byte[] data, int offset, int length) { + this.data = data; + this.offset = offset; + this.length = length; + } + } + + /** + * Input stream of encoded image data. + * + * @since 1 + */ + private static class InputStreamDataSource { + private final InputStream is; + + InputStreamDataSource(InputStream is) { + this.is = is; + } + } + + /** + * File of encoded image data. + * + * @since 1 + */ + private static class FileDataSource { + private final File file; + + FileDataSource(File file) { + this.file = file; + } + } + + /** + * File descriptor of encoded image data. + * + * @since 1 + */ + private static class FileDescriptorDataSource { + private final FileDescriptor fd; + + FileDescriptorDataSource(FileDescriptor fd) { + this.fd = fd; + } + } + + static { + LOGGER.debug("Begin loading image_source_jni library"); + String osName = System.getProperty("os.name"); + String jniLibName = "image_source_jni.z"; + if (osName != null) { + osName = osName.toUpperCase(Locale.US); + if (osName.contains("WINDOWS")) { + jniLibName = "libimage_source_jni"; + } else if (osName.contains("MAC")) { + jniLibName = "image_source_jni"; + } else { + jniLibName = "image_source_jni.z"; + } + } + try { + System.loadLibrary(jniLibName); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary %{public}s fail", jniLibName); + } + nativeInit(); + } + + /** + * Private constructor called by JNI. + * + * @param nativePtr the native object point. + */ + private ImageSource(long nativePtr) { + nativeImageSource = nativePtr; + } + + /** + * Obtains supported image formats for decoding, which are represented by MIME type strings. + * + * @return Returns the supported formats represented by MIME type strings. + * @since 1 + */ + public static HashSet getSupportedFormats() { + return nativeGetSupportedFormats(); + } + + /** + * Listens for the events occurred during image decoding. + * + *

To listen for the events, you should implement the {@link #onDecodeEvent} method, which + * obtains the {@link ImageSource} and {@link ohos.media.image.common.DecodeEvent}. + * + * @since 4 + */ + public static interface DecodeEventListener { + /** + * Called when a decoding event occurs. + * + * @param source Indicates the image source. + * @param event Indicates the event, which can be + * {@link ohos.media.image.common.DecodeEvent#EVENT_COMPLETE_DECODE} + * or {@link ohos.media.image.common.DecodeEvent#EVENT_PARTIAL_DECODE}. + * @since 4 + */ + void onDecodeEvent(ImageSource source, DecodeEvent event); + } + + /** + * Sets a listener for observing decoding events. + * + * @param listener Indicates the listener to set. + * @since 4 + */ + public void setDecodeEventListener(DecodeEventListener listener) { + decodeEventListener = listener; + nativeSetDecodeEventListener(this, nativeImageSource); + } + + private void postEventFromNative(ImageSource source, int event) { + if (decodeEventListener == null) { + LOGGER.error("decodeEventListener is null."); + return; + } + + DecodeEvent recEvent = DecodeEvent.getDecodeEvent(event); + if (recEvent.getValue() >= DecodeEvent.EVENT_LAST.getValue()) { + LOGGER.error("event is invalid: %{public}d", event); + return; + } + decodeEventListener.onDecodeEvent(source, recEvent); + } + + /** + * Sets memory use preference. + * + * @param preference Indicates the preference to set, + * which is defined in {@link ohos.media.image.common.MemoryUsagePreference}. + * @since 4 + */ + public void setMemoryUsagePreference(MemoryUsagePreference preference) { + nativeSetMemoryUsagePreference(nativeImageSource, preference); + } + + /** + * Creates an {@link ImageSource} based on an input stream. + * + *

This method takes an {@code InputStream} instance as the source where the image data derives from. The {@code + * ImageSource} instance to create cannot be used to obtain Exif information. + * + * @param is Indicates an input stream of the image data source. + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource create(InputStream is, SourceOptions opts) { + if (is == null) { + throw new IllegalArgumentException("is is null"); + } + + ImageSource imgSource = nativeCreateImageSource(is, opts); + inputOpts = opts; + if (imgSource == null) { + LOGGER.error("create ImageSource from input stream fail."); + return null; + } + + imgSource.imgDataSource = new InputStreamDataSource(is); + try { + fileSize = is.available(); + } catch (IOException e) { + LOGGER.error("get file size failed of InputStream ImageSource"); + } + return imgSource; + } + + /** + * Creates an {@link ImageSource} based on a byte array. + * + * @param data Indicates the byte array containing the source data. + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource create(byte[] data, SourceOptions opts) { + if (data == null) { + throw new IllegalArgumentException("data is null"); + } + + return create(data, 0, data.length, opts); + } + + /** + * Creates an {@code ImageSource} based on a {@link java.nio.ByteBuffer} and source options. + * + * @param data Indicates the {@code ByteBuffer} that contains the image source data. + * @param opts Indicates the source options. + * @return Returns the {@code ImageSource} if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if an input parameter is invalid. + * @since 4 + */ + public static ImageSource create(ByteBuffer data, SourceOptions opts) { + if (data == null) { + throw new IllegalArgumentException("data is null"); + } + data.flip(); + int length = data.limit() - data.position(); + byte[] byteData = new byte[length]; + if (data.isReadOnly()) { + throw new IllegalArgumentException("data is read only"); + } else { + data.get(byteData); + } + + return create(byteData, 0, byteData.length, opts); + } + + /** + * Creates an {@code ImageSource} based on a {@link ohos.global.resource.RawFileDescriptor} + * that is returned by a {@code Callable} object. + * + * @param callable Indicates the object that implements the {@link java.util.concurrent.Callable} interface. + * @param opts Indicates the source options. + * @return Returns the {@link ImageSource} if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if an input parameter is invalid. + * @since 4 + */ + public static ImageSource create(Callable callable, SourceOptions opts) { + if (callable == null) { + throw new IllegalArgumentException("RawFileDescriptor is null"); + } + RawFileDescriptor rawFileDes = null; + try { + rawFileDes = callable.call(); + } catch (Exception e) { + if (e instanceof IOException) { + LOGGER.error("create ImageSource from raw file descriptor fail, reason : IOException."); + return null; + } else { + LOGGER.error("create ImageSource from raw file descriptor fail, reason : Exception."); + return null; + } + } + if (rawFileDes == null) { + throw new IllegalArgumentException("rawFileDes is null"); + } + FileDescriptor fileDes = rawFileDes.getFileDescriptor(); + long startPosition = rawFileDes.getStartPosition(); + if (startPosition < 0 || rawFileDes.getFileSize() < 0) { + LOGGER.error("rawFileDes startPosition is illegal %{public}d", startPosition); + closeRawFileDescriptor(rawFileDes); + return null; + } + FileInputStream inputStream = new FileInputStream(fileDes); + try { + inputStream.skip(startPosition); + } catch (IOException e) { + LOGGER.error("inputStream skip fail, reason : IOException"); + closeInputStream(inputStream); + closeRawFileDescriptor(rawFileDes); + return null; + } + return create(inputStream, opts); + } + + /** + * Creates an {@link ImageSource} based on a byte array with specified offset and length. + * + * @param data Indicates the byte array containing the source data. + * @param offset Indicates the offset into image data for where the reading begins. + * @param length Indicates the image data size, in bytes. + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @throws IndexOutOfBoundsException Throws this exception if the offset or length is invalid. + * @since 1 + */ + public static ImageSource create(byte[] data, int offset, int length, SourceOptions opts) { + if (data == null) { + throw new IllegalArgumentException("data is null"); + } + if ((offset < 0) || (length < 0) || (offset >= data.length) || (offset + length > data.length)) { + throw new IndexOutOfBoundsException("offset or length is invalid"); + } + + ImageSource imgSource = nativeCreateImageSource(data, offset, length, opts); + inputOpts = opts; + if (imgSource == null) { + LOGGER.error("create ImageSource from data array fail. offset : %{public}d, length : %{public}d.", offset, + length); + return null; + } + + imgSource.imgDataSource = new ByteArrayDataSource(data, offset, length); + fileSize = length; + return imgSource; + } + + /** + * Creates an {@link ImageSource} based on an image file path. + * + * @param pathName Indicates the file path based on which the {@link ImageSource} is created. + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource create(String pathName, SourceOptions opts) { + if ((pathName == null) || pathName.isEmpty()) { + throw new IllegalArgumentException("pathName is invalid"); + } + + if (!Files.isReadable(Paths.get(pathName))) { + throw new DataSourceUnavailableException("pathName can not read"); + } + + ImageSource imageSource = nativeCreateImageSource(pathName, opts); + inputOpts = opts; + if (imageSource == null) { + LOGGER.error("create ImageSource from file path fail"); + return null; + } + imageSource.imgDataSource = new FilePathDataSource(pathName); + fileSize = (new File(pathName)).length(); + return imageSource; + } + + /** + * Creates an {@link ImageSource} based on a {@link java.io.File} object. + * + * @param file Indicates a {@link java.io.File} object. + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource create(File file, SourceOptions opts) { + if (file == null) { + throw new IllegalArgumentException("file is null"); + } + + ImageSource imgSource; + try (InputStream inStream = new FileInputStream(file)) { + imgSource = nativeCreateImageSource(inStream, opts); + inputOpts = opts; + if (imgSource == null) { + LOGGER.error("create ImageSource from file fail"); + return null; + } + + imgSource.imgDataSource = new FileDataSource(file); + } catch (FileNotFoundException fe) { + LOGGER.error("create ImageSource from file fail, reason : file not found."); + return null; + } catch (IOException ioe) { + LOGGER.error("create ImageSource from file, IO Exception"); + return null; + } + fileSize = file.length(); + return imgSource; + } + + /** + * Creates an {@link ImageSource} based on a file descriptor. + * + *

This method takes a {@code FileDescriptor} instance as the source where the image data derives from. The + * {@code ImageSource} instance to create cannot be used to obtain Exif information. + * + * @param fd Indicates the descriptor of an image source file. + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource create(FileDescriptor fd, SourceOptions opts) { + if ((fd == null) || (!fd.valid())) { + throw new IllegalArgumentException("fd is invalid"); + } + + ImageSource imgSource; + try (InputStream inStream = new FileInputStream(fd)) { + imgSource = nativeCreateImageSource(inStream, opts); + inputOpts = opts; + if (imgSource == null) { + LOGGER.error("createImageSource from fd fail"); + return null; + } + + imgSource.imgDataSource = new FileDescriptorDataSource(fd); + fileSize = inStream.available(); + } catch (SecurityException fe) { + LOGGER.error("createImageSource from file descriptor fail, SecurityException : %{public}s.", + fe.getMessage()); + return null; + } catch (IOException ioe) { + LOGGER.error("createImageSource from file, IO Exception"); + return null; + } + return imgSource; + } + + /** + * Creates an incremental data source based on a {@link SourceOptions} object. + * + *

This method is used with {@link ImageSource#updateData(byte[], int, int, boolean)} to update incremental + * data. + * + * @param opts Indicates data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource createIncrementalSource(SourceOptions opts) { + IncrementalSourceOptions increOpts = new IncrementalSourceOptions(); + increOpts.opts = opts; + inputOpts = opts; + return createIncrementalSource(increOpts); + } + + /** + * Creates an incremental data source based on an {@link IncrementalSourceOptions} object. + * + *

This method is used with {@link ImageSource#updateData(byte[], int, int, boolean)} to update incremental + * data. + * + * @param opts Indicates incremental data source options. + * @return Returns the {@link ImageSource} object if created; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public static ImageSource createIncrementalSource(IncrementalSourceOptions opts) { + return nativeCreateIncrementalImageSource(opts); + } + + /** + * Decodes source image data and creates a pixel map. + * + *

For a source containing multiple images, the image data of index 0 is decoded by default. + * + * @param opts Indicates image decoding options. + * @return Returns the image if the data is decoded; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public PixelMap createPixelmap(DecodingOptions opts) { + return createPixelmap(0, opts); + } + + /** + * Decodes source image data based on a specified index location in the {@link ImageSource} and creates a pixel + * map. + * + *

For a source containing multiple images, use an index to specify the image location. + * + * @param index Indicates an index specifying the image location. The index starts from 0. + * @param opts Indicates image decoding options. + * @return Returns the image if the data is decoded; returns {@code null} if an exception occurs. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public PixelMap createPixelmap(int index, DecodingOptions opts) { + if (index < 0) { + throw new IllegalArgumentException("index must not be negative"); + } + + checkReleased(); + + PixelMap pixelMap = null; + String traceVal = "ImageSource_createPixelmap"; + TRACER.startTrace(traceVal); + pixelMap = nativeCreatePixelmap(this, nativeImageSource, index, opts); + TRACER.finishTrace(traceVal); + return pixelMap; + } + + /** + * Decodes thumbnail data contained in the {@link ImageSource} instance to generate a thumbnail and creates a + * thumbnail pixel map. + * + * @param opts Indicates image decoding options. + * @param allowFromImage Specifies whether to allow creation based on the original image if the {@link ImageSource} + * does not contain thumbnail data. + * @return Returns the created {@link PixelMap} if the decoding is successful; returns {@code null} if the decoding + * fails. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @throws IllegalStateException Throws this exception if native resources associated with this {@link ImageSource} + * have been released. + * @since 2 + */ + public PixelMap createThumbnailPixelmap(DecodingOptions opts, boolean allowFromImage) { + LOGGER.info("enter createThumbnailPixelmap"); + checkExifSource(); + byte[] data = exifAdapter.getThumbnailBytes(); + if (data == null) { + LOGGER.info("image source has no inner thumbnail"); + if (allowFromImage) { + LOGGER.info("create thumbnail pixel map from original image"); + return createPixelmap(opts); + } + LOGGER.info("get thumbnail data null"); + return null; + } + + ImageSource imageSource = ImageSource.create(data, null); + if (imageSource == null) { + LOGGER.error("create thumbnail image source failed"); + return null; + } + LOGGER.info("createThumbnailPixelmap from inner thumbnail bytes"); + return imageSource.createPixelmap(opts); + } + + /** + * Updates incremental data to an image data source using a byte array. + * + *

When incremental data is obtained, use this method to update source data. + * Input data requirements are described by {@link UpdateMode}. + * + * @param data Indicates the byte array inputting incremental data. + * @param isFinal Indicates whether the data update is the last batch. + * @return Returns {@code true} if the source data is updated; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public boolean updateData(byte[] data, boolean isFinal) { + return updateData(data, 0, data.length, isFinal); + } + + /** + * Updates incremental data to an image data source using a byte array with specified offset and length. + * + *

When incremental data is obtained, use this method to update source data. + * Input data requirements are described by {@link UpdateMode}. + * + * @param data Indicates the byte array inputting incremental data. + * @param offset Indicates offset into image data for where the reading starts. + * @param length Indicates the size of the incremental data, in bytes. + * @param isFinal Indicates whether the data is the last batch. + * @return Returns {@code true} if the data is updated; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @throws IndexOutOfBoundsException Throws this exception if the offset or length is invalid. + * @since 1 + */ + public boolean updateData(byte[] data, int offset, int length, boolean isFinal) { + if (data == null) { + throw new IllegalArgumentException("data must not be null"); + } + if ((offset < 0) || (length < 0) || (offset >= data.length) || (offset + length > data.length)) { + throw new IndexOutOfBoundsException("offset or length is invalid"); + } + + checkReleased(); + int ret = nativeUpdateData(nativeImageSource, data, offset, length, isFinal); + if (ret != SUCCESS) { + LOGGER.error("updateData failed from data array, error code is %{public}d", ret); + return false; + } + + return true; + } + + /** + * Obtains basic image information. + * + * @return Returns the {@link ohos.media.image.common.ImageInfo} object if obtained; returns {@code null} otherwise. + * Note that the returned {@code ImageInfo} object contains only the {@link ohos.media.image.common.ImageInfo#size} + * of this {@code ImageSource} object. Other image information can be obtained only after image decoding. + * @since 1 + */ + public ImageInfo getImageInfo() { + return getImageInfo(0); + } + + /** + * Obtains basic information about the image at a specified index. + * + * @param index Indicates the image index, which starts from 0. + * @return Returns the {@link ohos.media.image.common.ImageInfo} object if obtained; returns {@code null} otherwise. + * Note that the returned {@code ImageInfo} object contains only the {@link ohos.media.image.common.ImageInfo#size} + * of this {@code ImageSource} object. Other image information can be obtained only after image decoding. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 1 + */ + public ImageInfo getImageInfo(int index) { + if (index < 0) { + throw new IllegalArgumentException("index must not be negative"); + } + checkReleased(); + return nativeGetImageInfo(nativeImageSource, index); + } + + /** + * Obtains the string value of a specified image property key. + * + * @param key Indicates a key defined in {@code PropertyKey}. + * @return Returns the property key value if obtained; returns {@code null} if the property does not exist. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code ImageSource} + * instance have been released. + * @throws IllegalArgumentException Throws this exception if {@code key} is null. + * @since 4 + */ + public final String getImagePropertyString(String key) { + if (key == null) { + throw new IllegalArgumentException("key is null"); + } + + checkExifSource(); + return exifAdapter.getImagePropertyString(key); + } + + /** + * Obtains the integer value of a specified image property key. + * + * @param key Indicates a key defined in {@code PropertyKey}. + * @param defaultValue Indicates the custom default value of the property key. + * @return Returns the integer value if obtained; returns the custom default value if the property key does not + * exist or is incompatible with integers. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code ImageSource} + * instance have been released. + * @throws IllegalArgumentException Throws this exception if {@code key} is null. + * @since 4 + */ + public final int getImagePropertyInt(String key, int defaultValue) { + return getImagePropertyInt(0, key, defaultValue); + } + + /** + * Obtains the integer value of a specified property key for an image at the given index in the {@link + * ImageSource}. + * + * @param index Indicates an index specifying the image location. The index starts from 0. + * @param key Indicates a key defined in {@code PropertyKey}. + * @param defaultValue Indicates the custom default value of the property key. + * @return Returns the integer value if obtained; returns the custom default value if the property key does not + * exist or is incompatible with integers. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code ImageSource} + * instance have been released. + * @throws IllegalArgumentException Throws this exception if {@code key} is null. + * @since 4 + */ + public final int getImagePropertyInt(int index, String key, int defaultValue) { + if (key == null) { + throw new IllegalArgumentException("key is null"); + } + + checkExifSource(); + if (key.startsWith("GIF")) { + return nativeGetImagePropertyInt(nativeImageSource, index, key, defaultValue); + } else { + return exifAdapter.getImagePropertyInt(key, defaultValue); + } + } + + /** + * Obtains basic information (such as the size) about the thumbnail from the {@code ImageSource} instance. + *

Currently, only thumbnails in JPEG format can be identified. + * + * @return Returns the basic information if obtained; returns {@code null} if the thumbnail is not in JPEG format. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code ImageSource} + * instance have been released. + * @throws UnsupportedOperationException Throws this exception if the source image file does not contain a + * thumbnail. + * @since 4 + */ + public ImageInfo getThumbnailInfo() { + checkExifSource(); + byte[] data = exifAdapter.getThumbnailBytes(); + if (data == null) { + throw new UnsupportedOperationException("image does not contain thumbnail"); + } + + ImageSource imageSource = ImageSource.create(data, null); + if (imageSource == null) { + LOGGER.error("getThumbnailInfo: create thumbnail image source failed"); + return null; + } + return imageSource.getImageInfo(); + } + + /** + * Obtains the byte data of the JPEG thumbnail stored in the Exif information + * about this JPEG {@code ImageSource} instance. + * + * @return Returns a {@code byte} array containing the thumbnail data if the + * Exif information of this JPEG {@code ImageSource} instance contains a + * thumbnail in JPEG format; returns {@code null} if the Exif + * information does not contain a thumbnail or the thumbnail is not a + * JPEG file. + * @throws IllegalStateException IllegalStateException Throws this exception if + * this {@code ImageSource} instance: + *

    + *
  • Is in an unknown format.
  • + *
  • Is abnormal.
  • + *
  • Has been released.
  • + *
+ * @since 6 + */ + public byte[] getInnerJpegThumbnail() { + checkExifSource(); + return exifAdapter.getThumbnail(); + } + + /** + * Obtains the start position and data length of the thumbnail data saved in the + * Exif information about this JPEG {@code ImageSource} instance. + * + * @return Returns a {@code long} array containing the start position of the + * thumbnail data and the data length if the Exif information of this + * JPEG {@code ImageSource} instance has thumbnail data; returns + * {@code null} if there is no thumbnail data in the Exif information or + * the thumbnail data is discrete. + * @throws IllegalStateException Throws this exception if this + * {@code ImageSource} instance: + *
    + *
  • Is in an unknown format.
  • + *
  • Is abnormal.
  • + *
  • Has been released.
  • + *
+ * @since 6 + */ + public long[] getInnerThumbnailScope() { + checkExifSource(); + long[] offsetLength = null; + try { + offsetLength = exifAdapter.getThumbnailRange(); + } catch (IllegalStateException e) { + throw new IllegalStateException("Current state illegal,offsets may have changed"); + } + return offsetLength; + } + + /** + * Obtains raw data of the thumbnail from the {@code ImageSource} instance. + * + * @return Returns the byte array containing the thumbnail data if the thumbnail exists. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code ImageSource} + * instance have been released. + * @throws UnsupportedOperationException Throws this exception if the source image file does not contain a + * thumbnail. + * @since 3 + */ + public byte[] getImageThumbnailBytes() { + checkExifSource(); + if (exifAdapter.getThumbnailBytes() == null) { + throw new UnsupportedOperationException("image does not contain thumbnail"); + } + return exifAdapter.getThumbnailBytes(); + } + + /** + * Obtains the format of the thumbnail from the {@code ImageSource} instance.

Currently, only thumbnails in JPEG + * format can be identified. + * + * @return Returns {@link ohos.media.image.common.ImageFormat#JPEG} if the thumbnail is in JPEG format; returns + * {@link ohos.media.image.common.ImageFormat#UNKNOWN} otherwise. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code ImageSource} + * have been released. + * @throws UnsupportedOperationException Throws this exception if the source image file does not contain a + * thumbnail. + * @since 3 + */ + public int getThumbnailFormat() { + checkExifSource(); + if (exifAdapter.getThumbnailBytes() == null) { + throw new UnsupportedOperationException("image does not contain thumbnail"); + } + + if (exifAdapter.getThumbnail() != null) { + return ImageFormat.JPEG; + } + + return ImageFormat.UNKNOWN; + } + + private static void closeInputStream(FileInputStream inputStream) { + try { + inputStream.close(); + } catch(IOException e) { + LOGGER.error("create ImageSource inputStream close reason : Exception."); + } + } + + private static void closeRawFileDescriptor(RawFileDescriptor rawFileDes) { + try { + rawFileDes.close(); + } catch(IOException e) { + LOGGER.error("create ImageSource rawFileDes close reason : Exception."); + } + } + + private void checkReleased() { + if (isReleased()) { + throw new IllegalStateException("native resources has been released"); + } + } + + /** + * Obtains image source information. + * + * @return Returns the image source information if obtained; returns {@code null} if an exception occurs. + * @since 1 + */ + public SourceInfo getSourceInfo() { + checkReleased(); + return nativeGetSourceInfo(nativeImageSource); + } + + /** + * Releases native resources associated with an object. + * + * @since 1 + */ + public void release() { + if (!isReleased()) { + nativeRelease(nativeImageSource); + nativeImageSource = 0L; + exifAdapter = null; + } + imgDataSource = null; + } + + /** + * Used to determine if the native resources of the Image Source has been released. + * + * @return True if the native resources of the ImageSource has been released + * @since 4 + */ + public boolean isReleased() { + return nativeImageSource == 0; + } + + @Override + protected void finalize() throws Throwable { + release(); + super.finalize(); + } + + private void checkExifSource() { + checkReleased(); + if (exifAdapter == null) { + synchronized (exifLock) { + if (exifAdapter == null) { + try { + if (imgDataSource instanceof FilePathDataSource) { + FilePathDataSource dataSource = (FilePathDataSource) imgDataSource; + exifAdapter = new ExifAdapter(dataSource.filePath); + } else if (imgDataSource instanceof ByteArrayDataSource) { + ByteArrayDataSource dataSource = (ByteArrayDataSource) imgDataSource; + exifAdapter = new ExifAdapter(dataSource.data, dataSource.offset, dataSource.length); + } else if (imgDataSource instanceof InputStreamDataSource) { + InputStreamDataSource dataSource = (InputStreamDataSource) imgDataSource; + dataSource.is.mark(0); + dataSource.is.reset(); + exifAdapter = new ExifAdapter(dataSource.is); + } else if (imgDataSource instanceof FileDataSource) { + FileDataSource dataSource = (FileDataSource) imgDataSource; + exifAdapter = new ExifAdapter(dataSource.file); + } else if (imgDataSource instanceof FileDescriptorDataSource) { + FileDescriptorDataSource dataSource = (FileDescriptorDataSource) imgDataSource; + exifAdapter = new ExifAdapter(dataSource.fd); + } else { + throw new IllegalStateException("unknown type of image source"); + } + } catch (IOException e) { + LOGGER.error("create exif adapter from data source failed"); + throw new IllegalStateException("image data source invalid:" + e.getMessage()); + } + } + } + } + } + + final double getImagePropertyDouble(String key, double defaultValue) { + if (key == null) { + throw new IllegalArgumentException("key is null"); + } + + checkExifSource(); + return exifAdapter.getImagePropertyDouble(key, defaultValue); + } + + ExifAdapter getExifAdapterInstance() { + checkExifSource(); + return exifAdapter; + } + + /** + * get updated ImageSource if image file source changed, such as after edit exif infos. + * + * @return new ImageSoure instance. + * @since 3 + */ + ImageSource updateImageSource() { + try { + if (imgDataSource instanceof FilePathDataSource) { + FilePathDataSource dataSource = (FilePathDataSource) imgDataSource; + return create(dataSource.filePath, inputOpts); + } else if (imgDataSource instanceof ByteArrayDataSource) { + ByteArrayDataSource dataSource = (ByteArrayDataSource) imgDataSource; + return create(dataSource.data, dataSource.offset, dataSource.length, inputOpts); + } else if (imgDataSource instanceof InputStreamDataSource) { + InputStreamDataSource dataSource = (InputStreamDataSource) imgDataSource; + dataSource.is.mark(0); + dataSource.is.reset(); + return create(dataSource.is, inputOpts); + } else if (imgDataSource instanceof FileDataSource) { + FileDataSource dataSource = (FileDataSource) imgDataSource; + return create(dataSource.file, inputOpts); + } else if (imgDataSource instanceof FileDescriptorDataSource) { + FileDescriptorDataSource dataSource = (FileDescriptorDataSource) imgDataSource; + return create(dataSource.fd, inputOpts); + } else { + LOGGER.error("update ImageSource failed."); + return null; + } + }catch (IOException e) { + LOGGER.error("update ImageSource failed of IOException"); + } + return null; + } + + /** + * Used to get ImageSource related file Size. + * + * @return valid fileSize or -1 means get file size error. + * @since 3 + */ + long getFileSize() { + return fileSize > 0 ? fileSize : -1; + } + + private static native void nativeInit(); + + private native void nativeRelease(long nativePtr); + + private native void nativeSetDecodeEventListener(ImageSource sourceObj, long nativePtr); + + private static native HashSet nativeGetSupportedFormats(); + + private static native ImageSource nativeCreateImageSource(String pathName, SourceOptions opts); + + private static native ImageSource nativeCreateImageSource(InputStream is, SourceOptions opts); + + private static native ImageSource nativeCreateImageSource(byte[] data, int offset, int length, SourceOptions opts); + + private static native ImageSource nativeCreateIncrementalImageSource(IncrementalSourceOptions opts); + + private native int nativeUpdateData(long nativePtr, byte[] data, int offset, int length, boolean isCompleted); + + private native PixelMap nativeCreatePixelmap(ImageSource sourceObj, long nativePtr, + int index, DecodingOptions opts); + + private native ImageInfo nativeGetImageInfo(long nativePtr, int index); + + private native SourceInfo nativeGetSourceInfo(long nativePtr); + + private native int nativeGetImagePropertyInt(long nativePtr, int index, String key, int defaultValue); + + private native void nativeSetMemoryUsagePreference(long nativePtr, MemoryUsagePreference preference); +} diff --git a/interfaces/kits/java/src/ohos/media/image/PixelMap.java b/interfaces/kits/java/src/ohos/media/image/PixelMap.java new file mode 100644 index 0000000000000000000000000000000000000000..96db0ac34b216da4278db40dd0caa1c0c5128f9d --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/PixelMap.java @@ -0,0 +1,990 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.image.common.AlphaType; +import ohos.media.image.common.ImageInfo; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.Position; +import ohos.media.image.common.Rect; +import ohos.media.image.common.ScaleMode; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.system.Parameters; +import ohos.utils.Parcel; +import ohos.utils.Sequenceable; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.Objects; +import java.util.Locale; + +import ark.system.NativeAllocationNotifier; + +/** + * Provides images in forms of pixel matrices. + * + *

Applications can use methods, such as {@link #getImageInfo}, to obtain basic image information. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class PixelMap implements Sequenceable { + private static final Logger LOGGER = LoggerFactory.getImageLogger(PixelMap.class); + + /** + * Creates a {@link PixelMap} instance from a {@link Parcel}. If the class has a final member variable whose value + * cannot be changed by {@link Sequenceable#unmarshalling}. + * + * @since 1 + */ + public static final Sequenceable.Producer PRODUCER = new Sequenceable.Producer() { + /** + * Create a new instance of the Sequenceable class from the given parcel and + * the parcel had been inited. + */ + public PixelMap createFromParcel(Parcel parcel) { + if (parcel.readInt() == 0) { + return null; + } + PixelMap pixelMap = nativeCreateFromParcel(parcel); + if (pixelMap == null) { + LOGGER.error("create pixel map from parcel failed."); + } + return pixelMap; + } + }; + + /** + * Pixelmap default density data + */ + private static final int DENSITY_DEFAULT = 160; + + /** + * Pixelmap unknown density. + */ + private static final int DENSITY_NONE = 0; + + /** + * max width or height. + */ + private static final int MAX_DIMENSION = Integer.MAX_VALUE >> 2; + + static { + LOGGER.debug("Begin loading pixelmap_jni library"); + String osName = System.getProperty("os.name"); + String jniLibName = "pixelmap_jni.z"; + if (osName != null) { + osName = osName.toUpperCase(Locale.US); + if (osName.contains("WINDOWS")) { + jniLibName = "libpixelmap_jni"; + } else if (osName.contains("MAC")) { + jniLibName = "pixelmap_jni"; + } else { + jniLibName = "pixelmap_jni.z"; + } + } + try { + System.loadLibrary(jniLibName); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary %{public}s fail", jniLibName); + } + } + + /** + * Accessed by native methods + */ + private long nativeImagePixelMap; + + /** + * Accessed by native methods + */ + private byte[] nativeNinePatchChunk; + + /** + * Accessed by native methods + */ + private long nativeImageRelatedRes; + + /** + * Pixelmap init the desity and mipmap data + */ + private int baseDensity = getdefaultBaseDensity(); + + private boolean useMipMap = false; + + private Size size; + + /** + * A constructor used to create a {@link PixelMap} instance. + * + * @param nativeImagePixelMap the native object pointer. + * @param nativeAllocBytes the native object size. + * @since 1 + */ + protected PixelMap(long nativeImagePixelMap, long nativeAllocBytes) { + this.nativeImagePixelMap = nativeImagePixelMap; + String osName = System.getProperty("os.name"); + if (osName != null) { + osName = osName.toUpperCase(Locale.US); + if (!(osName.contains("WINDOWS") || osName.contains("MAC"))) { + NativeAllocationNotifier.notifyMallocAllocation(PixelMap.class.getClassLoader(), + nativeGetFreeFunction(), nativeAllocBytes, this, nativeImagePixelMap); + } + } else { + NativeAllocationNotifier.notifyMallocAllocation(PixelMap.class.getClassLoader(), nativeGetFreeFunction(), + nativeAllocBytes, this, nativeImagePixelMap); + } + } + + /** + * Private constructor called by JNI. + * + * @param nativeImagePixelMap the native object pointer. + * @param nativeAllocBytes the native object size. + * @param nativeImageRelatedRes the native related object pointer. + */ + private PixelMap(long nativeImagePixelMap, long nativeAllocBytes, long nativeImageRelatedRes) { + this(nativeImagePixelMap, nativeAllocBytes); + this.nativeImageRelatedRes = nativeImageRelatedRes; + } + + /** + * Private constructor called by JNI. + * + * @param nativeImagePixelMap the native object pointer. + * @param nativeAllocBytes the native object size. + * @param nativeNinePatchChunk the native nine patch object pointer. + */ + private PixelMap(long nativeImagePixelMap, long nativeAllocBytes, byte[] nativeNinePatchChunk) { + this(nativeImagePixelMap, nativeAllocBytes); + this.nativeNinePatchChunk = nativeNinePatchChunk; + } + + /** + * Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type) and + * the data source described by a pixel color array. + * + * @param colors Indicates an int array of pixel colors. Each element in the array is in {@link + * PixelFormat#ARGB_8888} format. + * @param opts Indicates initialization options of the pixel map. + * @return Returns the {@code PixelMap} instance if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if any of the following occurs:

  • The image size is + * {@code null}.
  • The width and height are less than or equal to {@code 0}.
  • The length of the pixel + * color array is less than the number of image pixels.
+ * @since 3 + */ + public static PixelMap create(int[] colors, InitializationOptions opts) { + if (Objects.isNull(opts) || Objects.isNull(opts.size)) { + throw new IllegalArgumentException("initial options or size is null"); + } + return doCreate(colors, 0, opts.size.width, opts); + } + + /** + * Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type) and + * the data source described by a pixel color array, start offset, and number of pixels in a row. + * + * @param colors Indicates an int array of color values. Each element in the array is in {@link + * PixelFormat#ARGB_8888} format. + * @param offset Indicates the offset from where to read pixel color data in the array. + * @param stride Indicates the number of pixel color elements in each row of the array. The value must be greater + * than or equal to the width of the pixel map to be created. + * @param opts Indicates initialization options of the pixel map. + * @return Returns the {@code PixelMap} instance if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if any of the following occurs:
  • The image size is + * {@code null}.
  • The width and height are less than or equal to {@code 0}.
  • The number of available + * elements in the array is less than the number of image pixels.
  • The value of {@code stride} is smaller + * than the width of the pixel map.
+ * @since 3 + */ + public static PixelMap create(int[] colors, int offset, int stride, InitializationOptions opts) { + if (Objects.isNull(opts) || Objects.isNull(opts.size)) { + throw new IllegalArgumentException("initial options or size is null"); + } + return doCreate(colors, offset, stride, opts); + } + + private static PixelMap doCreate(int[] colors, int offset, int stride, InitializationOptions opts) { + if (Objects.isNull(colors) || colors.length <= 0) { + throw new IllegalArgumentException("init colors is invalid"); + } + int width = opts.size.width; + int height = opts.size.height; + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("init size is invalid"); + } + if (stride < width) { + throw new IllegalArgumentException("init stride must be >= width"); + } + long lastLine = (height - 1) * (long) stride + offset; + if (offset < 0 || offset + width > colors.length || lastLine + width > colors.length) { + throw new IllegalArgumentException("colors length is less than target pixelMap"); + } + return nativeCreate(colors, offset, stride, opts.size.width, opts.size.height, opts.pixelFormat.getValue(), + opts.alphaType.getValue(), opts.editable); + } + + /** + * Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type). + * + * @param opts Indicates initialization options of the pixel map. + * @return Returns the {@code PixelMap} instance if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if the image size is {@code null}, or the width and height + * are less than or equal to {@code 0}. + * @since 3 + */ + public static PixelMap create(InitializationOptions opts) { + if (Objects.isNull(opts) || Objects.isNull(opts.size)) { + throw new IllegalArgumentException("initial options or size is null"); + } + if (opts.size.width <= 0 || opts.size.height <= 0) { + throw new IllegalArgumentException("init size is invalid"); + } + return nativeCreate(opts.size.width, opts.size.height, opts.pixelFormat.getValue(), opts.alphaType.getValue(), + opts.editable); + } + + /** + * Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type) and + * the data source described by a source pixel map. + * + * @param source Indicates the {@code PixelMap} instance as the data source. + * @param opts Indicates initialization options of the pixel map. If the value is {@code null}, the target pixel map + * will be created from a copy of the source pixel map. + * @return Returns the new {@code PixelMap} instance if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if any of the following occurs:
  • The source pixel + * map is {@code null}.
  • Native resources associated with the source pixel map have been released.
  • + *
  • The image width or height specified in {@code opts} is less than {@code 0}.
+ * @since 3 + */ + public static PixelMap create(PixelMap source, InitializationOptions opts) { + return create(source, null, opts); + } + + /** + * Creates a pixel map based on initialization options (such as the image size, pixel format, and alpha type) and + * the data source described by a source pixel map and the expected area on it. + * + * @param source Indicates the source {@code PixelMap}. + * @param srcRegion Indicates the expected region on the source pixel map. + * @param opts Indicates initialization options of the pixel map. If this parameter is {@code null}, the new pixel + * map will be a copy of the source pixel map. + * @return Returns the new {@code PixelMap} instance if the creation is successful; returns {@code null} otherwise. + * @throws IllegalArgumentException Throws this exception if any of the following occurs:
  • The source pixel + * map is {@code null}.
  • Native resources associated with the source pixel map have been released.
  • + *
  • The {@code srcRegion} is out of the source pixel map.
  • The image width or height specified in {@code + * opts} is less than {@code 0}.
+ * @since 3 + */ + public static PixelMap create(PixelMap source, Rect srcRegion, InitializationOptions opts) { + if (Objects.isNull(source) || source.isReleased()) { + throw new IllegalArgumentException("the source pixelMap is invalid, maybe has released"); + } + if (srcRegion == null) { + srcRegion = new Rect(); + } + if (opts == null) { + opts = new InitializationOptions(); + } + if (opts.size == null) { + opts.size = new Size(); + } + if (srcRegion.minX < 0 || srcRegion.minY < 0 || srcRegion.width < 0 || srcRegion.height < 0 + || opts.size.width < 0 || opts.size.height < 0) { + throw new IllegalArgumentException("srcRegion or option size invalid"); + } + PixelMap pixelMap = nativeCreate(source, srcRegion.minX, srcRegion.minY, srcRegion.width, srcRegion.height, + opts.size.width, opts.size.height, opts.pixelFormat.getValue(), opts.alphaType.getValue(), + opts.scaleMode.getValue(), opts.useSourceIfMatch, opts.editable); + if (pixelMap != null && source.nativeImagePixelMap != pixelMap.nativeImagePixelMap && opts != null + && opts.releaseSource && !opts.useSourceIfMatch) { + LOGGER.debug("release source pixelMap"); + source.release(); + } + return pixelMap; + } + + /** + * Obtains basic image information. + * + *

Basic image information is provided by {@link ImageInfo}, + * including the image size, pixel format, and color space. + * + * @return Returns an {@link ImageInfo} object. + * @since 1 + */ + public ImageInfo getImageInfo() { + return nativeGetImageInfo(nativeImagePixelMap); + } + + /** + * Releases native resources associated with an object. + * + * @since 1 + */ + public void release() { + if (!isReleased()) { + nativeRelease(nativeImagePixelMap, nativeImageRelatedRes); + nativeImagePixelMap = 0L; + nativeImageRelatedRes = 0L; + nativeNinePatchChunk = null; + size = null; + } + } + + @Override + protected void finalize() throws Throwable { + release(); + super.finalize(); + } + + /** + * Obtains 9 patch chunk data of this {@code PixelMap}. + * + * @return Returns the 9 patch chunk data if any; returns {@code null} otherwise. + * @since 3 + */ + public byte[] getNinePatchChunk() { + return nativeNinePatchChunk; + } + + /** + * Checks whether native resources have been released. + * + * @return Returns {@code true} if resources are released; returns {@code false} otherwise. + * @since 1 + */ + public boolean isReleased() { + return nativeImagePixelMap == 0; + } + + private void checkRelease(String errorMsg) { + if (isReleased()) { + throw new IllegalStateException(errorMsg); + } + } + + /** + * Writes a {@link PixelMap} object into a {@link Parcel}. + * + * @param out Indicates the {@link Parcel} object to which the {@link PixelMap} object will be written. + * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + * @since 1 + */ + public boolean marshalling(Parcel out) { + return nativeWriteToParcel(nativeImagePixelMap, out); + } + + /** + * Restores a {@link PixelMap} object from a {@link Parcel}. + * + * @param in Indicates the {@link Parcel} object into which the {@link PixelMap} object has been written. + * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + * @since 1 + */ + public boolean unmarshalling(Parcel in) { + return false; + } + + /** + * Obtains the number of bytes in each row of pixels. + * + * @return Returns the number of bytes. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public int getBytesNumberPerRow() { + checkRelease("getBytesNumberPerRow but current pixelmap had released."); + return nativeGetBytesNumberPerRow(nativeImagePixelMap); + } + + /** + * Obtains the pixel data size in bytes. + * + * @return Returns the number of bytes of all the pixel data. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public long getPixelBytesNumber() { + checkRelease("getBytesNumber but current pixelmap had released."); + return nativeGetBytesNumber(nativeImagePixelMap); + } + + /** + * Obtains the memory capacity for storing the pixels of this {@code PixelMap}. + * + * @return Returns the memory capacity. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public long getPixelBytesCapacity() { + checkRelease("getPixelBytesCapacity but current pixelmap had released."); + return nativeGetPixelBytesCapacity(nativeImagePixelMap); + } + + /** + * Checks whether this {@code PixelMap} can be edited. + * + * @return Returns {@code true} if the pixel map is editable; returns {@code false} otherwise. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public boolean isEditable() { + checkRelease("isEditable but current pixelmap had released."); + return nativeIsEditable(nativeImagePixelMap); + } + + /** + * Checks whether this {@code PixelMap} is the same as the specified one, including the attribute information + * described by the {@code ImageInfo} instance and pixel data. + * + * @param other Indicates the specified {@code PixelMap} to compare. + * @return Returns {@code true} if the two images are the same; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the specified {@code PixelMap} is empty. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public boolean isSameImage(PixelMap other) { + if (other == null) { + LOGGER.error("isSameImage input other pixelmap is null."); + throw new IllegalStateException("other pixelmap object is null."); + } + checkRelease("isSameImage but current pixelmap had released."); + return nativeIsSameImage(nativeImagePixelMap, other.nativeImagePixelMap); + } + + /** + * Reads the color value at the specified position. + * + * @param pos Indicates the coordinate of the pixel. + * @return Returns the color value, which is of the {@link AlphaType#UNPREMUL} type and in {@link + * PixelFormat#ARGB_8888} format. + * @throws IllegalArgumentException Throws this exception if the passed coordinate position is {@code null} or out + * of the valid range of the image. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public int readPixel(Position pos) { + if (pos == null || pos.posX > MAX_DIMENSION || pos.posY > MAX_DIMENSION || pos.posX < 0 || pos.posY < 0) { + LOGGER.error("readPixel pos object is invalid."); + throw new IllegalArgumentException("read Pixelpos object is invalid."); + } + checkRelease("readPixel but current pixelmap had released."); + return nativeReadPixel(nativeImagePixelMap, pos.posX, pos.posY); + } + + /** + * Reads the color values of a specified region and writes them into a {@code pixels} array with the specified start + * offset and stride. The color values are of the {@link AlphaType#UNPREMUL} type and in {@link + * PixelFormat#ARGB_8888} format. + * + * @param pixels Indicates the array storing the color value copies. + * @param offset Indicates the offset into which the color values will be written. + * @param stride Indicates the number of color values stored in each row of the array. The parameter value must be + * greater than or equal to the width of the specified source region. + * @param region Indicates the source region to obtain the color values. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @throws IllegalArgumentException Throws this exception if any of the following occurs:

  • The {@code pixels} + * array is {@code null}.
  • The {@code offset} value is less than {@code 0} or larger than the {@code pixels} + * array length.
  • The {@code stride} value is less than {@code 0}.
  • The {@code region} value is + * {@code null} or out of the valid range of the image.
+ * @throws ArrayIndexOutOfBoundsException Throws this exception if the {@code pixels} array is too small to + * accommodate the color values. + * @since 3 + */ + public void readPixels(int[] pixels, int offset, int stride, Rect region) { + if (region == null || region.height < 0 || region.height > MAX_DIMENSION || region.width < 0 + || region.width > MAX_DIMENSION) { + LOGGER.error("readPixels region object is invalid."); + throw new IllegalArgumentException("read Pixels region object is invalid."); + } + if (pixels == null) { + LOGGER.error("readPixels pixels array is null."); + throw new IllegalArgumentException("read Pixels array is null."); + } + if (offset < 0 || stride < 0 || offset > (pixels.length)) { + LOGGER.error("readPixels offset or stride is invalid."); + throw new IllegalArgumentException("read Pixels offset or stride is invalid."); + } + checkRelease("readPixels called read Pixels to int[] but the pixelmap is release."); + if (!nativeReadPixels(nativeImagePixelMap, pixels, offset, stride, region.minX, region.minY, region.width, + region.height)) { + LOGGER.error("nativeReadPixels return fail."); + throw new IllegalStateException("native readPixels fail."); + } + } + + /** + * Reads a copy of color values of this {@code PixelMap} instance and stores it to the specified buffer. + * + * @param dst Indicates the buffer storing the color value copies. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @throws IllegalArgumentException Throws this exception if the buffer is {@code null} or the format is not + * supported. + * @throws ArrayIndexOutOfBoundsException Throws this exception if the size of the color values exceeds the buffer + * capacity. + * @since 3 + */ + public void readPixels(Buffer dst) { + if (dst == null) { + LOGGER.error("readPixels Buffer is null."); + throw new IllegalArgumentException("read pixels but Buffer is null"); + } + checkRelease("called read Pixels to Buffer but the pixelmap is release."); + int len = dst.remaining(); + int shift; + if (dst instanceof ByteBuffer) { + shift = 0; // byte buffer type is same pixel bytes + } else if (dst instanceof ShortBuffer) { + shift = 1; // short buffer type need buffer len << 1 bit + } else if (dst instanceof IntBuffer) { + shift = 2; // Int buffer type need buffer len << 2 bit + } else { + LOGGER.error("readPixels dst is invalid."); + throw new IllegalArgumentException("unsupported Buffer subclass"); + } + long dstSize = ((long) len) << shift; + long curPixelSize = getPixelBytesNumber(); + + if (dstSize < curPixelSize) { + LOGGER.error("readPixels dstSize:%{public}d < curPixelSize:%{public}d.", dstSize, curPixelSize); + throw new ArrayIndexOutOfBoundsException("Buffer not large enough for pixels"); + } + + if (!nativeReadPixels(nativeImagePixelMap, dst, dstSize)) { + LOGGER.error("nativeImagePixelMap return fail."); + throw new IllegalStateException("native readPixels fail."); + } + + // now update the buffer's position + int pos = dst.position(); + pos += curPixelSize >> shift; + dst.position(pos); + } + + /** + * Resets the size and pixel format of this {@code PixelMap}. This method does not change the original pixel data, + * or reallocate the memory for storing the pixel data. + * + * @param size Indicates the target image size after the reset, in bytes. The value must not exceed the memory + * occupied by this {@code PixelMap}. + * @param pixelFormat Indicates pixel format to reset. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released, or the {@code PixelMap} cannot be edited. + * @throws IllegalArgumentException Throws this exception if the memory capacity required by the target image size + * and pixel format exceeds the available capacity. + * @since 3 + */ + public void resetConfig(Size size, PixelFormat pixelFormat) { + if (size == null || size.height <= 0 || size.width <= 0 || size.height > MAX_DIMENSION + || size.width > MAX_DIMENSION) { + LOGGER.error("resetConfig input parameter invalid."); + throw new IllegalArgumentException("reset config width and height must be > 0"); + } + if (pixelFormat == null || pixelFormat == PixelFormat.UNKNOWN) { + LOGGER.error("resetConfig pixelFormat invalid."); + throw new IllegalArgumentException("reset config pixelFormat invalid"); + } + checkRelease("reset pixelmap but it is release."); + if (!nativeResetConfig(nativeImagePixelMap, size.width, size.height, pixelFormat.getValue())) { + LOGGER.error("nativeReset return fail."); + throw new IllegalStateException("native reset config fail."); + } + } + + /** + * Sets the alpha type of this {@code PixelMap}. + * + * @param alphaType Indicates the {@code AlphaType} to set. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released, or the {@code PixelMap} cannot be edited. + * @throws IllegalArgumentException Throws this exception if the input {@code AlphaType} is invalid. + * @since 3 + */ + public void setAlphaType(AlphaType alphaType) { + if (alphaType == null || alphaType == AlphaType.UNKNOWN) { + LOGGER.error("setAlphaType input alphaType is unknown."); + throw new IllegalArgumentException("set AlphaType is UNKNOWN."); + } + checkRelease("set current pixelmap Alpha but pixlmap is release."); + if (!nativeSetAlphaType(nativeImagePixelMap, alphaType.getValue())) { + LOGGER.error("nativeSetAlphaType return fail."); + throw new IllegalArgumentException("set Alpha Type fail."); + } + } + + /** + * Writes the color value into the specified position. + * + * @param pos Indicates the coordinate position to write the pixel value. + * @param color Indicates the color value to write, which is of the {@link AlphaType#UNPREMUL} type and in {@link + * PixelFormat#ARGB_8888} format. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released, or the {@code PixelMap} cannot be edited. + * @throws IllegalArgumentException Throws this exception if the coordinate position is {@code null} or out of the + * valid range of the image. + * @since 3 + */ + public void writePixel(Position pos, int color) { + if (pos == null || pos.posX < 0 || pos.posY < 0 || pos.posX > MAX_DIMENSION || pos.posY > MAX_DIMENSION) { + LOGGER.error("writePixel input invalid."); + throw new IllegalArgumentException("write pixel pos object is invalid"); + } + checkRelease("write current pixelmap by color but pixlmap is release."); + if (!nativeWritePixel(nativeImagePixelMap, pos.posX, pos.posY, color)) { + LOGGER.error("nativeWritePixel return fail."); + throw new IllegalStateException("native write pixel fail."); + } + } + + /** + * Writes data from the specified color data array (based on the start offset and stride) into the specified region + * of this {@code PixelMap}. The color data to write is of the {@link AlphaType#UNPREMUL} type and in {@link + * PixelFormat#ARGB_8888} format. + * + * @param pixels Indicates the array of color data. + * @param offset Indicates the offset from which the color data will be read. + * @param stride Indicates the number of pixels in each row of the array. The value must be greater than or equal to + * the width of the target region in this {@code PixelMap}. + * @param region Indicates the target pixel map region into which the data will be written. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released, or the {@code PixelMap} cannot be edited. + * @throws IllegalArgumentException Throws this exception if any of the following occurs:
  • The {@code pixels} + * array is {@code null}.
  • The {@code offset} value is less than {@code 0} or larger than the {@code pixels} + * array length.
  • The {@code stride} value is less than {@code 0}.
  • The {@code region} value is out + * of the valid range of the image.
+ * @since 3 + */ + public void writePixels(int[] pixels, int offset, int stride, Rect region) { + if (region == null || region.height < 0 || region.height > MAX_DIMENSION || region.width < 0 + || region.width > MAX_DIMENSION) { + LOGGER.error("writePixels region object is invalid."); + throw new IllegalArgumentException("write pixels region object is invalid."); + } + if (pixels == null) { + LOGGER.error("writePixels pixels array is null."); + throw new IllegalArgumentException("write pixels array is null."); + } + if (offset < 0 || stride < 0 || offset > (pixels.length)) { + LOGGER.error("writePixels offset or stride is invalid."); + throw new IllegalArgumentException("write pixels offset or stride is invalid."); + } + checkRelease("writePixels from intArray but the pixelmap is release."); + if (!nativeWritePixels(nativeImagePixelMap, pixels, offset, stride, region.minX, region.minY, region.width, + region.height)) { + LOGGER.error("nativeWritePixels return fail."); + throw new IllegalStateException("native WritePixels from intArray fail."); + } + } + + /** + * Writes the pixel data in the specified buffer into this {@code PixelMap}. The buffer data will overwrite the + * {@code PixelMap} data, so the color format of the source data must be compatible with this {@code PixelMap}. + * + * @param src Indicates the buffer whose pixel data will be written. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released, or the {@code PixelMap} cannot be edited. + * @throws IllegalArgumentException Throws this exception if the buffer is {@code null} or the format is not + * supported. + * @throws ArrayIndexOutOfBoundsException Throws this exception if the data in the buffer is insufficient to fill + * the {@code PixelMap}. + * @since 3 + */ + public void writePixels(Buffer src) { + if (src == null) { + LOGGER.error("writePixels Buffer is null."); + throw new IllegalArgumentException("write pixels but Buffer is null"); + } + checkRelease("writePixels from Buffer but the pixelmap is release."); + int len = src.remaining(); + int shift; + if (src instanceof ByteBuffer) { + shift = 0; // byte buffer type is same pixel bytes + } else if (src instanceof ShortBuffer) { + shift = 1; // short buffer type need buffer len << 1 bit + } else if (src instanceof IntBuffer) { + shift = 2; // Int buffer type need buffer len << 2 bit + } else { + LOGGER.error("writePixels src is invalid."); + throw new IllegalStateException("unsupported Buffer subclass"); + } + long srcSize = ((long) len) << shift; + long curPixelSize = getPixelBytesNumber(); + + if (srcSize < curPixelSize) { + LOGGER.error("writePixels srcSize:%{public}d < curPixelSize:%{public}d.", srcSize, curPixelSize); + throw new ArrayIndexOutOfBoundsException("write pixels Buffer not large enough for pixels"); + } + if (!nativeWritePixels(nativeImagePixelMap, src, srcSize)) { + LOGGER.error("nativeWritePixels by Buffer return false."); + throw new IllegalStateException("native WritePixels from Buffer fail."); + } + // now update the buffer's position + int pos = src.position(); + pos += curPixelSize >> shift; + src.position(pos); + } + + /** + * Writes the specified color value into this {@code PixelMap}. + * + * @param color Indicates the color value to write, which is of the {@link AlphaType#UNPREMUL} type and in {@link + * PixelFormat#ARGB_8888} format. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released, or the {@code PixelMap} cannot be edited. + * @since 3 + */ + public void writePixels(int color) { + checkRelease("writePixels from int color but the pixelmap is release."); + if (!nativeWritePixels(nativeImagePixelMap, color)) { + LOGGER.error("nativeWritePixels by int color return false."); + throw new IllegalStateException("nativeWritePixels from int color fail."); + } + } + + /** + * Sets the base pixel density of this {@code PixelMap}. + * + * @param baseDensity Indicates the base pixel density to set. + * @since 3 + */ + public void setBaseDensity(int baseDensity) { + this.baseDensity = baseDensity; + } + + /** + * Obtains the base pixel density of this {@code PixelMap}. + * + * @return Returns the base pixel density. + * @since 3 + */ + public int getBaseDensity() { + return baseDensity; + } + + /** + * Sets whether MIP mapping will be used for rendering this {@code PixelMap}. + * + * @param useMipmap Specifies whether to use MIP mapping. Set it to {@code true} if the renderer will use MIP + * mapping and to {@code false} otherwise. + * @since 3 + */ + public final void setUseMipmap(boolean useMipmap) { + this.useMipMap = useMipmap; + } + + /** + * Checks whether MIP mapping will be used for rendering this {@code PixelMap}. + * + * @return Returns {@code true} if the renderer will try MIP mapping; returns {@code false} otherwise. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public final boolean useMipmap() { + checkRelease("call useMipmap() but the pixelmap is release."); + return useMipMap; + } + + /** + * Obtains the image size that fits the specified pixel density. + * + * @param targetDensity Indicates the pixel density. + * @return Returns the image size fitting the specified pixel density. + * @throws IllegalStateException Throws this exception if native resources associated with this {@code PixelMap} + * have been released. + * @since 3 + */ + public Size getFitDensitySize(int targetDensity) { + if (size == null) { + checkRelease("PixelMap has been released"); + ImageInfo imageInfo = getImageInfo(); + if (imageInfo == null) { + LOGGER.error("getFitDensitySize getImageInfo failed."); + throw new IllegalStateException("PixelMap does not contain valid info."); + } + size = imageInfo.size; + } + int sourceDensity = baseDensity; + if (sourceDensity == DENSITY_NONE || targetDensity == DENSITY_NONE || sourceDensity == targetDensity) { + return size; + } + + int targetHeight = (size.height * targetDensity + (sourceDensity >> 1)) / sourceDensity; + int targetWidth = (size.width * targetDensity + (sourceDensity >> 1)) / sourceDensity; + return new Size(targetWidth, targetHeight); + } + + /** + * Creates a {@code PixelMap} using the alpha channel of this {@code PixelMap}. + * + * @return Returns the new {@code PixelMap} containing only the alpha channel. + * @since 4 + */ + public PixelMap createFromAlpha() { + return nativeCreateFromAlpha(nativeImagePixelMap); + } + + private int getdefaultBaseDensity() { + int realMaxDeviceDensity = Parameters.getInt("ro.sf.real_lcd_density", + Parameters.getInt("ro.sf.lcd_density", DENSITY_DEFAULT)); + if (Parameters.getInt("persist.sys.rog.width", 0) > 0) { + int dpi = Parameters.getInt("persist.sys.dpi", realMaxDeviceDensity); + return Parameters.getInt("persist.sys.realdpi", dpi); + } + int dpi = Parameters.getInt("persist.sys.dpi", 0); + if ((dpi > 0) && (dpi != realMaxDeviceDensity)) { + return dpi; + } + return Parameters.getInt("qemu.sf.lcd_density", realMaxDeviceDensity); + } + + private native void nativeRelease(long nativeImagePixelMap, long nativeImageRelatedRes); + + private native ImageInfo nativeGetImageInfo(long nativeImagePixelMap); + + private native boolean nativeWriteToParcel(long nativeImagePixelMap, Parcel parcel); + + private static native PixelMap nativeCreateFromParcel(Parcel parcel); + + private static native PixelMap nativeCreate(int[] colors, int offset, int stride, int width, int height, + int pixelFormat, int alphaType, boolean editable); + + private static native PixelMap nativeCreate(int width, int height, int pixelFormat, int alphaType, + boolean editable); + + private static native PixelMap nativeCreate(PixelMap srcPixelMap, int srcRectX, int srcRectY, int srcRectWidth, + int srcRectHeight, int width, int height, int pixelFormat, int alphaType, int scaleMode, + boolean useSourceIfMatch, boolean editable); + + private native int nativeGetBytesNumberPerRow(long nativePixelMap); + + private native long nativeGetBytesNumber(long nativePixelMap); + + private native long nativeGetPixelBytesCapacity(long nativePixelMap); + + private native boolean nativeIsEditable(long nativePixelMap); + + private native boolean nativeIsSameImage(long nativePixelMap, long otherNativePixelMap); + + private native int nativeReadPixel(long nativePixelMap, int x, int y); + + private native boolean nativeReadPixels(long nativePixelMap, int[] pixels, int offset, int stride, int x, int y, + int width, int height); + + private native boolean nativeReadPixels(long nativePixelMap, Buffer dst, long dstSize); + + private native boolean nativeResetConfig(long nativePixelMap, int width, int height, int pixelFormat); + + private native boolean nativeSetAlphaType(long nativePixelMap, int alphaType); + + private native boolean nativeWritePixel(long nativePixelMap, int x, int y, int color); + + private native boolean nativeWritePixels(long nativePixelMap, int[] pixels, int offset, int stride, int x, int y, + int width, int height); + + private native boolean nativeWritePixels(long nativePixelMap, Buffer source, long srcSize); + + private native boolean nativeWritePixels(long nativePixelMap, int color); + + private static native long nativeGetFreeFunction(); + + private native PixelMap nativeCreateFromAlpha(long nativePixelMap); + + /** + * Represents pixel map initialization options, including the image size, pixel format, and alpha type. + * + * @since 3 + */ + public static class InitializationOptions { + /** + * Indicates the expected size of the pixel map to be created. If the value is {@code null} and there is a + * source pixel map, the size of the source pixel map will be used for the creation. + * + * @since 3 + */ + public Size size; + + /** + * Indicates the scaling effect used when the aspect ratio of the original image is different from that of the + * target image. The default value is {@link ScaleMode#FIT_TARGET_SIZE}. + * + * @since 3 + */ + public ScaleMode scaleMode = ScaleMode.FIT_TARGET_SIZE; + + /** + * Indicates the expected format of the pixel map to be created. When the value is {@link PixelFormat#UNKNOWN}: + *
  • If there is a source pixel map, its format will be used for the creation.
  • If there is no + * source pixel map, {@link PixelFormat#ARGB_8888} will be used.
. + * + * @since 3 + */ + public PixelFormat pixelFormat = PixelFormat.UNKNOWN; + + /** + * Indicates the expected alpha type of the pixel map to be created. When the value is {@link + * AlphaType#UNKNOWN}:
  • If there is a source pixel map, its alpha type will be used for the + * creation.
  • If there is no source pixel map, either {@link AlphaType#PREMUL} (for the alpha channel is + * included in the pixel format) or {@link AlphaType#OPAQUE} (for the alpha channel not included in the pixel + * format) will be used for the creation.
+ * + * @since 3 + */ + public AlphaType alphaType = AlphaType.UNKNOWN; + + /** + * Specifies whether pixel values of the pixel map to be created can be edited. Value {@code true} means that + * the values can be edited, and {@code false} means the opposite. The default value is {@code false}. + * + * @since 3 + */ + public boolean editable = false; + + /** + * Specifies whether the source pixel map will be directly returned as a new one when the source one matches the + * initialization options for creating the new one. Value {@code true} means that the source pixel map will be + * returned, and {@code false} means the opposite. The default value is {@code false}. + * + * @since 3 + */ + public boolean useSourceIfMatch = false; + + /** + * Specifies whether the source pixel map will be automatically released after a new one is created based on the + * source one. Value {@code true} means that the source one will be released except that it is directly returned + * as the new pixel map, and {@code false} means that the source one will not be released. + * + * @since 3 + */ + public boolean releaseSource = false; + } +} \ No newline at end of file diff --git a/interfaces/kits/java/src/ohos/media/image/PropertyFilter.java b/interfaces/kits/java/src/ohos/media/image/PropertyFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..6bc82272b4a461b0b52e8362bd930b7c9275a027 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/PropertyFilter.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.image.common.Filter; +import ohos.media.image.exifadapter.ExifAdapter; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.HashMap; +import java.util.Map; + +/** + * Provides methods for setting image Exif properties, including adding, deleting, and modifying Exif properties. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 4 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class PropertyFilter extends Filter { + private static final Logger LOGGER = LoggerFactory.getImageLogger(PropertyFilter.class); + private ExifAdapter mExifAdapter; + private ConcurrentHashMap mProperties = new ConcurrentHashMap<>(); + private String nullKeyTag = "NULL_KEY"; + private boolean mRestored = false; + + /** + * Sets an Exif property of the int type. + * + * @param key Indicates the property key, which is defined in {@link ohos.media.image.common.PropertyKey}. + * @param value Indicates the property value. + * @return Returns this {@code PropertyFilter} object with the Exif property of the int type. This object can + * be used for subsequent Exif-related operations. + * @since 4 + */ + public PropertyFilter setPropertyInt(String key, int value) { + if (key == null) { + mProperties.put(nullKeyTag, nullKeyTag); + LOGGER.error("invalid input key of setPropertyInt."); + return this; + } + mProperties.put(key, String.valueOf(value)); + return this; + } + + /** + * Sets an Exif property of the double type. + * + * @param key Indicates the property key, which is defined in {@link ohos.media.image.common.PropertyKey}. + * @param value Indicates the property value. + * @return Returns this {@code PropertyFilter} object with the Exif property of the double type. The object + * can be used for subsequent Exif-related operations. + * @since 4 + */ + public PropertyFilter setPropertyDouble(String key, double value) { + if (key == null) { + mProperties.put(nullKeyTag, nullKeyTag); + LOGGER.error("invalid input key of setPropertyDouble."); + return this; + } + + mProperties.put(key, String.valueOf(value)); + return this; + } + + /** + * Sets an Exif property of the string type. + * + * @param key Indicates the property key, which is defined in {@link ohos.media.image.common.PropertyKey}. + * @param value Indicates the property value. + * @return Returns this {@code PropertyFilter} object with the Exif property of the string type. The object + * can be used for subsequent Exif-related operations. + * @since 4 + */ + public PropertyFilter setPropertyString(String key, String value) { + if (key == null) { + mProperties.put(nullKeyTag, nullKeyTag); + LOGGER.error("invalid input key of setPropertyString."); + return this; + } + mProperties.put(key, value); + return this; + } + + /** + * Restores a specified Exif property. This method applies only to the properties that have not been applied + * to the source file via {@code applyToSource(ImageSource)}. + * + * @param key Indicates the property key, which is defined in {@link ohos.media.image.common.PropertyKey}. + * @return Returns this {@code PropertyFilter} object with the restored Exif property. The object can be used + * for subsequent Exif-related operations. + * @since 4 + */ + public PropertyFilter rollbackProperty(String key) { + if (key == null) { + mProperties.remove(nullKeyTag); + return this; + } + mProperties.remove(key); + return this; + } + + /** + * Restores all Exif properties. This method applies only to the properties that have not been applied to the + * source file via {@code applyToSource(ImageSource)}. + * + * @return Returns this {@code PropertyFilter} object with the restored Exif properties. The object can be used + * for subsequent Exif-related operations. + * @since 4 + */ + @Override + public PropertyFilter restore() { + mProperties.clear(); + mRestored = true; + return this; + } + + /** + * Applies the configured Exif properties to the source file. + * + *

This method requires the permission to modify the source file represented by the {@code ImageSource} + * object. The configured Exif properties do not take effect until this method is called. + *

This method is applicable to the {@code ImageSource} object that has been created + * based on a {@code File} object or a specified file path. + * + * @param source Indicates the image source file to which the properties will be applied. + * @return Returns the size (in bytes) of the image file edited based on the Exif properties if the operation + * is successful; returns {@code -1} otherwise. + * @throws IOException Throws this exception if the modification permission has not been obtained. + * @throws IllegalArgumentException Throws this exception if the image source is empty. + * @throws IllegalStateException Throws this exception if the {@code ImageSource} object has been released. + * @since 4 + */ + @Override + public long applyToSource(ImageSource source) throws IOException { + if (source == null) { + throw new IllegalArgumentException("invalid input ImageSource null value of applyToSource."); + } + if (source.isReleased()) { + throw new IllegalStateException("invalid input ImageSource status of applyToSource."); + } + if (mProperties.size() == 1 && mProperties.containsKey(nullKeyTag)) { + LOGGER.error("invalid key set operation"); + return -1; + } + mProperties.remove(nullKeyTag); + if (mProperties.size() == 0) { + if (mRestored) { + return -1; + } + return source.getFileSize(); + } + mExifAdapter = source.getExifAdapterInstance(); + int setFailed = 0; + for (Map.Entry oneProperty : mProperties.entrySet()) { + mExifAdapter.setImageProperty(oneProperty.getKey(), oneProperty.getValue()); + // check all properties + String readValue = mExifAdapter.getImagePropertyString(oneProperty.getKey()); + if (readValue == null || !readValue.equals(oneProperty.getValue())) { + setFailed++; + } + } + if (setFailed == mProperties.size()) { + LOGGER.error("all property set failed"); + return -1; + } + mExifAdapter.saveAttributes(); + + ImageSource newSource = source.updateImageSource(); + if (newSource == null) { + LOGGER.error("update source failed"); + return -1; + } + return newSource.getFileSize(); + } +} + diff --git a/interfaces/kits/java/src/ohos/media/image/SourceDataIncompleteException.java b/interfaces/kits/java/src/ohos/media/image/SourceDataIncompleteException.java new file mode 100644 index 0000000000000000000000000000000000000000..d92e212084e269d335f1b8f77096c61c7696fa08 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/SourceDataIncompleteException.java @@ -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. + */ + +package ohos.media.image; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Provides the exception for reading data error. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class SourceDataIncompleteException extends ImageException { + private static final long serialVersionUID = -426469142788895449L; + + /** + * A constructor used to create an {@code SourceDataIncompleteException} instance based on the exception message. + * + * @param msg Indicates the string representation of the exception message. + * @since 3 + */ + public SourceDataIncompleteException(String msg) { + super(msg); + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/SourceDataMalformedException.java b/interfaces/kits/java/src/ohos/media/image/SourceDataMalformedException.java new file mode 100644 index 0000000000000000000000000000000000000000..3554999dd94f4ec0bd3efcf65126ba4c7a6f0f84 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/SourceDataMalformedException.java @@ -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. + */ + +package ohos.media.image; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Provides the exception for unsupported image format. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class SourceDataMalformedException extends ImageException { + private static final long serialVersionUID = 3362901618450277181L; + + /** + * A constructor used to create an {@code SourceDataMalformedException} instance based on the exception message. + * + * @param msg Indicates the string representation of the exception message. + * @since 3 + */ + public SourceDataMalformedException(String msg) { + super(msg); + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/AllocatorType.java b/interfaces/kits/java/src/ohos/media/image/common/AllocatorType.java new file mode 100644 index 0000000000000000000000000000000000000000..ea5c6fe4da31189b96d0714be6b6ace3040e8811 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/AllocatorType.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Enumerates the memory allocation type for decoded image data. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 4 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum AllocatorType { + /** + * Indicates that the system automatically selects the most appropriate storage allocation. + */ + DEFAULT(0), + + /** + * Indicates that heap memory is allocated to stored decoded image data. + */ + HEAP(1), + + /** + * Indicates that shared memory is allocated to stored decoded image data. + */ + SHARED_MEMORY(2); + + private final int typeValue; + + AllocatorType(int value) { + this.typeValue = value; + } + + /** + * Obtains the value of this enum. + * + * @return Returns the enum value. + * @since 4 + */ + public int getValue() { + return typeValue; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/AlphaType.java b/interfaces/kits/java/src/ohos/media/image/common/AlphaType.java new file mode 100644 index 0000000000000000000000000000000000000000..4e04d2f28f5057bb213e0700e7bcd18bac2c9c21 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/AlphaType.java @@ -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. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Represents the alpha type of an image. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum AlphaType { + /** + * Indicates an unknown alpha type. + */ + UNKNOWN(0), + + /** + * Indicates that the image format does not include the alpha channel, or the alpha type of all pixels is opaque. + */ + OPAQUE(1), + + /** + * Indicates that the color channel of each pixel is premultiplied by the alpha channel value. + */ + PREMUL(2), + + /** + * Indicates that the color component of each pixel is independent from the alpha channel and is not + * premultiplied by the value. + */ + UNPREMUL(3); + + private final int typeValue; + + AlphaType(int value) { + this.typeValue = value; + } + + /** + * Obtains the enum value of the alpha type. + * + * @return Returns the integer enum value. + * @since 3 + */ + public int getValue() { + return typeValue; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/ColorSpace.java b/interfaces/kits/java/src/ohos/media/image/common/ColorSpace.java new file mode 100644 index 0000000000000000000000000000000000000000..865439fa63e39f6f972889630677bdd33f18c471 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/ColorSpace.java @@ -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. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Describes types of image color space. + * + *

Image color space defines how colors are organized and represented. + * Common color space standards include SRGB and DISPLAY_P3. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum ColorSpace { + /** + * Indicates an unknown color space. + */ + UNKNOWN(0), + + /** + * Indicates the color space based on SMPTE RP 431-2-2007 and IEC 61966-2.1:1999. + */ + DISPLAY_P3(1), + + /** + * Indicates the standard red green blue (SRGB) color space based on IEC 61966-2.1:1999. + */ + SRGB(2), + + /** + * Indicates the SRGB using a linear transfer function based on the IEC 61966-2.1:1999 standard. + */ + LINEAR_SRGB(3), + + /** + * Indicates the color space based on IEC 61966-2-2:2003. + */ + EXTENDED_SRGB(4), + + /** + * Indicates the color space based on IEC 61966-2-2:2003. + */ + LINEAR_EXTENDED_SRGB(5), + + /** + * Indicates the color space based on the standard illuminant with D50 as the white point. + */ + GENERIC_XYZ(6), + + /** + * Indicates the color space using CIE XYZ D50 as the profile conversion space. + */ + GENERIC_LAB(7), + + /** + * Indicates the color space based on SMPTE ST 2065-1:2012. + */ + ACES(8), + + /** + * Indicates the color space based on Academy S-2014-004. + */ + ACES_CG(9), + + /** + * Indicates the color space based on Adobe RGB (1998). + */ + ADOBE_RGB_1998(10), + + /** + * Indicates the color space based on SMPTE RP 431-2-2007. + */ + DCI_P3(11), + + /** + * Indicates the color space based on Rec.ITU-R BT.709-5. + */ + ITU_709(12), + + /** + * Indicates the color space based on Rec.ITU-R BT.2020-1. + */ + ITU_2020(13), + + /** + * Indicates the color space based on ISO 22028-2:2013. + */ + ROMM_RGB(14), + + /** + * Indicates the color space based on the NTSC 1953 standard. + */ + NTSC_1953(15), + + /** + * Indicates the color space based on SMPTE C. + */ + SMPTE_C(16); + + private final int colorValue; + + ColorSpace(int value) { + this.colorValue = value; + } + + /** + * Obtains an enum value. + * + * @return Returns the enum value. + * @since 1 + */ + public int getValue() { + return colorValue; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/DecodeEvent.java b/interfaces/kits/java/src/ohos/media/image/common/DecodeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..ce58c76d5b4467230cf508f5af185f5423feb995 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/DecodeEvent.java @@ -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. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Enumerates the events during the decoding process. + * It should be in sync with native definition. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 4 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum DecodeEvent { + /** + * Indicates that decoding is complete. + */ + EVENT_COMPLETE_DECODE(0), + + /** + * Indicates that partial decoding is complete. + */ + EVENT_PARTIAL_DECODE(1), + + /** + * Indicates that the file header has been decoded. + * + * @since 5 + */ + EVENT_HEADER_DECODE(2), + + /** + * Indicates the end of the event list. + * + * @since 5 + */ + EVENT_LAST(3); + + + private final int decodeEventValue; + + DecodeEvent(int value) { + this.decodeEventValue = value; + } + + /** + * Creates a {@code DecodeEvent} instance based on the passed enum value. + * + * @param val Indicates the enum value of the event. + * @return Returns the created {@code DecodeEvent}. + * @since 5 + */ + public static DecodeEvent getDecodeEvent(int val) { + for (DecodeEvent event : DecodeEvent.values()) { + if (event.getValue() == val) { + return event; + } + } + return DecodeEvent.EVENT_LAST; + } + + /** + * Obtains the value of this enum. + * + * @return Returns the enum value. + * @since 4 + */ + public int getValue() { + return decodeEventValue; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/Filter.java b/interfaces/kits/java/src/ohos/media/image/common/Filter.java new file mode 100644 index 0000000000000000000000000000000000000000..7b74cc0a4774774b8efbd72930bc92e22e36199b --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/Filter.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.media.image.ImageSource; +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.io.IOException; + +/** + * Abstract base class for image processing. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 4 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public abstract class Filter { + /** + * Clears all configurations that have not been applied to the source file. + * + * @return Returns this {@code Filter} object, which can be used for subsequent setting operations. + * @since 4 + */ + public abstract Filter restore(); + + /** + * Applies the configurations to the source file. + * + *

This method requires the permission to modify the source file represented by the {@code ImageSource} + * object. The configurations do not take effect until this method is called. + * + * @param source Indicates the image source file to which the configurations will be applied. + * @return Returns the size (in bytes) of the image file edited based on the configurations if the operation is + * successful; returns {@code -1} otherwise. + * @throws IOException Throws this exception if the modification permission has not been obtained. + * @since 4 + */ + public abstract long applyToSource(ImageSource source) throws IOException; +} + diff --git a/interfaces/kits/java/src/ohos/media/image/common/ImageFormat.java b/interfaces/kits/java/src/ohos/media/image/common/ImageFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..86472d1eb78f25f789556ccc74918037a97f4942 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/ImageFormat.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.util.HashMap; +import java.util.Map; + +/** + * Defines the image format and provides interfaces for obtaining image format information. + * + *

This class defines how image data is organized and represented, and provides interfaces for obtaining + * the number of image format components and bits per pixel adopted by a format. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public final class ImageFormat { + /** + * Indicates an unknown encoding format. + * + * @since 1 + */ + public static final int UNKNOWN = 0; + + /** + * Indicates the YUV420 format with NV21 encoding. + * + * @since 1 + */ + public static final int NV21 = 1; + + /** + * Indicates the generic YUV420 format with 8 bits per component (Y, U, and V). + * + * @since 1 + */ + public static final int YUV420_888 = 2; + + /** + * Indicates the JPEG encoding format. + * + * @since 1 + */ + public static final int JPEG = 3; + + /** + * Indicates the RAW10 format with 10 bits per component. + * + * @since 1 + */ + public static final int RAW10 = 4; + + /** + * Indicates the RAW10 format with 16 bits per component. + * + * @since 1 + */ + public static final int RAW16 = 5; + + /** + * Indicates the H264 encoding format. + * + * @since 5 + */ + public static final int H264 = 6; + + /** + * Indicates the H265 encoding format. + * + * @since 5 + */ + public static final int H265 = 7; + + /** + * Describes the component type of encoding formats. + * + *

This enum defines the meaning and form of the components, which represent the structure model of image data. + * + * @since 1 + */ + public enum ComponentType { + /** + * Indicates the Y component in the YUV format. + */ + YUV_Y(1), + + /** + * Indicates the U component in the YUV format. + */ + YUV_U(2), + + /** + * Indicates the V component in the YUV format. + */ + YUV_V(3), + + /** + * Indicates the JPEG format, which has no component. + */ + JPEG(4), + + /** + * Indicates the RAW10 format, which has no component. + */ + RAW10(5), + + /** + * Indicates the RAW16 format, which has no component. + */ + RAW16(6), + + /** + * Indicates the H264 format, which has no component. + */ + H264(7), + + /** + * Indicates the H265 format, which has no component. + */ + H265(8); + + private final int value; + + ComponentType(int value) { + this.value = value; + } + + /** + * Obtains a {@link ComponentType} enum name based on its enum value. + * + * @param value Indicates the enum value. + * @return Returns the enum name if any; returns {@code null} otherwise. + */ + public static ComponentType valueOf(int value) { + for (ComponentType componentType : values()) { + if (componentType.value == value) { + return componentType; + } + } + return null; + } + } + + // format mapping. + private static final Map FORMAT_MAPPING = new HashMap<>(); + + private static final int BITS_SHIFT = 8; + + private static final int SHIFT_MASK = 0xFF; + + // format pixel bits num + private static final int BITS_12 = 12; + + private static final int BITS_10 = 10; + + private static final int BITS_16 = 16; + + // format component num + private static final int COMPONENT_3 = 3; + + private static final int COMPONENT_2 = 2; + + private static final int COMPONENT_1 = 1; + + static { + FORMAT_MAPPING.put(NV21, BITS_12 << BITS_SHIFT | COMPONENT_3); + FORMAT_MAPPING.put(YUV420_888, BITS_12 << BITS_SHIFT | COMPONENT_3); + FORMAT_MAPPING.put(RAW10, BITS_10 << BITS_SHIFT | COMPONENT_1); + FORMAT_MAPPING.put(RAW16, BITS_16 << BITS_SHIFT | COMPONENT_1); + FORMAT_MAPPING.put(JPEG, COMPONENT_1); + FORMAT_MAPPING.put(H264, COMPONENT_1); + FORMAT_MAPPING.put(H265, COMPONENT_1); + } + + private ImageFormat() { + } + + /** + * Obtains the number of bits per pixel of the specified image format. + * + * @param format Indicates an image format. + * @return Returns the number of bits per pixel. + * @since 1 + */ + public static int getBitsNumberPerPixel(int format) { + return FORMAT_MAPPING.getOrDefault(format, 0) >> BITS_SHIFT & SHIFT_MASK; + } + + /** + * Obtains the number of components of a specified image format. + * + * @param format Indicates an image format. + * @return Returns the number of components. + * @since 1 + */ + public static int getComponentNumber(int format) { + return FORMAT_MAPPING.getOrDefault(format, 0) & SHIFT_MASK; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/ImageInfo.java b/interfaces/kits/java/src/ohos/media/image/common/ImageInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..3fb9f1d0f5f777c53a289303f16211df23a04bad --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/ImageInfo.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.util.Locale; + +/** + * Describes basic image information, including image dimensions, pixel formats, + * and color space. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class ImageInfo { + /** + * Indicates image dimensions specified by a {@link Size} object. + * + * @since 1 + */ + public Size size; + + /** + * Indicates a pixel format specified by a {@link PixelFormat} enum. + * + * @since 1 + */ + public PixelFormat pixelFormat; + + /** + * Indicates the color space specified by a {@link ColorSpace} enum. + * + * @since 1 + */ + public ColorSpace colorSpace; + + /** + * Indicates the alpha type specified by an {@link AlphaType} enum. + * + * @since 3 + */ + public AlphaType alphaType; + + /** + * Default constructor used to create a {@link ImageInfo} instance. + * + * @since 1 + */ + public ImageInfo() { + } + + /** + * ImageInfo as string. + * + * @since 5 + */ + @Override + public String toString() { + return ((size == null) ? "size:UNKNOWN" : size.toString()) + + ", pixelFormat:" + pixelFormat + + ", colorSpace:" + colorSpace + + ", alphaType:" + alphaType; + } + + /** + * Called by JNI + */ + private void setPixelFormat(int pixelFormat) { + for (PixelFormat item : PixelFormat.values()) { + if (item.getValue() == pixelFormat) { + this.pixelFormat = item; + break; + } + } + } + + /** + * Called by JNI + */ + private void setColorSpace(int colorSpace) { + for (ColorSpace item : ColorSpace.values()) { + if (item.getValue() == colorSpace) { + this.colorSpace = item; + break; + } + } + } + + /** + * Called by JNI + */ + private void setAlphaType(int alphaType) { + for (AlphaType item : AlphaType.values()) { + if (item.getValue() == alphaType) { + this.alphaType = item; + break; + } + } + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/MemoryUsagePreference.java b/interfaces/kits/java/src/ohos/media/image/common/MemoryUsagePreference.java new file mode 100644 index 0000000000000000000000000000000000000000..d8bc1c30008ab65509c5865259fee96e6ea90d61 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/MemoryUsagePreference.java @@ -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. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Enumerates memory use preferences for image decoding. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 4 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum MemoryUsagePreference { + /** + * Indicates the default preference, which preferentially uses the provided decoding parameters. + */ + DEFAULT(0), + + /** + * Indicates low memory usage, which saves memory by sacrificing the image quality. + * For example, an image format with an opaque alpha channel can be + * decoded to {@link ohos.media.image.common.PixelFormat#RGB_565}. + */ + LOW_RAM(1); + + private final int memoryUsagePreference; + + MemoryUsagePreference(int value) { + this.memoryUsagePreference = value; + } + + /** + * Obtains the value of this enum. + * + * @return Returns the enum value. + * @since 3 + */ + public int getValue() { + return memoryUsagePreference; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/PixelFormat.java b/interfaces/kits/java/src/ohos/media/image/common/PixelFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..93a42baabe9f932b583493737beede50e3fded10 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/PixelFormat.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Describes image pixel formats. + * + *

A pixel format of image data describes the components of a pixel and the layout of the components + * stored in memory. Common pixel formats include ARGB_8888 and RGBA_8888. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum PixelFormat { + /** + * Indicates an unknown format. + */ + UNKNOWN(0), + + /** + * Indicates that each pixel is stored on 32 bits. Components A, R, G, and B each occupies 8 bits + * and are stored from the higher-order to the lower-order bits. + */ + ARGB_8888(1), + + /** + * Indicates that each pixel is stored on 16 bits. Only the R, G, and B components are encoded + * from the higher-order to the lower-order bits: red is stored with 5 bits of precision, + * green is stored with 6 bits of precision, and blue is stored with 5 bits of precision. + */ + RGB_565(2), + + /** + * Indicates that each pixel is stored on 32 bits. Components R, G, B, and A each occupies 8 bits + * and are stored from the higher-order to the lower-order bits.\ + * + * @hide internal use + */ + RGBA_8888(3), + + /** + * Indicates that each pixel is stored on 32 bits. Components B, G, R, and A each occupies 8 bits + * and are stored from the higher-order to the lower-order bits. + * + * @hide internal use + */ + BGRA_8888(4), + + /** + * Indicates that each pixel is stored on 8 bit. + * Only A occupies 8 bits are stored. + * + * @hide internal use for now + * @since 5 + */ + ALPHA_8(6), + + /** + * Indicates that each pixel is stored on 32 bits. CMYK color format. + * CMYK format. + * + * @hide internal use for now + * @since 5 + */ + CMYK(10); + + + private final int pixelFormatValue; + + PixelFormat(int value) { + this.pixelFormatValue = value; + } + + /** + * Obtains an enum value. + * + * @return Returns the enum value. + * @since 1 + */ + public int getValue() { + return pixelFormatValue; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/Position.java b/interfaces/kits/java/src/ohos/media/image/common/Position.java new file mode 100644 index 0000000000000000000000000000000000000000..e41be716565268a069b52b55587e7fbe5f1578d0 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/Position.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.util.Objects; + +/** + * Describes location information of image pixels in a two-dimensional coordinate system. + * + *

The location information includes abscissa and ordinate values of pixels. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class Position { + /** + * Indicates the abscissa of a pixel in the coordinate system. + * + * @since 1 + */ + public int posX; + + /** + * Indicates the ordinate of a pixel in the coordinate system. + * + * @since 1 + */ + public int posY; + + /** + * A constructor used to create a {@link Position} instance. + * + *

Abscissa and ordinate values of the image pixel are set to 0. + * + * @since 1 + */ + public Position() { + } + + /** + * A constructor used to create a {@link Position} instance based on specified abscissa and ordinate values. + * + * @since 1 + */ + public Position(int px, int py) { + posX = px; + posY = py; + } + + /** + * Obtains the string representation of the {@link Position} object. + * + * @return Returns the string representation. + * @since 1 + */ + @Override + public String toString() { + return "Position{" + "posX=" + posX + ", posY=" + posY + '}'; + } + + /** + * Checks whether the {@link Position} object is the same as the one + * passed through the input parameter. + * + *

This method overrides the {@code equals} method. + * + * @param obj Indicates the {@link Position} object. + * @return Returns {@code true} if the {@link Position} objects are the same; + * returns {@code false} otherwise. + * @since 1 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + if (obj instanceof Position) { + Position position = (Position) obj; + return posX == position.posX && posY == position.posY; + } + return false; + } + + /** + * Generates a hash code value based on the {@link Position} object. + * + * @return Returns the hash code value. + * @since 1 + */ + @Override + public int hashCode() { + return Objects.hash(posX, posY); + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/PropertyKey.java b/interfaces/kits/java/src/ohos/media/image/common/PropertyKey.java new file mode 100644 index 0000000000000000000000000000000000000000..3026cf67312b1e13912a270c6a782d8b4e10853d --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/PropertyKey.java @@ -0,0 +1,1005 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Provides definitions of image property keys. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public final class PropertyKey { + private PropertyKey() { + } + + /** + * Provides definitions of image Exif property keys. + * + * @since 1 + */ + public static final class Exif { + /** + * Property value type is String. + * + * @since 1 + */ + public static final String ARTIST = "Artist"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String BITS_PER_SAMPLE = "BitsPerSample"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String COMPRESSION = "Compression"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String COPYRIGHT = "Copyright"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String DATETIME = "DateTime"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String IMAGE_DESCRIPTION = "ImageDescription"; + + /** + * Property value type is unsigned int. + * + * @since 1 + */ + public static final String IMAGE_LENGTH = "ImageLength"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String IMAGE_WIDTH = "ImageWidth"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String ORIENTATION = "Orientation"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String PLANAR_CONFIGURATION = "PlanarConfiguration"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String RESOLUTION_UNIT = "ResolutionUnit"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String ROWS_PER_STRIP = "RowsPerStrip"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SAMPLES_PER_PIXEL = "SamplesPerPixel"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String STRIP_BYTE_COUNTS = "StripByteCounts"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String STRIP_OFFSETS = "StripOffsets"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String TRANSFER_FUNCTION = "TransferFunction"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String Y_CB_CR_POSITIONING = "YCbCrPositioning"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String COLOR_SPACE = "ColorSpace"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String CONTRAST = "Contrast"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String CUSTOM_RENDERED = "CustomRendered"; + + /** + * Property value type is double not negative. + * + * @since 1 + */ + public static final String DIGITAL_ZOOM_RATIO = "DigitalZoomRatio"; + + /** + * Property value type is double. + * + * @since 1 + */ + public static final String EXPOSURE_BIAS_VALUE = "ExposureBiasValue"; + + /** + * Property value type is rational not negative. + * + * @since 1 + */ + public static final String EXPOSURE_INDEX = "ExposureIndex"; + + /** + * Property value type is unsigned short. + * + * @since 1 + */ + public static final String EXPOSURE_MODE = "ExposureMode"; + + /** + * Property value type is unsigned short. + * + * @since 1 + */ + public static final String EXPOSURE_PROGRAM = "ExposureProgram"; + + /** + * Property value type is double not negative. + * + * @since 1 + */ + public static final String EXPOSURE_TIME = "ExposureTime"; + + /** + * Property value type is double not negative. + * + * @since 1 + */ + public static final String F_NUMBER = "FNumber"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String FLASH = "Flash"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String GAIN_CONTROL = "GainControl"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String ISO_SPEED_RATINGS = "ISOSpeedRatings"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String METERING_MODE = "MeteringMode"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String NEW_SUBFILE_TYPE = "NewSubfileType"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String PIXEL_X_DIMENSION = "PixelXDimension"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String PIXEL_Y_DIMENSION = "PixelYDimension"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SATURATION = "Saturation"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SCENE_CAPTURE_TYPE = "SceneCaptureType"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SENSING_METHOD = "SensingMethod"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SHARPNESS = "Sharpness"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SUBFILE_TYPE = "SubfileType"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SUBJECT_AREA = "SubjectArea"; + + /** + * Property value type is double not negative. + * + * @since 1 + */ + public static final String SUBJECT_DISTANCE = "SubjectDistance"; + + /** + * Property value type is unsigned short. + * + * @since 1 + */ + public static final String SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String SUBJECT_LOCATION = "SubjectLocation"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String WHITE_BALANCE = "WhiteBalance"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String GPS_ALTITUDE_REF = "GPSAltitudeRef"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String GPS_DIFFERENTIAL = "GPSDifferential"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String DNG_VERSION = "DNGVersion"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String DEFAULT_CROP_SIZE = "DefaultCropSize"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String ORF_PREVIEW_IMAGE_START = "PreviewImageStart"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String ORF_ASPECT_FRAME = "AspectFrame"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String RW2_SENSOR_TOP_BORDER = "SensorTopBorder"; + + /** + * Property value type is int. + * + * @since 1 + */ + public static final String RW2_ISO = "ISO"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String PRIMARY_CHROMATICITIES = "PrimaryChromaticities"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String REFERENCE_BLACK_WHITE = "ReferenceBlackWhite"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String WHITE_POINT = "WhitePoint"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String X_RESOLUTION = "XResolution"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String Y_RESOLUTION = "YResolution"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String APERTURE_VALUE = "ApertureValue"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String BRIGHTNESS_VALUE = "BrightnessValue"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String FLASH_ENERGY = "FlashEnergy"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String FOCAL_LENGTH = "FocalLength"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String MAX_APERTURE_VALUE = "MaxApertureValue"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String SHUTTER_SPEED_VALUE = "ShutterSpeedValue"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_ALTITUDE = "GPSAltitude"; + + /** + * Property value type is rational, format is "num1/denom1,num2/denom2,num3/denom3". + * + * @since 1 + */ + public static final String GPS_LATITUDE = "GPSLatitude"; + + /** + * Property value type is rational, format is "num1/denom1,num2/denom2,num3/denom3". + * + * @since 1 + */ + public static final String GPS_LONGITUDE = "GPSLongitude"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_DEST_DISTANCE = "GPSDestDistance"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_DEST_LATITUDE = "GPSDestLatitude"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_DEST_LONGITUDE = "GPSDestLongitude"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_IMG_DIRECTION = "GPSImgDirection"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_SPEED = "GPSSpeed"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_TRACK = "GPSTrack"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_DOP = "GPSDOP"; + + /** + * Property value type is rational. + * + * @since 1 + */ + public static final String GPS_DEST_BEARING = "GPSDestBearing"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String MAKE = "Make"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String MODEL = "Model"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SOFTWARE = "Software"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String CFA_PATTERN = "CFAPattern"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String COMPONENTS_CONFIGURATION = "ComponentsConfiguration"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String DATETIME_DIGITIZED = "DateTimeDigitized"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String DATETIME_ORIGINAL = "DateTimeOriginal"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String EXIF_VERSION = "ExifVersion"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String FILE_SOURCE = "FileSource"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String FLASHPIX_VERSION = "FlashpixVersion"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String IMAGE_UNIQUE_ID = "ImageUniqueID"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String LIGHT_SOURCE = "LightSource"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String MAKER_NOTE = "MakerNote"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String OECF = "OECF"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String RELATED_SOUND_FILE = "RelatedSoundFile"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SCENE_TYPE = "SceneType"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SPECTRAL_SENSITIVITY = "SpectralSensitivity"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SUBSEC_TIME = "SubSecTime"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String USER_COMMENT = "UserComment"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_AREA_INFORMATION = "GPSAreaInformation"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_DATESTAMP = "GPSDateStamp"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_DEST_BEARING_REF = "GPSDestBearingRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_LATITUDE_REF = "GPSLatitudeRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_LONGITUDE_REF = "GPSLongitudeRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_MAP_DATUM = "GPSMapDatum"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_MEASURE_MODE = "GPSMeasureMode"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_PROCESSING_METHOD = "GPSProcessingMethod"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_SATELLITES = "GPSSatellites"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_SPEED_REF = "GPSSpeedRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_STATUS = "GPSStatus"; + + /** + * Property value type is String, format is "hh:mm:ss". + * + * @since 1 + */ + public static final String GPS_TIMESTAMP = "GPSTimeStamp"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_TRACK_REF = "GPSTrackRef"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String GPS_VERSION_ID = "GPSVersionID"; + + /** + * Property value type is String. + * + * @since 1 + */ + public static final String INTEROPERABILITY_INDEX = "InteroperabilityIndex"; + + /** + * Property value type is undefined. + * + * @since 1 + */ + public static final String ORF_THUMBNAIL_IMAGE = "ThumbnailImage"; + + /** + * PanasonicRaw tags. Property value type is undefined. + * + * @since 1 + */ + public static final String RW2_JPG_FROM_RAW = "JpgFromRaw"; + + /** + * Property value type is undefined. + * + * @since 1 + */ + public static final String XMP = "Xmp"; + } + + /** + * Provides definitions of GIF property keys. + * + * @since 4 + */ + public static final class GIF { + /** + * Property value type is Integer. + * + * @since 4 + */ + public static final String LOOP_COUNT = "GIFLoopCount"; + + /** + * Property value type is Integer. + * + * @since 4 + */ + public static final String DELAY_TIME = "GIFDelayTime"; + } + +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/Rect.java b/interfaces/kits/java/src/ohos/media/image/common/Rect.java new file mode 100644 index 0000000000000000000000000000000000000000..7e87127f827c4eab39ddb541593b36783e3ccd42 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/Rect.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.util.Objects; + +/** + * Describes rectangle areas of images. + * + *

A rectangle area is represented by the abscissa and ordinate of the upper-left point, width and height. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class Rect { + /** + * Indicates the minimum abscissa value of a rectangle, which is the abscissa of the upper left point. + * + * @since 1 + */ + public int minX; + + /** + * Indicates the minimum ordinate value of a rectangle, which is the ordinate of the upper left point. + * + * @since 1 + */ + public int minY; + + /** + * Indicates the width of a rectangle. + * + * @since 1 + */ + public int width; + + /** + * Indicates the height of a rectangle. + * + * @since 1 + */ + public int height; + + /** + * A constructor used to create a {@link Rect} instance, + * with the abscissa and coordinate of the upper-left point, width, and height set to {@code 0}. + * + * @since 1 + */ + public Rect() { + } + + /** + * A constructor used to create a {@link Rect} instance. + * + *

The abscissa and coordinate of the upper-left point, + * and the width and height of the rectangle are used as input parameters. + * + * @since 1 + */ + public Rect(int minX, int minY, int width, int height) { + this.minX = minX; + this.minY = minY; + this.width = width; + this.height = height; + } + + /** + * A constructor used to create a {@link Rect} instance with another one as the input parameter. + * + *

If the input parameter is null, this method creates an empty {@link Rect} object + * with the abscissa and coordinate of the upper-left point, width, and height set to {@code 0}. + * + * @since 1 + */ + public Rect(Rect rect) { + if (rect == null) { + minX = 0; + minY = 0; + width = 0; + height = 0; + } else { + minX = rect.minX; + minY = rect.minY; + width = rect.width; + height = rect.height; + } + } + + /** + * Obtains the string representation of the {@link Rect} object. + * + * @return Returns the string representation. + * @since 1 + */ + @Override + public String toString() { + return "Rect{" + "minX=" + minX + ", minY=" + minY + ", width=" + width + ", height=" + height + '}'; + } + + /** + * Checks whether the {@link Rect} object is the same as the one + * passed through the input parameter. + * + *

This method overrides the {@code equals} method. + * + * @param obj Indicates the {@link Rect} object. + * @return Returns {@code true} if the {@link Rect} objects are the same; + * returns {@code false} otherwise. + * @since 1 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + if (obj instanceof Rect) { + Rect rect = (Rect) obj; + return minX == rect.minX && minY == rect.minY && width == rect.width && height == rect.height; + } + return false; + } + + /** + * Generates a hash code value based on the {@link Rect} object. + * + * @return Returns the hash code value. + * @since 1 + */ + @Override + public int hashCode() { + return Objects.hash(minX, minY, width, height); + } + + /** + * Sets the abscissa, coordinate, width, and height to {@code 0}. + *

+ * Sets the abscissa and coordinate of the upper-left point, width, and height to {@code 0}. + * + * @since 1 + */ + public void setEmpty() { + minX = 0; + minY = 0; + width = 0; + height = 0; + } + + /** + * Crops a rectangle area. + * + *

The intersection area of the original rectangle and the input rectangle is cropped to + * adjust the original rectangle area. + * + * @param minX Indicates the upper-left point abscissa of the input rectangle. + * @param minY Indicates the upper-left point ordinate of the input rectangle. + * @param width Indicates the width of the input rectangle. + * @param height Indicates the height of the input rectangle. + * @return Returns {@code true} if the original rectangle area is cropped; returns {@code false} otherwise. + * @since 1 + */ + public boolean cropRect(int minX, int minY, int width, int height) { + if ((this.minX < minX + width) && (minX < this.minX + this.width) && (this.minY < minY + height) && (minY + < this.minY + this.height)) { + if (this.minX < minX + width) { + this.minX = minX; + } + if (this.minY < minY + height) { + this.minY = minY; + } + if ((this.minX + this.width) > (minX + width)) { + this.width = width; + } + if ((this.minY + this.height) > (minY + height)) { + this.height = height; + } + return true; + } + return false; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/ScaleMode.java b/interfaces/kits/java/src/ohos/media/image/common/ScaleMode.java new file mode 100644 index 0000000000000000000000000000000000000000..41737f847d47fdc488baec2aa60cdc0e455377c7 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/ScaleMode.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +/** + * Represents the image scaling effect. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 3 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public enum ScaleMode { + /** + * Indicates the effect that fits the image into the target size. + * + *

The image will be stretched when target aspect ratio differs from the original. + */ + FIT_TARGET_SIZE(0), + + /** + * Indicates the effect that scales an image to fill the target image area and center-crops + * the part outside the area. + * + *

The original image will be scaled up or down at the original aspect ratio to fill the + * target dimensions, and any additional height or width that does not fit will be cropped + * out from each side. For example to scale a 200 x 100 image to 500 x 300, the effect scales + * the image to 600 x 300, centers the image horizontally, and then crops out the extra 50 + * pixels of width from each side. + */ + CENTER_CROP(1); + + private final int modeValue; + + ScaleMode(int value) { + this.modeValue = value; + } + + /** + * Obtains the enum value of the image scaling effect. + * + * @return Returns the integer enum value. + * @since 3 + */ + public int getValue() { + return modeValue; + } +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/Size.java b/interfaces/kits/java/src/ohos/media/image/common/Size.java new file mode 100644 index 0000000000000000000000000000000000000000..95b47a9f1236841b2cfeee8667012e624f5a2601 --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/Size.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import ohos.utils.system.SystemCap; +import ohos.utils.system.SystemCapability; + +import java.util.Objects; + +/** + * Provides image size information, includes the width and height. + * + * @Syscap {@link SystemCapability.Multimedia#IMAGE} + * @since 1 + */ +@SystemCap("SystemCapability.Multimedia.Image") +public class Size { + /** + * Indicates the image width. + * + * @since 1 + */ + public int width; + + /** + * Indicates the image height. + * + * @since 1 + */ + public int height; + + /** + * A constructor used to create a {@link Size} instance. + * + *

The width and height of an image are set to 0. + * + * @since 1 + */ + public Size() { + } + + /** + * A constructor used to create a {@link Size} instance based on a specified width and height. + * + * @param width Indicates the image width. + * @param height Indicates the image height. + * @since 1 + */ + public Size(int width, int height) { + this.width = width; + this.height = height; + } + + /** + * Checks whether the {@link Size} object is the same as the one + * passed through the input parameter. + * + *

This method overrides the {@code equals} method. + * + * @param obj Indicates the {@link Size} object. + * @return Returns {@code true} if the {@link Size} objects are the same; + * returns {@code false} otherwise. + * @since 1 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + if (obj instanceof Size) { + Size size = (Size) obj; + return width == size.width && height == size.height; + } + return false; + } + + /** + * Generates a hash code value based on the {@link Size} object. + * + * @return Returns the hash code value. + * @since 1 + */ + @Override + public int hashCode() { + return Objects.hash(width, height); + } + + /** + * Obtains the string representation of the {@link Size} object. + * + * @return Returns the string representation. + * @since 1 + */ + @Override + public String toString() { + return "Size{" + "width=" + width + ", height=" + height + '}'; + } + +} diff --git a/interfaces/kits/java/src/ohos/media/image/common/package-info.java b/interfaces/kits/java/src/ohos/media/image/common/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..e1d2d179e030f9273af2360ce6f42d9e8214face --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/common/package-info.java @@ -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. + */ + +/** + * Provides definitions of common classes that image-related functions may be dependent on. + * + * @since 1 + */ +package ohos.media.image.common; \ No newline at end of file diff --git a/interfaces/kits/java/src/ohos/media/image/package-info.java b/interfaces/kits/java/src/ohos/media/image/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..fc03c330a1f1fc1d43a383eb24e1f5a7bda9b1fe --- /dev/null +++ b/interfaces/kits/java/src/ohos/media/image/package-info.java @@ -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. + */ + +/** + * Provides APIs of image-related functions, including encoding and decoding, image processing, and image receiving. + * + * @since 1 + */ +package ohos.media.image; \ No newline at end of file diff --git a/interfaces/kits/java/test/BUILD.gn b/interfaces/kits/java/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5557e37dcdf97077aab964f29cd8f44ea456d43b --- /dev/null +++ b/interfaces/kits/java/test/BUILD.gn @@ -0,0 +1,116 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "multimedia_image/image" + +ohos_java_unittest("test_imagecodec_java_maple") { + sub_output_dir = "$module_output_path/" + + java_files = [ + "unittest/src/ohos/media/image/common/PositionTest.java", + "unittest/src/ohos/media/image/common/RectTest.java", + "unittest/src/ohos/media/image/common/SizeTest.java", + "unittest/src/ohos/media/image/PropertyFilterTest.java", + "unittest/src/ohos/media/image/ImagePackerTest.java", + "unittest/src/ohos/media/image/ImagePixelMapKitTest.java", + "unittest/src/ohos/media/image/ImageSourceKitTest.java", + "unittest/src/ohos/media/image/PixelMapNdkTest.java", + ] + + classpath_deps = [ "//foundation/multimedia/image/adapter/frameworks/exif:image_exifadapter_java" ] + + deps = [ + "//foundation/multimedia/image/interfaces/kits/java:image_maple_java", + "//foundation/multimedia/image/interfaces/kits/native/ndk_test_example:image_ndk_test_jni", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + "//utils/java:utils_java", + "//utils/java:utils_maple_java", + ] + + external_deps = [ + "hilog:hilog_maple_java", + "ipc:ipc_java", + "resmgr:kits_java", + "startup:syspara_java", + "utils:utils_maple_java", + ] + + resource_config_file = + "//foundation/multimedia/image/test/resource/image/ohos_test.xml" +} + +ohos_java_unittest("test_imagereceiver_java_maple") { + sub_output_dir = "$module_output_path/" + + java_files = [ + "unittest/src/ohos/media/image/common/ImageFormatTest.java", + "unittest/src/ohos/media/image/ImageTest.java", + "unittest/src/ohos/media/image/ImageReceiverTest.java", + ] + + deps = [ + "//foundation/multimedia/image/interfaces/kits/java:image_receiver_maple_java", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + ] + + external_deps = [ + "appexecfwk:eventhandler_java_maple", + "graphic:agp_maple_java", + "hilog:hilog_maple_java", + "utils:utils_maple_java", + ] + + resource_config_file = + "//foundation/multimedia/image/test/resource/image/ohos_test.xml" +} + +group("unittest") { + testonly = true + deps = [ + ":test_imagecodec_java_maple", + ":test_imagereceiver_java_maple", + ] +} + +ohos_java_performancetest("image_performance_test_java_maple") { + java_files = [ + "performancetest/src/ohos/media/image/ImagePerformanceTest.java", + "//foundation/multimedia/utils/java/test/unittest/src/ohos/media/utils/PerformanceUtil.java", + "//foundation/multimedia/utils/java/test/unittest/src/ohos/media/utils/PrivateMemberAccess.java", + ] + + deps = [ + "//foundation/multimedia/image/interfaces/kits/java:image_maple_java", + "//foundation/multimedia/utils/java:multimedia_utils_maple_java", + "//test/developertest/libs/jtr/common/java:perf_test_framework_java", + ] + + external_deps = [ + "appexecfwk:appexecfwk_java_maple", + "appexecfwk:eventhandler_java_maple", + "hilog:hilog_maple_java", + "startup:syspara_java", + "utils:utils_maple_java", + ] + + sub_output_dir = "$module_output_path/" + resource_config_file = + "//foundation/multimedia/image/test/resource/image/ohos_test.xml" +} + +group("performance") { + testonly = true + deps = [ ":image_performance_test_java_maple" ] +} diff --git a/interfaces/kits/java/test/performancetest/src/ohos/media/image/ImagePerformanceTest.java b/interfaces/kits/java/test/performancetest/src/ohos/media/image/ImagePerformanceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c202ec0aea332fc7576aa4192c971e376c403870 --- /dev/null +++ b/interfaces/kits/java/test/performancetest/src/ohos/media/image/ImagePerformanceTest.java @@ -0,0 +1,861 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import ohos.app.Context; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; +import ohos.media.image.common.DecodeEvent; +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.ImageInfo; +import ohos.media.image.common.MemoryUsagePreference; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.PropertyKey; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.media.utils.PerformanceUtil; +import ohos.media.utils.PrivateMemberAccess; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; +import ohos.unittest.perf.BaseLine; +import ohos.unittest.perf.PerfVerify; +import ohos.unittest.TestTarget; + +import org.easymock.EasyMockSupport; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.Ignore; + +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.IntBuffer; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +/** + * The performance test for Image + * + * @since 3 + */ +public class ImagePerformanceTest extends EasyMockSupport { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImagePerformanceTest.class); + + private static final String PNG_SRC_FILE_PATH = "/data/test/test.png"; + + private static final String PNG_NINE_PATCH_SRC_FILE_PATH = "/data/test/test.9.png"; + + private static final String JPG_PACKED_FILE_PATH = "/data/test/test_packer.jpg"; + + private static final String JPG_SRC_FILE_PATH = "/data/test/test.jpg"; + + private static final String JPG_THUMBNAIL_SRC_FILE_PATH = "/data/test/test_exif.jpg"; + + private static final String DNG_SRC_FILE_PATH = "/data/test/test.dng"; + + private static final String COLORS_DATA = "/data/test/colors.txt"; + + private static final String TAG = "ImagePerformanceTest"; + + private static final int REPEAT_TIMES = 1000; + + private static final int TEST_NUM_FOR_SIMPLE_CASE = 1000; + + private static final int TEST_NUM_FOR_COMPLICATED_CASE = 10; + + private static final int COOL_DOWN_TIME_CASE = 1000; + + private static String BASE_LINE_XML_NAME = "ImagePerformanceTest_baseline.xml"; + + private static BaseLine baseLine; + + private Context mockContext; + + private DecodeEvent partialImageListenerTest; + + /** + * Init baseline + */ + @BeforeClass + public static void beforeClass() { + String baseLineConfigFile = "/data/test/" + BASE_LINE_XML_NAME; + baseLine = new BaseLine(baseLineConfigFile); + } + + /** + * Clear baseline + */ + @AfterClass + public static void afterClass() { + BASE_LINE_XML_NAME = null; + baseLine = null; + } + + /** + * Set up for each case + * + * @throws Exception Any exception + */ + @Before + public void setUp() throws Exception { + mockContext = mock(Context.class); + } + + /** + * Tear down for each case + * + * @throws Exception Any exception + */ + @After + public void tearDown() throws Exception { + mockContext = null; + } + + private void coolDown4Case() { + coolDown(COOL_DOWN_TIME_CASE); + } + + private void coolDown(int time) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + LOGGER.warn("coolDown exception", e); + } + } + + + private PixelMap createSrcPixelMap(int[] myColors) { + LOGGER.debug("myColors length: %{public}d", myColors.length); + PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions(); + initializationOptions.size = new Size(300, 300); + initializationOptions.pixelFormat = PixelFormat.RGBA_8888; + PixelMap pixelMap = PixelMap.create(myColors, initializationOptions); + assertNotNull(pixelMap); + return pixelMap; + } + + private int[] constructColors() { + File file = new File(COLORS_DATA); + assertNotNull(file); + try (BufferedReader br = new BufferedReader(new FileReader(COLORS_DATA))) { + List lists = new ArrayList<>(); + String line; + while ((line = br.readLine()) != null) { + String[] strArray = line.trim().split(","); + for (String item : strArray) { + lists.add(Integer.parseInt(item.trim())); + } + } + return lists.stream().mapToInt(Integer::valueOf).toArray(); + } catch (IOException e) { + LOGGER.error("construct data error. " + e.getMessage()); + } + return new int[0]; + } + + private void recordAndReset(List timeList, List cacheList, String label) { + Objects.requireNonNull(timeList); + Objects.requireNonNull(cacheList); + long middleTime = timeList.stream().sorted().collect(Collectors.toList()).get(timeList.size() / 2); + LOGGER.warn(label + "===>" + middleTime); + timeList.clear(); + cacheList.stream().forEach(obj -> { + if (obj instanceof PixelMap) { + ((PixelMap) obj).release(); + } + }); + cacheList.clear(); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + LOGGER.warn("resetAndSleeping occurs Exception"); + } + } + + private void recordAndResetOnlyTime(List timeList, String label) { + Objects.requireNonNull(timeList); + long middleTime = timeList.stream().sorted().collect(Collectors.toList()).get(timeList.size() / 2); + LOGGER.warn(label + "===>" + middleTime); + timeList.clear(); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + LOGGER.warn("recordAndResetOnlyTime occurs Exception"); + } + } + + private static PixelMap createTestPixelMap(String filePath) { + if (filePath == null) { + LOGGER.error("test pixelmap to check filePath fail."); + return null; + } + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = ""; + ImageSource imageSource = ImageSource.create(filePath, srcOpts); + if (imageSource == null) { + LOGGER.error("test pixelmap to create the imageSource fail."); + return null; + } + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + return imageSource.createPixelmap(decodingOpts); + } + + /** + * Perf test for getInnerJpegThumbnail. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", methodName = "public byte[] getInnerJpegThumbnail()") + public void testImageSource_getInnerJpegThumbnail_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + + String imagePath = JPG_THUMBNAIL_SRC_FILE_PATH; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(imagePath, srcOpts); + imageSource.getInnerThumbnailScope(); + long startTime = System.nanoTime(); + byte[] bytes = imageSource.getInnerJpegThumbnail(); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + if (bytes == null) { + fail("no thumbnail exits"); + } + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.averageDoubleUsec(times), 1); + } + + /** + * Perf test for getInnerThumbnailScope. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", methodName = "public long[] getInnerThumbnailScope()") + public void testImageSource_getInnerThumbnailScope_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + + String imagePath = JPG_THUMBNAIL_SRC_FILE_PATH; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(imagePath, srcOpts); + imageSource.getThumbnailFormat(); + long startTime = System.nanoTime(); + long[] scope = imageSource.getInnerThumbnailScope(); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + if (scope == null) { + fail("no thumbnail exits"); + } + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.averageDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", + methodName = "public static ImageSource create(String, ImageSource.SourceOptions)") + public void testImageSource_create_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + long startTime = System.nanoTime(); + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", + methodName = "public PixelMap createPixelmap(ImageSource.DecodingOptions)") + public void testImageSource_createPixelmap_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + long startTime = System.nanoTime(); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + imageSource.release(); + pixelMap.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", + methodName = "public static ImageSource create(ByteBuffer, ImageSource.SourceOptions)") + public void testImageSource_create_002() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + String pathName = JPG_SRC_FILE_PATH; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate((int) channel.size()); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + long startTime = System.nanoTime(); + ImageSource imageSource = ImageSource.create(byteBuffer, null); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + assertNotNull(imageSource); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", + methodName = "public static ImageSource create(File, ImageSource.SourceOptions)") + public void testImageSource_create_003() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + String pathName = JPG_SRC_FILE_PATH; + File file = new File(pathName); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + long startTime = System.nanoTime(); + // need test this function + ImageSource imageSource = ImageSource.create(file, srcOpts); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + assertNotNull(imageSource); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", + methodName = "public void setMemoryUsagePreference(MemoryUsagePreference)") + public void testImageSource_setMemoryUsagePreference_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + + long startTime = System.nanoTime(); + imageSource.setMemoryUsagePreference(MemoryUsagePreference.LOW_RAM); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + imageSource.release(); + pixelMap.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @Ignore + public void testImageSource_createPixelmap_002() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + imageSource.setMemoryUsagePreference(MemoryUsagePreference.LOW_RAM); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + + long startTime = System.nanoTime(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + imageSource.release(); + pixelMap.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + /** + * calculate dng file decode time. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @Ignore + public void testImageSource_createPixelmap_003() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES / 100; index++) { + ImageSource imageSource = ImageSource.create(DNG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + long startTime = System.nanoTime(); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + imageSource.release(); + pixelMap.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + class PartialImageListenerTest implements ImageSource.DecodeEventListener { + @Override + public void onDecodeEvent(ImageSource source, DecodeEvent event) { + partialImageListenerTest = event; + LOGGER.debug("event " + event.getValue()); + } + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.ImageSource", + methodName = "public void setDecodeEventListener(ImageSource.DecodeEventListener)") + public void testImageSource_setOnDecodeEventListener_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + ImageSource.DecodeEventListener testListener = new PartialImageListenerTest(); + + long startTime = System.nanoTime(); + imageSource.setDecodeEventListener(testListener); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + imageSource.release(); + pixelMap.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PropertyFilter", + methodName = "public long applyToSource(ImageSource)") + public void testPropertyFilter_applyToSource_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + String newArtist = "testImagePropertyFilterTest001_" + String.valueOf(System.currentTimeMillis()); + long ret = -100; + PropertyFilter mPropertyFilter = new PropertyFilter(); + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist); + long startTime = System.nanoTime(); + try { + ret = mPropertyFilter.applyToSource(imageSource); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + assertEquals(newArtist, imageSource.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertTrue(ret > 0); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PropertyFilter", + methodName = "public PropertyFilter setPropertyDouble(String, double)") + public void testPropertyFilter_setPropertyDouble_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + String oldLocation = imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + int newLocation = (int)(System.currentTimeMillis()/1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + PropertyFilter mPropertyFilter = new PropertyFilter(); + + long startTime = System.nanoTime(); + mPropertyFilter.setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + try { + ret = mPropertyFilter.applyToSource(imageSource); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + assertEquals(String.valueOf(newExposure), + imageSource.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertTrue(ret > 0); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PropertyFilter", + methodName = "public PropertyFilter setPropertyInt(String, int)") + public void testPropertyFilter_setPropertyInt_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + String oldLocation = imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + int newLocation = (int)(System.currentTimeMillis()/1.0E8); + long ret = -100; + PropertyFilter mPropertyFilter = new PropertyFilter(); + + long startTime = System.nanoTime(); + mPropertyFilter.setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + try { + ret = mPropertyFilter.applyToSource(imageSource); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + assertEquals(String.valueOf(newLocation), + imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertTrue(ret > 0); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PropertyFilter", + methodName = "public PropertyFilter setPropertyString(String, String)") + public void testPropertyFilter_setPropertyString_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + String oldArtist = imageSource.getImagePropertyString(PropertyKey.Exif.ARTIST); + String newArtist = "testPropertyFilter_setPropertyString_001" + String.valueOf(System.currentTimeMillis()); + long ret = -100; + PropertyFilter mPropertyFilter = new PropertyFilter(); + + long startTime = System.nanoTime(); + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + try { + ret = mPropertyFilter.applyToSource(imageSource); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + assertEquals(newArtist, imageSource.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertTrue(ret > 0); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PropertyFilter", + methodName = "public PropertyFilter rollbackProperty(String)") + public void testPropertyFilter_rollbackProperty_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + String oldLocation = imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + long ret = -100; + PropertyFilter mPropertyFilter = new PropertyFilter(); + + long startTime = System.nanoTime(); + mPropertyFilter.rollbackProperty(PropertyKey.Exif.SUBJECT_LOCATION); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + try { + ret = mPropertyFilter.applyToSource(imageSource); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + assertEquals(String.valueOf(oldLocation), + String.valueOf(imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION))); + assertTrue(ret > 0); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PropertyFilter", + methodName = "public PropertyFilter restore()") + public void testPropertyFilter_restore_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource imageSource = ImageSource.create(JPG_SRC_FILE_PATH, null); + assertNotNull(imageSource); + String oldArtist = imageSource.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = imageSource.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + String newArtist = "testsetPropertyFilter002_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis()/1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + PropertyFilter mPropertyFilter = new PropertyFilter(); + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure); + + long startTime = System.nanoTime(); + mPropertyFilter.restore(); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + try { + ret = mPropertyFilter.applyToSource(imageSource); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + assertEquals(oldArtist, imageSource.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + String.valueOf(imageSource.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION))); + assertEquals(String.valueOf(oldExposure), + String.valueOf(imageSource.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME))); + assertTrue(ret > 0); + imageSource.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PixelMap", + methodName = "public PixelMap createFromAlpha()") + public void testPixelMap_createFromAlpha_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = PNG_NINE_PATCH_SRC_FILE_PATH; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + long startTime = System.nanoTime(); + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + assertNotNull(alphaPixelMap); + imageSource.release(); + pixelMapSrc.release(); + alphaPixelMap.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.PixelMap", + methodName = "public boolean isReleased()") + public void testPixelMap_isReleased_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = PNG_NINE_PATCH_SRC_FILE_PATH; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + long startTime = System.nanoTime(); + boolean isReleased = pixelMapSrc.isReleased(); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + assertFalse(isReleased); + imageSource.release(); + pixelMapSrc.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.common.ImageInfo", + methodName = "public String toString()") + public void testImageInfo_toString_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = PNG_NINE_PATCH_SRC_FILE_PATH; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + ImageInfo info = pixelMapSrc.getImageInfo(); + + long startTime = System.nanoTime(); + info.toString(); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + imageSource.release(); + pixelMapSrc.release(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.PERF) + @TestTarget(className = "ohos.media.image.common.DecodeEvent", + methodName = "public static DecodeEvent getDecodeEvent(int)") + public void testDecodeEvent_getDecodeEvent_001() { + PerfVerify verify = new PerfVerify(baseLine); + List times = new ArrayList<>(); + for (int index = 0; index < REPEAT_TIMES; index++) { + int max = DecodeEvent.EVENT_LAST.getValue(); + int min = DecodeEvent.EVENT_COMPLETE_DECODE.getValue(); + Random random = new Random(); + int event = random.nextInt(max) % (max - min + 1) + min; + + long startTime = System.nanoTime(); + DecodeEvent decodeEvent = DecodeEvent.getDecodeEvent(event); + long endTime = System.nanoTime(); + times.add(endTime - startTime); + + decodeEvent.getValue(); + } + verify.expectSmaller(PerformanceUtil.middleDoubleUsec(times), 1); + } + +} diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/ImagePackerTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImagePackerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6a386c27f223ea9917cff7fbf917fc1ce11eb505 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImagePackerTest.java @@ -0,0 +1,871 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashSet; + +/** + * ImagePackerTest, test cases for ImagePacker class, mainly including test cases for image encoding functions + * + * @since 1 + */ +public class ImagePackerTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImagePackerTest.class); + + private static final String PNG_SRC_FILE_PATH = "/sdcard/multimedia/image/test.png"; + + private static final String JPG_PACKED_FILE_PATH = "/sdcard/multimedia/image/test_packer.jpg"; + + private static File pngFile; + + /** + * Action before all test case. + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + pngFile = new File(PNG_SRC_FILE_PATH); + if (!pngFile.exists()) { + LOGGER.error("test file not exist."); + fail("files not exist"); + } + } + + /** + * Action after all test case. + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + /** + * Action before test case. + */ + @Before + public void setUp() throws Exception { + File file = new File(JPG_PACKED_FILE_PATH); + if (file.exists()) { + file.delete(); + } + } + + /** + * Action after test case. + */ + @After + public void tearDown() throws Exception { + } + + /** + * @tc.name: testImagePacker001 + * @tc.desc: get supported image formats. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker001() { + /** + * @tc.steps: step1.get supported image formats. + * @tc.expected: step1.supported image formats not null + */ + HashSet formats = ImagePacker.getSupportedFormats(); + assertNotNull(formats); + + /** + * @tc.steps: step2.check supported image formats. + * @tc.expected: step2.supported image formats checked ok + */ + assertTrue(formats.contains("image/jpeg")); + } + + /** + * @tc.name: testImagePacker002 + * @tc.desc: create ImagePacker instance + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker002() { + /** + * @tc.steps: step1.create image packer instance. + * @tc.expected: step1.check the image packer valid. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + imagePacker.release(); + } + + /** + * @tc.name: testImagePacker003 + * @tc.desc: initialize packing settings + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker003() { + /** + * @tc.steps: step1.create image packer instance. + * @tc.expected: step1.check the image packer valid. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init image packer with byte array and option. + * @tc.expected: step2.check init image packer success. + */ + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + byte[] data = new byte[10]; + boolean succeeded = imagePacker.initializePacking(data, packingOptions); + assertTrue(succeeded); + + /** + * @tc.steps: step3.init image packer with byte array、offset and option. + * @tc.expected: step3.check init image packer success. + */ + int offset = 3; + succeeded = imagePacker.initializePacking(data, offset, packingOptions); + assertTrue(succeeded); + imagePacker.release(); + } + + /** + * @tc.name: testImagePacker004 + * @tc.desc: initialize packing settings with wrong parameters + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker004() { + /** + * @tc.steps: step1.create image packer instance. + * @tc.expected: step1.check the image packer valid. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init image packer with byte array and option. + * @tc.expected: step2.check init image packer success. + */ + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + byte[] data = new byte[10]; + boolean succeed = imagePacker.initializePacking(data, null); + assertTrue(succeed); + imagePacker.release(); + } + + /** + * @tc.name: testImagePacker005 + * @tc.desc: test add pixelMap to image packer + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker005() { + /** + * @tc.steps: step1.create image packer instance. + * @tc.expected: step1.check the image packer valid. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + byte[] data = new byte[10]; + boolean succeeded = imagePacker.initializePacking(data, packingOptions); + assertTrue(succeeded); + + /** + * @tc.steps: step2.add image source with default. + * @tc.expected: step2.check add image. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + succeeded = imagePacker.addImage(imageSource); + assertTrue(succeeded); + imagePacker.release(); + + /** + * @tc.steps: step3.add image source with index. + * @tc.expected: step3.check add image. + */ + ImagePacker imagePacker1 = ImagePacker.create(); + assertNotNull(imagePacker1); + succeeded = imagePacker1.initializePacking(data, packingOptions); + assertTrue(succeeded); + succeeded = imagePacker1.addImage(imageSource, 0); + assertTrue(succeeded); + imagePacker1.release(); + + /** + * @tc.steps: step4.add image source with index. + * @tc.expected: step4.check add image. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + ImagePacker imagePacker2 = ImagePacker.create(); + assertNotNull(imagePacker2); + succeeded = imagePacker2.initializePacking(data, packingOptions); + assertTrue(succeeded); + succeeded = imagePacker2.addImage(pixelMap); + assertTrue(succeeded); + imagePacker2.release(); + pixelMap.release(); + imageSource.release(); + } + + /** + * @tc.name: testImagePacker006 + * @tc.desc: test add pixelMap to image packer failed + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker006() { + /** + * @tc.steps: step1.create image packer instance. + * @tc.expected: step1.check the image packer valid. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + byte[] data = new byte[10]; + boolean succeeded = imagePacker.initializePacking(data, packingOptions); + assertTrue(succeeded); + + /** + * @tc.steps: step2.add image source with more than one time. + * @tc.expected: step2.check add image. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + imagePacker.addImage(imageSource); + succeeded = imagePacker.addImage(imageSource); + assertFalse(succeeded); + boolean failed = imagePacker.addImage(imageSource); + assertFalse(failed); + failed = imagePacker.addImage(imageSource, 0); + assertFalse(failed); + + /** + * @tc.steps: step3.add image source with wrong index. + * @tc.expected: step3.check add image. + */ + failed = imagePacker.addImage(imageSource, 10); + assertFalse(failed); + + /** + * @tc.steps: step4.add image source with index. + * @tc.expected: step4.check add image. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + failed = imagePacker.addImage(pixelMap); + assertFalse(failed); + imagePacker.release(); + imageSource.release(); + pixelMap.release(); + } + + /** + * @tc.name: testImagePacker007 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker007() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with not enough data. + * @tc.expected: step2.get image packer not null + */ + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 100; + byte[] data = new byte[1024]; + boolean result = imagePacker.initializePacking(data, 100, packingOptions); + assertTrue(result); + + /** + * @tc.steps: step3.check packed image. + * @tc.expected: step3.image info checked ok + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + result = imagePacker.addImage(imageSource); + assertTrue(result); + long dataSize = imagePacker.finalizePacking(); + assertEquals(dataSize, -1L); + imagePacker.release(); + imageSource.release(); + } + + /** + * @tc.name: testImagePacker008 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker008() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with enough data. + * @tc.expected: step2.get image packer not null + */ + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 100; + byte[] data = new byte[409600]; + boolean result = imagePacker.initializePacking(data, packingOptions); + assertTrue(result); + + /** + * @tc.steps: step3.check packed image. + * @tc.expected: step3.image info checked ok + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + result = imagePacker.addImage(imageSource); + assertTrue(result); + long dataSize = imagePacker.finalizePacking(); + assertNotEquals(dataSize, -1L); + imagePacker.release(); + + /** + * @tc.steps: step3.check packed image data. + * @tc.expected: step3.image info checked ok + */ + ImageSource packedSource = ImageSource.create(data, srcOpts); + checkPackImageValid(imageSource, packedSource); + imageSource.release(); + packedSource.release(); + } + + private void checkPackImageValid(ImageSource source, ImageSource packed) { + assertNotNull(source); + assertNotNull(packed); + // source + assertEquals(472, source.getImageInfo().size.width); + assertEquals(75, source.getImageInfo().size.height); + // packed + assertEquals(472, packed.getImageInfo().size.width); + assertEquals(75, packed.getImageInfo().size.height); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(472, 75); + PixelMap packedPixelMap = packed.createPixelmap(decodingOpts); + assertNotNull(packedPixelMap); + assertEquals(472, packedPixelMap.getImageInfo().size.width); + assertEquals(75, packedPixelMap.getImageInfo().size.height); + packedPixelMap.release(); + } + + /** + * @tc.name: testImagePacker009 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker009() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + imagePacker.release(); + + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 100; + + /** + * @tc.steps: step2.init with byte array use release imagePacker. + * @tc.expected: step2.packer the image + */ + byte[] data = new byte[10]; + boolean result = imagePacker.initializePacking(data, packingOptions); + assertFalse(result); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + result = imagePacker.addImage(pixelMap); + assertFalse(result); + long dataSize = imagePacker.finalizePacking(); + assertEquals(dataSize, -1L); + imagePacker.release(); + pixelMap.release(); + } + + /** + * @tc.name: testImagePacker0010 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker010() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 20; + + /** + * @tc.steps: step2.init with file. + * @tc.expected: step2.packer the image + */ + try (OutputStream outputStream = new FileOutputStream(JPG_PACKED_FILE_PATH);) { + boolean result = imagePacker.initializePacking(outputStream, packingOptions); + assertTrue(result); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + result = imagePacker.addImage(imageSource); + assertTrue(result); + long dataSize = imagePacker.finalizePacking(); + assertNotEquals(dataSize, -1L); + + /** + * @tc.steps: step3.check packed image data. + * @tc.expected: step3.image info checked ok + */ + ImageSource packedSource = ImageSource.create(JPG_PACKED_FILE_PATH, srcOpts); + checkPackImageValid(imageSource, packedSource); + imageSource.release(); + packedSource.release(); + } catch (FileNotFoundException e) { + LOGGER.error("ImagePacker, file not found"); + } catch (IOException fio) { + LOGGER.error("ImagePacker, IO Exception"); + } + imagePacker.release(); + } + + /** + * @tc.name: testImagePacker011 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker011() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 80; + + /** + * @tc.steps: step2.init with file. + * @tc.expected: step2.get image packer not null + */ + try (FileOutputStream outputStream = new FileOutputStream(JPG_PACKED_FILE_PATH)) { + boolean result = imagePacker.initializePacking(outputStream, packingOptions); + assertTrue(result); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + result = imagePacker.addImage(imageSource, 0); + assertTrue(result); + long dataSize = imagePacker.finalizePacking(); + assertNotEquals(dataSize, -1L); + + /** + * @tc.steps: step3.check packed image data. + * @tc.expected: step3.image info checked ok + */ + ImageSource packedSource = ImageSource.create(JPG_PACKED_FILE_PATH, srcOpts); + checkPackImageValid(imageSource, packedSource); + imageSource.release(); + packedSource.release(); + } catch (FileNotFoundException e) { + LOGGER.error("ImagePacker, file not found"); + } catch (IOException fio) { + LOGGER.error("ImagePacker, IO Exception"); + } + imagePacker.release(); + } + + /** + * @tc.name: testImagePacker012 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker012() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 0; + + /** + * @tc.steps: step2.init with file. + * @tc.expected: step2.get image packer not null + */ + try (FileOutputStream outputStream = new FileOutputStream(JPG_PACKED_FILE_PATH);) { + boolean result = imagePacker.initializePacking(outputStream, packingOptions); + assertTrue(result); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + result = imagePacker.addImage(imageSource); + assertTrue(result); + long dataSize = imagePacker.finalizePacking(); + assertNotEquals(dataSize, -1L); + /** + * @tc.steps: step3.check packed image data. + * @tc.expected: step3.image info checked ok + */ + ImageSource packedSource = ImageSource.create(JPG_PACKED_FILE_PATH, srcOpts); + checkPackImageValid(imageSource, packedSource); + imageSource.release(); + packedSource.release(); + } catch (FileNotFoundException e) { + LOGGER.error("ImagePacker, file not found"); + } catch (IOException fio) { + LOGGER.error("ImagePacker, IO Exception"); + } + imagePacker.release(); + } + + /** + * @tc.name: testImagePacker013 + * @tc.desc: encode image to file with specified object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker013() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with enough data. + * @tc.expected: step2.get image packer not null + */ + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 100; + byte[] data = new byte[409600]; + boolean result = imagePacker.initializePacking(data, 409600 - 1, packingOptions); + assertTrue(result); + + /** + * @tc.steps: step3.check packed image. + * @tc.expected: step3.image info checked ok + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, srcOpts); + result = imagePacker.addImage(imageSource); + assertTrue(result); + long dataSize = imagePacker.finalizePacking(); + assertEquals(dataSize, -1L); + imagePacker.release(); + imageSource.release(); + } + + /** + * @tc.name: testImagePacker014 + * @tc.desc: encode image to null byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker014() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with null byte array. + * @tc.expected: step2.throw IllegalArgumentException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = null; + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imagePacker.initializePacking(data, packingOptions); + }); + } + + /** + * @tc.name: testImagePacker015 + * @tc.desc: encode image to null byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker015() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with null byte array. + * @tc.expected: step2.throw IllegalArgumentException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = null; + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imagePacker.initializePacking(data, 0, packingOptions); + }); + } + + /** + * @tc.name: testImagePacker016 + * @tc.desc: encode image to byte array with negative offset. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker016() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with byte array by negative offset. + * @tc.expected: step2.throw IndexOutOfBoundsException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = new byte[1024]; + + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imagePacker.initializePacking(data, -1, packingOptions); + }); + } + + /** + * @tc.name: testImagePacker017 + * @tc.desc: encode image to byte array with large offset. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker017() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with byte array by large offset. + * @tc.expected: step2.throw IndexOutOfBoundsException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = new byte[1024]; + + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imagePacker.initializePacking(data, data.length, packingOptions); + }); + } + + /** + * @tc.name: testImagePacker018 + * @tc.desc: encode image to null output stream. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker018() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.init with null output stream. + * @tc.expected: step2.throw IllegalArgumentException. + */ + ImagePacker.PackingOptions packingOptions = null; + FileOutputStream outputStream = null; + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imagePacker.initializePacking(outputStream, packingOptions); + }); + } + + /** + * @tc.name: testImagePacker019 + * @tc.desc: add null pixel map to packer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker019() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.add null pixel map to packer. + * @tc.expected: step2.throw IllegalArgumentException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = new byte[1024]; + imagePacker.initializePacking(data, packingOptions); + + PixelMap pixelMap = null; + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imagePacker.addImage(pixelMap); + }); + } + + /** + * @tc.name: testImagePacker020 + * @tc.desc: add null image source to packer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker020() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.add null image source to packer. + * @tc.expected: step2.throw IllegalArgumentException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = new byte[1024]; + imagePacker.initializePacking(data, packingOptions); + + ImageSource imageSource = null; + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imagePacker.addImage(imageSource); + }); + } + + /** + * @tc.name: testImagePacker021 + * @tc.desc: add negative image source index to packer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePacker021() { + /** + * @tc.steps: step1.get image packer and start packing. + * @tc.expected: step1.get image packer not null. + */ + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + + /** + * @tc.steps: step2.add negative image source index to packer. + * @tc.expected: step2.throw IllegalArgumentException. + */ + ImagePacker.PackingOptions packingOptions = null; + byte[] data = new byte[1024]; + imagePacker.initializePacking(data, packingOptions); + + ImageSource imageSource = ImageSource.create(PNG_SRC_FILE_PATH, null); + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imagePacker.addImage(imageSource, -1); + }); + } +} + + diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/ImagePixelMapKitTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImagePixelMapKitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a469e5cb0e5a7ebbf1aa6db7567c47e1d10fb3df --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImagePixelMapKitTest.java @@ -0,0 +1,1774 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertNotEquals; + +import ohos.media.image.common.AllocatorType; +import ohos.media.image.common.AlphaType; +import ohos.media.image.common.ImageInfo; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.Position; +import ohos.media.image.common.Rect; +import ohos.media.image.common.ScaleMode; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.system.Parameters; +import ohos.rpc.MessageParcel; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; +import ohos.utils.Parcel; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.IntBuffer; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * ImagePixelTest, test cases for image pixelMap class. + * + * @since 1 + */ +public class ImagePixelMapKitTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImagePixelMapKitTest.class); + + private static final String COLORS_DATA = "/sdcard/multimedia/image/colors.txt"; + + private static final String SRC_RESULT = "/sdcard/multimedia/image/test/colors_test.jpeg"; + + private static final String FIT_TARGET_SIZE_RESULT = "/sdcard/multimedia/image/test/fit_target_size.jpeg"; + + private static final String CENTER_CROP_RESULT = "/sdcard/multimedia/image/test/center_crop.jpeg"; + + private static final String COPYED_RESULT = "/sdcard/multimedia/image/test/copyed_test.jpeg"; + + private static final String TEST_PNG_IMAGE_DIR = "/sdcard/multimedia/image/test.png"; + + private static final String PHONE_DEVICE = "default"; + + private static final String DEVICE_TYPE = "ro.build.characteristics"; + + private static int DEFAULT_DENSITY; + + private static int[] myColors; + + static { + try { + System.loadLibrary("ipc_core.z"); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary ipc_core.z fail"); + } + } + + private boolean isPhoneDevice = false; + + private int[] defaultColors; + + private Size defaultSize; + + private PixelMap.InitializationOptions initializationOptions; + + /** + * Action before all test case. + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + myColors = constructColors(); + File file = new File(FIT_TARGET_SIZE_RESULT); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdir(); + } + PixelMap.InitializationOptions options = new PixelMap.InitializationOptions(); + options.size = new Size(100, 200); + PixelMap pixelMap = PixelMap.create(myColors, options); + DEFAULT_DENSITY = pixelMap.getBaseDensity(); + } + + /** + * Action after all test case. + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + myColors = null; + } + + /** + * Action before test case. + */ + @Before + public void setUp() { + defaultColors = new int[] {5, 5, 5, 5, 6, 6, 3, 3, 3, 0}; + initializationOptions = new PixelMap.InitializationOptions(); + defaultSize = new Size(3, 2); + initializationOptions.size = defaultSize; + initializationOptions.pixelFormat = PixelFormat.ARGB_8888; + } + + /** + * @tc.name: testImagePixelMap001 + * @tc.desc: create pxielMap object with correct parameters. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap001() { + /** + * @tc.steps: step1. create pixelMap use correct parameters. + * @tc.expected: step1. get the valid pixelMap. + */ + int offset = 0; + int stride = 4; + PixelMap pixelMap = PixelMap.create(defaultColors, offset, stride, initializationOptions); + assertNotNull(pixelMap); + /** + * @tc.steps: step2. check the params are correct. + * @tc.expected: step2. the params is valid. + */ + ImageInfo imageInfo = pixelMap.getImageInfo(); + assertEquals(defaultSize.width, imageInfo.size.width); + assertEquals(defaultSize.height, imageInfo.size.height); + assertEquals(PixelFormat.ARGB_8888, imageInfo.pixelFormat); + assertEquals(AlphaType.PREMUL, imageInfo.alphaType); + pixelMap.release(); + } + + /** + * @tc.name: testImagePixelMap002 + * @tc.desc: create pixelMap with wrong parameters. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap002() { + /** + * @tc.steps: step1. create pixelMap use wrong parameters. + * @tc.expected: step1. get the pixelMap null. + */ + int offset = 5; + int stride = 5; + PixelMap pixelMap = null; + try { + pixelMap = PixelMap.create(defaultColors, offset, stride, initializationOptions); + } catch (IllegalArgumentException e) { + LOGGER.error("params invalid"); + } + assertNull(pixelMap); + } + + /** + * @tc.name: testImagePixelMap003 + * @tc.desc: create pixelMap use default offset and stride. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap003() { + /** + * @tc.steps: step1. create pixelMap use default offset and stride. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap pixelMap = PixelMap.create(defaultColors, initializationOptions); + assertNotNull(pixelMap); + pixelMap.release(); + } + + /** + * @tc.name: testImagePixelMap004 + * @tc.desc: create pixelMap use wrong colors parameter. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap004() { + /** + * @tc.steps: step1. create pixelMap use wrong colors parameter. + * @tc.expected: step1. get the pixelMap null. + */ + PixelMap pixelMap = null; + try { + pixelMap = PixelMap.create(new int[] {}, initializationOptions); + } catch (IllegalArgumentException e) { + LOGGER.error("params invalid"); + } + assertNull(pixelMap); + } + + /** + * @tc.name: testImagePixelMap005 + * @tc.desc: create pixelMap only use initialization options + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap005() { + /** + * @tc.steps: step1. create pixelMap only use initialization options. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap pixelMap = PixelMap.create(initializationOptions); + assertNotNull(pixelMap); + ImageInfo imageInfo = pixelMap.getImageInfo(); + assertEquals(defaultSize.width, imageInfo.size.width); + assertEquals(defaultSize.height, imageInfo.size.height); + assertEquals(PixelFormat.ARGB_8888, imageInfo.pixelFormat); + pixelMap.release(); + } + + /** + * @tc.name: testImagePixelMap006 + * @tc.desc: create pixelMap only use wrong initialization options. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap006() { + /** + * @tc.steps: step1. create pixelMap only use wrong initialization options. + * @tc.expected: step1. get the pixelMap null. + */ + initializationOptions.size.height = 0; + initializationOptions.size.width = 0; + PixelMap pixelMap = null; + try { + pixelMap = PixelMap.create(initializationOptions); + } catch (IllegalArgumentException e) { + LOGGER.error("params invalid"); + } + assertNull(pixelMap); + } + + /** + * @tc.name: testImagePixelMap007 + * @tc.desc: create scale fit target size pixelMap use src pixelMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap007() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + /** + * @tc.steps: step2. use source pixelMap create new scale fit target size pixelMap. + * @tc.expected: step2. check the target picture is valid. + */ + initializationOptions.size.height = 200; + initializationOptions.size.width = 100; + PixelMap copyPixelMap = PixelMap.create(source, initializationOptions); + assertNotNull(copyPixelMap); + ImageInfo copyImageInfo = copyPixelMap.getImageInfo(); + assertEquals(initializationOptions.size.width, copyImageInfo.size.width); + assertEquals(initializationOptions.size.height, copyImageInfo.size.height); + imageEncode(copyPixelMap, FIT_TARGET_SIZE_RESULT); + copyPixelMap.release(); + source.release(); + } + + /** + * @tc.name: testImagePixelMap008 + * @tc.desc: create center crop pixelMap use src pixelMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap008() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + /** + * @tc.steps: step2. use source pixelMap create new scale fit target size pixelMap. + * @tc.expected: step2. check the target picture is valid. + */ + initializationOptions.size.height = 500; + initializationOptions.size.width = 800; + initializationOptions.scaleMode = ScaleMode.CENTER_CROP; + initializationOptions.releaseSource = true; + PixelMap copyPixelMap = PixelMap.create(source, initializationOptions); + assertNotNull(copyPixelMap); + ImageInfo copyImageInfo = copyPixelMap.getImageInfo(); + assertEquals(initializationOptions.size.width, copyImageInfo.size.width); + assertEquals(initializationOptions.size.height, copyImageInfo.size.height); + imageEncode(copyPixelMap, CENTER_CROP_RESULT); + copyPixelMap.release(); + source.release(); + } + + /** + * @tc.name: testImagePixelMap009 + * @tc.desc: create pixelMap use source options and modify pixelFormat. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap009() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + /** + * @tc.steps: step2. create pixelMap use source options and modify pixelFormat. + * @tc.expected: step2. check the target is valid. + */ + PixelMap.InitializationOptions defaultOpts = new PixelMap.InitializationOptions(); + defaultOpts.pixelFormat = PixelFormat.ARGB_8888; + PixelMap copyedPixelMap = PixelMap.create(source, defaultOpts); + assertNotNull(copyedPixelMap); + ImageInfo sourceImageInfo = source.getImageInfo(); + ImageInfo copyedImageInfo = copyedPixelMap.getImageInfo(); + assertEquals(sourceImageInfo.size.width, copyedImageInfo.size.width); + assertEquals(sourceImageInfo.size.height, copyedImageInfo.size.height); + assertEquals(defaultOpts.pixelFormat, copyedImageInfo.pixelFormat); + source.release(); + copyedPixelMap.release(); + } + + /** + * @tc.name: testImagePixelMap010 + * @tc.desc: create rect pixelMap use src pixelMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap010() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = true; + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + /** + * @tc.steps: step2. create copied pixelMap and use rect and scale source operation. + * @tc.expected: step2. check the target picture is valid. + */ + Rect rect = new Rect(0, 0, 50, 100); + PixelMap.InitializationOptions defaultOpts = new PixelMap.InitializationOptions(); + defaultOpts.useSourceIfMatch = true; + defaultOpts.editable = true; + defaultOpts.size = new Size(600, 800); + PixelMap copyedPixelMap = PixelMap.create(source, rect, defaultOpts); + assertNotNull(copyedPixelMap); + ImageInfo copyedImageInfo = copyedPixelMap.getImageInfo(); + ImageInfo sourceImageInfo = source.getImageInfo(); + assertEquals(sourceImageInfo.size.width, 300); + assertEquals(copyedImageInfo.size.width, 600); + copyedPixelMap.release(); + source.release(); + } + + /** + * @tc.name: testImagePixelMap011 + * @tc.desc: create pixelMap use null initialization Options. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap011() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = false; + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + /** + * @tc.steps: step2. use null initializationOptions generate new pixelmap like source. + * @tc.expected: step2. check the target is valid. + */ + PixelMap copyedPixelMap = PixelMap.create(source, null); + assertNotNull(copyedPixelMap); + ImageInfo copyedImageInfo = copyedPixelMap.getImageInfo(); + ImageInfo sourceImageInfo = source.getImageInfo(); + assertEquals(sourceImageInfo.size.width, copyedImageInfo.size.width); + assertEquals(sourceImageInfo.size.height, copyedImageInfo.size.height); + imageEncode(copyedPixelMap, COPYED_RESULT); + source.release(); + copyedPixelMap.release(); + } + + /** + * @tc.name: testImagePixelMap012 + * @tc.desc: create pixelMap use source and initialization Options. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap012() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = false; + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + + /** + * @tc.steps: step2. response source pixelMap. + * @tc.expected: step2. check the target pixelMap is valid. + */ + initializationOptions.size.height = 300; + initializationOptions.size.width = 300; + initializationOptions.useSourceIfMatch = true; + initializationOptions.releaseSource = true; + PixelMap selfpixelMap = PixelMap.create(source, initializationOptions); + assertNotNull(selfpixelMap); + ImageInfo srcImageInfo = source.getImageInfo(); + ImageInfo selfImageInfo = selfpixelMap.getImageInfo(); + assertEquals(srcImageInfo.size.width, selfImageInfo.size.width); + assertEquals(srcImageInfo.size.height, selfImageInfo.size.height); + assertEquals(srcImageInfo.pixelFormat, selfImageInfo.pixelFormat); + assertEquals(selfpixelMap, source); + /** + * @tc.steps: step3. create new pixelMap from source with rect and crop scale. + * @tc.expected: step3. check the target pixelMap is valid. + */ + initializationOptions.size.height = 400; + initializationOptions.size.width = 400; + initializationOptions.scaleMode = ScaleMode.CENTER_CROP; + initializationOptions.pixelFormat = PixelFormat.BGRA_8888; + initializationOptions.releaseSource = true; + Rect rect = new Rect(0, 0, 50, 50); + PixelMap copyedPixelMap = PixelMap.create(source, rect, initializationOptions); + assertNotNull(copyedPixelMap); + srcImageInfo = source.getImageInfo(); + ImageInfo copyedImageInfo = copyedPixelMap.getImageInfo(); + assertEquals(srcImageInfo.size.width, 300); + assertEquals(copyedImageInfo.size.width, 400); + source.release(); + selfpixelMap.release(); + copyedPixelMap.release(); + } + + /** + * @tc.name: testImagePixelMap013 + * @tc.desc: create copy pixelMap use source and initialization Options. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap013() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = true; + initializationOptions.useSourceIfMatch = true; + initializationOptions.releaseSource = false; + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + ImageInfo srcImageInfo = source.getImageInfo(); + /** + * @tc.steps: step2. copy pixelMap use source. + * @tc.expected: step2. check the target pixelMap is valid. + */ + initializationOptions.size.width = 600; + initializationOptions.size.height = 500; + PixelMap copyedpixelMap = PixelMap.create(source, initializationOptions); + assertNotNull(copyedpixelMap); + ImageInfo copyedImageInfo = copyedpixelMap.getImageInfo(); + assertEquals(srcImageInfo.size.width, 300); + assertEquals(copyedImageInfo.size.width, 600); + copyedpixelMap.release(); + /** + * @tc.steps: step3. copy pixelMap from source with rect and crop scale. + * @tc.expected: step3. check the target pixelMap is valid. + */ + initializationOptions.size.height = 400; + initializationOptions.size.width = 400; + initializationOptions.scaleMode = ScaleMode.CENTER_CROP; + initializationOptions.pixelFormat = PixelFormat.BGRA_8888; + Rect rect = new Rect(0, 0, 50, 100); + PixelMap copyedPixelMap2 = PixelMap.create(source, rect, initializationOptions); + assertNotNull(copyedPixelMap2); + ImageInfo copyedImageInfo2 = copyedPixelMap2.getImageInfo(); + assertEquals(srcImageInfo.size.width, 300); + assertEquals(copyedImageInfo2.size.width, 400); + copyedPixelMap2.release(); + /** + * @tc.steps: step4. copy pixelMap from source with wrong rect and crop scale. + * @tc.expected: step4. get the pixelMap null. + */ + rect = new Rect(0, 0, 600, 600); + PixelMap copyedPixelMap3 = PixelMap.create(source, rect, initializationOptions); + assertNull(copyedPixelMap3); + source.release(); + } + + /** + * @tc.name: testImagePixelMap014 + * @tc.desc: create pixelMap use default initialization Options and response self. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMap014() { + /** + * @tc.steps: step1. create src pixelMap use file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = false; + PixelMap source = createSrcPixelMap(); + assertNotNull(source); + /** + * @tc.steps: step2. use default initializationOptions generate src pixelmap. + * @tc.expected: step2. check the target is valid. + */ + PixelMap.InitializationOptions defaultOpts = new PixelMap.InitializationOptions(); + defaultOpts.useSourceIfMatch = true; + defaultOpts.editable = false; + PixelMap selfPixelMap = PixelMap.create(source, defaultOpts); + assertNotNull(selfPixelMap); + ImageInfo selfImageInfo = selfPixelMap.getImageInfo(); + ImageInfo sourceImageInfo = source.getImageInfo(); + assertEquals(sourceImageInfo.size.width, selfImageInfo.size.width); + assertEquals(sourceImageInfo.size.height, selfImageInfo.size.height); + assertEquals(source, selfPixelMap); + source.release(); + selfPixelMap.release(); + } + + /** + * @tc.name: testImagePixelMapExt001 + * @tc.desc: get pxielMap object parameters. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt001() { + /** + * @tc.steps: step1. create pixelMap by test.png. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap testMap = createTestPixelMap(TEST_PNG_IMAGE_DIR); + assertNotNull(testMap); + /** + * @tc.steps: step2. check the params are correct. + * @tc.expected: step2. the params is valid. + */ + long capacity = testMap.getPixelBytesCapacity(); + long bytesNumber = testMap.getPixelBytesNumber(); + int rowBytes = testMap.getBytesNumberPerRow(); + AlphaType alpha = testMap.getImageInfo().alphaType; + assertEquals(141600, capacity); + assertEquals(141600, bytesNumber); + assertEquals(1888, rowBytes); + assertEquals(AlphaType.OPAQUE, alpha); + boolean isDefaultEditable = testMap.isEditable(); + assertEquals(false, isDefaultEditable); + /** + * @tc.steps: step3. set baseDensity and useMipMap params. + * @tc.expected: step3. the params is valid. + */ + testMap.setUseMipmap(true); + testMap.setBaseDensity(720); + boolean newUseMipMap = testMap.useMipmap(); + int newBaseDensity = testMap.getBaseDensity(); + assertEquals(true, newUseMipMap); + assertEquals(720, newBaseDensity); + testMap.release(); + } + + /** + * @tc.name: testImagePixelMapExt002 + * @tc.desc: get pxielMap object parameters. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt002() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = true; + PixelMap map = createSrcPixelMap(); + assertNotNull(map); + /** + * @tc.steps: step2. check the params are correct. + * @tc.expected: step2. the params is valid. + */ + long capacity = map.getPixelBytesCapacity(); + long bytesNumber = map.getPixelBytesNumber(); + int rowBytes = map.getBytesNumberPerRow(); + AlphaType alpha = map.getImageInfo().alphaType; + assertEquals(360000, capacity); + assertEquals(360000, bytesNumber); + assertEquals(1200, rowBytes); + assertEquals(AlphaType.PREMUL, alpha); + int defaultDesity = map.getBaseDensity(); + assertEquals(DEFAULT_DENSITY, defaultDesity); + boolean defaultMipMap = map.useMipmap(); + assertEquals(false, defaultMipMap); + boolean editable = map.isEditable(); + assertEquals(true, editable); + map.release(); + } + + /** + * @tc.name: testImagePixelMapExt003 + * @tc.desc: is same pxielMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt003() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap txtmap = createSrcPixelMap(); + PixelMap pngMap = createTestPixelMap(TEST_PNG_IMAGE_DIR); + assertNotNull(txtmap); + assertNotNull(pngMap); + /** + * @tc.steps: step2. check the two pixelmap is same. + * @tc.expected: step2. the params is valid. + */ + boolean isSame = txtmap.isSameImage(pngMap); + assertEquals(false, isSame); + txtmap.release(); + pngMap.release(); + } + + /** + * @tc.name: testImagePixelMapExt004 + * @tc.desc: is same pxielMap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt004() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap txtmap1 = createSrcPixelMap(); + PixelMap txtmap2 = createSrcPixelMap(); + assertNotNull(txtmap1); + assertNotNull(txtmap1); + /** + * @tc.steps: step2. check the two pixelmap is same. + * @tc.expected: step2. the params is valid. + */ + boolean isSame = txtmap1.isSameImage(txtmap2); + assertEquals(true, isSame); + txtmap1.release(); + txtmap2.release(); + } + + /** + * @tc.name: testImagePixelMapExt005 + * @tc.desc: set and get AlphaType. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt005() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap txtmap = createSrcPixelMap(); + assertNotNull(txtmap); + /** + * @tc.steps: step2. set and check the pixelmap AlphaType. + * @tc.expected: step2. the params is valid. + */ + txtmap.setAlphaType(AlphaType.PREMUL); + assertEquals(AlphaType.PREMUL, txtmap.getImageInfo().alphaType); + txtmap.release(); + } + + /** + * @tc.name: testImagePixelMapExt006 + * @tc.desc: set and get AlphaType. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt006() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.pixelFormat = PixelFormat.RGB_565; + PixelMap txtmap = createSrcPixelMap(); + assertNotNull(txtmap); + /** + * @tc.steps: step2. set and check the pixelmap AlphaType. + * @tc.expected: step2. the params is valid. + */ + txtmap.setAlphaType(AlphaType.PREMUL); + assertEquals(AlphaType.OPAQUE, txtmap.getImageInfo().alphaType); + txtmap.release(); + } + + /** + * @tc.name: testImagePixelMapExt007 + * @tc.desc: reset config. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt007() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap txtmap = createSrcPixelMap(); + assertNotNull(txtmap); + /** + * @tc.steps: step2. reset the pixelmap config. + * @tc.expected: step2. the params is valid. + */ + ImageInfo srcInfo = txtmap.getImageInfo(); + Size mSize = new Size(txtmap.getImageInfo().size.width - 100, txtmap.getImageInfo().size.width - 100); + PixelFormat mFormat = PixelFormat.RGB_565; + txtmap.resetConfig(mSize, mFormat); + ImageInfo info = txtmap.getImageInfo(); + assertEquals(200, info.size.width); + assertEquals(200, info.size.height); + assertEquals(AlphaType.OPAQUE, info.alphaType); + assertEquals(PixelFormat.RGB_565, info.pixelFormat); + assertEquals(360000, txtmap.getPixelBytesCapacity()); + assertEquals(400, txtmap.getBytesNumberPerRow()); + txtmap.release(); + } + + /** + * @tc.name: testImagePixelMapExt008 + * @tc.desc: reset config. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt008() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap txtmap = createSrcPixelMap(); + assertNotNull(txtmap); + /** + * @tc.steps: step2. reset the pixelmap config. + * @tc.expected: step2. the params is valid. + */ + ImageInfo srcInfo = txtmap.getImageInfo(); + Size mSize = new Size(txtmap.getImageInfo().size.width + 100, txtmap.getImageInfo().size.width + 100); + PixelFormat mFormat = PixelFormat.RGB_565; + txtmap.resetConfig(mSize, mFormat); + ImageInfo info = txtmap.getImageInfo(); + assertEquals(400, info.size.width); + assertEquals(400, info.size.height); + assertEquals(AlphaType.OPAQUE, info.alphaType); + assertEquals(PixelFormat.RGB_565, info.pixelFormat); + assertEquals(360000, txtmap.getPixelBytesCapacity()); + assertEquals(800, txtmap.getBytesNumberPerRow()); + txtmap.release(); + } + + /** + * @tc.name: testImagePixelMapExt009 + * @tc.desc: read and write per pixel by position. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt009() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + initializationOptions.editable = true; + PixelMap txtmap = createSrcPixelMap(); + assertNotNull(txtmap); + /** + * @tc.steps: step2. write color to pixelmap the position. + * @tc.expected: step2. the params is valid. + */ + Position pos = new Position(50, 50); + int color = 0xFFFF8040; + txtmap.writePixel(pos, color); + /** + * @tc.steps: step2. read pixelmap the position and check the color. + * @tc.expected: step2. the params is valid. + */ + int otherColor = txtmap.readPixel(pos); + LOGGER.debug("color:0x%{public}x, other:0x%{public}x.", color, otherColor); + assertEquals(true, color == otherColor); + txtmap.release(); + } + + /** + * @tc.name: testImagePixelMapExt010 + * @tc.desc: read per pixel by position abormal. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt010() { + /** + * @tc.steps: step1. create pixelMap by file data. + * @tc.expected: step1. get the valid pixelMap. + */ + PixelMap txtmap = createTestPixelMap(TEST_PNG_IMAGE_DIR); + assertNotNull(txtmap); + /** + * @tc.steps: step2. read the pixelmap position and the position > pixelmap.size. + * @tc.expected: step2. throw exception. + */ + ImageInfo info = txtmap.getImageInfo(); + Position pos = new Position(info.size.width + 1, info.size.height + 1); + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + int color = txtmap.readPixel(pos); + }); + txtmap.release(); + } + + /** + * @tc.name: testImagePixelMapExt011 + * @tc.desc: Get a new pixelmap data from the original pixelmap by region. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt011() { + /** + * @tc.steps: step1. decode png file to get original pixelmap. + * @tc.expected: step1. get the valid pixelMap from the png image. + */ + PixelMap txtmap = createTestPixelMap(TEST_PNG_IMAGE_DIR); + assertNotNull(txtmap); + /** + * @tc.steps: step2. read data from the specified region of pxielmap. + * @tc.expected: step2. get the valid pixelmap data and save to int array. + */ + int[] pixelArray = new int[50]; + Rect region = new Rect(0, 0, 10, 5); + txtmap.readPixels(pixelArray, 0, 10, region); + txtmap.release(); + LOGGER.debug("pixelArray:%{public}s.", + IntStream.of(pixelArray).mapToObj(item -> Integer.toHexString(item)).collect(Collectors.joining("."))); + /** + * @tc.steps: step3. Create another pixelmap and set it to be editable. + * @tc.expected: step3. get valid a editable pixelmap. + */ + initializationOptions.editable = true; + PixelMap otherMap = createSrcPixelMap(); + assertEquals(true, otherMap.isEditable()); + /** + * @tc.steps: step4. Write the data of the original image into a new pixelmap. + * @tc.expected: step4. write to new pixelmap successful. + */ + otherMap.writePixels(pixelArray, 0, 10, region); + /** + * @tc.steps: step5. Check if the written data is correct by read interface. + * @tc.expected: step5. the written data is the same as the original data. + */ + int[] otherPixelArray = new int[50]; + Rect otherRegion = new Rect(0, 0, 10, 5); + otherMap.readPixels(otherPixelArray, 0, 10, otherRegion); + otherMap.release(); + LOGGER.debug("otherPixelArray:%{public}s.", + IntStream.of(otherPixelArray).mapToObj(item -> Integer.toHexString(item)).collect(Collectors.joining("."))); + assertEquals(true, Arrays.equals(pixelArray, otherPixelArray)); + } + + /** + * @tc.name: testImagePixelMapExt012 + * @tc.desc: read and write pixels by Buffer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt012() { + /** + * @tc.steps: step1. create create byte buffer and init. + * @tc.expected: step1. get invalid int buffer. + */ + IntBuffer intBuf = IntBuffer.allocate(50); + intBuf.limit(50); + int color = 0xFFFF8080; // ARGB pink color + int[] array = intBuf.array(); + Arrays.fill(array, color); + intBuf.put(array); + intBuf.position(0); + assertNotNull(intBuf); + LOGGER.debug("otherPixelArray:%{public}s.", + IntStream.of(intBuf.array()).mapToObj(item -> Integer.toHexString(item)).collect(Collectors.joining("."))); + /** + * @tc.steps: step2. create the empty pixelmap. + * @tc.expected: step2. get invalid pixelMap. + */ + initializationOptions.size.height = 5; + initializationOptions.size.width = 10; + initializationOptions.editable = true; + PixelMap txtMap = PixelMap.create(initializationOptions); + assertNotNull(txtMap); + /** + * @tc.steps: step3. int buffer write to pixelmap. + * @tc.expected: step3. throw exception. + */ + txtMap.writePixels(intBuf); + /** + * @tc.steps: step4. read pixelmap and check. + * @tc.expected: step4. throw exception. + */ + IntBuffer otherBuf = IntBuffer.allocate(50); + assertNotNull(otherBuf); + txtMap.readPixels(otherBuf); + assertEquals(true, otherBuf.equals(intBuf)); + LOGGER.debug("otherBufArray:%{public}s.", IntStream.of(otherBuf.array()) + .mapToObj(item -> Integer.toHexString(item)) + .collect(Collectors.joining("."))); + txtMap.release(); + } + + /** + * @tc.name: testImagePixelMapExt013 + * @tc.desc: write color to the whole pixelmap. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt013() { + /** + * @tc.steps: step2. create the empty pixelmap. + * @tc.expected: step2. get invalid pixelMap. + */ + initializationOptions.editable = true; + PixelMap txtMap = createSrcPixelMap(); + assertNotNull(txtMap); + /** + * @tc.steps: step3. write color to pixelmap and check. + * @tc.expected: step3. throw exception. + */ + int color = 0xFFFF8080; // ARGB pink color + txtMap.writePixels(color); + Position pos = new Position(299, 299); + int otherColor = txtMap.readPixel(pos); + assertEquals(true, color == otherColor); + LOGGER.debug("color:0x%{public}x, otherColor:0x%{public}x.", color, otherColor); + txtMap.release(); + } + + /** + * @tc.name: testImagePixelMapExt014 + * @tc.desc: Get a new pixelmap data from the original pixelmap by region. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt014() { + /** + * @tc.steps: step1. decode png file to get original pixelmap. + * @tc.expected: step1. get the valid pixelMap from the png image. + */ + PixelMap txtmap = createTestPixelMap(TEST_PNG_IMAGE_DIR); + assertNotNull(txtmap); + /** + * @tc.steps: step2. read data from the specified region of pxielmap,minX>width minY>height. + * @tc.expected: step2. get the valid pixelmap data and save to int array. + */ + int[] pixelArray = new int[50]; + Rect region = new Rect(15, 8, 10, 5); + txtmap.readPixels(pixelArray, 0, 10, region); + txtmap.release(); + LOGGER.debug("pixelArray:%{public}s.", + IntStream.of(pixelArray).mapToObj(item -> Integer.toHexString(item)).collect(Collectors.joining("."))); + /** + * @tc.steps: step3. Create another pixelmap and set it to be editable. + * @tc.expected: step3. get valid a editable pixelmap. + */ + initializationOptions.editable = true; + PixelMap otherMap = createSrcPixelMap(); + assertEquals(true, otherMap.isEditable()); + /** + * @tc.steps: step4. Write the data of the original image into a new pixelmap. + * @tc.expected: step4. write to new pixelmap successful. + */ + otherMap.writePixels(pixelArray, 0, 10, region); + /** + * @tc.steps: step5. Check if the written data is correct by read interface. + * @tc.expected: step5. the written data is the same as the original data. + */ + int[] otherPixelArray = new int[50]; + Rect otherRegion = new Rect(0, 0, 10, 5); + otherMap.readPixels(otherPixelArray, 0, 10, otherRegion); + otherMap.release(); + LOGGER.debug("otherPixelArray:%{public}s.", + IntStream.of(otherPixelArray).mapToObj(item -> Integer.toHexString(item)).collect(Collectors.joining("."))); + assertEquals(true, Arrays.equals(pixelArray, otherPixelArray)); + } + + /** + * @tc.name: testImagePixelMapExt015 + * @tc.desc: test write pixel throw exception. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt015() { + /** + * @tc.steps: step1. decode png file to get original pixelmap. + * @tc.expected: step1. get the valid pixelMap from the png image. + */ + PixelMap txtmap = createTestPixelMap(TEST_PNG_IMAGE_DIR); + assertNotNull(txtmap); + + /** + * @tc.steps: step2. write pixel with pos Out of range. + * @tc.expected: step2. expect IllegalArgumentException. + */ + Position pos = new Position(1000, 1000); + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + txtmap.writePixel(pos, 0X12345678); + }); + /** + * @tc.steps: step3. write pixel with rect Out of range. + * @tc.expected: step3. expect IllegalArgumentException. + */ + int[] pixelArray = new int[50]; + Rect region = new Rect(500, 400, 500, 400); + PixelMap otherMap = createSrcPixelMap(); + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + otherMap.writePixels(pixelArray, 0, 10, region); + }); + } + + /** + * @tc.name: testImagePixelMapExt016 + * @tc.desc: check pixel map read and write + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt016() { + PixelMap pixelMap = createTestPixelMap("/sdcard/multimedia/image/test_large.webp"); + PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions(); + opts.editable = true; + PixelMap newPixelMap = PixelMap.create(pixelMap, opts); + + /** + * @tc.steps: step1.read pixel map by pos. + * @tc.expected: step1. expect pixel value ok. + */ + int color = newPixelMap.readPixel(new Position(360, 342)); + byte[] readByPos = new byte[4]; + readByPos[3] = (byte) (color & 0xff); // B 87 + readByPos[2] = (byte) (color >> 8 & 0xff); // G 248 + readByPos[1] = (byte) (color >> 16 & 0xff); // R 243 + readByPos[0] = (byte) (color >> 24 & 0xff); // A 255 + + assertEquals(readByPos[0], (byte) -1); + assertEquals(readByPos[1], (byte) 63); + assertEquals(readByPos[2], (byte) 71); + assertEquals(readByPos[3], (byte) -51); + + /** + * @tc.steps: step2.write pixel map by pos then read pixel map by rect. + * @tc.expected: step2. expect pixel value ok. + */ + newPixelMap.writePixel(new Position(360, 342), color); + + int[] pixels = new int[1]; + Rect rect = new Rect(360, 342, 1, 1); + newPixelMap.readPixels(pixels, 0, 1, rect); + byte[] readByRect = new byte[4]; + readByRect[3] = (byte) (pixels[0] & 0xff); // B 87 + readByRect[2] = (byte) (pixels[0] >> 8 & 0xff); // G 248 + readByRect[1] = (byte) (pixels[0] >> 16 & 0xff); // R 243 + readByRect[0] = (byte) (pixels[0] >> 24 & 0xff); // A 255 + + assertEquals(readByRect[0], (byte) -1); + assertEquals(readByRect[1], (byte) 63); + assertEquals(readByRect[2], (byte) 71); + assertEquals(readByRect[3], (byte) -51); + + /** + * @tc.steps: step3.write pixel map by rect then read pixel map by rect again. + * @tc.expected: step3. expect pixel value ok. + */ + newPixelMap.writePixels(pixels, 0, 1, rect); + int[] pixelsBack = new int[1]; + + newPixelMap.readPixels(pixelsBack, 0, 1, rect); + byte[] readByRectBack = new byte[4]; + readByRectBack[3] = (byte) (pixelsBack[0] & 0xff); // B 87 + readByRectBack[2] = (byte) (pixelsBack[0] >> 8 & 0xff); // G 248 + readByRectBack[1] = (byte) (pixelsBack[0] >> 16 & 0xff); // R 243 + readByRectBack[0] = (byte) (pixelsBack[0] >> 24 & 0xff); // A 255 + + assertEquals(readByRectBack[0], (byte) -1); + assertEquals(readByRectBack[1], (byte) 63); + assertEquals(readByRectBack[2], (byte) 71); + assertEquals(readByRectBack[3], (byte) -51); + } + + /** + * @tc.name: testImagePixelMapExt017 + * @tc.desc: check write editable pixel map + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt017() { + /** + * @tc.steps: step1. decode webp file to get editable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + ImageSource imageSource = ImageSource.create("/sdcard/multimedia/image/test_large.webp", null); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step1. write pixel map pixels. + * @tc.expected: step1. write ok. + */ + int color = 0xff123456; + pixelMap.writePixel(new Position(360, 342), color); + } + + /** + * @tc.name: testImagePixelMapExt018 + * @tc.desc: write uneditable pixel map + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImagePixelMapExt018() { + /** + * @tc.steps: step1. decode webp file to get uneditable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + ImageSource imageSource = ImageSource.create("/sdcard/multimedia/image/test_large.webp", null); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = false; + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step1. write pixel map pixels. + * @tc.expected: step1. write exception. + */ + int color = 0xff123456; + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + pixelMap.writePixel(new Position(360, 342), color); + }); + } + + /** + * @tc.name: testPixelMapParcelable001 + * @tc.desc: create pixel map and test the parcelable interface + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapParcelable001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.bmp"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + decodingOpts.allocator = AllocatorType.SHARED_MEMORY; + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + + /** + * @tc.steps: step3.marshall pixel map to parcel and create pixel map from parcel. + * @tc.expected: step3.marshall pixel map success and check information of the pixel map created from parcel ok + */ + MessageParcel parcel = MessageParcel.create(); + assertNotNull(parcel); + assertTrue(parcel.writeInt(1)); + boolean ret = pixelMap.marshalling(parcel); + assertEquals(ret, true); + PixelMap pixelMapFromParcel = PixelMap.PRODUCER.createFromParcel(parcel); + assertNotNull(pixelMapFromParcel); + assertEquals(472, pixelMapFromParcel.getImageInfo().size.width); + assertEquals(75, pixelMapFromParcel.getImageInfo().size.height); + assertFalse(pixelMap.unmarshalling(parcel)); + } + + /** + * @tc.name: testPixelMapDensitySize001 + * @tc.desc: application decode image file and display. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapDensitySize001() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + /** + * @tc.steps: step1.decode a image file to pixel map. + * @tc.expected: step1.created pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2.get proper pixel map size on a specified density. + * @tc.expected: step2.check pixel map size ok. + */ + Size targetSize = new Size(pixelMap.getImageInfo().size.width * 2, pixelMap.getImageInfo().size.height * 2); + assertEquals(targetSize, pixelMap.getFitDensitySize(DEFAULT_DENSITY * 2)); + + /** + * @tc.steps: step3.if pixel map is no longer needed, release native resource. + * @tc.expected: step3.check if native resource released. + */ + pixelMap.release(); + assertTrue(pixelMap.isReleased()); + } + + /** + * @tc.name: testPixelMapDensitySize002 + * @tc.desc: get fit size by density. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapDensitySize002() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + /** + * @tc.steps: step1.get image source form path and create pixel map. + * @tc.expected: step1.image source not null and pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2.get fit size by default density. + * @tc.expected: step2.size should be equal to original size. + */ + Size size = new Size(472, 75); + assertEquals(size, pixelMap.getFitDensitySize(DEFAULT_DENSITY)); + + /** + * @tc.steps: step3.get fit size by density 0. + * @tc.expected: step3.size should be equal to original size. + */ + Size emptySize = new Size(472, 75); + assertEquals(emptySize, pixelMap.getFitDensitySize(0)); + + /** + * @tc.steps: step4.get fit size by larger density or smaller density. + * @tc.expected: step4.size should be larger or smaller than original size. + */ + Size doubleSize = new Size(size.width * 3, size.height * 3); + assertEquals(doubleSize, pixelMap.getFitDensitySize(DEFAULT_DENSITY * 3)); + + Size halfSize = new Size(size.width / 2, size.height / 2 + 1); + assertEquals(halfSize, pixelMap.getFitDensitySize(DEFAULT_DENSITY / 2)); + + Size oneThirdSize = new Size(size.width / 3, size.height / 3); + assertEquals(oneThirdSize, pixelMap.getFitDensitySize(DEFAULT_DENSITY / 3)); + + Size oneFourthSize = new Size(size.width / 4, size.height / 4 + 1); + assertEquals(oneFourthSize, pixelMap.getFitDensitySize(DEFAULT_DENSITY / 4)); + + Size oneFifthSize = new Size(size.width / 5, size.height / 5); + assertEquals(oneFifthSize, pixelMap.getFitDensitySize(DEFAULT_DENSITY / 5)); + } + + /** + * @tc.name: testPixelMapDensitySize003 + * @tc.desc: check native resource released + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapDensitySize003() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + /** + * @tc.steps: step1.get image source form path and create pixel map. + * @tc.expected: step1.image source not null and pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2.release pixel map native resource, then check if native resources released. + * @tc.expected: step2.check ok. + */ + assertFalse(pixelMap.isReleased()); + pixelMap.release(); + assertTrue(pixelMap.isReleased()); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha001 + * @tc.desc: check createFromAlpha of Src PixelMap type of ARGB888 + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha001() { + /** + * @tc.steps: step1. get image source form path and create pixel map. + * @tc.expected: step1. image source not null and pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.9.png"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + /** + * @tc.steps: step2. get alpha pixelmap from source. + * @tc.expected: step2. check ok. + */ + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + assertNotNull(alphaPixelMap); + + /** + * @tc.steps: step3. check alpha pixelmap format. + * @tc.expected: step3.check ok. + */ + ImageInfo imageInfoAlpha = alphaPixelMap.getImageInfo(); + ImageInfo imageInfoSrc = pixelMapSrc.getImageInfo(); + assertEquals(imageInfoAlpha.size.height, imageInfoSrc.size.height); + assertEquals(imageInfoAlpha.size.width, imageInfoSrc.size.width); + assertEquals(imageInfoAlpha.alphaType, imageInfoSrc.alphaType); + assertTrue(Math.abs(pixelMapSrc.getBytesNumberPerRow()/4 - alphaPixelMap.getBytesNumberPerRow()) < 4); + + /** + * @tc.steps: step4. check alpha pixelmap format. + * @tc.expected: step4.check ok. + */ + alphaPixelMap.release(); + pixelMapSrc.release(); + assertTrue(alphaPixelMap.isReleased()); + assertTrue(pixelMapSrc.isReleased()); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha002 + * @tc.desc: check createFromAlpha of Src PixelMap type of RGB565 + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha002() { + /** + * @tc.steps: step1. get image source form path and create pixel map. + * @tc.expected: step1. image source not null and pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.jpg"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.RGB_565; + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + /** + * @tc.steps: step2. get alpha pixelmap from source. + * @tc.expected: step2. check ok. + */ + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + assertNotNull(alphaPixelMap); + + /** + * @tc.steps: step3. check alpha pixelmap format. + * @tc.expected: step3.check ok. + */ + ImageInfo imageInfoAlpha = alphaPixelMap.getImageInfo(); + ImageInfo imageInfoSrc = pixelMapSrc.getImageInfo(); + assertEquals(imageInfoAlpha.size.height, imageInfoSrc.size.height); + assertEquals(imageInfoAlpha.size.width, imageInfoSrc.size.width); + assertNotEquals(imageInfoAlpha.alphaType, imageInfoSrc.alphaType); + // RGB565 total 16 bytes, alpha has 8 bytes per pixel + assertTrue(Math.abs(pixelMapSrc.getBytesNumberPerRow() / 2 - alphaPixelMap.getBytesNumberPerRow()) < 4); + + /** + * @tc.steps: step4. check alpha pixelmap format. + * @tc.expected: step4.check ok. + */ + alphaPixelMap.release(); + pixelMapSrc.release(); + assertTrue(alphaPixelMap.isReleased()); + assertTrue(pixelMapSrc.isReleased()); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha003 + * @tc.desc: check createFromAlpha of Src PixelMap type of gif + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha003() { + /** + * @tc.steps: step1. get image source form path and create pixel map. + * @tc.expected: step1. image source not null and pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.gif"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + /** + * @tc.steps: step2. get alpha pixelmap from source. + * @tc.expected: step2. check ok. + */ + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + assertNotNull(alphaPixelMap); + + /** + * @tc.steps: step3. check alpha pixelmap format. + * @tc.expected: step3.check ok. + */ + ImageInfo imageInfoAlpha = alphaPixelMap.getImageInfo(); + ImageInfo imageInfoSrc = pixelMapSrc.getImageInfo(); + assertEquals(imageInfoAlpha.size.height, imageInfoSrc.size.height); + assertEquals(imageInfoAlpha.size.width, imageInfoSrc.size.width); + assertTrue(Math.abs(pixelMapSrc.getBytesNumberPerRow()/4 - alphaPixelMap.getBytesNumberPerRow()) < 4); + + /** + * @tc.steps: step4. check alpha pixelmap format. + * @tc.expected: step4.check ok. + */ + alphaPixelMap.release(); + pixelMapSrc.release(); + assertTrue(alphaPixelMap.isReleased()); + assertTrue(pixelMapSrc.isReleased()); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha004 + * @tc.desc: check createFromAlpha of Src PixelMap type of webp + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha004() { + /** + * @tc.steps: step1. get image source form path and create pixel map. + * @tc.expected: step1. image source not null and pixel map not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.webp"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMapSrc); + + /** + * @tc.steps: step2. get alpha pixelmap from source. + * @tc.expected: step2. check ok. + */ + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + assertNotNull(alphaPixelMap); + + /** + * @tc.steps: step3. check alpha pixelmap format. + * @tc.expected: step3.check ok. + */ + ImageInfo imageInfoAlpha = alphaPixelMap.getImageInfo(); + ImageInfo imageInfoSrc = pixelMapSrc.getImageInfo(); + assertEquals(imageInfoAlpha.size.height, imageInfoSrc.size.height); + assertEquals(imageInfoAlpha.size.width, imageInfoSrc.size.width); + assertTrue(Math.abs(pixelMapSrc.getBytesNumberPerRow()/4 - alphaPixelMap.getBytesNumberPerRow()) < 4); + + /** + * @tc.steps: step4. check alpha pixelmap format. + * @tc.expected: step4.check ok. + */ + alphaPixelMap.release(); + pixelMapSrc.release(); + assertTrue(alphaPixelMap.isReleased()); + assertTrue(pixelMapSrc.isReleased()); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha005 + * @tc.desc: check readPixel from Alpha + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha005() { + LOGGER.info("testPixelMapCreateFromAlpha005 begin"); + + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.RGB_565; + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + assertNotNull(alphaPixelMap); + + ImageInfo imageInfoAlpha = alphaPixelMap.getImageInfo(); + ImageInfo imageInfoSrc = pixelMapSrc.getImageInfo(); + assertEquals(imageInfoAlpha.size.height, imageInfoSrc.size.height); + assertEquals(imageInfoAlpha.size.width, imageInfoSrc.size.width); + + int xPos = alphaPixelMap.getImageInfo().size.width / 2; + int yPos = alphaPixelMap.getImageInfo().size.height / 2; + + Position pos = new Position(xPos, yPos); + int color = pixelMapSrc.readPixel(pos); + color = color & 0xFF000000; + assertEquals(0xFF000000, color); + assertEquals(0xFF000000, alphaPixelMap.readPixel(pos)); + assertNotEquals(imageInfoAlpha.alphaType, imageInfoSrc.alphaType); + + assertTrue(Math.abs(pixelMapSrc.getBytesNumberPerRow()/2 - alphaPixelMap.getBytesNumberPerRow()) < 4); + alphaPixelMap.release(); + pixelMapSrc.release(); + + assertTrue(alphaPixelMap.isReleased()); + assertTrue(pixelMapSrc.isReleased()); + + LOGGER.info("testPixelMapCreateFromAlpha005 end"); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha005 + * @tc.desc: check readPixel from Alpha + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha006() { + PixelMap.InitializationOptions options = new PixelMap.InitializationOptions(); + Size size = new Size(40, 40); + options.size = size; + options.pixelFormat = PixelFormat.RGB_565; + options.editable = true; + + PixelMap srcMap = PixelMap.create(options); + PixelMap alphaPixelMap = srcMap.createFromAlpha(); + + assertNotNull(alphaPixelMap); + + Position pos = new Position(20, 20); + int color1 = srcMap.readPixel(pos); + int color2 = alphaPixelMap.readPixel(pos); + + assertEquals(color1, color2); + } + + private PixelMap createSrcPixelMap() { + LOGGER.debug("myColors length: %{public}d", myColors.length); + initializationOptions.size.height = 300; + initializationOptions.size.width = 300; + PixelMap pixelMap = PixelMap.create(myColors, initializationOptions); + assertNotNull(pixelMap); + return pixelMap; + } + + private static PixelMap createTestPixelMap(String filePath) { + if (filePath == null) { + LOGGER.error("test pixelmap to check filePath fail."); + return null; + } + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = ""; + ImageSource imageSource = ImageSource.create(filePath, srcOpts); + if (imageSource == null) { + LOGGER.error("test pixelmap to create the imageSource fail."); + return null; + } + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + return imageSource.createPixelmap(decodingOpts); + } + + /** + * @tc.name: testPixelMapCreateFromAlpha007 + * @tc.desc: check readPixel from Alpha + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapCreateFromAlpha007() { + LOGGER.info("testPixelMapCreateFromAlpha007 begin"); + + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.jpg"; + ImageSource imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.RGB_565; + PixelMap pixelMapSrc = imageSource.createPixelmap(decodingOpts); + + PixelMap alphaPixelMap = pixelMapSrc.createFromAlpha(); + assertNotNull(alphaPixelMap); + + ImageInfo imageInfoAlpha = alphaPixelMap.getImageInfo(); + ImageInfo imageInfoSrc = pixelMapSrc.getImageInfo(); + + assertEquals(imageInfoAlpha.size.height, imageInfoSrc.size.height); + assertEquals(imageInfoAlpha.size.width, imageInfoSrc.size.width); + + int xPos = alphaPixelMap.getImageInfo().size.width / 2; + int yPos = alphaPixelMap.getImageInfo().size.height / 2; + Position pos = new Position(xPos, yPos); + int color = pixelMapSrc.readPixel(pos); + color = color & 0xFF000000; + assertEquals(0xFF000000, color); + assertEquals(0xFF000000, alphaPixelMap.readPixel(pos)); + assertNotEquals(imageInfoAlpha.alphaType, imageInfoSrc.alphaType); + + assertTrue(Math.abs(pixelMapSrc.getBytesNumberPerRow()/2 - alphaPixelMap.getBytesNumberPerRow()) < 4); + alphaPixelMap.release(); + pixelMapSrc.release(); + + assertTrue(alphaPixelMap.isReleased()); + assertTrue(pixelMapSrc.isReleased()); + + LOGGER.info("testPixelMapCreateFromAlpha007 end"); + } + + private static int[] constructColors() { + File file = new File(COLORS_DATA); + assertNotNull(file); + try (BufferedReader br = new BufferedReader(new FileReader(COLORS_DATA))) { + List lists = new ArrayList<>(); + String line; + while ((line = br.readLine()) != null) { + String[] strArray = line.trim().split(","); + for (String item : strArray) { + lists.add(Integer.parseInt(item.trim())); + } + } + return lists.stream().mapToInt(Integer::valueOf).toArray(); + } catch (IOException e) { + LOGGER.error("construct data error. " + e.getMessage()); + } + return new int[0]; + } + + private void imageEncode(PixelMap pixelMap, String targetPath) { + ImagePacker imagePacker = ImagePacker.create(); + assertNotNull(imagePacker); + ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions(); + packingOptions.format = "image/jpeg"; + packingOptions.quality = 100; + packingOptions.numberHint = 1; + try (OutputStream outputStream = new FileOutputStream(targetPath)) { + boolean result = imagePacker.initializePacking(outputStream, packingOptions); + assertTrue(result); + imagePacker.addImage(pixelMap); + imagePacker.finalizePacking(); + } catch (FileNotFoundException e) { + LOGGER.error("ImagePacker, file not found"); + } catch (IOException fio) { + LOGGER.error("ImagePacker, IO Exception"); + } + imagePacker.release(); + } +} diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageReceiverTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageReceiverTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fddc13bcefd7c7eaef4c493b67b8ba6f662bcdd5 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageReceiverTest.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import ohos.agp.graphics.Surface; +import ohos.media.image.ImageReceiver.IImageArrivalListener; +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.After; +import org.junit.Test; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * ImageReceiverTest, test cases for ImageReceiver class. + * + * @since 1 + */ +public class ImageReceiverTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageReceiverTest.class); + + private ImageReceiver imageReceiver; + + /** + * Action after test case. + */ + @After + public void tearDown() throws Exception { + try { + if (imageReceiver != null) { + imageReceiver.finalize(); + imageReceiver = null; + } + } catch (Throwable throwable) { + LOGGER.error("test case teardown fail, %{public}s", throwable.getMessage()); + } + } + + /** + * @tc.name: testImageReceiver001 + * @tc.desc: create ImageReceiver object and operate simple method. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageReceiver001() { + /** + * @tc.steps: step1. create image object use wrong parameters. + * @tc.expected: step1. the image object is null. + */ + try { + imageReceiver = getImageReceiver(false); + } catch (IllegalArgumentException e) { + LOGGER.error("create ImageReceiver throws exception."); + } + imageReceiver = getImageReceiver(true); + assertNotNull(imageReceiver); + /** + * @tc.steps: step2. get Surface. + * @tc.expected: step2. check the surface is not null. + */ + Surface surface = imageReceiver.getRecevingSurface(); + assertNotNull(surface); + + /** + * @tc.steps: step3. get image size. + * @tc.expected: step3. check the size is ok. + */ + Size size = imageReceiver.getImageSize(); + assertEquals(320, size.width); + assertEquals(240, size.height); + /** + * @tc.steps: step4. get the maximum number of images. + * @tc.expected: step4. check the capacity is ok. + */ + int capacity = imageReceiver.getCapacity(); + assertEquals(1, capacity); + /** + * @tc.steps: step5. get the format of image. + * @tc.expected: step5. check the format is ok. + */ + int format = imageReceiver.getImageFormat(); + assertEquals(ImageFormat.JPEG, format); + } + + /** + * @tc.name: testImageReceiver002 + * @tc.desc: read image from receiving queue. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageReceiver002() { + /** + * @tc.steps: step1. read the latest image from receiving queue. + * @tc.expected: step1. check the information is ok. + */ + imageReceiver = getImageReceiver(true); + Image image = null; + try { + image = imageReceiver.readLatestImage(); + } catch (IllegalStateException e) { + // operation will be called native, but buffer was set by app, only interface cover. + assertNull(image); + } + /** + * @tc.steps: step2. read the next image from receiving queue. + * @tc.expected: step2. check the information is ok. + */ + try { + image = imageReceiver.readNextImage(); + } catch (IllegalStateException e) { + // operation will be called native, but buffer was set by app, only interface cover. + assertNull(image); + } + } + + /** + * @tc.name: testImageReceiver003 + * @tc.desc: native event callback. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageReceiver003() { + /** + * @tc.steps: step1. native event callback. + * @tc.expected: step1. check the information is ok. + */ + imageReceiver = getImageReceiver(true); + try { + Class clazz = Class.forName("ohos.media.image.ImageReceiver"); + Method method = clazz.getDeclaredMethod("onEventFromNative", Object.class); + method.setAccessible(true); + WeakReference weakRef = new WeakReference<>(imageReceiver); + method.invoke(imageReceiver, weakRef); + } catch (Exception e) { + LOGGER.error("reflect invoke onEventFromNative throws exception."); + } + assertNotNull(imageReceiver); + } + + /** + * @tc.name: testImageReceiver004 + * @tc.desc: set image arrival listener. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageReceiver004() { + try { + /** + * @tc.steps: step1. release the image arrival listener. + * @tc.expected: step1. check the information is ok. + */ + imageReceiver = getImageReceiver(true); + IImageArrivalListener arrivalListener = new IImageArrivalListener() { + @Override + public void onImageArrival(ImageReceiver imageReceiver) { + LOGGER.debug("on image arrival."); + } + }; + imageReceiver.setImageArrivalListener(null); + Class clazz = Class.forName("ohos.media.image.ImageReceiver"); + Field field = clazz.getDeclaredField("arrivalListener"); + field.setAccessible(true); + if (field.get(imageReceiver) instanceof IImageArrivalListener) { + IImageArrivalListener attribute = (IImageArrivalListener) field.get(imageReceiver); + assertNull(attribute); + } + } catch (Exception e) { + LOGGER.error("reflect invoke arrivalListener throws exception."); + } + } + + private ImageReceiver getImageReceiver(boolean valid) { + int width = 320; + if (!valid) { + width = -1; + } + int height = 240; + int format = ImageFormat.JPEG; + int capacity = 1; + ImageReceiver newImageReceiver = ImageReceiver.create(width, height, format, capacity); + return newImageReceiver; + } +} \ No newline at end of file diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageSourceKitTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageSourceKitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4df619540b40dd15e72b2413fa8ce9bfa67da8fc --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageSourceKitTest.java @@ -0,0 +1,4228 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +import ohos.media.image.common.AllocatorType; +import ohos.media.image.common.DecodeEvent; +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.ImageInfo; +import ohos.media.image.common.MemoryUsagePreference; +import ohos.media.image.common.PixelFormat; +import ohos.media.image.common.PropertyKey; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.media.image.exifadapter.ExifAdapter; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.system.Parameters; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; +import ohos.utils.Pair; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.ArrayList; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.HashSet; +import java.util.List; + +/** + * ImageSourceKitTest, test cases for ImageSource class, mainly including test cases for image decoding functions + * + * @since 1 + */ +public class ImageSourceKitTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageSourceKitTest.class); + + private static File pngFile; + + private static final String PHONE_DEVICE = "default"; + + private static final String SHARED_MEMORY_STRING = "Ashmem"; + + private static final String HEAP_STRING = "Native"; + + private static final long CONST_NUMBER = 1000000000; + + private static final String DEVICE_TYPE = "ro.build.characteristics"; + + private boolean isPhoneDevice = false; + + private ImageSource imageSource; + + private PixelMap pixelMap; + + private ExifUtils exifUtils = new ExifUtils(); + + /** + * Action before all test case. + */ + @BeforeClass + public static void setUpBeforeClass() { + pngFile = new File("/sdcard/multimedia/image/test.png"); + if (!pngFile.exists()) { + fail("files not exist"); + } + } + + /** + * Action after all test case. + */ + @AfterClass + public static void tearDownAfterClass() { + } + + /** + * Action before test case. + */ + @Before + public void setUp() { + } + + /** + * Action after test case. + */ + @After + public void tearDown() { + try { + if (imageSource != null) { + imageSource.finalize(); + imageSource = null; + } + if (pixelMap != null) { + pixelMap.release(); + pixelMap = null; + } + } catch (Throwable throwable) { + LOGGER.error("test case teardown fail, %{public}s", throwable.getMessage()); + } + } + + /** + * @tc.name: testImageSource001 + * @tc.desc: get supported image formats. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource001() { + /** + * @tc.steps: step1.get supported image formats. + * @tc.expected: step1.supported image formats not null + */ + HashSet formats = ImageSource.getSupportedFormats(); + assertNotNull(formats); + + /** + * @tc.steps: step2.check supported image formats. + * @tc.expected: step2.supported image formats checked ok + */ + assertTrue(formats.contains("image/jpeg")); + assertTrue(formats.contains("image/png")); + assertTrue(formats.contains("image/gif")); + assertTrue(formats.contains("image/webp")); + } + + /** + * @tc.name: testImageSource002 + * @tc.desc: create image source from null stream. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource002() { + /** + * @tc.steps: step1.get image source from null input stream. + * @tc.expected: step1.throw IllegalArgumentException. + */ + FileInputStream inputStream = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(inputStream, srcOpts); + }); + } + + /** + * @tc.name: testImageSource003 + * @tc.desc: create image source from null byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource003() { + /** + * @tc.steps: step1.get image source from null byte array. + * @tc.expected: step1.throw IllegalArgumentException. + */ + byte[] soureData = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(soureData, srcOpts); + }); + } + + /** + * @tc.name: testImageSource004 + * @tc.desc: create image source from null byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource004() { + /** + * @tc.steps: step1.get image source from null byte array. + * @tc.expected: step1.throw IllegalArgumentException. + */ + byte[] soureData = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(soureData, 0, 0, srcOpts); + }); + } + + /** + * @tc.name: testImageSource005 + * @tc.desc: create image source from byte array with invalid offset. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource005() { + /** + * @tc.steps: step1.get image source from byte array with invalid offset. + * @tc.expected: step1.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource = ImageSource.create(soureData, -1, 0, srcOpts); + }); + } + + /** + * @tc.name: testImageSource006 + * @tc.desc: create image source from byte array with invalid length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource006() { + /** + * @tc.steps: step1.get image source from byte array with invalid length. + * @tc.expected: step1.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource = ImageSource.create(soureData, 0, -1, srcOpts); + }); + } + + /** + * @tc.name: testImageSource007 + * @tc.desc: create image source from byte array with invalid offset. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource007() { + /** + * @tc.steps: step1.get image source from byte array with invalid offset. + * @tc.expected: step1.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource = ImageSource.create(soureData, soureData.length, soureData.length, srcOpts); + }); + } + + /** + * @tc.name: testImageSource008 + * @tc.desc: create image source from byte array with invalid offset and length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource008() { + /** + * @tc.steps: step1.get image source from byte array with invalid offset and length. + * @tc.expected: step1.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource = ImageSource.create(soureData, 1, soureData.length, srcOpts); + }); + } + + /** + * @tc.name: testImageSource009 + * @tc.desc: create image source from null path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource009() { + /** + * @tc.steps: step1.get image source from null path. + * @tc.expected: step1.throw IllegalArgumentException. + */ + String pathName = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(pathName, srcOpts); + }); + } + + /** + * @tc.name: testImageSource010 + * @tc.desc: create image source from empty image path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource010() { + /** + * @tc.steps: step1.get image source from emplty image path. + * @tc.expected: step1.throw IllegalArgumentException. + */ + String pathName = ""; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(pathName, srcOpts); + }); + } + + /** + * @tc.name: testImageSource011 + * @tc.desc: create image source from unavailable image path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource011() { + /** + * @tc.steps: step1.get image source from unavailable image path. + * @tc.expected: step1.throw DataSourceUnavailableException. + */ + String pathName = "/random/to/image.jpg"; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw DataSourceUnavailableException", DataSourceUnavailableException.class, () -> { + imageSource = ImageSource.create(pathName, srcOpts); + }); + } + + /** + * @tc.name: testImageSource012 + * @tc.desc: create image source from null File object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource012() { + /** + * @tc.steps: step1.get image source from null File object. + * @tc.expected: step1.throw IllegalArgumentException. + */ + File imageFile = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(imageFile, srcOpts); + }); + } + + /** + * @tc.name: testImageSource013 + * @tc.desc: create image source from null FileDescriptor object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource013() { + /** + * @tc.steps: step1.get image source from null FileDescriptor object. + * @tc.expected: step1.throw IllegalArgumentException. + */ + FileDescriptor imageFile = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource = ImageSource.create(imageFile, srcOpts); + }); + } + + /** + * @tc.name: testImageSource014 + * @tc.desc: create pixel map from invalid index. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource014() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map from invalid index. + * @tc.expected: step2.throw IllegalArgumentException. + */ + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + pixelMap = imageSource.createPixelmap(-1, null); + }); + } + + /** + * @tc.name: testImageSource015 + * @tc.desc: create pixel map from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource015() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + pixelMap = imageSource.createPixelmap(0, null); + }); + } + + /** + * @tc.name: testImageSource016 + * @tc.desc: create thumbnail pixel map from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource016() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get thumbnail pixel map from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + pixelMap = imageSource.createThumbnailPixelmap(null, false); + }); + } + + /** + * @tc.name: testImageSource017 + * @tc.desc: create pixel map image info by invalid index. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource017() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map image info by invalid index. + * @tc.expected: step2.throw IllegalArgumentException. + */ + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource.getImageInfo(-1); + }); + } + + /** + * @tc.name: testImageSource018 + * @tc.desc: create pixel map image info from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource018() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map image info from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getImageInfo(0); + }); + } + + /** + * @tc.name: testImageSource019 + * @tc.desc: get pixel map image property by null key. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource019() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map image property by null key. + * @tc.expected: step2.throw IllegalArgumentException. + */ + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource.getImagePropertyString(null); + }); + } + + /** + * @tc.name: testImageSource020 + * @tc.desc: get pixel map image property by empty key. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource020() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map image property by empty key. + * @tc.expected: step2.check null. + */ + assertNull(imageSource.getImagePropertyString("")); + } + + /** + * @tc.name: testImageSource021 + * @tc.desc: get pixel map image property from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource021() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map image property from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getImagePropertyString(PropertyKey.Exif.APERTURE_VALUE); + }); + } + + /** + * @tc.name: testImageSource022 + * @tc.desc: get pixel map thumbnail from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource022() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map thumbnail from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getThumbnailInfo(); + }); + } + + /** + * @tc.name: testImageSource023 + * @tc.desc: get source info from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource023() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get source info from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getSourceInfo(); + }); + } + + /** + * @tc.name: testImageSource024 + * @tc.desc: update incremental image source with a null byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource024() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.update data with a null byte array. + * @tc.expected: step2.throw IllegalArgumentException. + */ + byte[] soureData = null; + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource.updateData(soureData, 0, 0, false); + }); + } + + /** + * @tc.name: testImageSource025 + * @tc.desc: update incremental image source from byte array with invalid offset. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource025() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.update data from byte array with invalid offset. + * @tc.expected: step2.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource.updateData(soureData, -1, 0, false); + }); + } + + /** + * @tc.name: testImageSource026 + * @tc.desc: update incremental image source from byte array with invalid length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource026() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.update data from byte array with invalid length. + * @tc.expected: step2.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource.updateData(soureData, 0, -1, false); + }); + } + + /** + * @tc.name: testImageSource027 + * @tc.desc: update incremental image source from byte array with invalid offset. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource027() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.update data from byte array with invalid offset. + * @tc.expected: step2.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource.updateData(soureData, soureData.length, soureData.length, false); + }); + } + + /** + * @tc.name: testImageSource028 + * @tc.desc: update incremental image source from byte array with invalid offset and length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource028() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.update data from byte array with invalid offset and length. + * @tc.expected: step2.throw IndexOutOfBoundsException. + */ + byte[] soureData = new byte[10]; + assertThrows("should throw IndexOutOfBoundsException", IndexOutOfBoundsException.class, () -> { + imageSource.updateData(soureData, 1, soureData.length, false); + }); + } + + /** + * @tc.name: testImageSource029 + * @tc.desc: update date with released incremental image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource029() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.update data from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + byte[] soureData = new byte[10]; + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.updateData(soureData, 0, soureData.length, false); + }); + } + + /** + * @tc.name: testImageSource030 + * @tc.desc: get pixel map thumbnail data from released image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource030() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + + /** + * @tc.steps: step2.get pixel map thumbnail data from released image source. + * @tc.expected: step2.throw IllegalStateException. + */ + imageSource.release(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getImageThumbnailBytes(); + }); + } + + /** + * @tc.name: testImageSource031 + * @tc.desc: get pixel map from incomplete image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource031() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + byte[] data = null; + try { + data = Files.readAllBytes(Paths.get(pathName)); + } catch (IOException e) { + fail("file read exception"); + } + imageSource = ImageSource.create(data, 0, data.length - 100, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map from incomplete image source. + * @tc.expected: step2.throw SourceDataIncompleteException. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allowPartialImage = false; + + assertThrows("should throw SourceDataIncompleteException", SourceDataIncompleteException.class, () -> { + imageSource.createPixelmap(decodingOpts); + }); + } + + /** + * @tc.name: testImageSource032 + * @tc.desc: get pixel map from malformed image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource032() { + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + byte[] data = null; + try { + data = Files.readAllBytes(Paths.get(pathName)); + } catch (IOException e) { + fail("file read exception"); + } + data[0] = 0xa; + imageSource = ImageSource.create(data, 0, data.length, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map from malformed image source. + * @tc.expected: step2.throw SourceDataMalformedException. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allowPartialImage = false; + + assertThrows("should throw SourceDataMalformedException", SourceDataMalformedException.class, () -> { + imageSource.createPixelmap(decodingOpts); + }); + } + + /** + * @tc.name: testImageSource033 + * @tc.desc: get pixel map from ByteBuffer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource033() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + + /** + * @tc.steps: step1.get image source ByteBuffer. + * @tc.expected: step1.get image source form ByteBuffer not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate((int) channel.size()); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + imageSource = ImageSource.create(byteBuffer, null); + assertNotNull(imageSource); + assertEquals(472, imageSource.getImageInfo().size.width); + assertEquals(226, imageSource.getImageInfo().size.height); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSource034 + * @tc.desc: get pixel map from ByteBuffer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource034() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + + /** + * @tc.steps: step1.get image source from null ByteBuffer. + * @tc.expected: step1.throw illegal argument exception + */ + ByteBuffer byteBuffer = null; + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + assertThrows("data is null", IllegalArgumentException.class, () -> { + ImageSource.create(byteBuffer, srcOpts); + }); + } + + /** + * @tc.name: testImageSource035 + * @tc.desc: get pixel map from ByteBuffer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource035() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + + /** + * @tc.steps: step1.get image source ByteBuffer. + * @tc.expected: step1.get image source form ByteBuffer not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate((int)channel.size()/2); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + imageSource = ImageSource.create(byteBuffer, null); + assertNotNull(imageSource); + assertEquals(472, imageSource.getImageInfo().size.width); + assertEquals(226, imageSource.getImageInfo().size.height); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + imageSource.release(); + pixelMap.release(); + } + + /** + * @tc.name: testImageSource036 + * @tc.desc: get pixel map from ByteBuffer. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource036() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + + /** + * @tc.steps: step1.get image source ByteBuffer. + * @tc.expected: step1.get image source form ByteBuffer not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate(1); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + imageSource = ImageSource.create(byteBuffer, null); + assertNotNull(imageSource); + assertNull(imageSource.getImageInfo()); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + assertThrows("should throw SourceDataIncompleteException", SourceDataIncompleteException.class, () -> { + imageSource.createPixelmap(decodingOpts); + }); + } + + /** + * @tc.name: testImageSource037 + * @tc.desc: get ImageInfo test. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSource037() { + isPhoneDevice = PHONE_DEVICE.equals(Parameters.get(DEVICE_TYPE)); + LOGGER.debug("device type is PHONE: %{public}s", isPhoneDevice); + if (!isPhoneDevice) { + return; + } + + /** + * @tc.steps: step1.get image source ByteBuffer. + * @tc.expected: step1.get image source form ByteBuffer not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate((int) channel.size()); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + imageSource = ImageSource.create(byteBuffer, null); + assertNotNull(imageSource); + assertEquals(472, imageSource.getImageInfo().size.width); + assertEquals(226, imageSource.getImageInfo().size.height); + assertTrue(imageSource.getImageInfo().toString().contains("pixelFormat")); + } + + /** + * @tc.name: testImageSourcePng001 + * @tc.desc: create image source from file path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/png", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + assertEquals(472, imageSource.getImageInfo().size.width); + assertEquals(75, imageSource.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourcePng002 + * @tc.desc: create image source from byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng002() { + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/png"; + String pathName = "/sdcard/multimedia/image/test.png"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(0, decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + assertEquals(472, imageSource.getImageInfo(0).size.width); + assertEquals(75, imageSource.getImageInfo(0).size.height); + } + + /** + * @tc.name: testImageSourcePng003 + * @tc.desc: create image source from byte array with offset and length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng003() { + /** + * @tc.steps: step1.get image source byte array with offset and length. + * @tc.expected: step1.get image source form byte array with offset and length not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, 0, data.length, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourcePng004 + * @tc.desc: create image source from File. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng004() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourcePng005 + * @tc.desc: create image source from FileDescriptor. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng005() { + /** + * @tc.steps: step1.get image source FileDescriptor. + * @tc.expected: step1.get image source form FileDescriptor not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + FileDescriptor fileDescriptor; + try (FileInputStream inputStream = new FileInputStream(pathName)) { + fileDescriptor = inputStream.getFD(); + imageSource = ImageSource.create(fileDescriptor, srcOpts); + assertNotNull(imageSource); + } catch (FileNotFoundException fe) { + LOGGER.error("createImageSource from InputStream, file not found."); + } catch (IOException fio) { + LOGGER.error("createImageSource from InputStream, IO Exception"); + } + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourcePng006 + * @tc.desc: create image source from InputStream. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng006() { + /** + * @tc.steps: step1.get image source InputStream. + * @tc.expected: step1.get image source form InputStream not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/png"; + String pathName = "/sdcard/multimedia/image/test.png"; + try (InputStream inputStream = new FileInputStream(pathName)) { + imageSource = ImageSource.create(inputStream, srcOpts); + assertNotNull(imageSource); + } catch (FileNotFoundException fe) { + LOGGER.error("createImageSource from InputStream, file not found"); + } catch (IOException ioe) { + LOGGER.error("file read io exception"); + } + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourcePng007 + * @tc.desc: create incremental image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourcePng007() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.createIncrementalSource(srcOpts); + + String pathName = "/sdcard/multimedia/image/test.png"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read io exception"); + fail("file read exception"); + } + imageSource.updateData(data, true); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceNinePathcPng001 + * @tc.desc: The upper-layer application(ex:graphic) obtained nine patch info from the .9.png file. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceNinePathcPng001() { + /** + * @tc.steps: step1.get image source from test.9.png file. + * @tc.expected: step1.get image source form File not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.9.png"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map by image source. + * @tc.expected: step2.create pixel map not null. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step3.get nine patch info from pixelmap, fill the content (ex:text,sound) + * and send or display by adjust (stretch) the nine patch info + * @tc.expected: step3.nine patch info is not null. + */ + byte[] result = pixelMap.getNinePatchChunk(); + assertNotNull(result); + } + + /** + * @tc.name: testImageSourceJpg001 + * @tc.desc: create image source from file path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, null); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/jpeg", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + assertEquals(472, imageSource.getImageInfo().size.width); + assertEquals(226, imageSource.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg002 + * @tc.desc: create image source from byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg002() { + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(0, null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg003 + * @tc.desc: create image source from byte array with offset and length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg003() { + /** + * @tc.steps: step1.get image source byte array with offset and length. + * @tc.expected: step1.get image source form byte array with offset and length not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, 0, data.length, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg004 + * @tc.desc: create image source from File. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg004() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg005 + * @tc.desc: create image source from FileDescriptor. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg005() { + /** + * @tc.steps: step1.get image source FileDescriptor. + * @tc.expected: step1.get image source form FileDescriptor not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + FileDescriptor fileDescriptor; + try (FileInputStream inputStream = new FileInputStream(pathName)) { + fileDescriptor = inputStream.getFD(); + imageSource = ImageSource.create(fileDescriptor, null); + ExifAdapter exifAdapter = new ExifAdapter(fileDescriptor); + assertNotNull(imageSource); + } catch (FileNotFoundException fe) { + LOGGER.error("createImageSource from InputStream, file not found."); + } catch (IOException fio) { + LOGGER.error("createImageSource from InputStream, IO Exception"); + } + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg006 + * @tc.desc: create image source from InputStream. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg006() { + /** + * @tc.steps: step1.get image source InputStream. + * @tc.expected: step1.get image source form InputStream not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + try (InputStream inputStream = new FileInputStream(pathName)) { + imageSource = ImageSource.create(inputStream, null); + ExifAdapter exifAdapter = new ExifAdapter(inputStream); + assertNotNull(imageSource); + } catch (FileNotFoundException fe) { + LOGGER.error("createImageSource from InputStream, file not found"); + } catch (IOException ioe) { + LOGGER.error("file read io exception"); + } + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg007 + * @tc.desc: create incremental image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg007() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = null; + imageSource = ImageSource.createIncrementalSource(srcOpts); + + String pathName = "/sdcard/multimedia/image/test.jpg"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read io exception"); + fail("file read exception"); + } + imageSource.updateData(data, true); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceJpg008 + * @tc.desc: create incremental image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg008() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.IncrementalSourceOptions incOpts = null; + imageSource = ImageSource.createIncrementalSource(incOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + final int size = 100; + byte[] data = new byte[size]; + File file = new File(pathName); + try (FileInputStream fileInputStream = new FileInputStream(file)) { + int bytes = 0; + while (bytes != -1) { + bytes = fileInputStream.read(data); + if (bytes == -1) { + break; + } + boolean isFinal = (bytes != size); + imageSource.updateData(data, 0, bytes, isFinal); + pixelMap = imageSource.createPixelmap(null); + assertNotNull(pixelMap); + if (pixelMap.getImageInfo().size.width == 0) { + continue; + } + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + pixelMap.release(); + } + } catch (IOException e) { + fail("file read exception"); + } + } + + /** + * @tc.name: testImageSourceJpg009 + * @tc.desc: decode editable pixel map + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg009() { + /** + * @tc.steps: step1. decode webp file to get editable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.jpg", null); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step1. check pixel map if editable. + * @tc.expected: step1. check ok. + */ + assertTrue(pixelMap.isEditable()); + } + + /** + * @tc.name: testImageSourceJpg010 + * @tc.desc: decode uneditable pixel map + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceJpg010() { + /** + * @tc.steps: step1. decode webp file to get uneditable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.jpg", null); + assertNotNull(imageSource); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = false; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step1. check pixel map if editable. + * @tc.expected: step1. check ok. + */ + assertFalse(pixelMap.isEditable()); + } + + /** + * @tc.name: testImageSourceExif001 + * @tc.desc: get image exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif001() { + /** + * @tc.steps: step1.get imagesource. + * @tc.expected: step1.imagesource not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif info. + * @tc.expected: step2.check image exif info not null and ok. + */ + byte[] thumbnailData = imageSource.getImageThumbnailBytes(); + assertNotNull(thumbnailData); + assertEquals(ImageFormat.JPEG, imageSource.getThumbnailFormat()); + + /** + * @tc.steps: step3.get image thumbnail pixel map. + * @tc.expected: step3.check thumbnail pixel map ok. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNotNull(thumbnailPixelmap); + PixelMap thumbnailPixelmap2 = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNotNull(thumbnailPixelmap2); + assertEquals(160, thumbnailPixelmap.getImageInfo().size.width); + assertEquals(120, thumbnailPixelmap.getImageInfo().size.height); + assertEquals(160, imageSource.getThumbnailInfo().size.width); + assertEquals(120, imageSource.getThumbnailInfo().size.height); + + /** + * @tc.steps: step4.get image property info. + * @tc.expected: step4.check image property info ok. + */ + PropertyKey.Exif exif = new PropertyKey.Exif(); + assertEquals("6", imageSource.getImagePropertyString(PropertyKey.Exif.COMPRESSION)); + assertEquals(5952, imageSource.getImagePropertyInt(PropertyKey.Exif.PIXEL_X_DIMENSION, 0)); + } + + /** + * @tc.name: testImageSourceExif002 + * @tc.desc: get image thumbnail pixel map from image without exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif002() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif thumbnail from original image. + * @tc.expected: step2.check image thumbnail info not null and ok. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(40, 10); + PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, true); + assertNotNull(thumbnailPixelmap); + assertEquals(40, thumbnailPixelmap.getImageInfo().size.width); + assertEquals(10, thumbnailPixelmap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceExif003 + * @tc.desc: get image exif thumbnail data from image without exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif003() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif info. + * @tc.expected: step2.check image exif info null. + */ + assertThrows("should throw UnsupportedOperationException", UnsupportedOperationException.class, () -> { + imageSource.getImageThumbnailBytes(); + }); + } + + /** + * @tc.name: testImageSourceExif004 + * @tc.desc: get image exif thumbnail pixel map from image without exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif004() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image thumbnail info. + * @tc.expected: step2.check image thumbnail info null. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNull(thumbnailPixelmap); + } + + /** + * @tc.name: testImageSourceExif005 + * @tc.desc: get image exif thumbnail info from image without exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif005() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif thumbnail info. + * @tc.expected: step2.check image exif thumbnail info null. + */ + assertThrows("should throw UnsupportedOperationException", UnsupportedOperationException.class, () -> { + imageSource.getThumbnailInfo(); + }); + } + + /** + * @tc.name: testImageSourceExif006 + * @tc.desc: get image exif tag info from image without exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif006() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif tag info. + * @tc.expected: step2.check image exif tag info null. + */ + assertNull(imageSource.getImagePropertyString(PropertyKey.Exif.COMPRESSION)); + } + + /** + * @tc.name: testImageSourceExif007 + * @tc.desc: get image exif thumbnail data when source released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif007() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + imageSource.release(); + + /** + * @tc.steps: step2.get image exif thumbnail data. + * @tc.expected: step2.check exception ok. + */ + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getImageThumbnailBytes(); + }); + } + + /** + * @tc.name: testImageSourceExif008 + * @tc.desc: get image exif thumbnail pixel map when source released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif008() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.imagesource not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + imageSource.release(); + + /** + * @tc.steps: step2.get image exif thumbnail pixel map. + * @tc.expected: step2.check image exif thumbnail pixel map exception. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.createThumbnailPixelmap(decodingOpts, false); + }); + } + + /** + * @tc.name: testImageSourceExif009 + * @tc.desc: get image exif thumbnail info when source released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif009() { + /** + * @tc.steps: step1.get imagesource. + * @tc.expected: step1.imagesource not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + imageSource.release(); + + /** + * @tc.steps: step2.get image exif thumbnail info. + * @tc.expected: step2.check image exif thumbnail info exception. + */ + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getThumbnailInfo(); + }); + } + + /** + * @tc.name: testImageSourceExif010 + * @tc.desc: get image exif info when source released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif010() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + imageSource.release(); + + /** + * @tc.steps: step2.get image exif info. + * @tc.expected: step2.check image exif info exception. + */ + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getImagePropertyString(PropertyKey.Exif.COMPRESSION); + }); + } + + /** + * @tc.name: testImageSourceExif011 + * @tc.desc: get image exif info when source released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif011() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif info. + * @tc.expected: step2.check image exif info exception. + */ + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + imageSource.getImagePropertyString(null); + }); + } + + /** + * @tc.name: testImageSourceExif012 + * @tc.desc: check whether image has thumbnail on image without exif. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif012() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif thumbnail info. + * @tc.expected: step2.check image exif thumbnail info false. + */ + assertThrows("should throw UnsupportedOperationException", UnsupportedOperationException.class, () -> { + imageSource.getThumbnailInfo(); + }); + } + + /** + * @tc.name: testImageSourceExif013 + * @tc.desc: check whether image has thumbnail on image with exif. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif013() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif thumbnail info. + * @tc.expected: step2.check image exif thumbnail info ok. + */ + assertNotNull(imageSource.getThumbnailInfo()); + } + + /** + * @tc.name: testImageSourceExif014 + * @tc.desc: get image exif latitude and longitude info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif014() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif latitude and longitude info. + * @tc.expected: step2.check image exif info ok. + */ + Pair latlong = ExifUtils.getLatLong(imageSource); + assertEquals(31.258055, latlong.f, 1e-6); + assertEquals(121.619164, latlong.s, 1e-6); + } + + /** + * @tc.name: testImageSourceExif015 + * @tc.desc: get image exif latitude and longitude info which not exist. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif015() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif latitude and longitude info. + * @tc.expected: step2.check image exif info ok. + */ + assertNull(ExifUtils.getLatLong(imageSource)); + } + + /** + * @tc.name: testImageSourceExif016 + * @tc.desc: get image exif altitude info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif016() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif altitude info. + * @tc.expected: step2.check image exif info ok. + */ + double defaultValue = 1.0; + assertEquals(0.0, ExifUtils.getAltitude(imageSource, defaultValue), 1e-6); + } + + /** + * @tc.name: testImageSourceExif017 + * @tc.desc: get image exif altitude info which not exist. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif017() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif altitude info. + * @tc.expected: step2.check image exif info ok. + */ + double defaultValue = 1.0; + assertEquals(defaultValue, ExifUtils.getAltitude(imageSource, defaultValue), 1e-6); + } + + /** + * @tc.name: testImageSourceExif018 + * @tc.desc: get image exif info with byte array image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif018() { + /** + * @tc.steps: step1.get image source from byte array. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif info. + * @tc.expected: step2.check image exif info not null and ok. + */ + byte[] thumbnailData = imageSource.getImageThumbnailBytes(); + assertNotNull(thumbnailData); + assertEquals(ImageFormat.JPEG, imageSource.getThumbnailFormat()); + + /** + * @tc.steps: step3.get image thumbnail pixel map. + * @tc.expected: step3.check thumbnail pixel map ok. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNotNull(thumbnailPixelmap); + PixelMap thumbnailPixelmap2 = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNotNull(thumbnailPixelmap2); + assertEquals(160, thumbnailPixelmap.getImageInfo().size.width); + assertEquals(120, thumbnailPixelmap.getImageInfo().size.height); + assertEquals(160, imageSource.getThumbnailInfo().size.width); + assertEquals(120, imageSource.getThumbnailInfo().size.height); + + /** + * @tc.steps: step4.get image property info. + * @tc.expected: step4.check image property info ok. + */ + assertEquals("6", imageSource.getImagePropertyString(PropertyKey.Exif.COMPRESSION)); + assertEquals(5952, imageSource.getImagePropertyInt(PropertyKey.Exif.PIXEL_X_DIMENSION, 0)); + } + + /** + * @tc.name: testImageSourceExif019 + * @tc.desc: get image exif thumbnail format from image without exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif019() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif thumbnail format info. + * @tc.expected: step2.check image exif thumbnail format info exception. + */ + assertThrows("should throw UnsupportedOperationException", UnsupportedOperationException.class, () -> { + imageSource.getThumbnailFormat(); + }); + } + + /** + * @tc.name: testImageSourceExif020 + * @tc.desc: get image exif info with file image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceExif020() { + /** + * @tc.steps: step1.get image source from file object. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image exif info. + * @tc.expected: step2.check image exif info not null and ok. + */ + byte[] thumbnailData = imageSource.getImageThumbnailBytes(); + assertNotNull(thumbnailData); + assertEquals(ImageFormat.JPEG, imageSource.getThumbnailFormat()); + + /** + * @tc.steps: step3.get image thumbnail pixel map. + * @tc.expected: step3.check thumbnail pixel map ok. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap thumbnailPixelmap = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNotNull(thumbnailPixelmap); + PixelMap thumbnailPixelmap2 = imageSource.createThumbnailPixelmap(decodingOpts, false); + assertNotNull(thumbnailPixelmap2); + assertEquals(160, thumbnailPixelmap.getImageInfo().size.width); + assertEquals(120, thumbnailPixelmap.getImageInfo().size.height); + assertEquals(160, imageSource.getThumbnailInfo().size.width); + assertEquals(120, imageSource.getThumbnailInfo().size.height); + + /** + * @tc.steps: step4.get image property info. + * @tc.expected: step4.check image property info ok. + */ + assertEquals("6", imageSource.getImagePropertyString(PropertyKey.Exif.COMPRESSION)); + assertEquals(5952, imageSource.getImagePropertyInt(PropertyKey.Exif.PIXEL_X_DIMENSION, 0)); + } + + /** + * test get inner thumbnail. + * + * @tc.name: testGetInnerJpegThumbnail010 + * @tc.desc: test get inner thumbnail. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerJpegThumbnail010() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + byte[] thumbnailData = imageSource.getInnerJpegThumbnail(); + assertNotNull(thumbnailData); + imageSource.release(); + } + + /** + * test get inner thumbnail from jpeg after released. + * + * @tc.name: testGetInnerJpegThumbnail020 + * @tc.desc: test get inner thumbnail from jpeg after released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerJpegThumbnail020() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + imageSource.release(); + + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getInnerJpegThumbnail(); + }); + } + + /** + * test get inner thumbnail from jpeg without thumbnail. + * + * @tc.name: testGetInnerJpegThumbnail030 + * @tc.desc: test get inner thumbnail from jpeg without thumbnail. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerJpegThumbnail030() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + byte[] thumbnailData = imageSource.getInnerJpegThumbnail(); + assertEquals(thumbnailData, null); + imageSource.release(); + } + + /** + * test get inner thumbnail from jpeg with exception. + * + * @tc.name: testGetInnerJpegThumbnail040 + * @tc.desc: test get inner thumbnail from jpeg with exception. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerJpegThumbnail040() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + InputStream inputStream = null; + try { + inputStream = new FileInputStream(pathName); + imageSource = ImageSource.create(inputStream, srcOpts); + assertNotNull(imageSource); + } catch (FileNotFoundException | IllegalArgumentException e) { + fail("file read exception"); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getInnerJpegThumbnail(); + }); + imageSource.release(); + } + + /** + * test get inner thumbnail from jpeg and assert size of thumbnail. + * + * @tc.name: testGetInnerJpegThumbnail050 + * @tc.desc: test get and compare inner thumbnail size from jpeg. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerJpegThumbnail050() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + byte[] thumbnailData = imageSource.getInnerJpegThumbnail(); + ImageSource newImageSource = ImageSource.create(thumbnailData, null); + PixelMap craetedThumb = newImageSource.createPixelmap(null); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap innerThumb = imageSource.createThumbnailPixelmap(decodingOpts, false); + + assertEquals(innerThumb.getImageInfo().size.width, craetedThumb.getImageInfo().size.width); + assertEquals(innerThumb.getImageInfo().size.height, craetedThumb.getImageInfo().size.height); + imageSource.release(); + newImageSource.release(); + } + + /** + * test get inner thumbnail from jpeg and assert created thumbnail. + * + * @tc.name: testGetInnerJpegThumbnail060 + * @tc.desc: test get inner thumbnail from jpeg and assert size of thumbnail. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerJpegThumbnail060() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_hw.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + byte[] thumbnailData = imageSource.getInnerJpegThumbnail(); + assertNotNull(thumbnailData); + + int hightFromTag = imageSource.getImagePropertyInt(PropertyKey.Exif.THUMBNAIL_IMAGE_LENGTH, 160); + int widthFromTag = imageSource.getImagePropertyInt(PropertyKey.Exif.THUMBNAIL_IMAGE_WIDTH, 120); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + ImageSource newImageSource = ImageSource.create(thumbnailData, null); + PixelMap thumbnailPixelmap = newImageSource.createPixelmap(null); + + assertEquals(hightFromTag, thumbnailPixelmap.getImageInfo().size.height); + assertEquals(widthFromTag, thumbnailPixelmap.getImageInfo().size.width); + imageSource.release(); + newImageSource.release(); + } + + /** + * test get inner thumbnail scope. + * + * @tc.name: testGetInnerThumbnailScope010 + * @tc.desc: test get inner thumbnail scope. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerThumbnailScope010() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + byte[] thumbnailData = imageSource.getInnerJpegThumbnail(); + assertNotNull(thumbnailData); + + long[] range = imageSource.getInnerThumbnailScope(); + assertNotNull(range); + imageSource.release(); + } + + /** + * test get inner thumbnail scope and assert offset and length in scope. + * + * @tc.name: testGetInnerThumbnailScope020 + * @tc.desc: test get inner thumbnail scope and assert offset and length in scope. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerThumbnailScope020() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + long[] range = imageSource.getInnerThumbnailScope(); + assertEquals(5448L, range[0]); + assertEquals(18601L, range[1]); + imageSource.release(); + } + + /** + * test get inner thumbnail scope. + * + * @tc.name: testGetInnerThumbnailScope030 + * @tc.desc: test get inner thumbnail scope from a jpeg without thumbnail. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerThumbnailScope030() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + byte[] thumbnailData = imageSource.getInnerJpegThumbnail(); + assertEquals(thumbnailData, null); + + long[] range = imageSource.getInnerThumbnailScope(); + assertEquals(range, null); + imageSource.release(); + } + + /** + * test get inner thumbnail scope after source released. + * + * @tc.name: testGetInnerThumbnailScope040 + * @tc.desc: test get inner thumbnail scope after source released. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerThumbnailScope040() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + imageSource.release(); + + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getInnerThumbnailScope(); + }); + } + + /** + * test get inner thumbnail scope with exception. + * + * @tc.name: testGetInnerThumbnailScope050 + * @tc.desc: test get inner thumbnail scope with exception. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testGetInnerThumbnailScope050() { + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/jpeg"; + String pathName = "/sdcard/multimedia/image/test_exif.jpg"; + InputStream inputStream = null; + try { + inputStream = new FileInputStream(pathName); + imageSource = ImageSource.create(inputStream, srcOpts); + assertNotNull(imageSource); + } catch (FileNotFoundException | IllegalArgumentException e) { + fail("file read exception"); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + imageSource.getInnerThumbnailScope(); + }); + imageSource.release(); + } + + /** + * @tc.name: testImageSourceGif001 + * @tc.desc: get image property loop count. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceGif001() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/gif"; + String pathName = "/sdcard/multimedia/image/moving_test.gif"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + PropertyKey.GIF gif = new PropertyKey.GIF(); + + /** + * @tc.steps: step2.get image property loop count. + * @tc.expected: step2.check image loop count ok. + */ + int defaultValue = 10; + assertEquals(0, imageSource.getImagePropertyInt(-1, PropertyKey.GIF.LOOP_COUNT, defaultValue)); + assertEquals(0, imageSource.getImagePropertyInt(0, PropertyKey.GIF.LOOP_COUNT, defaultValue)); + assertEquals(0, imageSource.getImagePropertyInt(1, PropertyKey.GIF.LOOP_COUNT, defaultValue)); + assertEquals(0, imageSource.getImagePropertyInt(2, PropertyKey.GIF.LOOP_COUNT, defaultValue)); + assertEquals(0, imageSource.getImagePropertyInt(3, PropertyKey.GIF.LOOP_COUNT, defaultValue)); + + /** + * @tc.steps: step2.get image property delay time. + * @tc.expected: step2.check image delay time ok. + */ + assertNotEquals(70, imageSource.getImagePropertyInt(-1, PropertyKey.GIF.DELAY_TIME, defaultValue)); + assertEquals(70, imageSource.getImagePropertyInt(0, PropertyKey.GIF.DELAY_TIME, defaultValue)); + assertEquals(70, imageSource.getImagePropertyInt(1, PropertyKey.GIF.DELAY_TIME, defaultValue)); + assertEquals(70, imageSource.getImagePropertyInt(2, PropertyKey.GIF.DELAY_TIME, defaultValue)); + assertNotEquals(70, imageSource.getImagePropertyInt(3, PropertyKey.GIF.DELAY_TIME, defaultValue)); + } + + /** + * @tc.name: testImageSourceGif002 + * @tc.desc: get image property loop count. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceGif002() { + /** + * @tc.steps: step1.get image source. + * @tc.expected: step1.image source not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/gif"; + String pathName = "/sdcard/multimedia/image/test.gif"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.get image property loop count. + * @tc.expected: step2.check image loop count ok. + */ + int defaultValue = 10; + assertEquals(0, imageSource.getImagePropertyInt(PropertyKey.GIF.LOOP_COUNT, defaultValue)); + + /** + * @tc.steps: step2.get image property delay time. + * @tc.expected: step2.check image delay time ok. + */ + assertEquals(70, imageSource.getImagePropertyInt(PropertyKey.GIF.DELAY_TIME, defaultValue)); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.RGB_565; + pixelMap = imageSource.createPixelmap(decodingOpts); + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.RGB_565, pixelFormat); + } + + /** + * @tc.name: testImageSourceWebp001 + * @tc.desc: create image source from file path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.webp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/webp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(286, pixelMap.getImageInfo().size.width); + assertEquals(221, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWebp002 + * @tc.desc: create image source from byte array. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp002() { + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/webp"; + String pathName = "/sdcard/multimedia/image/test.webp"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(0, decodingOpts); + assertNotNull(pixelMap); + assertEquals(286, pixelMap.getImageInfo().size.width); + assertEquals(221, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWebp003 + * @tc.desc: create image source from byte array with offset and length. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp003() { + /** + * @tc.steps: step1.get image source byte array with offset and length. + * @tc.expected: step1.get image source form byte array with offset and length not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.webp"; + Path fileLocation = Paths.get(pathName); + byte[] data = null; + try { + data = Files.readAllBytes(fileLocation); + } catch (IOException e) { + LOGGER.error("file read exception"); + fail("file read exception"); + } + imageSource = ImageSource.create(data, 0, data.length, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(286, pixelMap.getImageInfo().size.width); + assertEquals(221, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWebp004 + * @tc.desc: create image source from File. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp004() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.webp"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(1000, 500); + decodingOpts.desiredRegion = new Rect(10, 10, 187, 152); + decodingOpts.rotateDegrees = 90; + decodingOpts.desiredPixelFormat = PixelFormat.BGRA_8888; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(1000, pixelMap.getImageInfo().size.width); + assertEquals(500, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWebp005 + * @tc.desc: create image source from InputStream. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp005() { + /** + * @tc.steps: step1.get image source InputStream. + * @tc.expected: step1.get image source form InputStream not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.formatHint = "image/webp"; + String pathName = "/sdcard/multimedia/image/test.webp"; + try (InputStream inputStream = new FileInputStream(pathName)) { + imageSource = ImageSource.create(inputStream, srcOpts); + assertNotNull(imageSource); + } catch (FileNotFoundException fe) { + LOGGER.error("createImageSource from InputStream, file not found"); + } catch (IOException ioe) { + LOGGER.error("file read io exception"); + } + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + decodingOpts.rotateDegrees = 180; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(286, pixelMap.getImageInfo().size.width); + assertEquals(221, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWebp006 + * @tc.desc: create incremental image source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp006() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource.IncrementalSourceOptions incOpts = new ImageSource.IncrementalSourceOptions(); + incOpts.opts = srcOpts; + incOpts.mode = ImageSource.UpdateMode.INCREMENTAL_DATA; + imageSource = ImageSource.createIncrementalSource(incOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(100, 60); + decodingOpts.desiredRegion = new Rect(10, 10, 150, 120); + decodingOpts.rotateDegrees = 90; + decodingOpts.desiredPixelFormat = PixelFormat.BGRA_8888; + decodingOpts.allowPartialImage = true; + + String pathName = "/sdcard/multimedia/image/test.webp"; + final int size = 1024; + byte[] data = new byte[size]; + File file = new File(pathName); + try (FileInputStream fileInputStream = new FileInputStream(file)) { + int bytes = 0; + while (bytes != -1) { + bytes = fileInputStream.read(data); + if (bytes == -1) { + break; + } + boolean isFinal = (bytes != size); + imageSource.updateData(data, 0, bytes, isFinal); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + if (pixelMap.getImageInfo().size.width == 0) { + continue; + } + if (isFinal) { + assertEquals(100, pixelMap.getImageInfo().size.width); + assertEquals(60, pixelMap.getImageInfo().size.height); + } else { + assertEquals(286, pixelMap.getImageInfo().size.width); + assertEquals(221, pixelMap.getImageInfo().size.height); + } + pixelMap.release(); + } + } catch (IOException e) { + fail("file read exception"); + } + } + + /** + * @tc.name: testImageSourceWebp007 + * @tc.desc: create image source from file path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWebp007() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.webp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/webp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(0, 0); + decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(286, pixelMap.getImageInfo().size.width); + assertEquals(221, pixelMap.getImageInfo().size.height); + + PixelMap pixelMap1 = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap1); + assertEquals(286, pixelMap1.getImageInfo().size.width); + assertEquals(221, pixelMap1.getImageInfo().size.height); + } + + private static final class RawImage { + /** + * file path. + */ + public final String path; + /** + * file mime. + */ + public final String mime; + /** + * image width. + */ + public final int width; + /** + * image height. + */ + public final int height; + + RawImage(String pathName, String mime, int width, int height) { + this.path = pathName; + this.mime = mime; + this.width = width; + this.height = height; + } + } + + /** + * @tc.name: testImageSourceRaw001 + * @tc.desc: decode all raw img from file path. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceRaw001() { + RawImage[] rawImgs = new RawImage[]{ + new RawImage("/sdcard/multimedia/image/test.dng", "image/x-adobe-dng", 5976, 3992), + new RawImage("/sdcard/multimedia/image/test.arw", "image/x-sony-arw", 1920, 1080), + new RawImage("/sdcard/multimedia/image/test.cr2", "image/x-canon-cr2", 5616, 3744), + new RawImage("/sdcard/multimedia/image/test.nrw", "image/x-nikon-nrw", 4000, 3000), + new RawImage("/sdcard/multimedia/image/test.pef", "image/x-pentax-pef", 4928, 3264), + new RawImage("/sdcard/multimedia/image/test.raf", "image/x-fuji-raf", 2048, 1536), + new RawImage("/sdcard/multimedia/image/test.rw2", "image/x-panasonic-rw2", 1920, 1440), + }; + + for (RawImage img : rawImgs) { + LOGGER.info("createImageSource file :%{public}s", img.path); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.create(img.path, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + if (img.path.endsWith("dng")) { + assertEquals("image/x-adobe-dng", sourceInfo.encodedFormat); + } else { + assertEquals("image/jpeg", sourceInfo.encodedFormat); + } + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(img.width, pixelMap.getImageInfo().size.width); + assertEquals(img.height, pixelMap.getImageInfo().size.height); + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.ARGB_8888, pixelFormat); + } + } + + /** + * @tc.name: testImageSourceRaw002 + * @tc.desc: create image source by correct raw file path and wrong format hit + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceRaw002() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.dng"; + imageSource = ImageSource.create(pathName, srcOpts); + srcOpts.formatHint = "image/png"; + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/x-adobe-dng", sourceInfo.encodedFormat); + } + + /** + * @tc.name: testImageSourceRaw003 + * @tc.desc: create image source from file path with wrong data + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceRaw003() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.dng"; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate((int) channel.size()); + LOGGER.info("createImageSource file size:%{public}d", channel.size()); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + byteBuffer.put(2, (byte)12); + byteBuffer.put(3, (byte)34); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.create(byteBuffer, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/x-raw", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map should fail + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + assertThrows("should throw SourceDataMalformedException", SourceDataMalformedException.class, () -> { + imageSource.createPixelmap(decodingOpts); + }); + } + + /** + * @tc.name: testImageSourceRaw004 + * @tc.desc: decode all raw img from file path multiple times + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceRaw004() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.dng"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/x-adobe-dng", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(5976, pixelMap.getImageInfo().size.width); + assertEquals(3992, pixelMap.getImageInfo().size.height); + + PixelMap pixelMap1 = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap1); + + PixelMap pixelMap2 = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap2); + } + + /** + * @tc.name: testImageSourceWbmp001 + * @tc.desc: create image source by correct wbmp file + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWbmp001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.wbmp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/vnd.wap.wbmp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWbmp002 + * @tc.desc: create image source by wrong hint + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWbmp002() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.wbmp"; + srcOpts.formatHint = "image/png"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/vnd.wap.wbmp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testImageSourceWbmp003 + * @tc.desc: create image source by wrong wbmp file + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWbmp003() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + String pathName = "/sdcard/multimedia/image/test.wbmp"; + File file = new File(pathName); + FileChannel channel = null; + FileInputStream fileStream = null; + ByteBuffer byteBuffer = null; + try { + fileStream = new FileInputStream(file); + channel = fileStream.getChannel(); + byteBuffer = ByteBuffer.allocate((int) channel.size()); + LOGGER.info("createImageSource file size:%{public}d", channel.size()); + channel.read(byteBuffer); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + channel.close(); + } catch (IOException e) { + LOGGER.error("channel close IOException"); + } + try { + fileStream.close(); + } catch (IOException e) { + LOGGER.error("fileStream close IOException"); + } + } + + byteBuffer.put(1, (byte)12); + byteBuffer.put(2, (byte)34); + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + imageSource = ImageSource.create(byteBuffer, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/x-raw", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map should fail + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + assertThrows("should throw SourceDataMalformedException", SourceDataMalformedException.class, () -> { + imageSource.createPixelmap(decodingOpts); + }); + } + + /** + * @tc.name: testImageSourceWbmp004 + * @tc.desc: create image source multiple times + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceWbmp004() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.wbmp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals("image/vnd.wap.wbmp", sourceInfo.encodedFormat); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + PixelMap pixelMap1 = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap1); + + PixelMap pixelMap2 = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap2); + } + + /** + * @tc.name: testImageSourceBmp001 + * @tc.desc: create image source from bmp file path, decode to ARGB_8888 format pixel map, then scale/rotate/crop + * the pixel map. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageSourceBmp001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.bmp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/bmp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.set decode option about crop/rotate/scale, corp to 100*50 from [150, 10] point, + * rotate 90 degree and then scale to 100*200 size. + * @tc.expected: step2.create pixel map not null and check information ok. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredRegion = new Rect(150, 10, 100, 50); + decodingOpts.rotateDegrees = 90; + decodingOpts.desiredSize = new Size(100, 200); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + decodingOpts.allowPartialImage = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(100, pixelMap.getImageInfo().size.width); + assertEquals(200, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testMemoryPolicy001 + * @tc.desc: low memory will change pixelFormat to RGB_565 + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testMemoryPolicy001() { + /** + * @tc.steps: step1. decode jpg file to get editable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.jpg", null); + assertNotNull(imageSource); + imageSource.setMemoryUsagePreference(MemoryUsagePreference.LOW_RAM); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2. get pixelFormat from pixelMap. + * @tc.expected: step2. pixelFormat equals RGB_565. + */ + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.RGB_565, pixelFormat); + } + + /** + * @tc.name: testMemoryPolicy002 + * @tc.desc: low memory will not change pixelFormat to RGB_565, because AlphaType not equals OPAQUE + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testMemoryPolicy002() { + /** + * @tc.steps: step1. decode webp file to get editable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.webp", null); + assertNotNull(imageSource); + imageSource.setMemoryUsagePreference(MemoryUsagePreference.LOW_RAM); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2. get pixelFormat from pixelMap. + * @tc.expected: step2. pixelFormat equals ARGB_8888. + */ + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.ARGB_8888, pixelFormat); + } + + /** + * @tc.name: testMemoryPolicy003 + * @tc.desc: test default memory + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testMemoryPolicy003() { + /** + * @tc.steps: step1. decode webp file to get editable pixelmap. + * @tc.expected: step1. get the valid pixelMap from the image and set memory default. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.webp", null); + assertNotNull(imageSource); + imageSource.setMemoryUsagePreference(MemoryUsagePreference.DEFAULT); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2. get pixelFormat from pixelMap. + * @tc.expected: step2. pixelFormat equals ARGB_8888. + */ + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.ARGB_8888, pixelFormat); + } + + /** + * @tc.name: testMemoryPolicy004 + * @tc.desc: test low memory and desired pixel format set at same time + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testMemoryPolicy004() { + /** + * @tc.steps: step1. decode jpg file to get editable pixelmap, set desired pixel format ARGB_8888 + * and memory low ram. + * @tc.expected: step1. get the valid pixelMap from the image. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.jpg", null); + assertNotNull(imageSource); + imageSource.setMemoryUsagePreference(MemoryUsagePreference.LOW_RAM); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + /** + * @tc.steps: step2. get pixelFormat from pixelMap. + * @tc.expected: step2. pixelFormat equals ARGB_8888. + */ + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.ARGB_8888, pixelFormat); + } + + class MyDecodeListener implements ImageSource.DecodeEventListener { + private List decodeEvents = new ArrayList(); + + private ImageSource imageSouceBack; + + private ImageInfo imageInfoInListener; + + private MemoryUsagePreference memUsage = MemoryUsagePreference.DEFAULT; + + @Override + public void onDecodeEvent(ImageSource source, DecodeEvent event) { + LOGGER.info("onDecodeEvent event: %{public}d", event.getValue()); + decodeEvents.add(event); + if (imageSouceBack == null) { + imageSouceBack = source; + } + DecodeEvent myEvent = DecodeEvent.getDecodeEvent(2); + if (event == myEvent) { + imageInfoInListener = source.getImageInfo(); + + if (memUsage != MemoryUsagePreference.DEFAULT) { + source.setMemoryUsagePreference(memUsage); + } + } + } + + List getEvents() { + return decodeEvents; + } + + ImageSource getMySource() { + return imageSouceBack; + } + + ImageInfo getMyImageInfo() { + return imageInfoInListener; + } + + void setMemoryUsage(MemoryUsagePreference preference) { + memUsage = preference; + } + } + + /** + * @tc.name: testDecodeEventListener001 + * @tc.desc: set a listener and will get a listener + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener001() { + /** + * @tc.steps: step1.get image source from path name. + * @tc.expected: step1.get image source form path name not null. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.webp", null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set a decode event listener. + * @tc.expected: step2.partialImageListenerTest equals EVENT_COMPLETE_DECODE, + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_COMPLETE_DECODE)); + assertEquals(testListener.getMySource(), imageSource); + assertNotNull(pixelMap); + } + + /** + * @tc.name: testDecodeEventListener002 + * @tc.desc: set a listener and will get a listener + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener002() { + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + byte[] data = null; + try { + data = Files.readAllBytes(Paths.get(pathName)); + } catch (IOException e) { + fail("file read exception"); + } + imageSource = ImageSource.create(data, 0, data.length - 100, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set a decode event listener. + * @tc.expected: step2.partialImageListenerTest equals EVENT_PARTIAL_DECODE, + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allowPartialImage = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_PARTIAL_DECODE)); + assertEquals(testListener.getMySource(), imageSource); + assertNotNull(pixelMap); + } + + /** + * @tc.name: testDecodeEventListener003 + * @tc.desc: set a listener and will not get a listener because not allow partial image + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener003() { + /** + * @tc.steps: step1.get image source byte array. + * @tc.expected: step1.get image source form byte array not null + */ + String pathName = "/sdcard/multimedia/image/test.jpg"; + byte[] data = null; + try { + data = Files.readAllBytes(Paths.get(pathName)); + } catch (IOException e) { + fail("file read exception"); + } + imageSource = ImageSource.create(data, 0, data.length - 100, null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set a decode event listener. + * @tc.expected: step2.throw SourceDataIncompleteException. + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allowPartialImage = false; + assertThrows("should throw SourceDataIncompleteException", SourceDataIncompleteException.class, () -> { + imageSource.createPixelmap(decodingOpts); + }); + } + + /** + * @tc.name: testDecodeEventListener004 + * @tc.desc: set a listener and will get a callback at proper time. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener004() { + /** + * @tc.steps: step1.get image source from path name. + * @tc.expected: step1.get image source form path name not null. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.webp", null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set a decode event listener. + * @tc.expected: step2.we can get EVENT_HEADER_DECODE, + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertEquals(testListener.getMySource(), imageSource); + ImageInfo myInfo = testListener.getMyImageInfo(); + ImageInfo info = imageSource.getImageInfo(); + assertEquals(myInfo.size, info.size); + assertEquals(myInfo.pixelFormat, info.pixelFormat); + assertNotNull(pixelMap); + } + + /** + * @tc.name: testDecodeEventListener005 + * @tc.desc: set two listener and check state. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener005() { + /** + * @tc.steps: step1.get image source from path name. + * @tc.expected: step1.get image source form path name not null. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.webp", null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set two decode event listener. + * @tc.expected: step2.we can get EVENT_HEADER_DECODE, + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + + MyDecodeListener testListener2 = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener2); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertFalse(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertTrue(testListener2.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertNull(testListener.getMySource()); + assertEquals(testListener2.getMySource(), imageSource); + assertNotNull(pixelMap); + } + + /** + * @tc.name: testDecodeEventListener006 + * @tc.desc: set listener and check state in listener. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener006() { + /** + * @tc.steps: step1.get image source from path name. + * @tc.expected: step1.get image source form path name not null. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.jpg", null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set decode event listener. + * @tc.expected: step2. set memory usage is effect when header is decoded. + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + testListener.setMemoryUsage(MemoryUsagePreference.LOW_RAM); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + + /** + * @tc.steps: step3. get pixelFormat from pixelMap. + * @tc.expected: step3. pixelFormat equals RGB_565. + */ + PixelFormat pixelFormat = pixelMap.getImageInfo().pixelFormat; + assertEquals(PixelFormat.RGB_565, pixelFormat); + } + + /** + * @tc.name: testDecodeEventListener007 + * @tc.desc: set same listener on two source. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener007() { + /** + * @tc.steps: step1.get image source from path name. + * @tc.expected: step1.get image source form path name not null. + */ + imageSource = ImageSource.create("/sdcard/multimedia/image/test.jpg", null); + assertNotNull(imageSource); + + ImageSource imageSource2 = ImageSource.create("/sdcard/multimedia/image/test.webp", null); + assertNotNull(imageSource); + + /** + * @tc.steps: step2.set decode event listener on different imagesource. + * @tc.expected: step2. check the state. + */ + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + imageSource2.setDecodeEventListener(testListener); + + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.editable = true; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + PixelMap pixelMap2 = imageSource2.createPixelmap(decodingOpts); + assertNotNull(pixelMap2); + + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_COMPLETE_DECODE)); + } + + /** + * @tc.name: testDecodeEventListener008 + * @tc.desc: set listener for Incremental decode. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener008() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource.IncrementalSourceOptions incOpts = new ImageSource.IncrementalSourceOptions(); + incOpts.opts = srcOpts; + incOpts.mode = ImageSource.UpdateMode.INCREMENTAL_DATA; + imageSource = ImageSource.createIncrementalSource(incOpts); + assertNotNull(imageSource); + + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(100, 60); + decodingOpts.desiredRegion = new Rect(10, 10, 150, 120); + decodingOpts.rotateDegrees = 90; + decodingOpts.desiredPixelFormat = PixelFormat.BGRA_8888; + decodingOpts.allowPartialImage = true; + decodingOpts.allocator = AllocatorType.HEAP; + + String pathName = "/sdcard/multimedia/image/test.webp"; + final int size = 1024; + int accumulatedData = 0; + byte[] data = new byte[size]; + File file = new File(pathName); + try (FileInputStream fileInputStream = new FileInputStream(file)) { + int bytes = 0; + while (bytes != -1) { + bytes = fileInputStream.read(data); + if (bytes == -1) { + break; + } + boolean isFinal = (bytes != size); + imageSource.updateData(data, 0, bytes, isFinal); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + + accumulatedData += bytes; + if (accumulatedData > 1024) { + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + } + // assume we can get a valid header now + if (accumulatedData > 2048) { + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_HEADER_DECODE)); + assertEquals(286, testListener.getMyImageInfo().size.width); + assertEquals(221, testListener.getMyImageInfo().size.height); + } + + if (isFinal) { + assertTrue(testListener.getEvents().contains(DecodeEvent.EVENT_COMPLETE_DECODE)); + } + } + } catch (IOException e) { + fail("file read exception"); + } finally { + pixelMap.release(); + } + } + + /** + * @tc.name: testDecodeEventListener009 + * @tc.desc: set listener for Incremental decode. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDecodeEventListener009() { + /** + * @tc.steps: step1.get incremental image source. + * @tc.expected: step1.get incremental image source not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + ImageSource.IncrementalSourceOptions incOpts = new ImageSource.IncrementalSourceOptions(); + incOpts.opts = srcOpts; + incOpts.mode = ImageSource.UpdateMode.INCREMENTAL_DATA; + imageSource = ImageSource.createIncrementalSource(incOpts); + assertNotNull(imageSource); + + MyDecodeListener testListener = new MyDecodeListener(); + imageSource.setDecodeEventListener(testListener); + + /** + * @tc.steps: step2.create pixel map. + * @tc.expected: step2.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.desiredSize = new Size(100, 60); + decodingOpts.desiredRegion = new Rect(10, 10, 150, 120); + decodingOpts.rotateDegrees = 90; + decodingOpts.desiredPixelFormat = PixelFormat.BGRA_8888; + decodingOpts.allowPartialImage = true; + + String pathName = "/sdcard/multimedia/image/test.webp"; + final int size = 1024; + int accumulatedData = 0; + byte[] data = new byte[size]; + File file = new File(pathName); + long fileLength = file.length(); + try (FileInputStream fileInputStream = new FileInputStream(file)) { + int bytes = 0; + boolean done = false; + while (!done) { + bytes = fileInputStream.read(data); + if (bytes == -1) { + break; + } + accumulatedData += bytes; + // assume we can get a valid header now + if (accumulatedData > (fileLength / 2)) { + imageSource.updateData(data, 0, bytes, true); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + done = true; + } else { + imageSource.updateData(data, 0, bytes, false); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + } + } + assertFalse(testListener.getEvents().contains(DecodeEvent.EVENT_PARTIAL_DECODE)); + assertFalse(testListener.getEvents().contains(DecodeEvent.EVENT_COMPLETE_DECODE)); + } catch (IOException e) { + fail("file read exception"); + } finally { + pixelMap.release(); + } + } + + /** + * @tc.name: testDensityChange001 + * @tc.desc: set fitDensity and baseDensity, size will change + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDensityChange001() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.baseDensity = 200; + String pathName = "/sdcard/multimedia/image/test.bmp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/bmp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.get the image after density change. + * @tc.expected: step2.width and height will be doubled, base density is the density set before. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.fitDensity = 400; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(200, pixelMap.getBaseDensity()); + assertEquals(944, pixelMap.getImageInfo().size.width); + assertEquals(150, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testDensityChange002 + * @tc.desc: set fitDensity and baseDensity, also set desired size, size will change by desired size + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDensityChange002() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.baseDensity = 200; + String pathName = "/sdcard/multimedia/image/test.bmp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/bmp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.get the image after density change. + * @tc.expected: step2.width and height will be same with desired width and height. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.fitDensity = 400; + decodingOpts.desiredSize = new Size(100, 200); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(200, pixelMap.getBaseDensity()); + assertEquals(100, pixelMap.getImageInfo().size.width); + assertEquals(200, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testDensityChange003 + * @tc.desc: just set baseDensity + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testDensityChange003() { + /** + * @tc.steps: step1.get image source form path. + * @tc.expected: step1.get image source form path not null. + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + srcOpts.baseDensity = 200; + String pathName = "/sdcard/multimedia/image/test.bmp"; + imageSource = ImageSource.create(pathName, srcOpts); + assertNotNull(imageSource); + ImageSource.SourceInfo sourceInfo = imageSource.getSourceInfo(); + assertNotNull(sourceInfo); + assertEquals(1, sourceInfo.topLevelImageNum); + assertEquals("image/bmp", sourceInfo.encodedFormat); + + /** + * @tc.steps: step2.get the image after density change. + * @tc.expected: step2.width and height will be same with original width and height. + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.fitDensity = 0; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(200, pixelMap.getBaseDensity()); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + private double[] getMemorySize(String filePath) { + double[] memorySize = new double[2]; + File txtFile = new File(filePath); + if (txtFile.exists()) { + FileReader fileReader = null; + BufferedReader bufferReader = null; + try { + fileReader = new FileReader(txtFile); + bufferReader = new BufferedReader(fileReader); + String lineContent = null; + while ((lineContent = bufferReader.readLine()) != null) { + String[] content = lineContent.split("\\s+"); + if (content.length > 0 && HEAP_STRING.equals(content[1])) { + memorySize[0] = Integer.valueOf(content[3]) / CONST_NUMBER; + } + if (content.length > 0 && SHARED_MEMORY_STRING.equals(content[1])) { + memorySize[1] = Integer.valueOf(content[3]) / CONST_NUMBER; + break; + } + } + } catch (FileNotFoundException e) { + LOGGER.error("read file FileNotFoundException"); + } catch (IOException e) { + LOGGER.error("read file IOException"); + } finally { + try { + bufferReader.close(); + fileReader.close(); + } catch (IOException e) { + LOGGER.error("close stream IOException"); + } + } + } + return memorySize; + } + + /** + * @tc.name: testAllocatorType001 + * @tc.desc: create pixel map with shared memory + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testAllocatorType001() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step3.create pixel map with shared memory. + * @tc.expected: step3.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allocator = AllocatorType.SHARED_MEMORY; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testAllocatorType002 + * @tc.desc: create pixel map with heap + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testAllocatorType002() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step3.create pixel map with heap. + * @tc.expected: step3.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allocator = AllocatorType.HEAP; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testAllocatorType003 + * @tc.desc: create pixel map with default memory + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testAllocatorType003() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.png"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + + /** + * @tc.steps: step3.create pixel map with default memory. + * @tc.expected: step3.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + decodingOpts.allocator = AllocatorType.DEFAULT; + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(75, pixelMap.getImageInfo().size.height); + } + + /** + * @tc.name: testAllocatorType004 + * @tc.desc: create pixel map with default memory + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testAllocatorType004() { + /** + * @tc.steps: step1.get image source File. + * @tc.expected: step1.get image source form File not null + */ + ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); + String pathName = "/sdcard/multimedia/image/test.jpg"; + File file = new File(pathName); + imageSource = ImageSource.create(file, srcOpts); + assertNotNull(imageSource); + /** + * @tc.steps: step3.create pixel map with default memory. + * @tc.expected: step3.create pixel map not null and check information ok + */ + ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); + pixelMap = imageSource.createPixelmap(decodingOpts); + assertNotNull(pixelMap); + assertEquals(472, pixelMap.getImageInfo().size.width); + assertEquals(226, pixelMap.getImageInfo().size.height); + } +} diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..735d1e2873ff0a7abd6a7a12f774197a7a626cf6 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/ImageTest.java @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Constructor; +import java.nio.ByteBuffer; + +/** + * ImageTest, test cases for Image class. + * + * @since 1 + */ +public class ImageTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageTest.class); + private ImageReceiver imageReceiver; + private Image image; + + /** + * Action before test case. + */ + @Before + public void setUp() { + imageReceiver = getImageReceiver(true); + image = new Image(imageReceiver); + image.setImageStatus(true); + } + + /** + * Action after test case. + */ + @After + public void tearDown() { + try { + if (imageReceiver != null) { + imageReceiver.finalize(); + imageReceiver = null; + } + if (image != null) { + image.finalize(); + image = null; + } + } catch (Throwable e) { + LOGGER.error("test case teardown fail, %{public}s", e.getMessage()); + } + } + + /** + * @tc.name: testImage001 + * @tc.desc: create image object. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImage001() { + /** + * @tc.steps: step1. create image object use wrong parameters. + * @tc.expected: step1. the image object is null. + */ + image = null; + try { + imageReceiver = getImageReceiver(false); + image = new Image(imageReceiver); + } catch (IllegalArgumentException e) { + LOGGER.error("create ImageReceiver throws exception."); + assertNull(image); + } + } + + /** + * @tc.name: testImage002 + * @tc.desc: operate image simple method. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImage002() { + /** + * @tc.steps: step1. set image status true. + * @tc.expected: step1. check the information is ok. + */ + image.setImageStatus(true); + assertEquals(true, image.getImageStatus()); + /** + * @tc.steps: step2. get the format of this image. + * @tc.expected: step2. check the information is ok. + */ + int format = image.getFormat(); + // operation will be called native, but buffer was set by app, only interface cover. + assertEquals(0, format); + /** + * @tc.steps: step3. get the size of this image. + * @tc.expected: step3. check the information is ok. + */ + Size size = image.getImageSize(); + // operation will be called native, but buffer was set by app, only interface cover. + assertEquals(0, size.width); + assertEquals(0, size.height); + /** + * @tc.steps: step4. get the timestamp of the image. + * @tc.expected: step4. check the information is ok. + */ + long timestamp = image.getTimestamp(); + assertEquals(timestamp, 0L); + } + + /** + * @tc.name: testImage003 + * @tc.desc: get and set the clip rectangle of the image. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImage003() { + /** + * @tc.steps: step1. set the clip rectangle in range of the image. + * @tc.expected: step1. check the information is ok. + */ + Rect newCrop = new Rect(0, 0, 100, 120); + image.setClipRect(newCrop); + Rect crop = image.getClipRect(); + // operation will be called native, but buffer was set by app, only interface cover. + assertEquals(0, crop.width); + assertEquals(0, crop.height); + /** + * @tc.steps: step2. set the clip rectangle out range of the image. + * @tc.expected: step2. check the information is ok. + */ + newCrop = new Rect(0, 0, 1080, 1920); + image.setClipRect(newCrop); + crop = image.getClipRect(); + // operation will be called native, but buffer was set by app, only interface cover. + assertEquals(0, crop.width); + assertEquals(0, crop.height); + } + + /** + * @tc.name: testImage004 + * @tc.desc: get the specified component of image. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImage004() { + /** + * @tc.steps: step1. get the specified component of image. + * @tc.expected: step1. check the information is ok. + */ + Image.Component component = null; + try { + // operation will be called native, but buffer was set by app, only interface cover. + component = image.getComponent(ImageFormat.ComponentType.JPEG); + } catch (IllegalStateException e) { + assertNull(component); + } + } + + /** + * @tc.name: testImage005 + * @tc.desc: create component object and operate methods. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImage005() { + /** + * @tc.steps: step1. create component object. + * @tc.expected: step1. check the information is ok. + */ + Image.Component component = getComponent(); + assertNotNull(component); + /** + * @tc.steps: step2. read one byte from byteBuffer. + * @tc.expected: step2. check the information is ok. + */ + int ret = component.read(); + assertEquals(0, ret); + /** + * @tc.steps: step3. read bulk data from byteBuffer. + * @tc.expected: step3. check the information is ok. + */ + byte[] dstArray = new byte[2]; + ret = component.read(dstArray); + assertEquals(0, ret); + /** + * @tc.steps: step4. read bulk data from byteBuffer. + * @tc.expected: step4. check the information is ok. + */ + ret = component.read(dstArray, 0, 1); + assertEquals(0, ret); + /** + * @tc.steps: step5. get the current position. + * @tc.expected: step5. check the information is ok. + */ + ret = component.tell(); + assertEquals(4, ret); + /** + * @tc.steps: step6. set the current position of the component buffer. + * @tc.expected: step6. check the information is ok. + */ + ret = component.seek(0); + assertEquals(0, ret); + /** + * @tc.steps: step7. get the size of remaining data in the component buffer. + * @tc.expected: step7. check the information is ok. + */ + ret = component.remaining(); + assertEquals(4, ret); + /** + * @tc.steps: step8. release the native resources associated with this component. + * @tc.expected: step8. check the information is ok. + */ + component.release(); + assertNotNull(component); + } + + /** + * @tc.name: testImage006 + * @tc.desc: create component object and operate methods. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImage006() { + /** + * @tc.steps: step1. create component object. + * @tc.expected: step1. check the information is ok. + */ + Image.Component component = getComponent(); + assertNotNull(component); + /** + * @tc.steps: step2. get the buffer object in the component. + * @tc.expected: step2. check the information is ok. + */ + ByteBuffer byteBuffer = component.getBuffer(); + assertNotNull(byteBuffer); + /** + * @tc.steps: step3. release the native resources associated with this component. + * @tc.expected: step3. check the information is ok. + */ + component.release(); + // the component release only set byteBuffer null, but the direct memory not release, its depends on system + assertNotNull(byteBuffer); + /** + * @tc.steps: step4. after component release to continue get the buffer object. + * @tc.expected: step4. check the information is ok. + */ + ByteBuffer byteBufferNew = null; + try { + byteBufferNew = component.getBuffer(); + } catch (IllegalStateException e) { + assertNull(byteBufferNew); + } + } + + private ImageReceiver getImageReceiver(boolean valid) { + int width = 320; + if (!valid) { + width = -1; + } + int height = 240; + int format = ImageFormat.JPEG; + int capacity = 1; + ImageReceiver newImageReceiver = ImageReceiver.create(width, height, format, capacity); + return newImageReceiver; + } + + private Image.Component getComponent() { + try { + Class clazz = Class.forName("ohos.media.image.Image$Component"); + Class[] classes = new Class[] { int.class, int.class, int.class, java.nio.ByteBuffer.class }; + Constructor constructor = clazz.getDeclaredConstructor(classes); + constructor.setAccessible(true); + Object componentObj = constructor.newInstance(ImageFormat.JPEG, 1, 1, ByteBuffer.allocate(4)); + if (componentObj instanceof Image.Component) { + Image.Component component = (Image.Component) componentObj; + return component; + } + } catch (Exception e) { + LOGGER.error("reflect private Image.Component object error. %{public}s", e.getMessage()); + } + return null; + } +} \ No newline at end of file diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/PixelMapNdkTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/PixelMapNdkTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dd96f6d9e1643087f9e2cf98b4257107c8d698b7 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/PixelMapNdkTest.java @@ -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. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; +import ohos.media.image.common.ImageInfo; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import java.io.File; + +public class PixelMapNdkTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(PixelMapNdkTest.class); + + static { + try { + System.loadLibrary("image_ndk_test_jni.z"); + } catch (UnsatisfiedLinkError | NullPointerException e) { + LOGGER.error("loadLibrary image_ndk_test_jni.z fail"); + } + nativeInit(); + } + + private static File file; + + private ImageSource imageSource; + + private PixelMap pixelMap; + + /** + * Action before all test case. + */ + @BeforeClass + public static void setUpBeforeClass() { + file = new File("/sdcard/multimedia/image/test_large.webp"); + if (!file.exists()) { + LOGGER.error("test file not exist."); + } + } + + /** + * Action after all test case. + */ + @AfterClass + public static void tearDownAfterClass() { + } + + /** + * Action before test case. + */ + @Before + public void setUp() { + pixelMap = createTestPixelMap(file.getPath()); + } + + /** + * Action after test case. + */ + @After + public void tearDown() { + try { + if (imageSource != null) { + imageSource.finalize(); + imageSource = null; + } + if (pixelMap != null) { + pixelMap.release(); + pixelMap = null; + } + } catch (Throwable throwable) { + LOGGER.error("test case teardown fail, %{public}s", throwable.getMessage()); + } + } + + /** + * @tc.name: testPixelMapNdk001 + * @tc.desc: compare the width and height with native pixels + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapNdk001() { + /** + * @tc.steps: step1. input correct width/height. + * @tc.expected: step1. expect 0 ok. + */ + ImageInfo imageInfo = pixelMap.getImageInfo(); + int result = nativeValidatePixelMapInfo(pixelMap, imageInfo.size.width, imageInfo.size.height, false); + assertEquals(result, 0); + + /** + * @tc.steps: step2. input incorrect width/height. + * @tc.expected: step2. expect -1 ok. + */ + result = nativeValidatePixelMapInfo(pixelMap, 1, 1, false); + assertEquals(result, -1); + } + + /** + * @tc.name: testPixelMapNdk002 + * @tc.desc: access/unaccess pixels + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapNdk002() { + /** + * @tc.steps: step1. access pixels. + * @tc.expected: step1. expect 0 ok. + */ + int result = nativeAccessPixels(pixelMap); + assertEquals(result, 0); + + /** + * @tc.steps: step2. unaccess pixels. + * @tc.expected: step2. expect 0 ok. + */ + result = nativeUnAccessPixels(pixelMap); + assertEquals(result, 0); + } + + /** + * @tc.name: testPixelMapNdk003 + * @tc.desc: get pixel format + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapNdk003() { + /** + * @tc.steps: step1. get native pixel format. + * @tc.expected: step1. expect RGBA format ok. + */ + int result = nativeGetPixelFormat(pixelMap); + assertEquals(result, 3); + } + + /** + * @tc.name: testPixelMapNdk004 + * @tc.desc: native read pixel and check value + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPixelMapNdk004() { + /** + * @tc.steps: step1. get pixel value,pos is 360,342. + * @tc.expected: step1. expect value ok. + */ + int result = nativeReadPixelsValue(pixelMap); + assertEquals(result, -3324097); + + /** + * @tc.steps: step2. release pixel map then access pixel. + * @tc.expected: step2. expect -2 exception. + */ + pixelMap.release(); + result = nativeAccessPixels(pixelMap); + assertEquals(result, -2); + } + + private static PixelMap createTestPixelMap(String filePath) { + ImageSource.SourceOptions opts = new ImageSource.SourceOptions(); + opts.formatHint = ""; + ImageSource imageSource = ImageSource.create(filePath, opts); + if (imageSource == null) { + LOGGER.error("test pixelmap to create the imageSource fail."); + return null; + } + ImageSource.DecodingOptions options = new ImageSource.DecodingOptions(); + return imageSource.createPixelmap(options); + } + + private static native void nativeInit(); + + private native int nativeValidatePixelMapInfo(PixelMap pixelMap, int width, int height, boolean is565); + + private native int nativeAccessPixels(PixelMap pixelMap); + + private native int nativeReadPixelsValue(PixelMap pixelMap); + + private native int nativeUnAccessPixels(PixelMap pixelMap); + + private native int nativeGetPixelFormat(PixelMap pixelMap); +} \ No newline at end of file diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/PropertyFilterTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/PropertyFilterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..29c5e88758abee40c55dfa17e3ef0d53cbb36fc7 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/PropertyFilterTest.java @@ -0,0 +1,864 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +import ohos.media.image.common.PropertyKey; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.system.Parameters; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; +import ohos.utils.Pair; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.io.InputStream; + +/** + * PropertyFilterTest, test cases for PropertyFilter class. + * + * @since 3 + */ +public class PropertyFilterTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(PropertyFilterTest.class); + + private static final String TEST_JPEG = "/sdcard/multimedia/image/test.jpg"; + + private static final String HAS_NO_EXIF = "/sdcard/multimedia/image/hasNoExif.JPG"; + + private static File pngFile; + ImageSource mImageSourcePath; + ImageSource mImageSourceFile; + PropertyFilter mPropertyFilter; + + /** + * Action before all test case. + */ + @BeforeClass + public static void setUpBeforeClass() { + pngFile = new File(TEST_JPEG); + if (!pngFile.exists()) { + fail("files not exist"); + } + } + + /** + * Action before test case. + */ + @Before + public void setUp() { + mImageSourcePath = ImageSource.create(TEST_JPEG, null); + mImageSourceFile = ImageSource.create(new File(TEST_JPEG), null); + assertNotNull(mImageSourcePath); + assertNotNull(mImageSourceFile); + mPropertyFilter = new PropertyFilter(); + } + + /** + * Action after test case. + */ + @After + public void tearDown() { + } + + /** + * @tc.name: testsetPropertyFilter001 + * @tc.desc: set property of filePath ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter001() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter001_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(newArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(newLocation), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertTrue(ret > 0); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourcePath = ImageSource.create(TEST_JPEG, null); + assertEquals(newArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(newLocation), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + } + + /** + * @tc.name: testsetPropertyFilter002 + * @tc.desc: set property of File ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter002() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter002_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure) + .applyToSource(mImageSourceFile); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(newArtist, mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(newLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertTrue(ret > 0); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourceFile = ImageSource.create(new File(TEST_JPEG), null); + assertEquals(newArtist, mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(newLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + } + + /** + * @tc.name: testsetPropertyFilter003 + * @tc.desc: reset property of FilePath ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter003() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter003_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure) + .restore() + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(oldArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(oldExposure), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertEquals(-1, ret); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourcePath = ImageSource.create(TEST_JPEG, null); + assertEquals(oldArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(oldExposure), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + } + + /** + * @tc.name: testsetPropertyFilter004 + * @tc.desc: reset property of File ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter004() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter004_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure) + .restore() + .applyToSource(mImageSourceFile); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(oldArtist, mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(oldExposure), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertEquals(-1, ret); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourceFile = ImageSource.create(new File(TEST_JPEG), null); + assertEquals(oldArtist, mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(oldExposure), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + } + + /** + * @tc.name: testsetPropertyFilter005 + * @tc.desc: remove partial property of filePath ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter005() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter005_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure) + .rollbackProperty(PropertyKey.Exif.SUBJECT_LOCATION) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(newArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertTrue(ret > 0); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourcePath = ImageSource.create(TEST_JPEG, null); + assertEquals(newArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + } + + /** + * @tc.name: testsetPropertyFilter006 + * @tc.desc: remove partial property of File ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter006() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter006_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .setPropertyDouble(PropertyKey.Exif.EXPOSURE_TIME, newExposure) + .rollbackProperty(PropertyKey.Exif.SUBJECT_LOCATION) + .applyToSource(mImageSourceFile); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(newArtist, mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + assertTrue(ret > 0); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourceFile = ImageSource.create(new File(TEST_JPEG), null); + assertEquals(newArtist, mImageSourceFile.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(String.valueOf(oldLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertEquals(String.valueOf(newExposure), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME)); + } + + /** + * @tc.name: testsetPropertyFilter007 + * @tc.desc: set property of filePath ImageSource and test invalid key. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter007() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter007_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(null, newLocation) + .setPropertyDouble("invalid_key_test", newExposure) + .rollbackProperty(null) + .rollbackProperty("invalid_key_test_rollback") + .restore() + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(oldArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertNotEquals(String.valueOf(newExposure), + mImageSourcePath.getImagePropertyString("invalid_key_test")); + assertEquals(String.valueOf(newLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + assertTrue(ret > 0); + + /** + * @tc.steps: step4. get properties of changed reloaded ImageSource. + * @tc.expected: step4. equal to changed value. + */ + mImageSourcePath = ImageSource.create(TEST_JPEG, null); + assertEquals(oldArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertNotEquals(String.valueOf(newExposure), + mImageSourcePath.getImagePropertyString("invalid_key_test")); + assertEquals(String.valueOf(newLocation), + mImageSourceFile.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION)); + } + + /** + * @tc.name: testsetPropertyFilter008 + * @tc.desc: set property of filePath ImageSource and test invalid imagesource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter008() { + /** + * @tc.steps: step1. set properties for released ImageSource. + * @tc.expected: step1. no Exception and return error code. + */ + String newArtist = "testsetPropertyFilter008_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + mImageSourcePath.release(); + + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .applyToSource(mImageSourcePath); + }); + } + + /** + * @tc.name: testsetPropertyFilter009 + * @tc.desc: set property of filePath ImageSource and test invalid imagesource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter009() { + /** + * @tc.steps: step1. set properties for null. + * @tc.expected: step1. no Exception and return error code + */ + String newArtist = "testsetPropertyFilter009_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + + assertThrows("should throw IllegalArgumentException", IllegalArgumentException.class, () -> { + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .applyToSource(null); + }); + } + + /** + * @tc.name: testsetPropertyFilter010 + * @tc.desc: set property of unsupported ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter010() { + InputStream inputStream = null; + try { + /** + * @tc.steps: step1. construct unsupported ImageSource of inputStream source. + */ + File file = new File(TEST_JPEG); + inputStream = new FileInputStream(file); + ImageSource imageSourceStream = ImageSource.create(inputStream, null); + assertNotNull(imageSourceStream); + + /** + * @tc.steps: step2. set properties for unsupported ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter010_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + + assertThrows("should throw IllegalStateException", IllegalStateException.class, () -> { + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .applyToSource(imageSourceStream); + }); + } catch (FileNotFoundException e) { + LOGGER.error("FileNotFoundException in testsetPropertyFilter010"); + fail("FileNotFoundException in testsetPropertyFilter010"); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + fail("inputStream.close failed in testsetPropertyFilter010"); + } + } + } + + /** + * @tc.name: testsetPropertyFilter011 + * @tc.desc: set property of unsupported ImageSource. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter011() { + /** + * @tc.steps: step1. construct unsupported ImageSource of byte buffer source. + */ + ImageSource imageSourceByte = getByteImageSource(); + assertNotNull(imageSourceByte); + + /** + * @tc.steps: step2. set properties for unsupported ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter011_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + + assertThrows("should throw IOException", IOException.class, () -> { + mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .applyToSource(imageSourceByte); + }); + } + + /** + * @tc.name: testsetPropertyFilter012 + * @tc.desc: set property of null key. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter012() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter012_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(null, newArtist) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertEquals(oldArtist, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST)); + assertEquals(-1, ret); + mImageSourcePath.release(); + } + + /** + * @tc.name: testsetPropertyFilter013 + * @tc.desc: set property of null key and rollbackProperty. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter013() { + /** + * @tc.steps: step1. get current properties of ImageSource. + */ + String oldArtist = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.ARTIST); + String oldLocation = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.SUBJECT_LOCATION); + String oldExposure = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.EXPOSURE_TIME); + + /** + * @tc.steps: step2. set properties for ImageSource. + * @tc.expected: step2. no error + */ + String newArtist = "testsetPropertyFilter013_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int)(System.currentTimeMillis() / 1.0E8); + Double newExposure = Double.valueOf(newLocation + 0.1); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(null, newArtist) + .rollbackProperty(null) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step3. get properties of changed ImageSource. + * @tc.expected: step3. equal to changed value. + */ + assertTrue(ret > 0); + mImageSourcePath.release(); + } + + /** + * @tc.number testsetPropertyFilter014 + * @tc.name string exif interface, two parameters + * @tc.desc Edit the pic exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter014() { + LOGGER.info("testsetPropertyFilter014 begin"); + boolean exceptionFlag = false; + + /** + * @tc.steps: step1. set properties for ImageSource. + * @tc.expected: step1. the properties is correct. + */ + String oldValue = mImageSourcePath.getImagePropertyString(PropertyKey.Exif.MAKE); + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString("", "").applyToSource(mImageSourcePath); + } catch (IOException e) { + exceptionFlag = true; + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step2. get properties of changed ImageSource. + * @tc.expected: step2. equal to changed value. + */ + assertEquals(oldValue, mImageSourcePath.getImagePropertyString(PropertyKey.Exif.MAKE)); + assertEquals(-1, ret); + assertFalse(exceptionFlag); + + mImageSourcePath.release(); + + /** + * @tc.steps: step3. get properties of changed reloaded ImageSource. + * @tc.expected: step3. equal to changed value. + */ + ImageSource newImageSource = ImageSource.create(TEST_JPEG, null); + assertEquals(oldValue, newImageSource.getImagePropertyString(PropertyKey.Exif.MAKE)); + + newImageSource.release(); + LOGGER.info("testsetPropertyFilter014 end"); + } + + /** + * @tc.number testsetPropertyFilter015 + * @tc.name the image does not contain exif + * @tc.desc Edite the pic exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter015() { + LOGGER.info("testsetPropertyFilter015 begin"); + boolean exceptionFlag = false; + + /** + * @tc.steps: step1. set properties for ImageSource. + * @tc.expected: step1. the properties is correct. + */ + ImageSource noExifImageSource = ImageSource.create(HAS_NO_EXIF, null); + assertNotNull(noExifImageSource); + mPropertyFilter = new PropertyFilter(); + + String newStringValue = String.valueOf(System.currentTimeMillis()); + int newIntValue = (int) (System.currentTimeMillis() / 1.0E8); + Double newDoubleValue = 2.5; + LOGGER.error("file newIntValue %{public}d", newIntValue); + + long ret = -100; + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.MAKE, newStringValue) + .setPropertyDouble(PropertyKey.Exif.F_NUMBER, newDoubleValue) + .setPropertyInt(PropertyKey.Exif.EXIF_VERSION, newIntValue) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + exceptionFlag = true; + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } + + /** + * @tc.steps: step2. get properties of changed ImageSource. + * @tc.expected: step2. equal to changed value. + */ + assertEquals(null, noExifImageSource.getImagePropertyString(PropertyKey.Exif.MAKE)); + assertEquals(0, noExifImageSource.getImagePropertyInt(PropertyKey.Exif.EXIF_VERSION, 0)); + assertEquals(null, noExifImageSource.getImagePropertyString(PropertyKey.Exif.F_NUMBER)); + assertFalse(exceptionFlag); + + noExifImageSource.release(); + + /** + * @tc.steps: step3. get properties of changed reloaded ImageSource. + * @tc.expected: step3. equal to changed value. + */ + ImageSource newImageSource = ImageSource.create(HAS_NO_EXIF, null); + + assertEquals(null, newImageSource.getImagePropertyString(PropertyKey.Exif.MAKE)); + assertEquals(0, newImageSource.getImagePropertyInt(PropertyKey.Exif.EXIF_VERSION, 0)); + assertEquals(null, newImageSource.getImagePropertyString(PropertyKey.Exif.F_NUMBER)); + + newImageSource.release(); + LOGGER.info("testsetPropertyFilter015 end"); + } + + /** + * @tc.number testsetPropertyFilter016 + * @tc.name get exif failure after image source released + * @tc.desc Edite the pic exif info. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testsetPropertyFilter016() { + LOGGER.info("testsetPropertyFilter016 begin"); + boolean exceptionFlag = false; + + /** + * @tc.steps: step1. set properties for released ImageSource. + * @tc.expected: step1. no Exception and return error code. + */ + String newArtist = "testEditingPictureExif040_" + String.valueOf(System.currentTimeMillis()); + int newLocation = (int) (System.currentTimeMillis() / 1.0E8); + long ret = -100; + mImageSourcePath.release(); + + try { + ret = mPropertyFilter.setPropertyString(PropertyKey.Exif.ARTIST, newArtist) + .setPropertyInt(PropertyKey.Exif.SUBJECT_LOCATION, newLocation) + .applyToSource(mImageSourcePath); + } catch (IOException e) { + LOGGER.error("file applyToSource exception"); + fail("file applyToSource exception"); + } catch (IllegalStateException e) { + exceptionFlag = true; + LOGGER.error("file applyToSource exception"); + } + + /** + * @tc.steps: step2. get result of applyToSource null. + * @tc.expected: step2. equal to error code. + */ + assertTrue(exceptionFlag); + + LOGGER.info("testsetPropertyFilter016 end"); + } + + private ImageSource getByteImageSource() { + byte[] data = null; + try { + data = Files.readAllBytes(Paths.get(TEST_JPEG)); + } catch (IOException e) { + LOGGER.error("file readAllBytes get exception"); + fail("file readAllBytes exception"); + } + data[0] = 0xa; + return ImageSource.create(data, null); + } + +} diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/common/ImageFormatTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/ImageFormatTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c9d4add95d4539de4639143e6699ee8cb6aa5029 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/ImageFormatTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.Test; + +import java.lang.reflect.Constructor; + +/** + * ImageFormatTest, test cases for ImageFormat class. + * + * @since 1 + */ +public class ImageFormatTest { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageFormatTest.class); + + /** + * @tc.name: testImageFormat001 + * @tc.desc: create ImageFormat info for image operations. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageFormat001() { + /** + * @tc.steps: step1. create image format info. + * @tc.expected: step1. the image format is not null. + */ + ImageFormat imageFormat = null; + try { + Class clazz = Class.forName("ohos.media.image.common.ImageFormat"); + Constructor constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + Object imageFormatObj = constructor.newInstance(); + if (imageFormatObj instanceof ImageFormat) { + imageFormat = (ImageFormat) imageFormatObj; + assertNotNull(imageFormat); + } + } catch (Exception e) { + LOGGER.error("reflect image private constructor failed."); + assertNull(imageFormat); + } + } + + /** + * @tc.name: testImageFormat002 + * @tc.desc: get pixel bits number by format. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageFormat002() { + /** + * @tc.steps: step1. get pixel bits number by format. + * @tc.expected: step1. check the information is ok. + */ + int bitsByPixel = ImageFormat.getBitsNumberPerPixel(ImageFormat.JPEG); + assertEquals(bitsByPixel, 0); + /** + * @tc.steps: step2. get pixel bits number by format. + * @tc.expected: step2. check the information is ok. + */ + bitsByPixel = ImageFormat.getBitsNumberPerPixel(ImageFormat.RAW16); + assertEquals(bitsByPixel, 16); + } + + /** + * @tc.name: testImageFormat003 + * @tc.desc: get pixel component number by format. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testImageFormat003() { + /** + * @tc.steps: step1. get pixel component number by format. + * @tc.expected: step1. check the information is ok. + */ + int componentNum = ImageFormat.getComponentNumber(ImageFormat.JPEG); + assertEquals(componentNum, 1); + /** + * @tc.steps: step2. get pixel component number by format. + * @tc.expected: step2. check the information is ok. + */ + componentNum = ImageFormat.getComponentNumber(ImageFormat.YUV420_888); + assertEquals(componentNum, 3); + } +} \ No newline at end of file diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/common/PositionTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/PositionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..121d7ea1df4e063b361c557ea6632a80cc90d556 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/PositionTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.Test; + +import java.util.HashSet; + +/** + * PositionTest, test cases for Position class, mainly including test cases for position operations + * + * @since 1 + */ +public class PositionTest { + /** + * @tc.name: testPosition001 + * @tc.desc: create position info for image operations. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testPosition001() { + /** + * @tc.steps: step1.create position size info . + * @tc.expected: step1.position info not null + */ + Position position1 = new Position(); + Position position2 = new Position(1, 2); + assertNotNull(position1); + assertNotNull(position2); + Position position3 = new Position(1, 2); + assertEquals(position2, position3); + assertEquals(String.valueOf(position2), String.valueOf(position3)); + HashSet sets = new HashSet<>(); + sets.add(position3); + assertTrue(sets.contains(position3)); + + /** + * @tc.steps: step2.check position info. + * @tc.expected: step2.check information ok + */ + assertEquals(position2.posX, 1); + assertEquals(position2.posY, 2); + } +} diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/common/RectTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/RectTest.java new file mode 100644 index 0000000000000000000000000000000000000000..27c2d1db185fc274ba399a6f81cbb26066031f63 --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/RectTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.Test; + +import java.util.HashSet; + +/** + * RectTest, test cases for Rect class, mainly including test cases for rect operations + * + * @since 1 + */ +public class RectTest { + /** + * @tc.name: testRect001 + * @tc.desc: create rect info for image operations. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testRect001() { + /** + * @tc.steps: step1.create image rect info . + * @tc.expected: step1.rect info not null + */ + Rect rect1 = new Rect(); + Rect rect2 = new Rect(1, 2, 3, 4); + assertNotNull(rect1); + assertNotNull(rect2); + assertEquals(rect2.minX, 1); + assertEquals(rect2.minY, 2); + assertEquals(rect2.width, 3); + assertEquals(rect2.height, 4); + Rect rect3 = new Rect(rect2); + assertEquals(rect3.minX, 1); + assertEquals(rect3.minY, 2); + assertEquals(rect3.width, 3); + assertEquals(rect3.height, 4); + assertEquals(rect2, rect3); + assertEquals(String.valueOf(rect2), String.valueOf(rect3)); + HashSet sets = new HashSet<>(); + sets.add(rect3); + assertTrue(sets.contains(rect3)); + + /** + * @tc.steps: step2.check rect info. + * @tc.expected: step2.check information ok + */ + rect2.setEmpty(); + assertEquals(rect2.minX, 0); + assertEquals(rect2.minY, 0); + assertEquals(rect2.width, 0); + assertEquals(rect2.height, 0); + } + + /** + * @tc.name: testRect002 + * @tc.desc: for image crop operations. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testRect002() { + /** + * @tc.steps: step1.create image rect info . + * @tc.expected: step1.rect info not null + */ + Rect rect = new Rect(0, 0, 300, 400); + assertNotNull(rect); + + /** + * @tc.steps: step2.crop rect. + * @tc.expected: step2.check information ok + */ + rect.cropRect(10, 10, 100, 200); + assertEquals(rect.minX, 10); + assertEquals(rect.minY, 10); + assertEquals(rect.width, 100); + assertEquals(rect.height, 200); + } +} \ No newline at end of file diff --git a/interfaces/kits/java/test/unittest/src/ohos/media/image/common/SizeTest.java b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/SizeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..75b8b426cafe500fa83f07bd2cc5495b0bde634f --- /dev/null +++ b/interfaces/kits/java/test/unittest/src/ohos/media/image/common/SizeTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import ohos.unittest.CaseLevel; +import ohos.unittest.CaseType; +import ohos.unittest.Level; +import ohos.unittest.Type; + +import org.junit.Test; + +import java.util.HashSet; + +/** + * SizeTest, test cases for Size class, mainly including test cases for size operations + * + * @since 1 + */ +public class SizeTest { + /** + * @tc.name: testSize001 + * @tc.desc: create size info for image operations. + */ + @Test + @CaseLevel(level = Level.LEVEL_3) + @CaseType(type = Type.FUNC) + public void testSize001() { + /** + * @tc.steps: step1.create image size info . + * @tc.expected: step1.size info not null + */ + Size size1 = new Size(); + Size size2 = new Size(1, 2); + assertNotNull(size1); + assertNotNull(size2); + + /** + * @tc.steps: step2.check size info. + * @tc.expected: step2.check information ok + */ + assertEquals(size2.width, 1); + assertEquals(size2.height, 2); + + Size size3 = new Size(3, 4); + Size size4 = new Size(3, 4); + assertEquals(size3, size4); + assertEquals(String.valueOf(size3), String.valueOf(size4)); + HashSet sets = new HashSet<>(); + sets.add(size4); + assertTrue(sets.contains(size4)); + } +} \ No newline at end of file diff --git a/interfaces/kits/native/BUILD.gn_old b/interfaces/kits/native/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..ee5a61c10634dfe2fe638308a2fabd0edc0ac703 --- /dev/null +++ b/interfaces/kits/native/BUILD.gn_old @@ -0,0 +1,57 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +SUBSYSTEM_DIR = "//foundation/multimedia/image_standard" + +ohos_ndk_library("libpixelmap") { + ndk_description_file = "./libimage_pixelmap.json" + min_compact_version = "1" + output_name = "image_pixelmap" +} + +ohos_ndk_headers("image_header") { + dest_dir = "$ndk_headers_out_dir/multimedia/image_standard" + sources = [ "./include/image_pixel_map.h" ] +} + +ohos_shared_library("libimage_pixelmap_ndk") { + sources = [ "src/image_pixel_map.cpp" ] + output_name = "image_pixelmap" + + include_dirs = [ + "include", + "//utils/native/base/include", + "//utils/jni/jnikit/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/include", + "$SUBSYSTEM_DIR/frameworks/jni/pixelmap/include", + ] + + deps = [ +# "$SUBSYSTEM_DIR/frameworks/jni/pixelmap:pixelmap_jni", + "$SUBSYSTEM_DIR/interfaces/kits/native:libpixelmap", + "//utils/native/base:utils", + ] + + version_script = + get_label_info(":libpixelmap", "target_gen_dir") + "/" + + get_label_info(":libpixelmap", "name") + version_script_suffix + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +group("multimedia_target") { + deps = [ ":libimage_pixelmap_ndk" ] +} diff --git a/interfaces/kits/native/include/image_pixel_map.h b/interfaces/kits/native/include/image_pixel_map.h new file mode 100644 index 0000000000000000000000000000000000000000..9dd564c6a413bca15b9c1cd9f5ed25ab9fb5d4e6 --- /dev/null +++ b/interfaces/kits/native/include/image_pixel_map.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup image + * @{ + * + * @brief Provides access to pixel data and pixel map information. + * + * @Syscap SystemCapability.Multimedia.Image + * @since 3 + * @version 1.0 + */ + +/** + * @file image_pixel_map.h + * + * @brief Declares functions for you to lock and access or unlock pixel data, and obtain the width and height of a pixel + * map. + * + * @since 3 + * @version 1.0 + */ + +#ifndef IMAGE_PIXEL_MAP_H +#define IMAGE_PIXEL_MAP_H +/* +#include +*/ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enumerates the result codes that may be returned by a function. + * + * @since 3 + * @version 1.0 + */ +enum { + /** Success result */ + OHOS_IMAGE_RESULT_SUCCESS = 0, + /** Invalid parameters */ + OHOS_IMAGE_RESULT_BAD_PARAMETER = -1, + /** JNI exception */ + /* + OHOS_IMAGE_RESULT_JNI_EXCEPTION = -2, + */ +}; + +/** + * @brief Enumerates pixel formats. + * + * @since 3 + * @version 1.0 + */ +enum { + /** + * Unknown format + */ + OHOS_PIXEL_MAP_FORMAT_NONE = 0, + /** + * 32-bit RGBA. Components R, G, B, and A each occupies 8 bits + * and are stored from the higher-order to the lower-order bits. + */ + OHOS_PIXEL_MAP_FORMAT_RGBA_8888 = 3, + /** + * 16-bit RGB. Only the R, G, and B components are encoded + * from the higher-order to the lower-order bits: red is stored with 5 bits of precision, + * green is stored with 6 bits of precision, and blue is stored with 5 bits of precision. + */ + OHOS_PIXEL_MAP_FORMAT_RGB_565 = 2, +}; + +/** + * @brief Defines pixel map information. + * + * @since 3 + * @version 1.0 + */ +struct OhosPixelMapInfo { + /** Image width, in pixels. */ + uint32_t width; + /** Image height, in pixels. */ + uint32_t height; + /** Number of bytes in each row of a pixel map */ + uint32_t rowSize; + /** Pixel format */ + int32_t pixelFormat; +}; + +/** + * @brief Obtains information about a given PixelMap and stores the information in a {@link OhosPixelMapInfo} + * structure. + * + * @param env Indicates the pointer to the JNI environment. + * @param pixelMapObject Indicates the Java PixelMap object. + * @param info Indicates the pointer to the pixel map information to obtain. For details, see {@link + * OhosPixelMapInfo}. + * @return Returns 0 if the information is obtained and stored in the structure; returns result codes if the + * operation fails. + * @see OhosPixelMapInfo + * @since 3 + * @version 1.0 + */ +/* +int32_t GetImageInfo(JNIEnv *env, jobject pixelMapObject, OhosPixelMapInfo &info); +*/ +/** + * @brief Obtains the memory address of a given PixelMap object and locks the memory. + * + * If this function call is successful, *addrPtr is set to the memory address. After accessing the pixel data, + * you must use {@link UnAccessPixels} to unlock the memory. Otherwise, resources cannot be released. + * After the memory is unlocked, it can be invalid and should not be accessed. + * + * @param env Indicates the pointer to the JNI environment. + * @param pixelMapObject Indicates the Java PixelMap object. + * @param addrPtr Indicates the double pointer to the memory address. + * @see UnAccessPixels + * @return Returns {@link OHOS_IMAGE_RESULT_SUCCESS} if the operation is successful; returns other result codes if + * the operation fails. + * @since 3 + * @version 1.0 + */ +/* +int32_t AccessPixels(JNIEnv *env, jobject pixelMapObject, void **addrPtr); +*/ +/** + * @brief Unlocks the memory storing the pixel data of a given PixelMap to balance a successful call to {@link + * AccessPixels}. + * + * @param env Indicates the pointer to the JNI environment. + * @param pixelMapObject Indicates the Java PixelMap object. + * @return Returns {@link OHOS_IMAGE_RESULT_SUCCESS} if the operation is successful; returns other result codes if + * the operation fails. + * @see AccessPixels + * @since 3 + * @version 1.0 + */ +/* +int32_t UnAccessPixels(JNIEnv *env, jobject pixelMapObject); +*/ + +#ifdef __cplusplus +}; +#endif + +/** @} */ +#endif // IMAGE_PIXEL_MAP_H diff --git a/interfaces/kits/native/libimage_pixelmap.json b/interfaces/kits/native/libimage_pixelmap.json new file mode 100644 index 0000000000000000000000000000000000000000..9bc37d8d2ee0d593e219d623ff5bddbe4dc95591 --- /dev/null +++ b/interfaces/kits/native/libimage_pixelmap.json @@ -0,0 +1,12 @@ +[ + { + "first_introduced": "1", + "name": "GetImageInfo" + }, + { + "name": "AccessPixels" + }, + { + "name": "UnAccessPixels" + } +] \ No newline at end of file diff --git a/interfaces/kits/native/ndk_test_example/BUILD.gn b/interfaces/kits/native/ndk_test_example/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9d2b773df81dde70b95528aef889fcdfc275f34d --- /dev/null +++ b/interfaces/kits/native/ndk_test_example/BUILD.gn @@ -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("//build/ohos.gni") + +config("image_ndk_test_jni_config") { + visibility = [ ":*" ] + include_dirs = [ + "//utils/native/base/include", + "//utils/jni/jnikit/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/interfaces/kits/native/include", + "//foundation/multimedia/image_standard/frameworks/jni/common/include", + "//foundation/multimedia/image_standard/frameworks/jni/pixelmap/include", + ] +} + +group("g_image_ndk_test_jni") { + deps = [ ":image_ndk_test_jni" ] +} + +ohos_shared_library("image_ndk_test_jni") { + sources = [ "ohos_image_PixelMapNdkTest.cpp" ] + + configs = [ ":image_ndk_test_jni_config" ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/kits/native:multimedia_target", +# "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + ] + +# external_deps = [ "hilog:libhilog" ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/interfaces/kits/native/ndk_test_example/ohos_image_PixelMapNdkTest.cpp b/interfaces/kits/native/ndk_test_example/ohos_image_PixelMapNdkTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d53e02cde543574853bf3864cd3a4a7ca0221f4 --- /dev/null +++ b/interfaces/kits/native/ndk_test_example/ohos_image_PixelMapNdkTest.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hilog/log.h" +#include "image_pixel_map.h" +#include "jkit_utils.h" +#include "log_tags.h" +#include "media_errors.h" + +using namespace OHOS::HiviewDFX; +using namespace OHOS::Media; + +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "PixelMapNdkTest_JNI" }; +static constexpr int32_t PIXEL_OFFSET = 588 * 342 + 360; +static jclass g_imageNdkTestClass; + +static bool InitImageNdkTest(JNIEnv *env) +{ + jclass imageClazz = env->FindClass("ohos/media/image/PixelMapNdkTest"); + if (imageClazz == nullptr) { + HiLog::Error(LABEL, "find PixelMapNdkTest class fail"); + return false; + } + g_imageNdkTestClass = static_cast(env->NewGlobalRef(imageClazz)); + env->DeleteLocalRef(imageClazz); + return true; +} + +void ohos_media_image_PixelMapNdkTest_nativeInit(JNIEnv *env, jclass thiz) +{ + HiLog::Debug(LABEL, "nativeInit begin"); + if (!InitImageNdkTest(env)) { + HiLog::Error(LABEL, "nativeInit InitImageNdkTest failed"); + return; + } + HiLog::Debug(LABEL, "nativeInit end"); +} + +static jint ohos_media_image_PixelMapNdkTest_ValidPixelMapInfo(JNIEnv *env, jobject thiz, jobject jpixelMap, + jint width, jint height, jboolean is565) +{ + HiLog::Debug(LABEL, "input:width[%{public}u], height[%{public}u]", static_cast(width), + static_cast(height)); + OhosPixelMapInfo info; + int32_t err = GetImageInfo(env, jpixelMap, info); + HiLog::Debug(LABEL, "output:width[%{public}u], height[%{public}u], format[%{public}d], err[%{public}d]", info.width, + info.height, info.pixelFormat, err); + int32_t format = is565 ? OHOS_PIXEL_MAP_FORMAT_RGB_565 : OHOS_PIXEL_MAP_FORMAT_RGBA_8888; + if (err == OHOS_IMAGE_RESULT_SUCCESS && format == info.pixelFormat && + static_cast(width) == info.width && static_cast(height) == info.height) { + return OHOS_IMAGE_RESULT_SUCCESS; + } + return OHOS_IMAGE_RESULT_BAD_PARAMETER; +} + +static jint ohos_media_image_PixelMapNdkTest_AccessPixels(JNIEnv *env, jobject thiz, jobject jpixelMap) +{ + void *pixels = nullptr; + return AccessPixels(env, jpixelMap, &pixels); +} + +static jint ohos_media_image_PixelMapNdkTest_ReadPixelsValue(JNIEnv *env, jobject thiz, jobject jpixelMap) +{ + void *pixels = nullptr; + int32_t err = AccessPixels(env, jpixelMap, &pixels); + if (err != OHOS_IMAGE_RESULT_SUCCESS) { + return OHOS_IMAGE_RESULT_BAD_PARAMETER; + } + uint32_t *offset = static_cast(pixels) + PIXEL_OFFSET; + return *offset; +} + +static jint ohos_media_image_PixelMapNdkTest_UnAccessPixels(JNIEnv *env, jobject thiz, jobject jpixelMap) +{ + return UnAccessPixels(env, jpixelMap); +} + +static jint ohos_media_image_PixelMapNdkTest_GetPixelFormat(JNIEnv *env, jobject thiz, jobject jpixelMap) +{ + OhosPixelMapInfo info; + info.pixelFormat = OHOS_PIXEL_MAP_FORMAT_NONE; + int err = 0; + err = GetImageInfo(env, jpixelMap, info); + if (err != OHOS_IMAGE_RESULT_SUCCESS) { + return OHOS_PIXEL_MAP_FORMAT_NONE; + } + return info.pixelFormat; +} + +static const JNINativeMethod METHODS[] = { + { "nativeInit", "()V", reinterpret_cast(ohos_media_image_PixelMapNdkTest_nativeInit) }, + { "nativeValidatePixelMapInfo", "(Lohos/media/image/PixelMap;IIZ)I", + reinterpret_cast(ohos_media_image_PixelMapNdkTest_ValidPixelMapInfo) }, + { "nativeAccessPixels", "(Lohos/media/image/PixelMap;)I", + (void *)ohos_media_image_PixelMapNdkTest_AccessPixels }, + { "nativeReadPixelsValue", "(Lohos/media/image/PixelMap;)I", + (void *)ohos_media_image_PixelMapNdkTest_ReadPixelsValue }, + { "nativeUnAccessPixels", "(Lohos/media/image/PixelMap;)I", + (void *)ohos_media_image_PixelMapNdkTest_UnAccessPixels }, + { "nativeGetPixelFormat", "(Lohos/media/image/PixelMap;)I", + (void *)ohos_media_image_PixelMapNdkTest_GetPixelFormat }, +}; + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + JNIEnv *env = nullptr; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { + return ERROR; + } + int ret = JkitRegisterNativeMethods(env, "ohos/media/image/PixelMapNdkTest", METHODS, ARRCOUNT(METHODS)); + if (ret == JNI_ERR) { + return ERROR; + } + Jkit::nativeInit(vm); + return JNI_VERSION_1_4; +} \ No newline at end of file diff --git a/interfaces/kits/native/src/image_pixel_map.cpp b/interfaces/kits/native/src/image_pixel_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9deb635982afc249d3744097b433cea6777d51c --- /dev/null +++ b/interfaces/kits/native/src/image_pixel_map.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_pixel_map.h" +#include "ohos_image_pixelmap.h" + +int32_t GetImageInfo(JNIEnv *env, jobject pixelMapObject, OhosPixelMapInfo &info) +{ + if (env == nullptr || pixelMapObject == nullptr) { + return OHOS_IMAGE_RESULT_BAD_PARAMETER; + } + + OHOS::Media::ohos_media_image_GetImageInfo(env, pixelMapObject, info); + return OHOS_IMAGE_RESULT_SUCCESS; +} + +int32_t AccessPixels(JNIEnv *env, jobject pixelMapObject, void **addrPtr) +{ + if (env == nullptr || pixelMapObject == nullptr) { + return OHOS_IMAGE_RESULT_BAD_PARAMETER; + } + + void *addr = OHOS::Media::ohos_media_image_AccessPixels(env, pixelMapObject); + if (!addr) { + return OHOS_IMAGE_RESULT_JNI_EXCEPTION; + } + + if (addrPtr) { + *addrPtr = addr; + } + return OHOS_IMAGE_RESULT_SUCCESS; +} + +int32_t UnAccessPixels(JNIEnv *env, jobject pixelMapObject) +{ + if (env == nullptr || pixelMapObject == nullptr) { + return OHOS_IMAGE_RESULT_BAD_PARAMETER; + } + + bool unAccessed = OHOS::Media::ohos_media_image_UnAccessPixels(env, pixelMapObject); + if (!unAccessed) { + return OHOS_IMAGE_RESULT_JNI_EXCEPTION; + } + return OHOS_IMAGE_RESULT_SUCCESS; +} diff --git a/interfaces/kits/native/test/BUILD.gn b/interfaces/kits/native/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ee60f67e03b7aa91f761b78c8413f6ebcd4684c3 --- /dev/null +++ b/interfaces/kits/native/test/BUILD.gn @@ -0,0 +1,44 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +module_output_path = "multimedia_image/image_standard" +ohos_unittest("pixlmapndktest") { + module_out_path = module_output_path + include_dirs = [ + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/googletest/googletest/include", + "//foundation/multimedia/image_standard/interfaces/kits/native/include", + "//utils/native/base/include", + ] + sources = [ "//foundation/multimedia/image_standard/interfaces/kits/native/test/unittest/pixel_map_ndk_test.cpp" ] + + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//foundation/multimedia/image_standard/interfaces/kits/native:multimedia_target", + "//foundation/multimedia/image_standard/interfaces/kits/native/ndk_test_example:image_ndk_test_jni", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] +# external_deps = [ "hilog:libhilog" ] + resource_config_file = + "//foundation/multimedia/image_standard/test/resource/image/ohos_test.xml" +} + +################################################ +group("unittest") { + testonly = true + deps = [ ":pixlmapndktest" ] +} +################################################ diff --git a/interfaces/kits/native/test/unittest/pixel_map_ndk_test.cpp b/interfaces/kits/native/test/unittest/pixel_map_ndk_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8483346cefee7e423b87b5fd4f0515ab51953cf --- /dev/null +++ b/interfaces/kits/native/test/unittest/pixel_map_ndk_test.cpp @@ -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. + */ + +#include +#include "image_pixel_map.h" +#include "pixel_map_manager.h" + +using namespace testing::ext; +using namespace OHOS::Media; +namespace OHOS { +namespace Multimedia { +class PixelMapNdkTest : public testing::Test { +public: + PixelMapNdkTest(){}; + ~PixelMapNdkTest(){}; +}; + +/** + * @tc.name: PixelMapNdkTest001 + * @tc.desc: override ndk interface,exception. + * @tc.type: FUNC + */ +HWTEST_F(PixelMapNdkTest, PixelMapNdkTest001, TestSize.Level3) +{ + /** + * @tc.steps: step1. test AccessPixels input Illegal pixelmap. + * @tc.expected: step1. expect ok. + */ + void *pixels = nullptr; + int err = AccessPixels(nullptr, nullptr, &pixels); + ASSERT_EQ(err, OHOS_IMAGE_RESULT_BAD_PARAMETER); + + /** + * @tc.steps: step2. test UnAccessPixels input Illegal pixelmap. + * @tc.expected: step2. expect ok. + */ + err = UnAccessPixels(nullptr, nullptr); + ASSERT_EQ(err, OHOS_IMAGE_RESULT_BAD_PARAMETER); + + /** + * @tc.steps: step2. test GetImageInfo input Illegal pixelmap. + * @tc.expected: step2. expect ok. + */ + OhosPixelMapInfo info; + err = GetImageInfo(nullptr, nullptr, info); + ASSERT_EQ(err, OHOS_IMAGE_RESULT_BAD_PARAMETER); +} +} // namespace Multimedia +} // namespace OHOS diff --git a/mock/java/src/ohos/BUILD.gn b/mock/java/src/ohos/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0217bb1e5f4ff75371286e60855b88f22fd043b9 --- /dev/null +++ b/mock/java/src/ohos/BUILD.gn @@ -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("//build/config/ohos/rules.gni") +import("//foundation/multimedia/image/ide/image_decode_config.gni") + +java_library("mock_java") { + java_files = [ + "hiviewdfx/HiLog.java", + "hiviewdfx/HiLogConstString.java", + "hiviewdfx/HiLogLabel.java", + "media/utils/log/Logger.java", + "media/utils/log/LoggerFactory.java", + "utils/Parcel.java", + "global/resource/RawFileDescriptor.java", + "utils/Sequenceable.java", + "system/Parameters.java", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/mock/java/src/ohos/global/resource/RawFileDescriptor.java b/mock/java/src/ohos/global/resource/RawFileDescriptor.java new file mode 100644 index 0000000000000000000000000000000000000000..52b20b95a29fc242bc1787ecb6d8d7e776ab0e5e --- /dev/null +++ b/mock/java/src/ohos/global/resource/RawFileDescriptor.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.global.resource; + +import java.io.Closeable; +import java.io.FileDescriptor; + +/** + * Provides the file descriptor of a raw file from {@code RawFileEntry}. + * + *

You can use the file descriptor to read data, obtain the data start position, and obtain the length of the raw + * file. This class inherits from {@code BaseFileDescriptor}. The {@code RawFileDescriptor} instance can be obtained + * only by using the {@link ohos.global.resource.RawFileEntry#openRawFileDescriptor()} method. + * + * @see RawFileEntry + * @see BaseFileDescriptor + * @since 3 + */ +public abstract class RawFileDescriptor implements Closeable { + /** + * Obtains the file descriptor of the raw file. + * + *

You can use the file descriptor to read data in the raw file. + * + * @return Returns the file descriptor. + * @since 3 + */ + public abstract FileDescriptor getFileDescriptor(); + + /** + * Obtains the size of the raw file. + * + * @return Returns the raw file size, in bytes. + * @since 3 + */ + public abstract long getFileSize(); + + /** + * Obtains the start position of data in the raw file. + * + * @return Returns the start position. + * @since 3 + */ + public abstract long getStartPosition(); +} \ No newline at end of file diff --git a/mock/java/src/ohos/hiviewdfx/HiLog.java b/mock/java/src/ohos/hiviewdfx/HiLog.java new file mode 100644 index 0000000000000000000000000000000000000000..ed7d077b778f285e7ae6867350f7fd87f874302e --- /dev/null +++ b/mock/java/src/ohos/hiviewdfx/HiLog.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.hiviewdfx; + +/** + * HiLog + * + * @since 1 + */ +public final class HiLog { + /** + * Log Type 1 + */ + public static final int LOG_INIT = 1; + /** + * Log Type 3 + */ + public static final int LOG_CORE = 3; + + /** + * log level debug + */ + public static final int DEBUG = 3; + /** + * log level info + */ + public static final int INFO = 4; + /** + * log level warn + */ + public static final int WARN = 5; + /** + * log level error + */ + public static final int ERROR = 6; + /** + * log level fatal + */ + public static final int FATAL = 7; + + /** + * print debug log + * + * @param label log label + * @param format log format + * @param args log format arguments + * @return result of success is large than 0 + */ + public static int debug(HiLogLabel label, @HiLogConstString String format, Object[] args) { + return DEBUG; + } + + /** + * print info log + * + * @param label log label + * @param format log format + * @param args log format arguments + * @return result of success is large than 0 + */ + public static int info(HiLogLabel label, @HiLogConstString String format, Object[] args) { + return INFO; + } + + /** + * print warn log + * + * @param label log label + * @param format log format + * @param args log format arguments + * @return result of success is large than 0 + */ + public static int warn(HiLogLabel label, @HiLogConstString String format, Object[] args) { + return WARN; + } + + /** + * print error log + * + * @param label log label + * @param format log format + * @param args log format arguments + * @return result of success is large than 0 + */ + public static int error(HiLogLabel label, @HiLogConstString String format, Object[] args) { + return ERROR; + } + + /** + * print fatal log + * + * @param label log label + * @param format log format + * @param args log format arguments + * @return result of success is large than 0 + */ + public static int fatal(HiLogLabel label, @HiLogConstString String format, Object[] args) { + return FATAL; + } + + /** + * whether debug + * + * @param domain log domain + * @param tag log tag + * @param level log level + * @return true is debug, false is not debug + */ + public static boolean isLoggable(int domain, String tag, int level) { + return true; + } +} \ No newline at end of file diff --git a/mock/java/src/ohos/hiviewdfx/HiLogConstString.java b/mock/java/src/ohos/hiviewdfx/HiLogConstString.java new file mode 100644 index 0000000000000000000000000000000000000000..72eb32c52268f53965b034f861df7774690389ad --- /dev/null +++ b/mock/java/src/ohos/hiviewdfx/HiLogConstString.java @@ -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. + */ + +package ohos.hiviewdfx; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Target; + +@Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER, + java.lang.annotation.ElementType.LOCAL_VARIABLE}) +public @interface HiLogConstString{ +} \ No newline at end of file diff --git a/mock/java/src/ohos/hiviewdfx/HiLogLabel.java b/mock/java/src/ohos/hiviewdfx/HiLogLabel.java new file mode 100644 index 0000000000000000000000000000000000000000..12ff6eae979453c61ad42bc761f83a9f1df28f6a --- /dev/null +++ b/mock/java/src/ohos/hiviewdfx/HiLogLabel.java @@ -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. + */ + +package ohos.hiviewdfx; + +/** + * HiLogLabel + * + * @since 1 + */ +public final class HiLogLabel { + /** + * log type + */ + public int type; + /** + * log domain + */ + public int domain; + /** + * log tag + */ + public String tag; + + /** + * HiLogLabel + * + * @param type log type + * @param domain log domain + * @param tag log tag + */ + public HiLogLabel(int type, int domain, String tag) { + this.type = type; + this.domain = domain; + this.tag = tag; + } +} \ No newline at end of file diff --git a/mock/java/src/ohos/media/image/ExifUtils.java b/mock/java/src/ohos/media/image/ExifUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2ef83aa80904ca93d179f8d1dd0f25f70e7de56a --- /dev/null +++ b/mock/java/src/ohos/media/image/ExifUtils.java @@ -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. + */ + +package ohos.media.image; + +import ohos.media.image.common.PropertyKey; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; +import ohos.utils.Pair; + +import java.util.Optional; + +/** + * Provides methods to obtain a combination of Exchangeable Image File Format (Exif) properties, such as the longitude, + * latitude, and altitude. + * + * @since 3 + */ +public class ExifUtils { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ExifUtils.class); + + private static final double MINUTES = 60.0; + + private static final double SECONDS = 3600.0; + + private static final int DEFAULT_VALUE = -1; + + private static final String RATIONAL_SEPARATOR = "/"; + + /** + * Obtains longitude and latitude information about the image in its Exif property. + * + * @param imageSource Indicates the image data source. + * @return Returns the {@code Pair} object containing the longitude and latitude information if the information + * exists; returns {@code null} otherwise. The {@code f} member of {@code Pair} indicates the latitude, and {@code + * s} indicates the longitude. + * @throws IllegalStateException Throws this exception if native resources associated with {@code imageSource} have + * been released. + * @throws IllegalArgumentException Throws this exception if {@code imageSource} is null. + * @since 3 + */ + public static Pair getLatLong(ImageSource imageSource) { + return null; + } + + /** + * Obtains altitude information about the image in its Exif property. + * + * @param imageSource Indicates the image data source. + * @param defaultValue Indicates the custom default value of the property. + * @return Returns the altitude information if it exists; returns the custom default value otherwise. + * @throws IllegalStateException Throws this exception if native resources associated with {@code imageSource} have + * been released. + * @throws IllegalArgumentException Throws this exception if {@code imageSource} is null. + * @since 3 + */ + public static double getAltitude(ImageSource imageSource, double defaultValue) { + return DEFAULT_VALUE; + } + + private static float convertRationalToFloat(String rationalNum, String ref) { + return DEFAULT_VALUE; + } +} diff --git a/mock/java/src/ohos/media/image/Image.java b/mock/java/src/ohos/media/image/Image.java new file mode 100644 index 0000000000000000000000000000000000000000..cba450a21cfa05f5ec8db4dc3724fde4bc287dc8 --- /dev/null +++ b/mock/java/src/ohos/media/image/Image.java @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.Rect; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + + +/** + * Provides basic image operations, including obtaining image information, and reading and writing image data. + * + *

An {@code Image} object can be generated by an {@link ImageReceiver} object. + * + * @since 1 + */ +public class Image { + private static final Logger LOGGER = LoggerFactory.getImageLogger(Image.class); + + private static final int FAILURE_VALUE = -1; + + /** + * Image availability status + */ + private volatile boolean isImageValid = false; + + /** + * Timestamp in nanosecond + */ + private long timestamp = 0L; + + /** + * Clip rectangle + */ + private Rect clipRect; + + /** + * Color components + */ + private Component[] components; + + /** + * Image Receiver + */ + private ImageReceiver imageReceiver; + + /** + * Native used,tracing native object + */ + private long nativeBuffer; + + /** + * Constructor + * + * @param imageReceiver The image receiver. + */ + Image(ImageReceiver imageReceiver) { + if (imageReceiver == null) { + LOGGER.error("imageReceiver is null."); + throw new IllegalArgumentException("imageReceiver is null."); + } + this.imageReceiver = imageReceiver; + } + + /** + * Set the image status. + * + * @param isImageValid The image status. + */ + void setImageStatus(boolean isImageValid) { + this.isImageValid = isImageValid; + } + + /** + * Get the image status. + * + * @return The image status. + */ + boolean getImageStatus() { + return false; + } + + /** + * Obtains the image format. + * + * @return Returns the image format, which is defined by {@link ImageFormat}. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public int getFormat() { + return FAILURE_VALUE; + } + + /** + * Obtains the image size. + * + * @return Returns the image size, which is specified by a {@link Size} object. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public Size getImageSize() { + Size size = new Size(); + return size; + } + + /** + * Obtains the image timestamp, in nanoseconds. + * + * @return Returns the timestamp. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public long getTimestamp() { + return FAILURE_VALUE; + } + + /** + * Obtains the cropped area of an image. + * + * @return Returns the cropped area, which is specified by a {@link Rect} object. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public Rect getClipRect() { + Rect rect = new Rect(); + return rect; + } + + /** + * Sets the image area to crop. + * + *

If the area exceeds the image size or is outside of the image, the cropping will not be operated. + * + * @param clipRect Indicates the image area to crop, which is specified by a {@link Rect} object. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public void setClipRect(Rect clipRect) { + return; + } + + /** + * Releases native resources associated with the image. + * + *

After the image data is released, any image operation will not be supported. + * + * @since 1 + */ + public void release() { + return; + } + + @Override + protected void finalize() throws Throwable { + return; + } + + /** + * Obtains the color component based on a specified component type. + * + * @param componentType Indicates a color component type, which is specified by {@link ImageFormat.ComponentType}. + * @return Returns the image color component if obtained; returns {@code null} if the image does not + * have the type of color component. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public Component getComponent(ImageFormat.ComponentType componentType) { + ByteBuffer buffer = ByteBuffer.allocate(1024); + Component component = new Component(FAILURE_VALUE, FAILURE_VALUE, FAILURE_VALUE, buffer); + return component; + } + + /** + * Get all component data from native. + * + * @throws IllegalStateException Error when image is invalid. + */ + private void initComponents() { + return; + } + + /** + * Check image is valid. + * + * @throws IllegalStateException Error when image is invalid. + */ + private void checkImageIsValid() { + return; + } + + /** + * Describes image color components. + * + *

This class provides methods for obtaining image color component attributes, + * and reading and writing color component data. + * + * @since 1 + */ + public static class Component { + /** + * Describes results of color component–related operations. + * + * @since 1 + */ + public static final class OperationResult { + /** + * Indicates that the color component–related operation is successful. + * + * @since 1 + */ + public static final int SUCCESS = 0; + + /** + * Indicates that the color component–related operation fails. + * + * @since 1 + */ + public static final int FAILURE = -1; + + /** + * Indicates that the operation is not supported because the specified color component has been released. + * + * @since 1 + */ + public static final int RELEASED = -2; + + private OperationResult() {} + } + + /** + * Byte unsigned mask. + */ + private static final int UNSIGNED_BYTE_MASK = 0xFF; + + /** + * Indicates the color component type defined in {@link ImageFormat.ComponentType}. + * + * @since 1 + */ + public final ImageFormat.ComponentType componentType; + + /** + * Indicates the distance in bytes between adjacent pixel rows. + * + * @since 1 + */ + public final int rowStride; + + /** + * Indicates the distance in bytes between adjacent pixels in a row. + * + * @since 1 + */ + public final int pixelStride; + + /** + * Buffer of image data. + */ + private ByteBuffer byteBuffer; + + /** + * Default constructor, be created by native. + * + * @param componentType ComponentType value {@link ImageFormat.ComponentType}. + * @param rowStride Distance of adjacent row pixels. + * @param pixelStride Distance of adjacent pixels. + * @param byteBuffer Buffer of image data. + */ + private Component(int componentType, int rowStride, int pixelStride, ByteBuffer byteBuffer) { + this.componentType = ImageFormat.ComponentType.valueOf(componentType); + this.rowStride = rowStride; + this.pixelStride = pixelStride; + this.byteBuffer = byteBuffer; + // Set the byteBuffer order in native order, otherwise the default order is BIG_ENDIAN + this.byteBuffer.order(ByteOrder.nativeOrder()); + } + + /** + * Reads color component data of one byte. + * + * @return Returns the data if the reading is successful; returns {@link OperationResult#FAILURE} + * constant if the reading fails; returns the {@link OperationResult#RELEASED} constant if the + * image or component data is released. + * @since 1 + */ + public int read() { + return FAILURE_VALUE; + } + + /** + * Reads color component data of multiple consecutive bytes. + * + * @param dstArray Indicates an array to store the data. + * @return Returns the {@link OperationResult#SUCCESS} constant if the reading is successful; + * returns the {@link OperationResult#FAILURE} constant if the reading fails; returns the + * {@link OperationResult#RELEASED} constant if the image or component data is released. + * @since 1 + */ + public int read(byte[] dstArray) { + return FAILURE_VALUE; + } + + /** + * Reads color component data of multiple consecutive bytes and write the data in an + * array with specified offsets and length. + * + * @param dstArray Indicates an array to store the data. + * @param offset Indicates where to write the data in the target array. + * @param length Indicates the maximum length allowed to write data into the target array. + * @return Returns the {@link OperationResult#SUCCESS} constant if the reading is successful; + * returns the {@link OperationResult#FAILURE} constant if the reading fails; returns the + * {@link OperationResult#RELEASED} constant if the image or component data is released. + * @since 1 + */ + public int read(byte[] dstArray, int offset, int length) { + return FAILURE_VALUE; + } + + /** + * Obtains the position of the current color component data to read. + * + * @return Returns the position of the current color component data if obtained; returns the + * {@link OperationResult#RELEASED} if the image or component data is released. + * @since 1 + */ + public int tell() { + return FAILURE_VALUE; + } + + /** + * Sets a position of the current color component data to read. + * + * @param newPosition Indicates a new position of the current color component data to read. + * @return Returns the {@link OperationResult#SUCCESS} constant if the reading position is set; + * returns the {@link OperationResult#FAILURE} constant if the setting fails; returns the + * {@link OperationResult#RELEASED} constant if the image or component data is released. + * @since 1 + */ + public int seek(int newPosition) { + return FAILURE_VALUE; + } + + /** + * Obtains the remaining data size (in bytes) of the color component. + * + * @return Returns the bytes of the remaining data if obtained; returns the {@link OperationResult#RELEASED} + * if the image or component data is released. + * @since 1 + */ + public int remaining() { + return FAILURE_VALUE; + } + + /** + * Obtains the {@link java.nio.ByteBuffer} object of the current color component. Note that the object directly + * maps to the native resource buffer. After the receiver or image resource is released, the object should + * not be used to read or write data. + * + * @return Returns the {@link java.nio.ByteBuffer} object of the current color component. + * @throws IllegalStateException Throws this exception if the operation is not supported, + * for example, if native resources associated with the receiver or image are released. + * @since 1 + */ + public ByteBuffer getBuffer() { + ByteBuffer buffer = ByteBuffer.allocate(1024); + return buffer; + } + + /** + * Releases native resources associated with the color component. + * + *

After this method is called, color component-related operations will no longer be supported. + * + * @since 1 + */ + public void release() { + return; + } + + private void checkParameterIsValid() { + return; + } + + /** + * Reflect invoke NioUtils freeDirectBuffer method. + * + * @param byteBuffer DirectByteBuffer object. + */ + private void reflectFreeDirectBuffer(ByteBuffer byteBuffer) { + return; + } + } +} diff --git a/mock/java/src/ohos/media/image/ImagePacker.java b/mock/java/src/ohos/media/image/ImagePacker.java new file mode 100644 index 0000000000000000000000000000000000000000..75e67eccfe3e1fc3ebdc017d1fe7aa16b13172a0 --- /dev/null +++ b/mock/java/src/ohos/media/image/ImagePacker.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; + +import java.io.OutputStream; +import java.util.HashSet; + +/** + * Represents the image packer that packs compressed images into files or other objects. + * + *

You can call {@code create} to create an image packer, {@code initializePacking} to set packing options, + * {@code addImage} to add image data to be packed, and {@code finalizePacking} to complete packing and output the + * target object. + * + * @since 3 + */ +public class ImagePacker { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImagePacker.class); + + /** + * Success state by image packer native interface return. + */ + private static final int SUCCESS = 0; + + private static final long FAILED = -1L; + + private static final int BUFFER_SIZE = 4096; + + /** + * Accessed by native methods, save object address + */ + private long nativeImagePacker; + + /** + * native used, write tmp buffer + */ + private byte[] nativeBuffer = new byte[BUFFER_SIZE]; + + /** + * Private constructor called by JNI. + * + * @param nativePtr the native object point. + */ + private ImagePacker(long nativePtr) { + nativeImagePacker = nativePtr; + } + + /** + * Creates an {@code ImagePacker} instance. + * + * @return Returns the {@code ImagePacker} instance if created; returns {@code null} if an exception occurs. + * @since 3 + */ + public static ImagePacker create() { + return new ImagePacker(FAILED); + } + + /** + * Obtains the supported output image formats for packing. + * + * @return Returns the set of supported output image formats, which are represented by MIME type strings, for + * example, {@code image/jpeg}. Currently, only the JPEG format is supported. + * @since 3 + */ + public static HashSet getSupportedFormats() { + HashSet hashSet = new HashSet<>(); + return hashSet; + } + + /** + * Describes options for compressing and packing. + * + *

The options include the output file format, compression quality, and other parameters. + * + * @since 3 + */ + public static class PackingOptions { + /** + * Indicates the output image format represented by an MIME type string. {@code image/jpeg} is supported. + * + * @since 3 + */ + public String format = "image/jpeg"; + + /** + * Indicates the image compression quality. The value ranges from 0 to 100. A larger value indicates better + * image quality but larger space occupied. + * + * @since 3 + */ + public int quality = 100; + + /** + * Indicates the prompt of the number of images to be packed. + * + * @since 3 + */ + public int numberHint = 1; + } + + /** + * Initializes the packing task that outputs the result to a byte array. + * + * @param data Indicates the byte array containing the packed images. + * @param opts Indicates the packing options. + * @return Returns {@code true} if the packing task is successfully initialized; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean initializePacking(byte[] data, PackingOptions opts) { + return false; + } + + /** + * Initializes the packing task that outputs the result to a byte array at a specific offset. + * + * @param data Indicates the byte array containing the packed images. + * @param offset Indicates the data array offset into which the compressed image data will be written. + * @param opts Indicates the packing options. + * @return Returns {@code true} if the packing task is successfully initialized; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean initializePacking(byte[] data, int offset, PackingOptions opts) { + return false; + } + + /** + * Initializes the packing task that outputs the result to a {@code OutputStream} object. + * + * @param outputStream Indicates the output stream of the packed images. + * @param opts Indicates the packing options. + * @return Returns {@code true} if the packing task is successfully initialized; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean initializePacking(OutputStream outputStream, PackingOptions opts) { + return false; + } + + /** + * Adds a {@link PixelMap} to the image packer. + * + *

This method adds only one {@link PixelMap} object at a time. + * + * @param pixelmap Indicates the {@link PixelMap} to be packed. + * @return Returns {@code true} if the pixel map is added; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean addImage(PixelMap pixelmap) { + return false; + } + + /** + * Adds the image in an {@link ImageSource} to the image packer. + * + *

If the {@link ImageSource} contains multiple images, only the first image will be added. + * + * @param source Indicates the {@code ImageSource}. + * @return Returns {@code true} if the image is added; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean addImage(ImageSource source) { + return false; + } + + /** + * Adds a specified image in an {@link ImageSource} to the image packer. + * + *

You can use an index to specify the image to be added. + * + * @param source Indicates the {@code ImageSource}. + * @param index Indicates the index of the target image in the {@code ImageSource}. The value starts from 0. + * @return Returns {@code true} if the specified image is added; returns {@code false} otherwise. + * @throws IllegalArgumentException Throws this exception if the input parameter is invalid. + * @since 3 + */ + public boolean addImage(ImageSource source, int index) { + return false; + } + + /** + * Completes the image packing. + * + *

Calling this method will inform the {@code ImagePacker} that all the required image data has been + * added for packing and the {@code ImagePacker} will pack the data into the specified object. + * + * @return Returns the output data size (in bytes) if the operation is successful; returns {@code -1} otherwise. + * @since 3 + */ + public long finalizePacking() { + return FAILED; + } + + /** + * Releases native resources associated with the {@code ImagePacker} object. + * + * @since 3 + */ + public void release() { + return; + } + + @Override + protected void finalize() throws Throwable { + release(); + super.finalize(); + } + + /** + * Checks whether native resources have been released. + * + * @return Returns {@code true} if the resources are released; returns {@code false} otherwise. + * @since 1 + */ + private boolean isReleased() { + return nativeImagePacker == 0; + } + + private boolean isPackerOptionValid(String format, int quality) { + return false; + } +} diff --git a/mock/java/src/ohos/media/image/ImageReceiver.java b/mock/java/src/ohos/media/image/ImageReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..03dc939478c0815494b50a3d7b5b6408aed306d1 --- /dev/null +++ b/mock/java/src/ohos/media/image/ImageReceiver.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image; + +import ohos.agp.graphics.Surface; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; +import ohos.media.image.common.ImageFormat; +import ohos.media.image.common.Size; +import ohos.media.utils.log.Logger; +import ohos.media.utils.log.LoggerFactory; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Set; + +/** + * Describes an image receiver that connects to an image output device and + * provides a buffer queue to receive image data. + * + * @since 1 + */ +public class ImageReceiver { + private static final Logger LOGGER = LoggerFactory.getImageLogger(ImageReceiver.class); + private static final int FAILURE_VALUE = -1; + private static final String HANDLER_NAME = "nativeEventHandler"; + private static final long USAGE_CPU_READ_OFTEN = 3L; // native hardware setting + private static final int MIN_POSITIVE = 1; + private final int width; + private final int height; + private final int format; + private final int capacity; + private final Object receiverLock = new Object(); + private volatile boolean isReceiverValid = false; // receiver availability status + private volatile IImageArrivalListener arrivalListener; // native callback listener + private final Set images = new HashSet<>(); // image release when free receiver + private long nativeContext; // native used,tracing native object + private volatile EventHandler handler; + + /** + * Creates an {@link ImageReceiver} instance based on a specified image width, height, format, + * and the buffer queue capacity. + * + * @param width Indicates the image width. + * @param height Indicates the image height. + * @param format Indicates the image format, which is defined by {@link ImageFormat}. + * @param capacity Indicates the maximum buffer capacity of the image receiver. The value must be greater than 0. + * @return Returns the {@link ImageReceiver} object. + * @throws IllegalArgumentException Throws this exception if a parameter is incorrect. + * @throws IllegalStateException Throws this exception if the operation is not supported in the current state, + * for example, if native resources fail to be applied for the receiver. + * @since 1 + */ + public static ImageReceiver create(int width, int height, int format, int capacity) { + return new ImageReceiver(width, height, format, capacity, USAGE_CPU_READ_OFTEN); + } + + /** + * Constructor implement. + * + * @param width The width in pixels of the image. + * @param height The height in pixels of the image. + * @param format The format of image, which is one of values from {@link ImageFormat}. + * @param capacity The maximum number of images cached by ImageReceiver, must be larger than 0. + * @param usage The intended usage of the image. + * @throws IllegalArgumentException when width, height or imageCount not valid. + * @throws IllegalStateException Error when native create failed. + */ + private ImageReceiver(int width, int height, int format, int capacity, long usage) { + if (width < MIN_POSITIVE || height < MIN_POSITIVE) { + LOGGER.error("The image size:[%{public}d, %{public}d] must be positive.", width, height); + throw new IllegalArgumentException("The image size must be positive."); + } + if (capacity < MIN_POSITIVE) { + LOGGER.error("The image capacity %{public}d must be larger than zero.", capacity); + throw new IllegalArgumentException("The image capacity must be larger than zero."); + } + // ImageReceiver can't support NV21 format + if (format == ImageFormat.NV21) { + LOGGER.error("NV21 format is not supported."); + throw new IllegalArgumentException("NV21 format is not supported."); + } + this.width = width; + this.height = height; + this.format = format; + this.capacity = capacity; + isReceiverValid = true; + } + + /** + * Obtains the receiver surface of the image receiver. + * + * @return Returns a {@link Surface} object of the image receiver. + * @since 3 + */ + public Surface getRecevingSurface() { + Surface surface = new Surface(); + return surface; + } + + /** + * Obtains the image size. + * + * @return Returns the image size specified in a {@link Size} object. + * @since 1 + */ + public Size getImageSize() { + return new Size(width, height); + } + + /** + * Obtains the maximum buffer capacity of the image receiver. + * + * @return Returns the buffer size of the image receiver. + * @since 1 + */ + public int getCapacity() { + return capacity; + } + + /** + * Obtains the image format. + * + * @return Returns the image format, which is defined by {@link ImageFormat}. + * @since 1 + */ + public int getImageFormat() { + return format; + } + + /** + * Reads the latest image data from the buffer queue and clears earlier images from the queue. + * + * @return Returns the latest image data if obtained; returns {@code null} otherwise. + * @throws IllegalStateException Throws this exception if the operation is not supported in the current state, + * for example, if native resources associated with the receiver are released. + * @since 1 + */ + public Image readLatestImage() { + ImageReceiver imageReceiver = + new ImageReceiver(FAILURE_VALUE, FAILURE_VALUE, FAILURE_VALUE, FAILURE_VALUE, FAILURE_VALUE); + return new Image(imageReceiver); + } + + /** + * Reads the next image from the buffer queue. + * + * @return Returns next image data if obtained; returns {@code null} otherwise. + * @throws IllegalStateException Throws this exception if the operation is not supported in the current state, + * for example, if native resources associated with the receiver are released. + * @since 1 + */ + public Image readNextImage() { + Image image = null; + return image; + } + + /** + * Releases native resources associated with the image receiver, including the surface and obtained images. + * + * @since 1 + */ + public void release() { + return; + } + + @Override + protected void finalize() throws Throwable { + return; + } + + /** + * Native call back when an Event happens. + * + * @param objectRef ImageReceiver reference form native. + */ + private static void onEventFromNative(Object objectRef) { + return; + } + + /** + * Sets the image listener which will be called when new image data is received. + * + * @param listener Indicates the image listener, which is defined by {@link IImageArrivalListener}. + * @since 1 + */ + public void setImageArrivalListener(IImageArrivalListener listener) { + return; + } + + /** + * Callback interface used when new image data is received. + * + * @since 1 + */ + public interface IImageArrivalListener { + /** + * Called when new image data is received. + * + * @param imageReceiver Indicates an {@link ImageReceiver} object. + * @since 1 + */ + void onImageArrival(ImageReceiver imageReceiver); + } +} diff --git a/mock/java/src/ohos/media/image/exifadapter/ExifAdapter.java b/mock/java/src/ohos/media/image/exifadapter/ExifAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..919260ca99bc9622c1d7e2bf0afd37df8b865edf --- /dev/null +++ b/mock/java/src/ohos/media/image/exifadapter/ExifAdapter.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.image.exifadapter; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; + +/** + * exif adapter for ImageSource. + * + * @since 3 + */ +public class ExifAdapter { + private static final int INT_RETURN = -1; + + private static final String STRING_RETURN = "-1"; + + private static final byte[] BYTE_RETURN = new byte[1]; + + private static final long[] LONG_RETURN = new long[2]; + + private static final double DOUBLE_RETURN = 1.11; + + /** + * Instantiates a new Exif adapter. + * + * @param pathName the path name + * @since 3 + */ + public ExifAdapter(String pathName) { + } + + /** + * Instantiates a new Exif adapter. + * + * @param inputStream the input stream + * @since 3 + */ + public ExifAdapter(InputStream inputStream) { + } + + /** + * Instantiates a new Exif adapter. + * + * @param data the data + * @param offset the offset + * @param length the length + * @since 3 + */ + public ExifAdapter(byte[] data, int offset, int length) { + } + + /** + * Instantiates a new Exif adapter. + * + * @param file the input file + * @since 3 + */ + public ExifAdapter(File file) { + } + + /** + * Instantiates a new Exif adapter. + * + * @param fd the input fd + * @since 3 + */ + public ExifAdapter(FileDescriptor fd) { + } + + /** + * Gets image property. + * + * @param key the key + * @return the image property + * @since 3 + */ + public String getImagePropertyString(String key) { + return STRING_RETURN; + } + + /** + * Gets image property int. + * + * @param key the key + * @param defaultValue the default value + * @return the image property int + * @since 3 + */ + public int getImagePropertyInt(String key, int defaultValue) { + return INT_RETURN; + } + + /** + * Get thumbnail bytes byte. + * + * @return the byte + * @since 3 + */ + public byte[] getThumbnailBytes() { + return BYTE_RETURN; + } + + /** + * Get thumbnail byte. + * + * @return the byte + * @since 3 + */ + public byte[] getThumbnail() { + return BYTE_RETURN; + } + + /** + * Get thumbnail offset and length. + * + * @return the long array. + * @since 5 + */ + public long[] getThumbnailRange() { + return LONG_RETURN; + } + + /** + * Gets image property double. + * + * @param key the key + * @param defaultValue the default value + * @return the image property double + */ + public double getImagePropertyDouble(String key, double defaultValue) { + return DOUBLE_RETURN; + } + + /** + * set image property. + * + * @param key the property key + * @param property value + * @since 3 + */ + public void setImageProperty(String key, String value) { + return; + } + + /** + * Save the setImageProperty property data into the original image file + * + * @throws IOException the io exception + * @since 3 + */ + public void saveAttributes() { + return; + } +} diff --git a/mock/java/src/ohos/media/utils/log/Logger.java b/mock/java/src/ohos/media/utils/log/Logger.java new file mode 100644 index 0000000000000000000000000000000000000000..67d9872823750453ef65fdfeabb8f9572eea4a6c --- /dev/null +++ b/mock/java/src/ohos/media/utils/log/Logger.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.utils.log; + +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogConstString; +import ohos.hiviewdfx.HiLogLabel; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Multimedia logger, based on OHOS HiLog, support turn off by system parameter {@code sys.multimedia.logger.on}. + * + * @since 1 + */ +public final class Logger { + /** + * Logger is off + * + * @since 3 + */ + public static final int LOGGER_OFF = -1; + + /** + * Logger level is debug + * + * @since 3 + */ + public static final int LEVEL_DEBUG = HiLog.DEBUG; + + /** + * Logger level is info + * + * @since 3 + */ + public static final int LEVEL_INFO = HiLog.INFO; + + /** + * Logger level is warn + * + * @since 3 + */ + public static final int LEVEL_WARN = HiLog.WARN; + + /** + * Logger level is error + * + * @since 3 + */ + public static final int LEVEL_ERROR = HiLog.ERROR; + + /** + * Logger level is fatal + * + * @since 3 + */ + public static final int LEVEL_FATAL = HiLog.FATAL; + + /** + * Logger level is off + * + * @since 3 + */ + public static final int LEVEL_OFF = Integer.MAX_VALUE; + + private final HiLogLabel label; + + private final int level; + + Logger(HiLogLabel label, int level) { + this.label = label; + this.level = level; + } + + /** + * Print debug level log. + * + * @param format String to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 1 + */ + public int debug(@HiLogConstString String format, Object... args) { + if (level <= LEVEL_DEBUG) { + return HiLog.debug(label, format, args); + } + return LOGGER_OFF; + } + + /** + * Print info level log. + * + * @param format String to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 1 + */ + public int info(@HiLogConstString String format, Object... args) { + if (level <= LEVEL_INFO) { + return HiLog.info(label, format, args); + } + return LOGGER_OFF; + } + + /** + * Print warn level log. + * + * @param format String to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 1 + */ + public int warn(@HiLogConstString String format, Object... args) { + if (level <= LEVEL_WARN) { + return HiLog.warn(label, format, args); + } + return LOGGER_OFF; + } + + /** + * Print error level log. + * + * @param format String to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 1 + */ + public int error(@HiLogConstString String format, Object... args) { + if (level <= LEVEL_ERROR) { + return HiLog.error(label, format, args); + } + return LOGGER_OFF; + } + + /** + * Print error level log, contains throwable stack trace. + * + * @param format String to print + * @param throwable The throwable to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 3 + */ + public int error(@HiLogConstString String format, Throwable throwable, Object... args) { + return LOGGER_OFF; + } + + private String parseStackTrace(Throwable throwable) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + throwable.printStackTrace(pw); + pw.close(); + return sw.toString(); + } + + /** + * Print fatal level log. + * + * @param format String to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 1 + */ + public int fatal(@HiLogConstString String format, Object... args) { + if (level <= LEVEL_FATAL) { + return HiLog.fatal(label, format, args); + } + return LOGGER_OFF; + } + + /** + * Print fatal level log, contains throwable stack trace. + * + * @param format String to print + * @param throwable The throwable to print + * @param args args to replace the type placeholder + * @return HiLog return value + * @since 3 + */ + public int fatal(@HiLogConstString String format, Throwable throwable, Object... args) { + return LOGGER_OFF; + } + + /** + * Print begin message in debug level log. + * + * @param msg Message to print + * @since 3 + */ + public void begin(String msg) { + if (level <= LEVEL_DEBUG) { + debug("%{public}s begin", msg); + } + } + + /** + * Print end message in debug level log. + * + * @param msg Message to print + * @since 3 + */ + public void end(String msg) { + if (level <= LEVEL_DEBUG) { + debug("%{public}s end", msg); + } + } + + /** + * Get the label of current logger. + * + * @return The label of current logger + * @since 1 + */ + public HiLogLabel getLabel() { + return label; + } +} diff --git a/mock/java/src/ohos/media/utils/log/LoggerFactory.java b/mock/java/src/ohos/media/utils/log/LoggerFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..c528429317c4c36f5767769ee6edd737eb19f53f --- /dev/null +++ b/mock/java/src/ohos/media/utils/log/LoggerFactory.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.media.utils.log; + +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; +import ohos.system.Parameters; + +/** + * Factory of multimedia logger. + * + * @since 1 + */ +public class LoggerFactory { + private static final int MEDIA_DOMAIN_ID = 0xD002B01; + + private static final int CAMERA_DOMAIN_ID = 0xD002B02; + + private static final int PLUGIN_DOMAIN_ID = 0xD002B03; + + private static final int DATA_TUNNEL_DOMAIN_ID = 0xD002B04; + + private static final int IMAGE_DOMAIN_ID = 0xD002B05; + + private static final int AUDIO_DOMAIN_ID = 0xD002B06; + + private static final int RADIO_DOMAIN_ID = 0xD002B07; + + /** + * Get audio logger. + * + * @param clazz class who uses the logger + * @return Audio logger + * @since 1 + */ + public static Logger getAudioLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, AUDIO_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + /** + * Get media logger. + * + * @param clazz class who uses the logger + * @return Media logger + * @since 1 + */ + public static Logger getMediaLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, MEDIA_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + /** + * Get camera logger. + * + * @param clazz class who uses the logger + * @return Camera logger + * @since 1 + */ + public static Logger getCameraLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, CAMERA_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + /** + * Get plugin logger. + * + * @param clazz class who uses the logger + * @return Plugin logger + * @since 1 + */ + public static Logger getPluginLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, PLUGIN_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + /** + * Get data tunnel logger. + * + * @param clazz class who uses the logger + * @return Data tunnel logger + * @since 1 + */ + public static Logger getDataTunnelLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, DATA_TUNNEL_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + /** + * Get image logger. + * + * @param clazz class who uses the logger + * @return Image logger + * @since 1 + */ + public static Logger getImageLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, IMAGE_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + /** + * Get radio logger. + * + * @param clazz class who uses the logger + * @return Radio logger + * @since 3 + */ + public static Logger getRadioLogger(Class clazz) { + String tag = clazz.getSimpleName(); + HiLogLabel label = new HiLogLabel(HiLog.LOG_CORE, RADIO_DOMAIN_ID, tag); + return new Logger(label, getLoggerLevel(tag)); + } + + private static int getLoggerLevel(String tag) { + return 0; + } + + private static boolean isLoggerEnable() { + return true; + } + + private static boolean isLoggable(String tag, int level) { + return HiLog.isLoggable(HiLog.LOG_CORE, tag, level); + } +} diff --git a/mock/java/src/ohos/system/Parameters.java b/mock/java/src/ohos/system/Parameters.java new file mode 100644 index 0000000000000000000000000000000000000000..d73c522099c3369f2bddf7121258573bb40f8b42 --- /dev/null +++ b/mock/java/src/ohos/system/Parameters.java @@ -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. + */ + +package ohos.system; + +/** + * The interface of system parameters class. + * + * @since 3 + */ +public final class Parameters { + private static final int INVALID = -1; + + /** + * Get the current value of the system parameter {@code key}, returned as an integer. + * + * @param key the key to lookup. + * @param def a default value to return. + * @return if the parameter is empty or doesn't exist or cannot be parsed, {@code def} will be returned. + * @since 3 + */ + public static int getInt(String key, int def) { + if ((key == null) || (key.trim().length() == 0)) { + return def; + } + return INVALID; + } + + /** + * Get the current value of the system parameter {@code key}, returned as a boolean. + * + * @param key the key to lookup. + * @param def a def ault value to return. + * @return the parameter is empty or doesn't exist or cannot be parsed, {@code def} will be returned. + * @since 3 + */ + public static boolean getBoolean(String s , boolean b) { + return true; + } +} \ No newline at end of file diff --git a/mock/java/src/ohos/utils/Parcel.java b/mock/java/src/ohos/utils/Parcel.java new file mode 100644 index 0000000000000000000000000000000000000000..a4587bd69d0e3fcad4816fcb00df02a66ad44439 --- /dev/null +++ b/mock/java/src/ohos/utils/Parcel.java @@ -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. + */ + +package ohos.utils; + +/** + * A data object used for inter-process communication (IPC). + *

+ * During IPC, the sender can use the write methods provided by {@code Parcel} to + * write the to-be-sent data into a {@code Parcel} object in a specific format, and the receiver can use the + * read methods provided by {@code Parcel} to read data of the specific format from the {@code Parcel} object. + *

+ *

+ * The default capacity of a {@code Parcel} instance is 200KB. If you want more or less, use {@link #setCapacity(int)} + * to change it. + *

+ * Note: Only data of the following data types can be written into or read from a {@code Parcel}: byte, + * byteArray, short, shortArray, int, intArray, long, longArray, float, floatArray, double, doubleArray, boolean, + * booleanArray, char, charArray, String, StringArray, {@link PlainBooleanArray}, {@link Serializable}, + * {@link Sequenceable}, and SequenceableArray. + * + * @since 1 + */ +public class Parcel { + private static final int INVALID = -1; + + protected Parcel() { + } + + /** + * Reads an integer value from the {@code Parcel} instance. + * + * @return Returns an integer value. + * + * @since 1 + */ + public final int readInt() { + return INVALID; + } +} diff --git a/mock/java/src/ohos/utils/Sequenceable.java b/mock/java/src/ohos/utils/Sequenceable.java new file mode 100644 index 0000000000000000000000000000000000000000..91b1e69a798b5f766e61472afc1ab7cb9a92ebc9 --- /dev/null +++ b/mock/java/src/ohos/utils/Sequenceable.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ohos.utils; + +/** + * Writes objects of a class into and restores them from a {@link Parcel} during + * inter-process communication (IPC). + *

+ * This can be done during IPC only after the class inherits from {@code Sequenceable} + * and implements the {@code marshalling} and {@code unmarshalling} methods provided in + * {@code Sequenceable}. If the class has a final member variable whose value cannot be + * changed by calling {@code unmarshalling}, you must also implement the {@code createFromParcel} + * method in {@link Sequenceable.Producer}. + *

+ * Example code: + * + *

+ * public class Example implements Sequenceable {
+ *     private int number;
+ *
+ *     private String name;
+ *
+ *     public boolean marshalling(Parcel out) {
+ *         return out.writeInt(number) && out.writeString(name);
+ *     }
+ *
+ *     public boolean unmarshalling(Parcel in) {
+ *         this.number = in.readInt();
+ *         this.name = in.readString();
+ *         return true;
+ *     }
+ *
+ *     public static final Sequenceable.Producer PRODUCER = new Sequenceable.Producer() {
+ *         public Example createFromParcel(Parcel in) {
+ *             // Initialize an instance first, then do customized unmarshlling.
+ *             Example instance = new Example();
+ *             instance.unmarshalling(in);
+ *             return instance;
+ *         }
+ *     };
+ * }
+ * 
+ * + * @since 1 + */ +public interface Sequenceable { + /** + * Checks whether the implementation class of this {@code Sequenceable} contains {@code FileDescriptor} object data. + *

+ * If the custom {@code Sequenceable} class contains any {@code FileDescriptor} data, you should override this + * method. + * This method return {@code false} by default. + * + * @return Returns {@code true} if it contains {@code FileDescriptor} data; returns {@code false} otherwise. + * @since 3 + */ + default boolean hasFileDescriptor() { + return false; + } + + /** + * Marshals this {@code Sequenceable} object into a {@link Parcel}. + * + * @param out Indicates the {@link Parcel} object to which the {@code Sequenceable} + * object will be marshaled.. + * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + * @throws ParcelException Throws this exception if the operation fails. + * @since 1 + */ + boolean marshalling(Parcel out); + + /** + * Unmarshals this {@code Sequenceable} object from a {@link Parcel}. + * + * @param in Indicates the {@link Parcel} object into which the {@code Sequenceable} + * object has been marshaled. + * @return Returns {@code true} if the unmarshalling is successful; returns {@code false} otherwise. + * @throws ParcelException Throws this exception if the operation fails. + * @since 1 + */ + boolean unmarshalling(Parcel in); + + /** + * Creates a {@code Sequenceable} instance from a {@link Parcel}. + * If the class has a final member variable whose value cannot be changed by + * {@link Sequenceable#unmarshalling(Parcel)}, it should contain an extra non-null static member variable + * {@code Sequenceable.Producer}. + * + * @since 1 + */ + interface Producer { + /** + * Creates a {@code Sequenceable} instance from a {@link Parcel}. + * + * @param parcel Indicates the {@link Parcel} object into which the {@code Sequenceable} + * object has been written. + * @return Returns an instance of the {@code Sequenceable} class. + * @since 1 + */ + T createFromParcel(Parcel parcel); + } +} diff --git a/mock/native/BUILD.gn b/mock/native/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..01a3e8dfa5b4d4b2537d8686bb97ca7dcb9057e9 --- /dev/null +++ b/mock/native/BUILD.gn @@ -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("//build/config/ohos/rules.gni") +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") +config("log_mock_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/multimedia/image_standard/mock/native/include", + "//foundation/multimedia/image_standard/mock/native/include/hilog", + ] +} + +ohos_static_library("log_mock_static") { + configs = [ ":log_mock_config" ] + sources = [ "//foundation/multimedia/image_standard/mock/native/src/HiLog.cpp" ] + subsystem_name = "multimedia" +} + +config("utils_mock_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/multimedia/image_standard/mock/native/include", + "//foundation/multimedia/utils/include", + ] +} + +ohos_static_library("utils_mock_static") { + if (use_mingw_win) { + defines = image_decode_windows_defines + } else if (use_clang_mac) { + defines = image_decode_mac_defines + } + configs = [ ":utils_mock_config" ] + sources = [ + "//foundation/multimedia/image_standard/mock/native/src/directory_ex.cpp", + "//foundation/multimedia/image_standard/mock/native/src/message_parcel.cpp", + "//foundation/multimedia/image_standard/mock/native/src/parcel.cpp", + "//foundation/multimedia/image_standard/mock/native/src/refbase.cpp", + "//foundation/multimedia/image_standard/mock/native/src/rwlock.cpp", + ] + deps = [ ":log_mock_static" ] + subsystem_name = "multimedia" +} diff --git a/mock/native/include/directory_ex.h b/mock/native/include/directory_ex.h new file mode 100644 index 0000000000000000000000000000000000000000..90e1cf34208a9c6f76a7059492e38e23482955e0 --- /dev/null +++ b/mock/native/include/directory_ex.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef DIRECTORY_EX_H +#define DIRECTORY_EX_H + +#include +#include +#include + +namespace OHOS { +/** + * The GetCurrentProcFullFileName function get the current process exe name. + */ +std::string GetCurrentProcFullFileName(); + +/** + * The GetCurrentProcPath function get the current process exe path. + */ +std::string GetCurrentProcPath(); + +/** + * The ExtractFilePath function extract the input file path. + */ +std::string ExtractFilePath(const std::string& fileFullName); + +/** + * The ExtractFilePath function extract the input file name. + */ +std::string ExtractFileName(const std::string& fileFullName); + +/** + * The ExtractFileExt function extract the input file name type. + */ +std::string ExtractFileExt(const std::string& fileName); + +/** + * The TransformFileName function transform the input file name for windows or mac. + */ +std::string TransformFileName(const std::string& fileName); + +/** + * The ExcludeTrailingPathDelimiter function exclude the end '/' from the strPath, + * return the path without the end '/'. + */ +std::string ExcludeTrailingPathDelimiter(const std::string& path); + +/** + * The IncludeTrailingPathDelimiter function include the end '/' from the strPath, + * return the path with the end '/'. + */ +std::string IncludeTrailingPathDelimiter(const std::string& path); + +/** + * The GetDirFiles function get all files in the path. + */ +void GetDirFiles(const std::string& path, std::vector& files); + +/** + * The IsEmptyFolder function judge the path is empty, + * return true if is empty, else false. + */ +bool IsEmptyFolder(const std::string& path); + +/** + * The ForceCreateDirectory function is force create the dir with subdir, + * return true if create succ, else false. + */ +bool ForceCreateDirectory(const std::string& path); + +/** + * The ForceRemoveDirectory function is force delete the dir with subdir and files, + * return true if remove succ, else false. + */ +bool ForceRemoveDirectory(const std::string& path); + +/** + * The RemoveFile function is remove the input strFileName, + * return true if remove succ, else false. + */ +bool RemoveFile(const std::string& fileName); + +/** + * The GetFolderSize function is get the folder size(bytes). + */ +uint64_t GetFolderSize(const std::string& path); + +/** + * The ChangeModeFile function is change the input file authority, + * return true if change succ, else false. + */ +bool ChangeModeFile(const std::string& fileName, const mode_t& mode); + +/** + * The ChangeModeDirectory function is change the input Directory authority, include subdir, + * return true if change succ, else false. + */ +bool ChangeModeDirectory(const std::string& path, const mode_t& mode); + +/** +* The PathToRealPath function is get real path from relative path, +* return true if change succ, else false. +*/ +bool PathToRealPath(const std::string& path, std::string& realPath); +} // namespace OHOS + +#endif // DIRECTORY_EX_H diff --git a/mock/native/include/errors.h b/mock/native/include/errors.h new file mode 100644 index 0000000000000000000000000000000000000000..97214e9db39ca5468e60f0f9579ea0317c17ca82 --- /dev/null +++ b/mock/native/include/errors.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef UTILS_BASE_ERRORS_H +#define UTILS_BASE_ERRORS_H + +#include + +namespace OHOS { +/** + * ErrCode layout + * + * +-----+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | Bit |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + * +-----+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |Field|Reserved| Subsystem | Module | Code | + * +-----+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + +using ErrCode = int; + +enum { + SUBSYS_COMMON = 0, + SUBSYS_AAFWK = 1, + SUBSYS_ACCOUNT = 2, + SUBSYS_AI = 3, + SUBSYS_APPEXECFWK = 4, + SUBSYS_APPLICATIONS = 5, + SUBSYS_ARVR = 6, + SUBSYS_ARVRHARDWARE = 7, + SUBSYS_BARRIERFREE = 8, + SUBSYS_BIOMETRICS = 9, + SUBSYS_CCRUNTIME = 10, + SUBSYS_COMMUNICATION = 11, + SUBSYS_DFX = 12, + SUBSYS_DISTRIBUTEDDATAMNG = 13, + SUBSYS_DISTRIBUTEDSCHEDULE = 14, + SUBSYS_DRIVERS = 15, + SUBSYS_GLOBAL = 16, + SUBSYS_GRAPHIC = 17, + SUBSYS_HBS = 18, + SUBSYS_IAWARE = 19, + SUBSYS_IDE = 20, + SUBSYS_INTELLIACCESSORIES = 21, + SUBSYS_INTELLISPEAKER = 22, + SUBSYS_INTELLITV = 23, + SUBSYS_IOT = 24, + SUBSYS_IOTHARDWARE = 25, + SUBSYS_IVIHARDWARE = 26, + SUBSYS_KERNEL = 27, + SUBSYS_LOCATION = 28, + SUBSYS_MSDP = 29, + SUBSYS_MULTIMEDIA = 30, + SUBSYS_MULTIMODAINPUT = 31, + SUBSYS_NOTIFICATION = 32, + SUBSYS_POWERMNG = 33, + SUBSYS_ROUTER = 34, + SUBSYS_SECURITY = 35, + SUBSYS_SENSORS = 36, + SUBSYS_SMALLSERVICES = 37, + SUBSYS_SOURCECODETRANSFORMER = 38, + SUBSYS_STARTUP = 39, + SUBSYS_TELEPONY = 40, + SUBSYS_UPDATE = 41, + SUBSYS_USB = 42, + SUBSYS_WEARABLE = 43, + SUBSYS_WEARABLEHARDWARE = 44, + SUBSYS_IVI = 45 + // new type +}; + +// be used to init the subsystem errorno. +constexpr ErrCode ErrCodeOffset(unsigned int subsystem, unsigned int module = 0) +{ + constexpr int SUBSYSTEM_BIT_NUM = 21; + constexpr int MODULE_BIT_NUM = 16; + return (subsystem << SUBSYSTEM_BIT_NUM) | (module << MODULE_BIT_NUM); +} + +// offset of common error, only be used in this file. +constexpr ErrCode BASE_ERR_OFFSET = ErrCodeOffset(SUBSYS_COMMON); + +enum { + ERR_OK = 0, + ERR_NO_MEMORY = BASE_ERR_OFFSET + ENOMEM, + ERR_INVALID_OPERATION = BASE_ERR_OFFSET + ENOSYS, + ERR_INVALID_VALUE = BASE_ERR_OFFSET + EINVAL, + ERR_NAME_NOT_FOUND = BASE_ERR_OFFSET + ENOENT, + ERR_PERMISSION_DENIED = BASE_ERR_OFFSET + EPERM, + ERR_NO_INIT = BASE_ERR_OFFSET + ENODEV, + ERR_ALREADY_EXISTS = BASE_ERR_OFFSET + EEXIST, + ERR_DEAD_OBJECT = BASE_ERR_OFFSET + EPIPE, + ERR_OVERFLOW = BASE_ERR_OFFSET + EOVERFLOW, + ERR_ENOUGH_DATA = BASE_ERR_OFFSET + ENODATA, + ERR_WOULD_BLOCK = BASE_ERR_OFFSET + EWOULDBLOCK, + ERR_TIMED_OUT = BASE_ERR_OFFSET + ETIMEDOUT +}; + +#define SUCCEEDED(errCode) ((errCode) == ERR_OK) +#define FAILED(errCode) ((errCode) != ERR_OK) +} // namespace OHOS + +#endif diff --git a/mock/native/include/hilog/log.h b/mock/native/include/hilog/log.h new file mode 100644 index 0000000000000000000000000000000000000000..5515244b1e5dee5203ca0a3a0d66b9ca6f5bcc89 --- /dev/null +++ b/mock/native/include/hilog/log.h @@ -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. + */ + + +#ifndef HIVIEWDFX_HILOG_H +#define HIVIEWDFX_HILOG_H + +#include "hilog/log_c.h" +#include "hilog/log_cpp.h" + +#endif // HIVIEWDFX_HILOG_H \ No newline at end of file diff --git a/mock/native/include/hilog/log_c.h b/mock/native/include/hilog/log_c.h new file mode 100644 index 0000000000000000000000000000000000000000..d64551d00b4e706319c1d3bd824073a0be230c86 --- /dev/null +++ b/mock/native/include/hilog/log_c.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef HIVIEWDFX_HILOG_C_H +#define HIVIEWDFX_HILOG_C_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Log domain +#ifndef LOG_DOMAIN +#define LOG_DOMAIN 0 +#endif + +// Log tag +#ifndef LOG_TAG +#define LOG_TAG NULL +#endif + +// Log type +typedef enum { + LOG_TYPE_MIN = 0, + // Log to kmsg, only used by init phase. + LOG_INIT = 1, + // Used by core service, framework. + LOG_CORE = 3, + LOG_TYPE_MAX +} LogType; + +// Log level +typedef enum { + LOG_LEVEL_MIN = 0, + LOG_DEBUG = 3, + LOG_INFO = 4, + LOG_WARN = 5, + LOG_ERROR = 6, + LOG_FATAL = 7, + LOG_LEVEL_MAX, +} LogLevel; + +int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) + __attribute__((__format__(os_log, 5, 6))); + +#define HILOG_DEBUG(type, ...) ((void)HiLogPrint((type), LOG_DEBUG, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_INFO(type, ...) ((void)HiLogPrint((type), LOG_INFO, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_WARN(type, ...) ((void)HiLogPrint((type), LOG_WARN, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_ERROR(type, ...) ((void)HiLogPrint((type), LOG_ERROR, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +#define HILOG_FATAL(type, ...) ((void)HiLogPrint((type), LOG_FATAL, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +bool HiLogIsLoggable(unsigned int domain, const char *tag, LogLevel level); + +#ifdef __cplusplus +} +#endif + +#endif // HIVIEWDFX_HILOG_C_H diff --git a/mock/native/include/hilog/log_cpp.h b/mock/native/include/hilog/log_cpp.h new file mode 100644 index 0000000000000000000000000000000000000000..e27379231ddd78114695e7d4cead7535c8ce6235 --- /dev/null +++ b/mock/native/include/hilog/log_cpp.h @@ -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. + */ + + +#ifndef HIVIEWDFX_HILOG_CPP_H +#define HIVIEWDFX_HILOG_CPP_H + +#include "hilog/log_c.h" + +#ifdef __cplusplus + +namespace OHOS { +namespace HiviewDFX { +typedef struct HiLogLabel { + LogType type; + unsigned int domain; + const char *tag; +} HiLogLabel; + +class HiLog final { +public: + static int Debug(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Info(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Warn(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Error(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Fatal(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); +}; +} // namespace HiviewDFX +} // namespace OHOS +#endif // __cplusplus +#endif // HIVIEWDFX_HILOG_CPP_H diff --git a/mock/native/include/message_parcel.h b/mock/native/include/message_parcel.h new file mode 100644 index 0000000000000000000000000000000000000000..c4045bc60f66004804922e084a6f79112b61f684 --- /dev/null +++ b/mock/native/include/message_parcel.h @@ -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. + */ + + +#ifndef ZIPC_MESSAGE_PARCEL_H +#define ZIPC_MESSAGE_PARCEL_H +#include +#include "parcel.h" +#include "refbase.h" + +namespace OHOS { +class IRemoteObject; +class MessageParcel : public Parcel { +public: + MessageParcel(); + ~MessageParcel(); + bool WriteFileDescriptor(int fd); + int ReadFileDescriptor(); +}; +} // namespace OHOS +#endif /* ZIPC_MESSAGE_PARCEL_H */ diff --git a/mock/native/include/nocopyable.h b/mock/native/include/nocopyable.h new file mode 100644 index 0000000000000000000000000000000000000000..383f8199b9a0b2caac2db599aa693fb5c6bd0a81 --- /dev/null +++ b/mock/native/include/nocopyable.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UTILS_BASE_NOCOPYABLE_H +#define UTILS_BASE_NOCOPYABLE_H +namespace OHOS { +#define DISALLOW_COPY_AND_MOVE(className) \ + DISALLOW_COPY(className); \ + DISALLOW_MOVE(className) + +#define DISALLOW_COPY(className) \ + className(const className&) = delete; \ + className& operator= (const className&) = delete + +#define DISALLOW_MOVE(className) \ + className(className&&) = delete; \ + className& operator= (className&&) = delete +class NoCopyable { +protected: + NoCopyable() {}; + virtual ~NoCopyable() {}; + +private: + DISALLOW_COPY_AND_MOVE(NoCopyable); +}; +} // namespace OHOS +#endif \ No newline at end of file diff --git a/mock/native/include/parcel.h b/mock/native/include/parcel.h new file mode 100644 index 0000000000000000000000000000000000000000..62d7678ccc0e13adc107ad475a3222eb663f9e15 --- /dev/null +++ b/mock/native/include/parcel.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ZIPC_PARCEL_H +#define ZIPC_PARCEL_H + +#include +#include +#include "nocopyable.h" +#include "refbase.h" + +namespace OHOS { +class Parcel; + +class Parcelable : public virtual RefBase { +public: + virtual ~Parcelable() = default; + + Parcelable(); + explicit Parcelable(bool asRemote); +}; + +class Parcel { +public: + Parcel(); + + ~Parcel(); + + size_t GetDataCapacity() const; + + bool SetDataCapacity(size_t newCapacity); + + bool WriteInt32(int32_t value); + + bool WriteBuffer(const void *data, size_t size); + + int32_t ReadInt32(); + + bool ReadInt32(int32_t &value); + + const uint8_t *ReadBuffer(size_t length); +}; +} // namespace OHOS +#endif // ZIPC_PARCEL_H diff --git a/mock/native/include/refbase.h b/mock/native/include/refbase.h new file mode 100644 index 0000000000000000000000000000000000000000..69426221acdb9ba9a055c59af20e7c219da50a51 --- /dev/null +++ b/mock/native/include/refbase.h @@ -0,0 +1,679 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef UTILS_BASE_REFBASE_H +#define UTILS_BASE_REFBASE_H + +#include +#include + +namespace OHOS { +#define INITIAL_PRIMARY_VALUE (1 << 28) + +class RefBase; + +class RefCounter { +public: + using RefPtrCallback = std::function; + + RefCounter(); + + explicit RefCounter(RefCounter *counter); + + RefCounter &operator=(const RefCounter &counter); + + virtual ~RefCounter(); + + void SetCallback(const RefPtrCallback& callback); + + void RemoveCallback(); + + int GetRefCount(); + + void IncRefCount(); + + void DecRefCount(); + + bool IsRefPtrValid(); + + int IncStrongRefCount(const void *objectId); + + int DecStrongRefCount(const void *objectId); + + int GetStrongRefCount(); + + int IncWeakRefCount(const void *objectId); + + int DecWeakRefCount(const void *objectId); + + int GetWeakRefCount(); + + void SetAttemptAcquire(); + + bool IsAttemptAcquireSet(); + + void ClearAttemptAcquire(); + + bool AttemptIncStrongRef(const void *objectId, int &outCount); + + bool IsLifeTimeExtended(); + + void ExtendObjectLifetime(); + +private: + std::atomic atomicStrong_; + std::atomic atomicWeak_; + std::atomic atomicRefCount_; + std::atomic atomicFlags_; + std::atomic atomicAttempt_; + RefPtrCallback callback_ = nullptr; + static constexpr unsigned int FLAG_EXTEND_LIFE_TIME = 0x00000002; +}; + +class WeakRefCounter { +public: + WeakRefCounter(RefCounter *base, void *cookie); + + virtual ~WeakRefCounter(); + + void *GetRefPtr(); + + void IncWeakRefCount(const void *objectId); + + void DecWeakRefCount(const void *objectId); + + bool AttemptIncStrongRef(const void *objectId); + +private: + std::atomic atomicWeak_; + RefCounter *refCounter_ = nullptr; + void *cookie_ = nullptr; +}; + +class RefBase { +public: + RefBase(); + + RefBase(const RefBase &refbase); + + RefBase &operator=(const RefBase &refbase); + + RefBase(RefBase &&refbase) noexcept; + + RefBase &operator=(RefBase &&refbase) noexcept; + + virtual ~RefBase(); + + void RefPtrCallback(); + + void ExtendObjectLifetime(); + + void IncStrongRef(const void *objectId); + + void DecStrongRef(const void *objectId); + + int GetSptrRefCount(); + + WeakRefCounter *CreateWeakRef(void *cookie); + + void IncWeakRef(const void *objectId); + + void DecWeakRef(const void *objectId); + + int GetWptrRefCount(); + + bool AttemptAcquire(const void *objectId); + + bool AttemptIncStrongRef(const void *objectId); + + bool IsAttemptAcquireSet(); + + bool IsExtendLifeTimeSet(); + + virtual void OnFirstStrongRef(const void *objectId); + + virtual void OnLastStrongRef(const void *objectId); + + virtual void OnLastWeakRef(const void *objectId); + + virtual bool OnAttemptPromoted(const void *objectId); + +private: + RefCounter *refs_ = nullptr; +}; + +template +class wptr; + +template +class sptr { + friend class wptr; + +public: + sptr(); + + ~sptr(); + + sptr(T *other); + + sptr(const sptr &other); + + sptr(sptr &&other); + + sptr &operator=(sptr &&other); + + template + sptr(const sptr &other); + + inline sptr(WeakRefCounter *p, bool force); + + inline T *GetRefPtr() const + { + return refs_; + } + + inline void ForceSetRefPtr(T *other); + + void clear(); + + inline operator T *() const + { + return refs_; + } + + inline T &operator*() const + { + return *refs_; + } + + inline T *operator->() const + { + return refs_; + } + + inline bool operator!() const + { + return refs_ == nullptr; + } + + sptr &operator=(T *other); + + sptr &operator=(const sptr &other); + + sptr &operator=(const wptr &other); + + template + sptr &operator=(const sptr &other); + + bool operator==(const T *other) const; + + inline bool operator!=(const T *other) const + { + return !operator==(other); + } + + bool operator==(const wptr &other) const; + + inline bool operator!=(const wptr &other) const + { + return !operator==(other); + } + + bool operator==(const sptr &other) const; + + inline bool operator!=(const sptr &other) const + { + return !operator==(other); + } + +private: + T *refs_ = nullptr; +}; + +template +inline void sptr::ForceSetRefPtr(T *other) +{ + refs_ = other; +} + +template +inline sptr::sptr() +{ + refs_ = nullptr; +} + +template +inline sptr::sptr(T *other) +{ + refs_ = other; + if (refs_ != nullptr) { + refs_->IncStrongRef(this); + } +} + +template +inline sptr::sptr(const sptr &other) +{ + refs_ = other.GetRefPtr(); + if (refs_ != nullptr) { + refs_->IncStrongRef(this); + } +} + +template +sptr::sptr(sptr &&other) +{ + refs_ = other.GetRefPtr(); + other.ForceSetRefPtr(nullptr); +} + +template +sptr &sptr::operator=(sptr &&other) +{ + if (refs_ != nullptr) { + refs_->DecStrongRef(this); + } + refs_ = other.GetRefPtr(); + other.ForceSetRefPtr(nullptr); + return *this; +} + +template +template +sptr::sptr(const sptr &other) : refs_(other.GetRefPtr()) +{ + if (refs_ != nullptr) { + refs_->IncStrongRef(this); + } +} + +template +inline sptr &sptr::operator=(T *other) +{ + if (other != nullptr) { + other->IncStrongRef(this); + } + if (refs_ != nullptr) { + refs_->DecStrongRef(this); + } + refs_ = other; + return *this; +} + +template +inline sptr &sptr::operator=(const sptr &other) +{ + T *otherRef(other.GetRefPtr()); + if (otherRef != nullptr) { + otherRef->IncStrongRef(this); + } + if (refs_ != nullptr) { + refs_->DecStrongRef(this); + } + refs_ = otherRef; + return *this; +} + +template +inline sptr &sptr::operator=(const wptr &other) +{ + if ((other != nullptr) && other.AttemptIncStrongRef(this)) { + refs_ = other.GetRefPtr(); + } else { + refs_ = nullptr; + } + return *this; +} + +template +template +sptr &sptr::operator=(const sptr &other) +{ + T *otherRef(other.GetRefPtr()); + if (otherRef != nullptr) { + otherRef->IncStrongRef(this); + } + if (refs_ != nullptr) { + refs_->DecStrongRef(this); + } + refs_ = otherRef; + return *this; +} + +template +inline bool sptr::operator==(const T *other) const +{ + return other == refs_; +} + +template +inline bool sptr::operator==(const wptr &other) const +{ + return refs_ == other.GetRefPtr(); +} + +template +inline bool sptr::operator==(const sptr &other) const +{ + return refs_ == other.GetRefPtr(); +} + +template +void sptr::clear() +{ + if (refs_) { + refs_->DecStrongRef(this); + refs_ = 0; + } +} + +template +inline sptr::~sptr() +{ + if (refs_ != nullptr) { + refs_->DecStrongRef(this); + } +} + +template +inline sptr::sptr(WeakRefCounter *p, bool /* force */) +{ + if ((p != nullptr) && p->AttemptIncStrongRef(this)) { + refs_ = reinterpret_cast(p->GetRefPtr()); + } else { + refs_ = nullptr; + } +} + +template +class wptr { + template + friend class wptr; + +public: + wptr(); + + wptr(T *other); + + wptr(const wptr &other); + + wptr(const sptr &other); + + template + wptr(const wptr &other); + + template + wptr(const sptr &other); + + wptr &operator=(T *other); + + template + wptr &operator=(O *other); + + wptr &operator=(const wptr &other); + + wptr &operator=(const sptr &other); + + template + wptr &operator=(const wptr &other); + + template + wptr &operator=(const sptr &other); + + inline T *operator*() const + { + return *refs_; + } + inline T *operator->() const + { + return reinterpret_cast(refs_->GetRefPtr()); + } + + bool operator==(const T *other) const; + + inline bool operator!=(const T *other) const + { + return !operator==(other); + }; + + bool operator==(const wptr &other) const; + + inline bool operator!=(const wptr &other) const + { + return !operator==(other); + } + + bool operator==(const sptr &other) const; + + inline bool operator!=(const sptr &other) const + { + return !operator==(other); + } + + T *GetRefPtr() const; + + inline bool AttemptIncStrongRef(const void *objectId) const + { + return refs_->AttemptIncStrongRef(objectId); + } + + const sptr promote() const; + + ~wptr(); + +private: + WeakRefCounter *refs_ = nullptr; +}; + +template +inline T *wptr::GetRefPtr() const +{ + return (refs_ != nullptr) ? reinterpret_cast(refs_->GetRefPtr()) : nullptr; +} + +template +wptr::wptr() +{ + refs_ = nullptr; +} + +template +wptr::wptr(T *other) +{ + if (other != nullptr) { + refs_ = other->CreateWeakRef(other); + if (refs_ != nullptr) { + refs_->IncWeakRefCount(this); + } + } else { + refs_ = nullptr; + } +} + +template +wptr::wptr(const wptr &other) +{ + refs_ = other.refs_; + if (refs_ != nullptr) { + refs_->IncWeakRefCount(this); + } +} + +template +wptr::wptr(const sptr &other) +{ + if (other.GetRefPtr() != nullptr) { + refs_ = other->CreateWeakRef(other.GetRefPtr()); + if (refs_ != nullptr) { + refs_->IncWeakRefCount(this); + } + } +} + +template +template +wptr::wptr(const wptr &other) +{ + refs_ = other.refs_; + if (refs_ != nullptr) { + refs_->IncWeakRefCount(this); + } +} + +template +template +wptr::wptr(const sptr &other) +{ + if (other.GetRefPtr() != nullptr) { + refs_ = other->CreateWeakRef(other.GetRefPtr()); + if (refs_ != nullptr) { + refs_->IncWeakRefCount(this); + } + } +} + +template +wptr &wptr::operator=(T *other) +{ + WeakRefCounter *newWeakRef = nullptr; + if (other != nullptr) { + newWeakRef = other->CreateWeakRef(other); + if (newWeakRef != nullptr) { + newWeakRef->IncWeakRefCount(this); + } + } + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } + refs_ = newWeakRef; + return *this; +} + +template +template +wptr &wptr::operator=(O *other) +{ + T *object = reinterpret_cast(other); + WeakRefCounter *newWeakRef = nullptr; + if (object != nullptr) { + newWeakRef = object->CreateWeakRef(object); + if (newWeakRef != nullptr) { + newWeakRef->IncWeakRefCount(this); + } + } + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } + + refs_ = newWeakRef; + return *this; +} + +template +inline wptr &wptr::operator=(const wptr &other) +{ + if (other.refs_ != nullptr) { + other.refs_->IncWeakRefCount(this); + } + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } + refs_ = other.refs_; + return *this; +} + +template +inline wptr &wptr::operator=(const sptr &other) +{ + WeakRefCounter *newWeakRef = nullptr; + if (other.GetRefPtr() != nullptr) { + newWeakRef = other->CreateWeakRef(other.GetRefPtr()); + if (newWeakRef != nullptr) { + newWeakRef->IncWeakRefCount(this); + } + } + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } + refs_ = newWeakRef; + return *this; +} + +template +template +wptr &wptr::operator=(const wptr &other) +{ + if (other.refs_ != nullptr) { + other.refs_->IncWeakRefCount(this); + } + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } + refs_ = other.refs_; + return *this; +} + +template +template +wptr &wptr::operator=(const sptr &other) +{ + WeakRefCounter *newWeakRef = nullptr; + if (other.GetRefPtr() != nullptr) { + newWeakRef = other->CreateWeakRef(other->GetRefPtr()); + if (newWeakRef != nullptr) { + newWeakRef->IncWeakRefCount(this); + } + } + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } + refs_ = newWeakRef; + return *this; +} + +template +inline bool wptr::operator==(const T *other) const +{ + return GetRefPtr() == other; +} + +template +inline bool wptr::operator==(const wptr &other) const +{ + return GetRefPtr() == other.GetRefPtr(); +} + +template +inline bool wptr::operator==(const sptr &other) const +{ + return GetRefPtr() == other.GetRefPtr(); +} + +template +inline const sptr wptr::promote() const +{ + return sptr(refs_, true); +} + +template +inline wptr::~wptr() +{ + if (refs_ != nullptr) { + refs_->DecWeakRefCount(this); + } +} +} // namespace OHOS +#endif diff --git a/mock/native/include/rwlock.h b/mock/native/include/rwlock.h new file mode 100644 index 0000000000000000000000000000000000000000..3a9f1f9af78680062f0b72027e13eb1f0deb9c0d --- /dev/null +++ b/mock/native/include/rwlock.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef UTILS_RWLOCK_H_ +#define UTILS_RWLOCK_H_ + +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace Utils { +class RWLock : NoCopyable { +public: + enum LockStatus { + LOCK_STATUS_WRITE = -1, + LOCK_STATUS_FREE = 0, + }; + + RWLock() : RWLock(true) {} + explicit RWLock(bool writeFirst); + virtual ~RWLock() {} + + void LockRead(); + void UnLockRead(); + + void LockWrite(); + void UnLockWrite(); + +private: + bool writeFirst_; + std::thread::id writeThreadID_; + + // Resource lock counter, -1 is write state, 0 is free state, and greater than 0 is shared read state + std::atomic_int lockCount_; + + // Thread counter waiting for write lock + std::atomic_uint writeWaitCount_; +}; + +template +class UniqueWriteGuard : NoCopyable { +public: + explicit UniqueWriteGuard(RWLockable &rwLockable) + : rwLockable_(rwLockable) + { + rwLockable_.LockWrite(); + } + + ~UniqueWriteGuard() + { + rwLockable_.UnLockWrite(); + } + +private: + UniqueWriteGuard() = delete; + +private: + RWLockable &rwLockable_; +}; + + +template +class UniqueReadGuard : NoCopyable { +public: + explicit UniqueReadGuard(RWLockable &rwLockable) + : rwLockable_(rwLockable) + { + rwLockable_.LockRead(); + } + + ~UniqueReadGuard() + { + rwLockable_.UnLockRead(); + } + +private: + UniqueReadGuard() = delete; + +private: + RWLockable &rwLockable_; +}; +} +} // namespace OHOS +#endif /* UTILS_RWLOCK_H_ */ + diff --git a/mock/native/include/secure/securec.h b/mock/native/include/secure/securec.h new file mode 100644 index 0000000000000000000000000000000000000000..0b9f3861b8b4ead0e10232a5168bd787c659b1e5 --- /dev/null +++ b/mock/native/include/secure/securec.h @@ -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. + */ + + +/* success */ +#ifndef EOK +#define EOK (0) +#endif + +#define F_DUPFD_CLOEXEC 1030 diff --git a/mock/native/include/singleton.h b/mock/native/include/singleton.h new file mode 100644 index 0000000000000000000000000000000000000000..5662fcfdc272a784ecc3e66728ee57ff20862fe6 --- /dev/null +++ b/mock/native/include/singleton.h @@ -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. + */ + +#ifndef UTILS_BASE_SINGLETON_H +#define UTILS_BASE_SINGLETON_H + +#include "nocopyable.h" +#include +#include + +namespace OHOS { +#define DECLARE_DELAYED_SINGLETON(MyClass) \ +public: \ + ~MyClass(); \ +private: \ + friend DelayedSingleton; \ + MyClass(); + +#define DECLARE_DELAYED_REF_SINGLETON(MyClass) \ +private: \ + friend DelayedRefSingleton; \ + ~MyClass(); \ + MyClass(); + + +#define DECLARE_SINGLETON(MyClass) \ +private: \ + friend Singleton; \ + MyClass& operator=(const MyClass&) = delete; \ + MyClass(const MyClass&) = delete; \ + MyClass(); \ + ~MyClass(); + + +template +class DelayedSingleton : public NoCopyable { +public: + static std::shared_ptr GetInstance(); + static void DestroyInstance(); + +private: + static std::shared_ptr instance_; + static std::mutex mutex_; +}; + +template +std::shared_ptr DelayedSingleton::instance_ = nullptr; + +template +std::mutex DelayedSingleton::mutex_; + +template +std::shared_ptr DelayedSingleton::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard lock(mutex_); + if (instance_ == nullptr) { + std::shared_ptr temp(new T); + instance_ = temp; + } + } + return instance_; +} + +template +void DelayedSingleton::DestroyInstance() +{ + std::lock_guard lock(mutex_); + if (instance_ != nullptr) { + instance_.reset(); + instance_ = nullptr; + } +} + +template +class DelayedRefSingleton : public NoCopyable { +public: + static T& GetInstance(); + +private: + static T* instance_; + static std::mutex mutex_; +}; + +template +T* DelayedRefSingleton::instance_ = nullptr; + +template +std::mutex DelayedRefSingleton::mutex_; + +template +T& DelayedRefSingleton::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard lock(mutex_); + if (instance_ == nullptr) { + instance_ = new T(); + } + } + return *instance_; +} + +template +class Singleton : public NoCopyable { +public: + static T& GetInstance() + { + return instance_; + } + +private: + static T instance_; +}; + +template +T Singleton::instance_; +} // namespace OHOS +#endif diff --git a/mock/native/src/HiLog.cpp b/mock/native/src/HiLog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73934f53460def19f2a350955907f1346daa8d19 --- /dev/null +++ b/mock/native/src/HiLog.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "hilog/log.h" +#include +#include +#include +#include + +namespace OHOS { +namespace HiviewDFX { +using namespace std; +int HiLog::Debug(const HiLogLabel &label, const char *fmt, ...) +{ + return 0; +} + +int HiLog::Info(const HiLogLabel &label, const char *fmt, ...) +{ + return 0; +} + +int HiLog::Warn(const HiLogLabel &label, const char *fmt, ...) +{ + std::cout << label.tag << ": " << fmt << std::endl; + return 0; +} + +int HiLog::Error(const HiLogLabel &label, const char *fmt, ...) +{ + std::cout << label.tag << ": " << fmt << std::endl; + return 0; +} + +int HiLog::Fatal(const HiLogLabel &label, const char *fmt, ...) +{ + std::cout << label.tag << ": " << fmt << std::endl; + return 0; +} +} +} // namespace OHOS \ No newline at end of file diff --git a/mock/native/src/directory_ex.cpp b/mock/native/src/directory_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37c5db18632f730bac2373487e3f9bd2ab57fa2a --- /dev/null +++ b/mock/native/src/directory_ex.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "directory_ex.h" +#include +#include +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "unistd.h" + +using namespace std; + +namespace OHOS { +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "directory_ex_mock" }; + +string ExtractFileExt(const string& fileName) +{ + string::size_type pos = fileName.rfind("."); + if (pos == string::npos) { + return ""; + } + return string(fileName).substr(pos + 1, fileName.size()); +} + +string TransformFileName(const string& fileName) +{ + string::size_type pos = fileName.find("."); + if (pos == string::npos) { + string transformfileName = fileName; + +#ifdef _WIN32 + transformfileName = transformfileName.append(".dll"); +#elif defined _APPLE + transformfileName = transformfileName.append(".dylib"); +#endif + + return transformfileName; + } else { + string transformfileName = string(fileName).substr(0, pos + 1); + +#ifdef _WIN32 + transformfileName = transformfileName.append("dll"); +#elif defined _APPLE + transformfileName = transformfileName.append("dylib"); +#endif + + return transformfileName; + } +} + +string IncludeTrailingPathDelimiter(const std::string& path) +{ + if (path.rfind("/") != path.size() - 1) { + return path + "/"; + } + return path; +} + +void GetDirFiles(const string& path, vector& files) +{ + struct stat info = { 0 }; + string pathStringWithDelimiter; + DIR *dir = opendir(path.c_str()); + if (dir == nullptr) { + return; + } + + while (true) { + struct dirent *ptr = readdir(dir); + if (ptr == nullptr) { + break; + } + + // current dir OR parrent dir + if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { + continue; + } else if (S_ISDIR(info.st_mode)) { + pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name); + GetDirFiles(pathStringWithDelimiter, files); + } else { + files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name)); + } + } + closedir(dir); +} + +bool PathToRealPath(const string& path, string& realPath) +{ +#if !defined(_WIN32) && !defined(_APPLE) + if (path.empty()) { + HiLog::Error(LABEL, "path is empty!"); + return false; + } +#endif + + if ((path.length() >= PATH_MAX)) { + HiLog::Error(LABEL, "path len is error, the len is: [%{public}zu]", path.length()); + return false; + } + + char tmpPath[PATH_MAX] = {0}; + +#ifdef _WIN32 + if (_fullpath(tmpPath, path.c_str(), PATH_MAX) == NULL) { + HiLog::Error(LABEL, "path to realpath error"); + return false; + } +#else + if (realpath(path.c_str(), tmpPath) == nullptr) { + HiLog::Error(LABEL, "path to realpath error"); + return false; + } +#endif + + realPath = tmpPath; + if (access(realPath.c_str(), F_OK) != 0) { + HiLog::Error(LABEL, "check realpath (%{public}s) error", realPath.c_str()); + return false; + } + return true; +} +} // namespace OHOS diff --git a/mock/native/src/message_parcel.cpp b/mock/native/src/message_parcel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64facda585902762e509077b1c1127223c506e48 --- /dev/null +++ b/mock/native/src/message_parcel.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "message_parcel.h" + +namespace OHOS { +bool WriteFileDescriptor(int fd) +{ + (void) fd; + return false; +} + +int ReadFileDescriptor() +{ + return 0; +} +} // namespace OHOS \ No newline at end of file diff --git a/mock/native/src/parcel.cpp b/mock/native/src/parcel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f77003f62cc38c92874d5fe75e09a656aed5928 --- /dev/null +++ b/mock/native/src/parcel.cpp @@ -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. + */ + +#include "parcel.h" + +namespace OHOS { +Parcelable::Parcelable() : Parcelable(false) +{} + +Parcelable::Parcelable(bool asRemote) +{} + +Parcel::Parcel() +{} + +Parcel::~Parcel() = default; + +size_t Parcel::GetDataCapacity() const +{ + return 0; +} + +bool Parcel::SetDataCapacity(size_t newCapacity) +{ + (void) newCapacity; + return false; +} + +bool Parcel::WriteBuffer(const void *data, size_t size) +{ + (void) data; + (void) size; + return false; +} + +bool Parcel::WriteInt32(int32_t value) +{ + (void) value; + return false; +} + +const uint8_t *Parcel::ReadBuffer(size_t length) +{ + (void) length; + return nullptr; +} + +int32_t Parcel::ReadInt32() +{ + return 0; +} +} // namespace OHOS diff --git a/mock/native/src/refbase.cpp b/mock/native/src/refbase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18dc3758ea75a211bac380352c7c946b5890d3d9 --- /dev/null +++ b/mock/native/src/refbase.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "refbase.h" + +namespace OHOS { +WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie) + : atomicWeak_(0), refCounter_(counter), cookie_(cookie) +{ + if (refCounter_ != nullptr) { + refCounter_->IncRefCount(); + } +} + +WeakRefCounter::~WeakRefCounter() +{ + if (refCounter_ != nullptr) { + refCounter_->DecRefCount(); + } +} + +void* WeakRefCounter::GetRefPtr() +{ + if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) { + cookie_ = nullptr; + } + return cookie_; +} + +void WeakRefCounter::IncWeakRefCount(const void *objectId) +{ + if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) { + refCounter_->IncWeakRefCount(objectId); + } +} + +void WeakRefCounter::DecWeakRefCount(const void *objectId) +{ + if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) { + refCounter_->DecWeakRefCount(objectId); + delete this; + } +} + +bool WeakRefCounter::AttemptIncStrongRef(const void *objectId) +{ + int unuse = 0; + return refCounter_->AttemptIncStrongRef(objectId, unuse); +} + +RefCounter::RefCounter() + : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0) +{ +} +int RefCounter::GetRefCount() +{ + return atomicRefCount_.load(std::memory_order_relaxed); +} + +void RefCounter::IncRefCount() +{ + atomicRefCount_.fetch_add(1, std::memory_order_relaxed); +} + +void RefCounter::DecRefCount() +{ + if (atomicRefCount_.load(std::memory_order_relaxed) > 0) { + if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) { + delete (this); + } + } +} + +void RefCounter::SetCallback(const RefPtrCallback& callback) +{ + callback_ = callback; +} + +void RefCounter::RemoveCallback() +{ + callback_ = nullptr; +} + +bool RefCounter::IsRefPtrValid() +{ + return callback_ != nullptr; +} + +RefCounter::~RefCounter() +{ +} + +int RefCounter::IncStrongRefCount(const void * /*objectId*/) +{ + int curCount = atomicStrong_.load(std::memory_order_relaxed); + if (curCount >= 0) { + curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); + if (curCount == INITIAL_PRIMARY_VALUE) { + atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); + } + } + return curCount; +} + +int RefCounter::DecStrongRefCount(const void * /*objectId*/) +{ + int curCount = GetStrongRefCount(); + if (curCount == INITIAL_PRIMARY_VALUE) { + // unexpected case: there had never a strong reference. + } else if (curCount > 0) { + // we should update the current count here. + // it may be changed after last operation. + curCount = atomicStrong_.fetch_sub(1, std::memory_order_release); + } + return curCount; +} + +int RefCounter::GetStrongRefCount() +{ + return atomicStrong_.load(std::memory_order_relaxed); +} + +int RefCounter::IncWeakRefCount(const void * /*objectId*/) +{ + return atomicWeak_.fetch_add(1, std::memory_order_relaxed); +} + +int RefCounter::DecWeakRefCount(const void * /*objectId*/) +{ + int curCount = GetWeakRefCount(); + if (curCount > 0) { + curCount = atomicWeak_.fetch_sub(1, std::memory_order_release); + } + int strongRefCount = GetStrongRefCount(); + if ((curCount == 1) || (strongRefCount == 0 && !IsLifeTimeExtended())) { + if (callback_) { + callback_(); + } + } + return curCount; +} + +int RefCounter::GetWeakRefCount() +{ + return atomicWeak_.load(std::memory_order_relaxed); +} + +void RefCounter::SetAttemptAcquire() +{ + (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed); +} + +bool RefCounter::IsAttemptAcquireSet() +{ + return static_cast(atomicAttempt_.load(std::memory_order_relaxed) > 0); +} + +void RefCounter::ClearAttemptAcquire() +{ + atomicAttempt_.fetch_sub(1, std::memory_order_relaxed); +} + +void RefCounter::ExtendObjectLifetime() +{ + atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed); +} + +bool RefCounter::IsLifeTimeExtended() +{ + return static_cast(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME); +} + +bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount) +{ + int curCount = GetStrongRefCount(); + IncWeakRefCount(objectId); + + // if the object already had strong references.just promoting it. + while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) { + if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { + goto attempt_success; + } + + // someone else changed the counter.re-acquire the counter value. + curCount = atomicStrong_.load(std::memory_order_relaxed); + } + + if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) { + // this object has a "normal" life-time, + while (curCount > 0) { + if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) { + goto attempt_success; + } + + curCount = atomicStrong_.load(std::memory_order_relaxed); + } + } + + if (IsLifeTimeExtended()) { + curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed); + } + +attempt_success: + if (curCount >= INITIAL_PRIMARY_VALUE) { + outCount = curCount; + atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release); + return true; + } + + if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) { + // the object destroyed on strong reference count reduce to zero. + DecWeakRefCount(objectId); + return false; + } + return true; +} + +RefBase::RefBase() : refs_(new RefCounter()) +{ + refs_->IncRefCount(); + refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this)); +} + +RefBase::RefBase(const RefBase& /*other*/) +{ + refs_ = new RefCounter(); + if (refs_ != nullptr) { + refs_->IncRefCount(); + refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this)); + } +} + +void RefBase::RefPtrCallback() +{ + delete this; +} + +/* + * The two ends of the assignment are two independent and exclusive, + * and the application should not share the reference counter. + * RISK: If there is a reference count on the left of the equal sign, + * it may cause a reference count exception + */ +RefBase &RefBase::operator=(const RefBase& /*other*/) +{ + if (refs_ != nullptr) { + refs_->RemoveCallback(); + refs_->DecRefCount(); + } + refs_ = new RefCounter(); + if (refs_ != nullptr) { + refs_->IncRefCount(); + refs_->SetCallback(std::bind(&RefBase::RefPtrCallback, this)); + } + return *this; +} + +RefBase::RefBase(RefBase &&other) noexcept +{ + refs_ = other.refs_; + if (other.refs_ != nullptr) { + other.refs_ = nullptr; + } +} + +RefBase &RefBase::operator=(RefBase &&other) noexcept +{ + if (refs_ == other.refs_) { + return *this; + } + if (refs_ != nullptr) { + refs_->RemoveCallback(); + refs_->DecRefCount(); + } + refs_ = other.refs_; + if (other.refs_ != nullptr) { + other.refs_ = nullptr; + } + return *this; +} + +RefBase::~RefBase() +{ + if (refs_ != nullptr) { + refs_->RemoveCallback(); + refs_->DecRefCount(); + refs_ = nullptr; + } +} + +void RefBase::ExtendObjectLifetime() +{ + refs_->ExtendObjectLifetime(); +} + +void RefBase::IncStrongRef(const void *objectId) +{ + if (refs_ == nullptr) { + return; + } + const int curCount = refs_->IncStrongRefCount(objectId); + IncWeakRef(objectId); + if (curCount == INITIAL_PRIMARY_VALUE) { + OnFirstStrongRef(objectId); + } + if (refs_->IsAttemptAcquireSet()) { + refs_->ClearAttemptAcquire(); + refs_->DecStrongRefCount(objectId); + } +} + +void RefBase::DecStrongRef(const void *objectId) +{ + if (refs_ == nullptr) { + return; + } + const int curCount = refs_->DecStrongRefCount(objectId); + if (curCount == 1) { + OnLastStrongRef(objectId); + } + DecWeakRef(objectId); +} + +int RefBase::GetSptrRefCount() +{ + if (refs_ != nullptr) { + return refs_->GetStrongRefCount(); + } else { + return 0; + } +} + +WeakRefCounter *RefBase::CreateWeakRef(void *cookie) +{ + if (refs_ != nullptr) { + return new WeakRefCounter(refs_, cookie); + } + + return nullptr; +} + +void RefBase::IncWeakRef(const void *objectId) +{ + if (refs_ != nullptr) { + refs_->IncWeakRefCount(objectId); + } +} + +void RefBase::DecWeakRef(const void *objectId) +{ + if (refs_ != nullptr) { + refs_->DecWeakRefCount(objectId); + } +} + +int RefBase::GetWptrRefCount() +{ + if (refs_ != nullptr) { + return refs_->GetWeakRefCount(); + } else { + return 0; + } +} + +bool RefBase::AttemptAcquire(const void *objectId) +{ + if (refs_ != nullptr) { + int count = 0; + if (refs_->AttemptIncStrongRef(objectId, count)) { + if (count == INITIAL_PRIMARY_VALUE) { + OnFirstStrongRef(objectId); + } + refs_->SetAttemptAcquire(); + return true; + } + } + return false; +} + +bool RefBase::AttemptIncStrongRef(const void *objectId) +{ + if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) { + int count = 0; + bool ret = refs_->AttemptIncStrongRef(objectId, count); + if (count == INITIAL_PRIMARY_VALUE) { + OnFirstStrongRef(objectId); + } + return ret; + } + return false; +} + +bool RefBase::IsAttemptAcquireSet() +{ + if (refs_ != nullptr) { + return refs_->IsAttemptAcquireSet(); + } + return false; +} + +bool RefBase::IsExtendLifeTimeSet() +{ + if (refs_ != nullptr) { + return refs_->IsLifeTimeExtended(); + } + return false; +} + +void RefBase::OnFirstStrongRef(const void * /*objectId*/) +{} + +void RefBase::OnLastStrongRef(const void * /*objectId*/) +{} + +void RefBase::OnLastWeakRef(const void * /*objectId*/) +{} + +bool RefBase::OnAttemptPromoted(const void * /*objectId*/) +{ + return true; +} +} // namespace OHOS diff --git a/mock/native/src/rwlock.cpp b/mock/native/src/rwlock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58c94c59fed9a4a66d8eb2d30bef9d1646decf01 --- /dev/null +++ b/mock/native/src/rwlock.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rwlock.h" +#include + +namespace OHOS { +namespace Utils { +RWLock::RWLock(bool writeFirst) + : writeFirst_(writeFirst), writeThreadID_(), lockCount_(0), writeWaitCount_(0) +{ +} + +void RWLock::LockRead() +{ + if (std::this_thread::get_id() != writeThreadID_) { + int count; + if (writeFirst_) { + do { + // In write priority mode, the state must be non-write locked and no other threads are waiting to write + while ((count = lockCount_) == LOCK_STATUS_WRITE || writeWaitCount_ > 0) { + } + } while (!lockCount_.compare_exchange_weak(count, count + 1)); + } else { + do { + // If it is not write priority, you only need the current state to be non-write-locked. + while ((count = lockCount_) == LOCK_STATUS_WRITE) {} + } while (!lockCount_.compare_exchange_weak(count, count + 1)); + } + } else { + // If the thread has obtained the write lock, it does not need to wait for the read lock to return directly. + // Lock counter does not need to be modified + } +} + +void RWLock::UnLockRead() +{ + // Supports the case of writing and reading nesting. + // If the write lock has been obtained before, the read lock is directly returned successfully, + // and then the thread is still directly returned when unlocking. + if (std::this_thread::get_id() != writeThreadID_) { + --lockCount_; + } +} + +void RWLock::LockWrite() +{ + // If this thread is already a thread that gets the write lock, return directly to avoid repeated locks. + if (std::this_thread::get_id() != writeThreadID_) { + ++writeWaitCount_; // Write wait counter plus 1 + + // Only when no thread has acquired a read lock or a write lock (the lock counter status is FREE) + // can the write lock be acquired and the counter set to WRITE; otherwise wait + for (int status = LOCK_STATUS_FREE; !lockCount_.compare_exchange_weak(status, LOCK_STATUS_WRITE); + status = LOCK_STATUS_FREE) { + } + + // After the write lock is successfully acquired, the write wait counter is decremented by 1. + --writeWaitCount_; + writeThreadID_ = std::this_thread::get_id(); + } +} + +void RWLock::UnLockWrite() +{ + if (std::this_thread::get_id() != writeThreadID_) { + return; + } + + if (lockCount_ != LOCK_STATUS_WRITE) { + return; + } + + writeThreadID_ = std::thread::id(); + lockCount_.store(LOCK_STATUS_FREE); +} +} // namespace Utils +} // namespace OHOS \ No newline at end of file diff --git a/ohos.build b/ohos.build new file mode 100755 index 0000000000000000000000000000000000000000..1e632475230fa55e38c95489243bbbe70164d69c --- /dev/null +++ b/ohos.build @@ -0,0 +1,39 @@ +{ + "subsystem": "multimedia", + "parts": { + "multimedia_image_standard": { + "variants": [ + "phone", + "ivi", + "wearable" + ], + "module_list": [ + "//foundation/multimedia/image_standard:image_framework", + "//foundation/multimedia/image_standard:plugins" + ], + "inner_kits": [ + { + "header": { + "header_files": [ + "pixel_map.h", + "image_packer.h", + "image_source.h", + "image_type.h", + "peer_listener.h", + "incremental_pixel_map.h", + "pixel_map_manager.h", + "decode_listener.h", + "pixel_map_parcel.h" + ], + "header_base": "//foundation/multimedia/image_standard/interfaces/innerkits/include" + }, + "name": "//foundation/multimedia/image_standard/interfaces/innerkits:image" + } + + ], + "system_capabilities":[ + "SystemCapability.Multimedia.Image" + ] + } + } +} diff --git a/plugins/common/libs/BUILD.gn b/plugins/common/libs/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d190540e1a879789cda15af1eaff6820437968ff --- /dev/null +++ b/plugins/common/libs/BUILD.gn @@ -0,0 +1,62 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +group("multimediaplugin") { + if (use_mingw_win || use_clang_mac) { + deps = [ + "image/formatagentplugin:formatagentmetadata", + "image/formatagentplugin:imageformatagent", + "image/libgifplugin:gifplugin", + "image/libgifplugin:gifpluginmetadata", + "image/libjpegplugin:jpegplugin", + "image/libjpegplugin:jpegpluginmetadata", + "image/libpngplugin:pngplugin", + "image/libpngplugin:pngpluginmetadata", + "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin:bmpplugin", + "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin:bmppluginmetadata", + "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin:wbmpplugin", + "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin:wbmppluginmetadata", + ] + } else { + DUAL_ADAPTER = true + deps = [ + "image/formatagentplugin:formatagentmetadata", + "image/formatagentplugin:imageformatagent", + "image/libgifplugin:gifplugin", + "image/libgifplugin:gifpluginmetadata", +# "image/libheifplugin:heifplugin", +# "image/libheifplugin:heifpluginmetadata", +# "image/libjpegplugin:jpegplugin", +# "image/libjpegplugin:jpegpluginmetadata", +# "image/libpngplugin:pngplugin", +# "image/libpngplugin:pngpluginmetadata", +# "image/libwebpplugin:webpplugin", +# "image/libwebpplugin:webppluginmetadata", +# "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin:hwjpegplugin", +# "//foundation/multimedia/image_standard/adapter/frameworks/libhwjpegplugin:hwjpegpluginmetadata", + ] + if (DUAL_ADAPTER) { + deps += [ +# "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin:bmpplugin", +# "//foundation/multimedia/image_standard/adapter/frameworks/libbmpplugin:bmppluginmetadata", +# "//foundation/multimedia/image_standard/adapter/frameworks/librawplugin:rawplugin", +# "//foundation/multimedia/image_standard/adapter/frameworks/librawplugin:rawpluginmetadata", +# "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin:wbmpplugin", +# "//foundation/multimedia/image_standard/adapter/frameworks/libwbmpplugin:wbmppluginmetadata", + ] + } + } +} diff --git a/plugins/common/libs/image/formatagentplugin/BUILD.gn b/plugins/common/libs/image/formatagentplugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c8b0d158a4606d42eaea49d48d54d2a8c8298c9d --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("imageformatagent") { + sources = [ + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/bmp_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/gif_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/heif_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/jpeg_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/plugin_export.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/png_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/raw_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/wbmp_format_agent.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/src/webp_format_agent.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/formatagentplugin/include", + "//foundation/multimedia/image_standard/plugins/manager/include/utils", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("formatagentmetadata") { + source = "imageformatagent.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/common/libs/image/formatagentplugin/imageformatagent.pluginmeta b/plugins/common/libs/image/formatagentplugin/imageformatagent.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..c0b5e7196cebbf4229dae201e93aedab73d37232 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/imageformatagent.pluginmeta @@ -0,0 +1,144 @@ +{ + "packageName":"LibImageFormatAgent", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libimageformatagent.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::JpegFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/jpeg" + } + ] + }, + { + "className":"OHOS::ImagePlugin::PngFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/png" + } + ] + }, + { + "className":"OHOS::ImagePlugin::GifFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/gif" + } + ] + }, + { + "className":"OHOS::ImagePlugin::HeifFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/heif" + } + ] + }, + { + "className":"OHOS::ImagePlugin::WebpFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/webp" + } + ] + }, + { + "className":"OHOS::ImagePlugin::BmpFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/bmp" + } + ] + }, + { + "className":"OHOS::ImagePlugin::WbmpFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/vnd.wap.wbmp" + } + ] + }, + { + "className":"OHOS::ImagePlugin::RawFormatAgent", + "services": [ + { + "interfaceID":1, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/x-raw" + } + ] + } + ] +} diff --git a/plugins/common/libs/image/formatagentplugin/include/bmp_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/bmp_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..08deaca6aba8f01469c2907f7bdb28edbe4678ce --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/bmp_format_agent.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BMP_FORMAT_AGENT_H +#define BMP_FORMAT_AGENT_H + +#include "hilog/log.h" +#include "log_tags.h" +#include "abs_image_format_agent.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class BmpFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // BMP_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/gif_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/gif_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..0ff3d4864ec5f175c9c082b6802b5c4bdd332f8b --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/gif_format_agent.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GIF_FORMAT_AGENT_H +#define GIF_FORMAT_AGENT_H + +#include "hilog/log.h" +#include "log_tags.h" +#include "abs_image_format_agent.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class GifFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // GIF_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/heif_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/heif_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..2d64bc6f5587a80da55a7b477849f8ec8a4f81aa --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/heif_format_agent.h @@ -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. + */ + +#ifndef HEIF_FORMAT_AGENT_H +#define HEIF_FORMAT_AGENT_H + +#include "abs_image_format_agent.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class HeifFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; + +private: + uint32_t Fourcc(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4); + uint32_t EndianSwap32(uint32_t value); + uint64_t EndianSwap64(uint64_t value); + bool IsHeif64(const void *buffer, const size_t bytesRead, int64_t &offset, uint64_t &chunkSize); +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HEIF_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/jpeg_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/jpeg_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..4bed30efaf1c0465a4ba655b5a436d6ea78a97cb --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/jpeg_format_agent.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JPEG_FORMAT_AGENT_H +#define JPEG_FORMAT_AGENT_H + +#include "hilog/log.h" +#include "log_tags.h" +#include "abs_image_format_agent.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class JpegFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // JPEG_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/png_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/png_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..884eb444e013a0b78c0f73f6da130ff5a7fefd7a --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/png_format_agent.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PNG_FORMAT_AGENT_H +#define PNG_FORMAT_AGENT_H + +#include "abs_image_format_agent.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class PngFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // PNG_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/raw_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/raw_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..e8fc1a9c149ef1a8302025c53920b1421409d77c --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/raw_format_agent.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef RAW_FORMAT_AGENT_H +#define RAW_FORMAT_AGENT_H + +#include "hilog/log.h" +#include "log_tags.h" +#include "abs_image_format_agent.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class RawFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // RAW_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/wbmp_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/wbmp_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..522871e8d7b45743a94f305dad7b30f90330e621 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/wbmp_format_agent.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef WBMP_FORMAT_AGENT_H +#define WBMP_FORMAT_AGENT_H + +#include "hilog/log.h" +#include "log_tags.h" +#include "abs_image_format_agent.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class WbmpFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; + bool read_byte(uint8_t *stream, uint8_t &value, uint32_t &offset, uint32_t dataSize); + bool read_mbf(uint8_t *stream, uint64_t &value, uint32_t &offset, uint32_t dataSize); + bool read_header(const void *stream, uint32_t dataSize); +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // WBMP_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/include/webp_format_agent.h b/plugins/common/libs/image/formatagentplugin/include/webp_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..4279ef0eb192387590a26bab9eee4ccf6377aeaa --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/include/webp_format_agent.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WEBP_FORMAT_AGENT_H +#define WEBP_FORMAT_AGENT_H + +#include "abs_image_format_agent.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class WebpFormatAgent : public AbsImageFormatAgent, public OHOS::MultimediaPlugin::PluginClassBase { +public: + std::string GetFormatType() override; + uint32_t GetHeaderSize() override; + bool CheckFormat(const void *headerData, uint32_t dataSize) override; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // WEBP_FORMAT_AGENT_H \ No newline at end of file diff --git a/plugins/common/libs/image/formatagentplugin/src/bmp_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/bmp_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ee380ecc66202d2b10d8e4008be9bfa4c1d874b --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/bmp_format_agent.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bmp_format_agent.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "BmpFormatAgent" }; +namespace { +const std::string FORMAT_TYPE = "image/bmp"; +constexpr uint8_t BMP_HEADER[] = { 0x42, 0x4D }; +} // namespace + +std::string BmpFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t BmpFormatAgent::GetHeaderSize() +{ + return sizeof(BMP_HEADER); +} + +bool BmpFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr) { + HiLog::Error(LABEL, "check format failed: header data is null."); + return false; + } + uint32_t headerSize = sizeof(BMP_HEADER); + if (dataSize < headerSize) { + HiLog::Error(LABEL, "read head size:[%{public}u] less than header size:[%{public}u].", dataSize, headerSize); + return false; + } + + if (memcmp(headerData, BMP_HEADER, headerSize) != 0) { + HiLog::Error(LABEL, "header stamp mismatch."); + return false; + } + return true; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/gif_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/gif_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..085a123d8f0c2a51c98fd313106eb82d9b0bb0ea --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/gif_format_agent.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gif_format_agent.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; + +static const std::string FORMAT_TYPE = "image/gif"; +static const char GIF87_STAMP[] = "GIF87a"; +static const char GIF89_STAMP[] = "GIF89a"; +static const uint8_t GIF_STAMP_LEN = 6; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "GifFormatAgent" }; + +std::string GifFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t GifFormatAgent::GetHeaderSize() +{ + return GIF_STAMP_LEN; +} + +bool GifFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr) { + HiLog::Error(LABEL, "check format failed: header data is null."); + return false; + } + + if (dataSize < GIF_STAMP_LEN) { + HiLog::Error(LABEL, "read head size:[%{public}u] less than header size:[%{public}u].", dataSize, GIF_STAMP_LEN); + return false; + } + + if (memcmp(GIF87_STAMP, headerData, GIF_STAMP_LEN) != 0 && memcmp(GIF89_STAMP, headerData, GIF_STAMP_LEN) != 0) { + HiLog::Error(LABEL, "header stamp mismatch."); + return false; + } + return true; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/heif_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/heif_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97376d78c45b3e9e65217dd4dfd27edb33bba2e7 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/heif_format_agent.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "heif_format_agent.h" +#include "hilog/log.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; + +const std::string FORMAT_TYPE = "image/heif"; +constexpr uint32_t HEADER_SIZE = 32; +constexpr uint32_t HEADER_LEAST_SIZE = 8; +constexpr size_t HEADER_NEXT_SIZE = 16; +constexpr uint32_t OFFSET_SIZE = 8; + +constexpr uint32_t SHIFT_BASE = 8; +constexpr uint32_t TIMES_SEVEN = 7; +constexpr uint32_t TIMES_FIVE = 5; +constexpr uint32_t TIMES_THREE = 3; +constexpr uint32_t TIMES_TWO = 2; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "HeifFormatAgent" }; + +std::string HeifFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t HeifFormatAgent::GetHeaderSize() +{ + return HEADER_SIZE; +} + +bool HeifFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr) { + HiLog::Error(LABEL, "check format failed: header data is null."); + return false; + } + // Any valid ftyp box should have at least 8 bytes. + if (dataSize < HEADER_LEAST_SIZE) { + HiLog::Error(LABEL, "data size[%{public}u] less than eight.", dataSize); + return false; + } + + const uint32_t *ptr = static_cast(headerData); + uint64_t chunkSize = EndianSwap32(ptr[0]); // first item + uint32_t chunkType = EndianSwap32(ptr[1]); // second item + if (chunkType != Fourcc('f', 't', 'y', 'p')) { + HiLog::Error(LABEL, "head type is not ftyp."); + return false; + } + + int64_t offset = OFFSET_SIZE; + if (!IsHeif64(headerData, dataSize, offset, chunkSize)) { + return false; + } + int64_t chunkDataSize = chunkSize - offset; + // It should at least have major brand (4-byte) and minor version (4-bytes). + // The rest of the chunk (if any) is a list of (4-byte) compatible brands. + if (chunkDataSize < HEADER_LEAST_SIZE) { + HiLog::Error(LABEL, "chunk data size [%{public}lld] less than eight.", static_cast(chunkDataSize)); + return false; + } + uint32_t numCompatibleBrands = (chunkDataSize - OFFSET_SIZE) / sizeof(uint32_t); + for (size_t i = 0; i < numCompatibleBrands + 2; ++i) { // need next 2 item + if (i == 1) { + // Skip this index, it refers to the minorVersion, not a brand. + continue; + } + auto *brandPtr = static_cast(headerData) + (numCompatibleBrands + i); + uint32_t brand = EndianSwap32(*brandPtr); + if (brand == Fourcc('m', 'i', 'f', '1') || brand == Fourcc('h', 'e', 'i', 'c') || + brand == Fourcc('m', 's', 'f', '1') || brand == Fourcc('h', 'e', 'v', 'c')) { + return true; + } + } + HiLog::Error(LABEL, "check heif format failed."); + return false; +} + +bool HeifFormatAgent::IsHeif64(const void *buffer, const size_t bytesRead, int64_t &offset, uint64_t &chunkSize) +{ + // If it is 1, a 64-bit check is required. + if (chunkSize == 1) { + // This indicates that the next 8 bytes represent the chunk size, + // and chunk data comes after that. + if (bytesRead < HEADER_NEXT_SIZE) { + HiLog::Error(LABEL, "bytes read [%{public}zd] less than sixteen.", bytesRead); + return false; + } + auto *chunkSizePtr = static_cast(buffer) + (offset / sizeof(uint64_t)); + chunkSize = EndianSwap64(*chunkSizePtr); + if (chunkSize < HEADER_NEXT_SIZE) { + // The smallest valid chunk is 16 bytes long in this case. + HiLog::Error(LABEL, "chunk size [%{public}llu] less than sixteen.", + static_cast(chunkSize)); + return false; + } + offset += OFFSET_SIZE; + } else if (chunkSize < HEADER_LEAST_SIZE) { + // The smallest valid chunk is 8 bytes long. + HiLog::Error(LABEL, "chunk size [%{public}llu] less than eight.", static_cast(chunkSize)); + return false; + } + + if (chunkSize > bytesRead) { + chunkSize = bytesRead; + } + return true; +} + +uint32_t HeifFormatAgent::Fourcc(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4) +{ + return (c1 << (SHIFT_BASE * TIMES_THREE)) | (c2 << (SHIFT_BASE * TIMES_TWO)) | (c3 << SHIFT_BASE) | (c4); +} + +uint32_t HeifFormatAgent::EndianSwap32(uint32_t value) +{ + return ((value & 0xFF) << (SHIFT_BASE * TIMES_THREE)) | ((value & 0xFF00) << SHIFT_BASE) | + ((value & 0xFF0000) >> SHIFT_BASE) | (value >> (SHIFT_BASE * TIMES_THREE)); +} + +uint64_t HeifFormatAgent::EndianSwap64(uint64_t value) +{ + return (((value & 0x00000000000000FFULL) << (SHIFT_BASE * TIMES_SEVEN)) | + ((value & 0x000000000000FF00ULL) << (SHIFT_BASE * TIMES_FIVE)) | + ((value & 0x0000000000FF0000ULL) << (SHIFT_BASE * TIMES_THREE)) | + ((value & 0x00000000FF000000ULL) << (SHIFT_BASE)) | ((value & 0x000000FF00000000ULL) >> (SHIFT_BASE)) | + ((value & 0x0000FF0000000000ULL) >> (SHIFT_BASE * TIMES_THREE)) | + ((value & 0x00FF000000000000ULL) >> (SHIFT_BASE * TIMES_FIVE)) | ((value) >> (SHIFT_BASE * TIMES_SEVEN))); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/jpeg_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/jpeg_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4654a2f0dd4abe877f15e3e6bd2a8f8ed71bd498 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/jpeg_format_agent.cpp @@ -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. + */ + +#include "jpeg_format_agent.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; + +static const std::string FORMAT_TYPE = "image/jpeg"; +static constexpr uint8_t JPEG_HEADER[] = { 0xFF, 0xD8, 0xFF }; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegFormatAgent" }; + +std::string JpegFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t JpegFormatAgent::GetHeaderSize() +{ + return sizeof(JPEG_HEADER); +} + +bool JpegFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr) { + HiLog::Error(LABEL, "check format failed: header data is null."); + return false; + } + uint32_t headerSize = sizeof(JPEG_HEADER); + if (dataSize < headerSize) { + HiLog::Error(LABEL, "read head size:[%{public}u] less than header size:[%{public}u].", dataSize, headerSize); + return false; + } + + if (memcmp(headerData, JPEG_HEADER, headerSize) != 0) { + HiLog::Error(LABEL, "header stamp mismatch."); + return false; + } + return true; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/plugin_export.cpp b/plugins/common/libs/image/formatagentplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63d32f2e640fce5ba6ab8505114732bd165f53d8 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/plugin_export.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_export.h" +#include "gif_format_agent.h" +#include "heif_format_agent.h" +#include "hilog/log.h" +#include "jpeg_format_agent.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "png_format_agent.h" +#include "webp_format_agent.h" +#include "bmp_format_agent.h" +#include "raw_format_agent.h" +#include "wbmp_format_agent.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibImageFormatAgent") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::JpegFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::PngFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::GifFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::HeifFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::WebpFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::BmpFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::RawFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::WbmpFormatAgent) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibImageFormatAgent" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/plugins/common/libs/image/formatagentplugin/src/png_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/png_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72a9d93660a8b76499f1a98932556bfc6b01b3de --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/png_format_agent.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "png_format_agent.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; + +static const std::string FORMAT_TYPE = "image/png"; +static constexpr uint8_t PNG_HEADER[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PngFormatAgent" }; + +std::string PngFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t PngFormatAgent::GetHeaderSize() +{ + return (sizeof(PNG_HEADER)); +} + +bool PngFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr || dataSize == 0) { + HiLog::Error(LABEL, "check format input parameter abnormal."); + return false; + } + uint32_t headerSize = sizeof(PNG_HEADER); + if (dataSize < headerSize) { + HiLog::Error(LABEL, "read head size:[%{public}u] less than header size:[%{public}u].", dataSize, headerSize); + return false; + } + return !memcmp(headerData, PNG_HEADER, headerSize); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/raw_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/raw_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbf78e7e148c92bf889a7f7d74443a5a9062d883 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/raw_format_agent.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "raw_format_agent.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace ImagePlugin; +using namespace MultimediaPlugin; + +/* +"image/x-sony-arw", +"image/x-canon-cr2", +"image/x-adobe-dng", +"image/x-nikon-nef", +"image/x-nikon-nrw", +"image/x-olympus-orf", +"image/x-fuji-raf", +"image/x-panasonic-rw2", +"image/x-pentax-pef", +"image/x-samsung-srw", +*/ +const std::string FORMAT_TYPE = "image/x-raw"; +constexpr uint32_t HEADER_SIZE = 32; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "RawFormatAgent" }; + +std::string RawFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t RawFormatAgent::GetHeaderSize() +{ + return HEADER_SIZE; +} + +bool RawFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr) { + HiLog::Error(LABEL, "check format failed: header data is null."); + return false; + } + + HiLog::Info(LABEL, "RawFormatAgent now pass all image format."); + return true; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/wbmp_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/wbmp_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37a0c9935528814241c16f60010968ac12091e39 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/wbmp_format_agent.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "wbmp_format_agent.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace ImagePlugin; +using namespace MultimediaPlugin; + +const std::string FORMAT_TYPE = "image/vnd.wap.wbmp"; +constexpr uint32_t HEADER_SIZE = 32; +constexpr uint8_t SHIF_BIT_MASK = 7; +constexpr uint8_t LOW_BIT_MASK = 0x7F; +constexpr uint8_t HIGH_BIT_MASK = 0x80; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WbmpFormatAgent" }; + +bool WbmpFormatAgent::read_byte(uint8_t *stream, uint8_t &value, uint32_t &offset, uint32_t dataSize) +{ + if (offset >= dataSize) { + HiLog::Error(LABEL, "read_header data offset %{public}u. dataSize %{public}u", offset, dataSize); + return false; + } + value = *(stream + offset); + offset++; + return true; +} + +bool WbmpFormatAgent::read_mbf(uint8_t *stream, uint64_t &value, uint32_t &offset, uint32_t dataSize) +{ + uint64_t n = 0; + uint8_t data; + const uint64_t kLimit = 0xFE00000000000000; + do { + if (n & kLimit) { // Will overflow on shift by 7. + return false; + } + if (!read_byte(stream, data, offset, dataSize)) { + return false; + } + n = (n << SHIF_BIT_MASK) | (data & LOW_BIT_MASK); + } while (data & HIGH_BIT_MASK); + value = n; + return true; +} + +bool WbmpFormatAgent::read_header(const void *stream, uint32_t dataSize) +{ + uint8_t data; + uint8_t *pData = (uint8_t *)stream; + uint32_t offset = 0; + + if (!read_byte(pData, data, offset, dataSize) || data != 0) { // unknown type + return false; + } + HiLog::Debug(LABEL, "read_header data %{public}u.", data); + + if (!read_byte(pData, data, offset, dataSize) || (data & 0x9F)) { // skip fixed header + return false; + } + HiLog::Debug(LABEL, "read_header data %{public}u.", data); + + uint64_t width, height; + if (!read_mbf(pData, width, offset, dataSize) || width > 0xFFFF || !width) { + return false; + } + HiLog::Debug(LABEL, "read_header width %{public}lld.", (long long)width); + + if (!read_mbf(pData, height, offset, dataSize) || height > 0xFFFF || !height) { + return false; + } + HiLog::Debug(LABEL, "read_header height %{public}lld.", (long long)height); + + return true; +} + + +std::string WbmpFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t WbmpFormatAgent::GetHeaderSize() +{ + return HEADER_SIZE; +} + +bool WbmpFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr) { + HiLog::Error(LABEL, "check format failed: header data is null."); + return false; + } + + if (!read_header(headerData, dataSize)) { + HiLog::Error(LABEL, "not wbmp image format."); + return false; + } + + HiLog::Debug(LABEL, "wbmp image format ok."); + return true; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/formatagentplugin/src/webp_format_agent.cpp b/plugins/common/libs/image/formatagentplugin/src/webp_format_agent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..739d4b05e56586fac6012af49152b28941e5d851 --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/src/webp_format_agent.cpp @@ -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. + */ + +#include "webp_format_agent.h" +#include + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; + +namespace { +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WebpFormatAgent" }; +const std::string FORMAT_TYPE = "image/webp"; +constexpr size_t WEBP_MINIMUM_LENGTH = 14; +const char *WEBP_HEADER_PRE = "RIFF"; +constexpr int32_t WEBP_HEADER_PRE_LENGTH = 4; +const char *WEBP_HEADER_POST = "WEBPVP"; +constexpr int32_t WEBP_HEADER_POST_LENGTH = 6; +} // namespace + +std::string WebpFormatAgent::GetFormatType() +{ + return FORMAT_TYPE; +} + +uint32_t WebpFormatAgent::GetHeaderSize() +{ + return WEBP_MINIMUM_LENGTH; +} + +bool WebpFormatAgent::CheckFormat(const void *headerData, uint32_t dataSize) +{ + if (headerData == nullptr || dataSize == 0) { + HiLog::Error(LABEL, "check format input parameter abnormal."); + return false; + } + + /* + * WEBP starts with the following: + * RIFFXXXXWEBPVP + * Where XXXX is unspecified. + */ + const char *head = static_cast(headerData); + return dataSize >= WEBP_MINIMUM_LENGTH && !memcmp(head, WEBP_HEADER_PRE, WEBP_HEADER_PRE_LENGTH) && + !memcmp(&head[8], WEBP_HEADER_POST, WEBP_HEADER_POST_LENGTH); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libgifplugin/BUILD.gn b/plugins/common/libs/image/libgifplugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0621c00edcb173d656fc1a2ac2455128a6d6f60e --- /dev/null +++ b/plugins/common/libs/image/libgifplugin/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("gifplugin") { + sources = [ + "//foundation/multimedia/image_standard/plugins/common/libs/image/libgifplugin/src/gif_decoder.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libgifplugin/src/plugin_export.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libgifplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//third_party/giflib", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/giflib:gif_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/giflib:gif_static", + "//utils/native/base:utilsecurec", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//third_party/giflib:libgif", + "//utils/native/base:utils", + ] +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + part_name = "multimedia_image" + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("gifpluginmetadata") { + source = "gifplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/common/libs/image/libgifplugin/gifplugin.pluginmeta b/plugins/common/libs/image/libgifplugin/gifplugin.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..71e33184911768723714c1c282b4e5ef2f546141 --- /dev/null +++ b/plugins/common/libs/image/libgifplugin/gifplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibGifPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libgifplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::GifDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/gif" + } + ] + } + ] +} diff --git a/plugins/common/libs/image/libgifplugin/include/gif_decoder.h b/plugins/common/libs/image/libgifplugin/include/gif_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..d9fff725e72c5aed65c53daa9d71f6259eaa8ea1 --- /dev/null +++ b/plugins/common/libs/image/libgifplugin/include/gif_decoder.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GIF_DECODER_H +#define GIF_DECODER_H + +#include +#include +#include +#include "abs_image_decoder.h" +#include "gif_lib.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "media_errors.h" +#include "nocopyable.h" +#include "plugin_class_base.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace ImagePlugin { +static constexpr uint8_t PIXEL_FORMAT_BYTE_SIZE = 4; + +class GifDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + GifDecoder(); + ~GifDecoder() override; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + uint32_t GetTopLevelImageNum(uint32_t &num) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + uint32_t GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) override; + +private: + static int32_t InputStreamReader(GifFileType *gif, GifByteType *bytes, int32_t size); + DISALLOW_COPY_AND_MOVE(GifDecoder); + uint32_t CheckIndex(uint32_t index); + uint32_t OverlapFrame(uint32_t startIndex, uint32_t endIndex); + uint32_t RedirectOutputBuffer(DecodeContext &context); + void GetTransparentAndDisposal(uint32_t index, int32_t &transparentColor, int32_t &disposalMode); + GraphicsControlBlock GetGraphicsControlBlock(uint32_t index); + uint32_t PaddingBgColor(const SavedImage *savedImage); + bool IsFramePreviousCoveredCurrent(const SavedImage *preSavedImage, const SavedImage *curSavedImage); + uint32_t PaddingData(const SavedImage *savedImage, int32_t transparentColor); + void CopyLine(const GifByteType *srcFrame, uint32_t *dstFrame, int32_t frameWidth, int32_t transparentColor, + const ColorMapObject *colorMap); + uint32_t GetPixelColor(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha); + void ParseBgColor(); + uint32_t UpdateGifFileType(int32_t updateFrameIndex); + uint32_t CreateGifFileTypeIfNotExist(); + uint32_t ParseFrameDetail(); + uint32_t SetSavedImageRasterBits(SavedImage *saveImagePtr, int32_t frameIndex, uint64_t imageSize, + int32_t imageWidth, int32_t imageHeight); + uint32_t ParseFrameExtension(); + uint32_t AllocateLocalPixelMapBuffer(); + void FreeLocalPixelMapBuffer(); + uint32_t DisposeBackground(uint32_t frameIndex, const SavedImage *curSavedImage); + uint32_t GetImageDelayTime(uint32_t index, int32_t &value); + uint32_t GetImageLoopCount(uint32_t index, int32_t &value); + + InputDataStream *inputStreamPtr_ = nullptr; + GifFileType *gifPtr_ = nullptr; + uint32_t *localPixelMapBuffer_ = nullptr; + uint32_t bgColor_ = 0; + int32_t lastPixelMapIndex_ = -1; + bool isLoadAllFrame_ = false; + int32_t savedFrameIndex_ = -1; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // GIF_DECODER_H diff --git a/plugins/common/libs/image/libgifplugin/src/gif_decoder.cpp b/plugins/common/libs/image/libgifplugin/src/gif_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf6b612a54607d22f9bbe688541662e624b22768 --- /dev/null +++ b/plugins/common/libs/image/libgifplugin/src/gif_decoder.cpp @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gif_decoder.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "GifDecoder" }; + +namespace { +#if __BYTE_ORDER == __LITTLE_ENDIAN +constexpr uint8_t RGBA_R_SHIFT = 0; +constexpr uint8_t RGBA_G_SHIFT = 8; +constexpr uint8_t RGBA_B_SHIFT = 16; +constexpr uint8_t RGBA_A_SHIFT = 24; +#else +constexpr uint8_t RGBA_R_SHIFT = 24; +constexpr uint8_t RGBA_G_SHIFT = 16; +constexpr uint8_t RGBA_B_SHIFT = 8; +constexpr uint8_t RGBA_A_SHIFT = 0; +#endif +constexpr uint8_t NO_TRANSPARENT = 0xFF; +constexpr uint8_t DELAY_TIME_TO_MS_RATIO = 10; +constexpr uint8_t EXTENSION_LEN_INDEX = 0; +constexpr uint8_t EXTENSION_DATA_INDEX = 1; +constexpr int32_t INTERLACED_PASSES = 4; +constexpr int32_t INTERLACED_OFFSET[] = { 0, 4, 2, 1 }; +constexpr int32_t INTERLACED_INTERVAL[] = { 8, 8, 4, 2 }; +const std::string GIF_IMAGE_DELAY_TIME = "GIFDelayTime"; +const std::string GIF_IMAGE_LOOP_COUNT = "GIFLoopCount"; +constexpr int32_t NETSCAPE_EXTENSION_LENGTH = 11; +constexpr int32_t DELAY_TIME_LENGTH = 3; +constexpr int32_t DELAY_TIME_INDEX1 = 1; +constexpr int32_t DELAY_TIME_INDEX2 = 2; +constexpr int32_t DELAY_TIME_SHIFT = 8; +} // namespace + +GifDecoder::GifDecoder() +{} + +GifDecoder::~GifDecoder() +{ + Reset(); +} + +void GifDecoder::SetSource(InputDataStream &sourceStream) +{ + Reset(); + inputStreamPtr_ = &sourceStream; +} + +// need decode all frame to get total number. +uint32_t GifDecoder::GetTopLevelImageNum(uint32_t &num) +{ + if (inputStreamPtr_ == nullptr) { + HiLog::Error(LABEL, "[GetTopLevelImageNum]set source need firstly"); + return ERR_IMAGE_DATA_ABNORMAL; + } + if (!inputStreamPtr_->IsStreamCompleted()) { + HiLog::Warn(LABEL, "[GetTopLevelImageNum]don't enough data to decode the frame number"); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + uint32_t errorCode = CreateGifFileTypeIfNotExist(); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[GetTopLevelImageNum]create GifFileType pointer failed %{public}u", errorCode); + return ERR_IMAGE_DECODE_ABNORMAL; + } + if (!isLoadAllFrame_) { + errorCode = UpdateGifFileType(INT_MAX); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[GetTopLevelImageNum]update GifFileType pointer failed %{public}u", errorCode); + return ERR_IMAGE_DECODE_ABNORMAL; + } + } + num = gifPtr_->ImageCount; + if (num <= 0) { + HiLog::Error(LABEL, "[GetTopLevelImageNum]image frame number must be larger than 0"); + return ERR_IMAGE_DATA_ABNORMAL; + } + return SUCCESS; +} + +// return background size but not specific frame size, cause of frame drawing on background. +uint32_t GifDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + uint32_t errorCode = CheckIndex(index); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[GetImageSize]index %{public}u is invalid %{public}u", index, errorCode); + return errorCode; + } + const int32_t bgWidth = gifPtr_->SWidth; + const int32_t bgHeight = gifPtr_->SHeight; + if (bgWidth <= 0 || bgHeight <= 0) { + HiLog::Error(LABEL, "[GetImageSize]background size [%{public}d, %{public}d] is invalid", bgWidth, bgHeight); + return ERR_IMAGE_INVALID_PARAMETER; + } + size.width = bgWidth; + size.height = bgHeight; + return SUCCESS; +} + +uint32_t GifDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + uint32_t errorCode = GetImageSize(index, info.size); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[SetDecodeOptions]get image size failed %{public}u", errorCode); + return errorCode; + } + info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + // only support RGBA pixel format for performance. + info.pixelFormat = PlPixelFormat::RGBA_8888; + return SUCCESS; +} + +uint32_t GifDecoder::Decode(uint32_t index, DecodeContext &context) +{ + PlSize imageSize; + uint32_t errorCode = GetImageSize(index, imageSize); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[Decode]index %{public}u is invalid %{public}u", index, errorCode); + return errorCode; + } + // compute start index and end index. + bool isOverlapped = false; + uint32_t startIndex = 0; + uint32_t endIndex = index; + int32_t acquiredIndex = static_cast(index); + if (acquiredIndex > lastPixelMapIndex_) { + startIndex = lastPixelMapIndex_ + 1; + } else if (acquiredIndex == lastPixelMapIndex_) { + isOverlapped = true; + } + // avoid local pixelmap buffer was reset, start with first frame again. + if (startIndex != 0 && localPixelMapBuffer_ == nullptr) { + startIndex = 0; + isOverlapped = false; + } + HiLog::Debug(LABEL, "[Decode]start frame: %{public}u, last frame: %{public}u," + "last pixelMapIndex: %{public}d, isOverlapped: %{public}d", + startIndex, endIndex, lastPixelMapIndex_, isOverlapped); + + if (!isOverlapped) { + errorCode = OverlapFrame(startIndex, endIndex); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[Decode]overlap frame failed %{public}u", errorCode); + return errorCode; + } + } + errorCode = RedirectOutputBuffer(context); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[Decode]redirect output stream failed %{public}u", errorCode); + return errorCode; + } + return SUCCESS; +} + +uint32_t GifDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + uint32_t errorCode = Decode(index, context.decodeContext); + // get promote decode progress, in percentage: 0~100. + context.totalProcessProgress = (errorCode == SUCCESS ? 100 : 0); + return errorCode; +} + +void GifDecoder::Reset() +{ + if (gifPtr_ != nullptr) { + DGifCloseFile(gifPtr_, nullptr); + gifPtr_ = nullptr; + } + FreeLocalPixelMapBuffer(); // free local pixelmap buffer + inputStreamPtr_ = nullptr; + isLoadAllFrame_ = false; + lastPixelMapIndex_ = -1; + savedFrameIndex_ = -1; + bgColor_ = 0; +} + +uint32_t GifDecoder::CreateGifFileTypeIfNotExist() +{ + if (gifPtr_ == nullptr) { + int32_t errorCode = Media::ERROR; + if (inputStreamPtr_ == nullptr) { + HiLog::Error(LABEL, "[CreateGifFileTypeIfNotExist]set source need firstly"); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + // DGifOpen will create GifFileType pointer and set header and screen desc + gifPtr_ = DGifOpen(inputStreamPtr_, InputStreamReader, &errorCode); + if (gifPtr_ == nullptr) { + HiLog::Error(LABEL, "[CreateGifFileTypeIfNotExist]open image error, %{public}d", errorCode); + inputStreamPtr_->Seek(0); + savedFrameIndex_ = -1; + return ERR_IMAGE_SOURCE_DATA; + } + ParseBgColor(); + } + return SUCCESS; +} + +int32_t GifDecoder::InputStreamReader(GifFileType *gif, GifByteType *bytes, int32_t size) +{ + uint32_t dataSize = 0; + if (gif == nullptr) { + HiLog::Error(LABEL, "[InputStreamReader]GifFileType pointer is null"); + return dataSize; + } + InputDataStream *inputStream = static_cast(gif->UserData); + if (inputStream == nullptr) { + HiLog::Error(LABEL, "[InputStreamReader]set source need firstly"); + return dataSize; + } + if (size <= 0) { + HiLog::Error(LABEL, "[InputStreamReader]callback size %{public}d is invalid", size); + return dataSize; + } + if (bytes == nullptr) { + HiLog::Error(LABEL, "[InputStreamReader]callback buffer is null"); + return dataSize; + } + inputStream->Read(size, bytes, size, dataSize); + return dataSize; +} + +uint32_t GifDecoder::CheckIndex(uint32_t index) +{ + if (!inputStreamPtr_->IsStreamCompleted()) { + HiLog::Warn(LABEL, "[CheckIndex]don't enough data to decode the frame number"); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + uint32_t errorCode = CreateGifFileTypeIfNotExist(); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[CheckIndex]create GifFileType failed %{public}u", errorCode); + return errorCode; + } + int32_t updateFrameIndex = static_cast(index); + if (!isLoadAllFrame_ && updateFrameIndex > savedFrameIndex_) { + errorCode = UpdateGifFileType(updateFrameIndex); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[CheckIndex]update saved frame to index %{public}u failed", index); + return errorCode; + } + } + uint32_t frameNum = gifPtr_->ImageCount; + if (index >= frameNum) { + HiLog::Error(LABEL, "[CheckIndex]index %{public}u out of frame range %{public}u", index, frameNum); + return ERR_IMAGE_INVALID_PARAMETER; + } + return SUCCESS; +} + +uint32_t GifDecoder::OverlapFrame(uint32_t startIndex, uint32_t endIndex) +{ + for (uint32_t frameIndex = startIndex; frameIndex <= endIndex; frameIndex++) { + const SavedImage *savedImage = gifPtr_->SavedImages + frameIndex; + if (savedImage == nullptr) { + HiLog::Error(LABEL, "[OverlapFrame]image frame %{public}u data is invalid", frameIndex); + return ERR_IMAGE_DECODE_ABNORMAL; + } + // acquire the frame graphices control information + int32_t transColor = NO_TRANSPARENT_COLOR; + int32_t disposalMode = DISPOSAL_UNSPECIFIED; + GetTransparentAndDisposal(frameIndex, transColor, disposalMode); + HiLog::Debug(LABEL, + "[OverlapFrame]frameIndex = %{public}u, transColor = %{public}d, " + "disposalMode = %{public}d", + frameIndex, transColor, disposalMode); + + if (frameIndex == 0 && AllocateLocalPixelMapBuffer() != SUCCESS) { + HiLog::Error(LABEL, "[OverlapFrame]first frame allocate local pixelmap buffer failed"); + return ERR_IMAGE_DECODE_ABNORMAL; + } + if (localPixelMapBuffer_ == nullptr) { + HiLog::Error(LABEL, "[OverlapFrame]local pixelmap is null, next frame can't overlap"); + return ERR_IMAGE_DECODE_ABNORMAL; + } + // current frame recover background + if (frameIndex != 0 && disposalMode == DISPOSE_BACKGROUND && + DisposeBackground(frameIndex, savedImage) != SUCCESS) { + HiLog::Error(LABEL, "[OverlapFrame]dispose frame %{public}d background failed", frameIndex); + return ERR_IMAGE_DECODE_ABNORMAL; + } + if (disposalMode != DISPOSE_PREVIOUS && + PaddingData(savedImage, transColor) != SUCCESS) { + HiLog::Error(LABEL, "[OverlapFrame]dispose frame %{public}u data color failed", frameIndex); + return ERR_IMAGE_DECODE_ABNORMAL; + } + } + lastPixelMapIndex_ = endIndex; + return SUCCESS; +} + +uint32_t GifDecoder::DisposeBackground(uint32_t frameIndex, const SavedImage *curSavedImage) +{ + int32_t preTransColor = NO_TRANSPARENT_COLOR; + int32_t preDisposalMode = DISPOSAL_UNSPECIFIED; + GetTransparentAndDisposal(frameIndex - 1, preTransColor, preDisposalMode); + SavedImage *preSavedImage = gifPtr_->SavedImages + frameIndex - 1; + if (preDisposalMode == DISPOSE_BACKGROUND && IsFramePreviousCoveredCurrent(preSavedImage, curSavedImage)) { + return SUCCESS; + } + if (PaddingBgColor(curSavedImage) != SUCCESS) { + HiLog::Error(LABEL, "[DisposeBackground]padding frame %{public}u background color failed", frameIndex); + return ERR_IMAGE_DECODE_ABNORMAL; + } + return SUCCESS; +} + +bool GifDecoder::IsFramePreviousCoveredCurrent(const SavedImage *preSavedImage, const SavedImage *curSavedImage) +{ + return ((preSavedImage->ImageDesc.Left <= curSavedImage->ImageDesc.Left) && + (preSavedImage->ImageDesc.Left + preSavedImage->ImageDesc.Width >= + curSavedImage->ImageDesc.Left + curSavedImage->ImageDesc.Width) && + (preSavedImage->ImageDesc.Top <= curSavedImage->ImageDesc.Top) && + (preSavedImage->ImageDesc.Top + preSavedImage->ImageDesc.Height >= + curSavedImage->ImageDesc.Top + curSavedImage->ImageDesc.Height)); +} + +uint32_t GifDecoder::AllocateLocalPixelMapBuffer() +{ + if (localPixelMapBuffer_ == nullptr) { + int32_t bgWidth = gifPtr_->SWidth; + int32_t bgHeight = gifPtr_->SHeight; + uint64_t pixelMapBufferSize = static_cast(bgWidth) * bgHeight * sizeof(uint32_t); + // create local pixelmap buffer, next frame depends on the previous + if (pixelMapBufferSize > PIXEL_MAP_MAX_RAM_SIZE) { + HiLog::Error(LABEL, "[AllocateLocalPixelMapBuffer]pixelmap buffer size %{public}llu out of max size", + static_cast(pixelMapBufferSize)); + return ERR_IMAGE_TOO_LARGE; + } + localPixelMapBuffer_ = reinterpret_cast(malloc(pixelMapBufferSize)); + if (localPixelMapBuffer_ == nullptr) { + HiLog::Error(LABEL, "[AllocateLocalPixelMapBuffer]allocate local pixelmap buffer memory error"); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#ifdef _WIN32 + memset(localPixelMapBuffer_, bgColor_, pixelMapBufferSize); +#else + if (memset_s(localPixelMapBuffer_, pixelMapBufferSize, bgColor_, pixelMapBufferSize) != EOK) { + HiLog::Error(LABEL, "[DisposeFirstPixelMap]memset local pixelmap buffer background failed"); + FreeLocalPixelMapBuffer(); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#endif + } + return SUCCESS; +} + +void GifDecoder::FreeLocalPixelMapBuffer() +{ + if (localPixelMapBuffer_ != nullptr) { + free(localPixelMapBuffer_); + localPixelMapBuffer_ = nullptr; + } +} + +uint32_t GifDecoder::PaddingBgColor(const SavedImage *savedImage) +{ + int32_t bgWidth = gifPtr_->SWidth; + int32_t bgHeight = gifPtr_->SHeight; + int32_t frameLeft = savedImage->ImageDesc.Left; + int32_t frameTop = savedImage->ImageDesc.Top; + int32_t frameWidth = savedImage->ImageDesc.Width; + int32_t frameHeight = savedImage->ImageDesc.Height; + if (frameLeft + frameWidth > bgWidth) { + frameWidth = bgWidth - frameLeft; + } + if (frameTop + frameHeight > bgHeight) { + frameHeight = bgHeight - frameTop; + } + if (frameWidth < 0 || frameHeight < 0) { + HiLog::Error(LABEL, "[PaddingBgColor]frameWidth || frameHeight is abnormal," + "bgWidth:%{public}d, bgHeight:%{public}d, " + "frameTop:%{public}d, frameLeft:%{public}d", + bgWidth, bgHeight, frameTop, frameLeft); + return ERR_IMAGE_DECODE_ABNORMAL; + } + uint32_t *dstPixelMapBuffer = localPixelMapBuffer_ + frameTop * bgWidth + frameLeft; + uint32_t lineBufferSize = frameWidth * sizeof(uint32_t); + for (int32_t row = 0; row < frameHeight; row++) { +#ifdef _WIN32 + memset(dstPixelMapBuffer, bgColor_, lineBufferSize); +#else + if (memset_s(dstPixelMapBuffer, lineBufferSize, bgColor_, lineBufferSize) != EOK) { + HiLog::Error(LABEL, "[PaddingBgColor]memset local pixelmap buffer failed"); + return ERR_IMAGE_MALLOC_ABNORMAL; + } +#endif + dstPixelMapBuffer += bgWidth; + } + return SUCCESS; +} + +uint32_t GifDecoder::PaddingData(const SavedImage *savedImage, int32_t transparentColor) +{ + const ColorMapObject *colorMap = gifPtr_->SColorMap; + if (savedImage->ImageDesc.ColorMap != nullptr) { + colorMap = savedImage->ImageDesc.ColorMap; // local color map + } + if (colorMap == nullptr) { + HiLog::Error(LABEL, "[PaddingData]color map is null"); + return ERR_IMAGE_DECODE_ABNORMAL; + } + int32_t colorCount = colorMap->ColorCount; + int32_t bitsPerPixel = colorMap->BitsPerPixel; + if ((bitsPerPixel < 0) || (colorCount != (1 << static_cast(bitsPerPixel)))) { + HiLog::Error(LABEL, "[PaddingData]colormap is invalid, bitsPerPixel: %{public}d, colorCount: %{public}d", + bitsPerPixel, colorCount); + return ERR_IMAGE_DECODE_ABNORMAL; + } + + int32_t bgWidth = gifPtr_->SWidth; + int32_t bgHeight = gifPtr_->SHeight; + int32_t frameLeft = savedImage->ImageDesc.Left; + int32_t frameTop = savedImage->ImageDesc.Top; + int32_t frameWidth = savedImage->ImageDesc.Width; + int32_t frameHeight = savedImage->ImageDesc.Height; + if (frameLeft + frameWidth > bgWidth) { + frameWidth = bgWidth - frameLeft; + } + if (frameTop + frameHeight > bgHeight) { + frameHeight = bgHeight - frameTop; + } + const GifByteType *srcFrame = savedImage->RasterBits; + uint32_t *dstPixelMapBuffer = localPixelMapBuffer_ + frameTop * bgWidth + frameLeft; + for (int32_t row = 0; row < frameHeight; row++) { + CopyLine(srcFrame, dstPixelMapBuffer, frameWidth, transparentColor, colorMap); + srcFrame += savedImage->ImageDesc.Width; + dstPixelMapBuffer += bgWidth; + } + return SUCCESS; +} + +void GifDecoder::CopyLine(const GifByteType *srcFrame, uint32_t *dstPixelMapBuffer, int32_t frameWidth, + int32_t transparentColor, const ColorMapObject *colorMap) +{ + for (int32_t col = 0; col < frameWidth; col++, srcFrame++, dstPixelMapBuffer++) { + if ((*srcFrame != transparentColor) && (*srcFrame < colorMap->ColorCount)) { + const GifColorType &colorType = colorMap->Colors[*srcFrame]; + *dstPixelMapBuffer = GetPixelColor(colorType.Red, colorType.Green, colorType.Blue, NO_TRANSPARENT); + } + } +} + +void GifDecoder::GetTransparentAndDisposal(uint32_t index, int32_t &transparentColor, int32_t &disposalMode) +{ + GraphicsControlBlock graphicsControlBlock = GetGraphicsControlBlock(index); + transparentColor = graphicsControlBlock.TransparentColor; + disposalMode = graphicsControlBlock.DisposalMode; +} + +GraphicsControlBlock GifDecoder::GetGraphicsControlBlock(uint32_t index) +{ + GraphicsControlBlock graphicsControlBlock = { DISPOSAL_UNSPECIFIED, false, 0, NO_TRANSPARENT_COLOR }; + DGifSavedExtensionToGCB(gifPtr_, index, &graphicsControlBlock); + return graphicsControlBlock; +} + +uint32_t GifDecoder::GetPixelColor(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha) +{ + return (red << RGBA_R_SHIFT) | (green << RGBA_G_SHIFT) | (blue << RGBA_B_SHIFT) | (alpha << RGBA_A_SHIFT); +} + +void GifDecoder::ParseBgColor() +{ + const int32_t bgColorIndex = gifPtr_->SBackGroundColor; + if (bgColorIndex < 0) { + HiLog::Warn(LABEL, "[ParseBgColor]bgColor index %{public}d is invalid, use default bgColor", bgColorIndex); + return; + } + const ColorMapObject *bgColorMap = gifPtr_->SColorMap; + if ((bgColorMap != nullptr) && (bgColorIndex < bgColorMap->ColorCount)) { + const GifColorType bgColorType = bgColorMap->Colors[bgColorIndex]; + bgColor_ = GetPixelColor(bgColorType.Red, bgColorType.Green, bgColorType.Blue, NO_TRANSPARENT); + } +} + +uint32_t GifDecoder::RedirectOutputBuffer(DecodeContext &context) +{ + if (localPixelMapBuffer_ == nullptr) { + HiLog::Error(LABEL, "[RedirectOutputBuffer]local pixelmap buffer is null, redirect failed"); + return ERR_IMAGE_DECODE_ABNORMAL; + } + int32_t bgWidth = gifPtr_->SWidth; + int32_t bgHeight = gifPtr_->SHeight; + uint64_t imageBufferSize = static_cast(bgWidth) * bgHeight * sizeof(uint32_t); + + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { + if (context.pixelsBuffer.buffer == nullptr) { +#if !defined(_WIN32) && !defined(_APPLE) + int fd = AshmemCreate("GIF RawData", imageBufferSize); + if (fd < 0) { + return ERR_SHAMEM_DATA_ABNORMAL; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + void* ptr = ::mmap(nullptr, imageBufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, imageBufferSize); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return ERR_SHAMEM_DATA_ABNORMAL; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = imageBufferSize; + context.pixelsBuffer.dataSize = imageBufferSize; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } + } else { + bool isPluginAllocateMemory = false; + if (context.pixelsBuffer.buffer == nullptr) { + // outer manage the buffer. + void *outputBuffer = malloc(imageBufferSize); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "[RedirectOutputBuffer]alloc output buffer size %{public}llu failed", + static_cast(imageBufferSize)); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = imageBufferSize; + isPluginAllocateMemory = true; + } + if (memcpy_s(context.pixelsBuffer.buffer, context.pixelsBuffer.bufferSize, + localPixelMapBuffer_, imageBufferSize) != 0) { + HiLog::Error(LABEL, "[RedirectOutputBuffer]memory copy size %{public}llu failed", + static_cast(imageBufferSize)); + if (isPluginAllocateMemory) { + context.pixelsBuffer.bufferSize = 0; + free(context.pixelsBuffer.buffer); + context.pixelsBuffer.buffer = nullptr; + } + return ERR_IMAGE_DECODE_ABNORMAL; + } + context.pixelsBuffer.dataSize = imageBufferSize; + context.allocatorType = AllocatorType::HEAP_ALLOC; + } + return SUCCESS; +} + +uint32_t GifDecoder::GetImageDelayTime(uint32_t index, int32_t &value) +{ + uint32_t errorCode = CheckIndex(index); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[GetImageDelayTime]index %{public}u is invalid", index); + return errorCode; + } + + GraphicsControlBlock graphicsControlBlock = GetGraphicsControlBlock(index); + // 0.01 sec in standard, update to ms + value = graphicsControlBlock.DelayTime * DELAY_TIME_TO_MS_RATIO; + return SUCCESS; +} + +uint32_t GifDecoder::GetImageLoopCount(uint32_t index, int32_t &value) +{ + for (int i = 0; i < gifPtr_->SavedImages[index].ExtensionBlockCount; i++) { + ExtensionBlock *ep = &gifPtr_->SavedImages[index].ExtensionBlocks[i]; + if (ep == nullptr) { + continue; + } + if ((ep->Function == APPLICATION_EXT_FUNC_CODE) && (ep->ByteCount >= NETSCAPE_EXTENSION_LENGTH) && + (memcmp(ep->Bytes, "NETSCAPE2.0", NETSCAPE_EXTENSION_LENGTH) == 0)) { + ep++; + if (ep->ByteCount >= DELAY_TIME_LENGTH) { + unsigned char *params = ep->Bytes; + value = params[DELAY_TIME_INDEX1] | (params[DELAY_TIME_INDEX2] << DELAY_TIME_SHIFT); + return SUCCESS; + } + } + } + return ERR_IMAGE_PROPERTY_NOT_EXIST; +} + +uint32_t GifDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) +{ + HiLog::Error(LABEL, "[GetImagePropertyInt] enter gif plugin, key:%{public}s", key.c_str()); + uint32_t errorCode = CheckIndex(0); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "[GetImagePropertyInt]index %{public}u is invalid", index); + return errorCode; + } + + if (key == GIF_IMAGE_DELAY_TIME) { + errorCode = GetImageDelayTime(index, value); + } else if (key == GIF_IMAGE_LOOP_COUNT) { + errorCode = GetImageLoopCount(0, value); + } else { + HiLog::Error(LABEL, "[GetImagePropertyInt]key(%{public}s) not supported", key.c_str()); + return ERR_IMAGE_INVALID_PARAMETER; + } + + return errorCode; +} + +uint32_t GifDecoder::ParseFrameDetail() +{ + if (DGifGetImageDesc(gifPtr_) == GIF_ERROR) { + HiLog::Error(LABEL, "[ParseFrameDetail]parse frame desc to gif pointer failed %{public}d", gifPtr_->Error); + return ERR_IMAGE_DECODE_ABNORMAL; + } + // DGifGetImageDesc use malloc or reallocarray allocate savedImages memory and increase imageCount. + // If error, we don't free the memory, next time decode will retry the allocated memory. + // The total memory free will be called DGifCloseFile. + int32_t frameIndex = gifPtr_->ImageCount - 1; + SavedImage *saveImagePtr = &gifPtr_->SavedImages[frameIndex]; + int32_t imageWidth = saveImagePtr->ImageDesc.Width; + int32_t imageHeight = saveImagePtr->ImageDesc.Height; + uint64_t imageSize = static_cast(imageWidth) * imageHeight; + if (imageWidth <= 0 || imageHeight <= 0 || imageSize > SIZE_MAX) { + HiLog::Error(LABEL, "[ParseFrameDetail]check frame size[%{public}d, %{public}d] failed", imageWidth, + imageHeight); + // if error, imageCount go back and next time DGifGetImageDesc will retry. + gifPtr_->ImageCount--; + return ERR_IMAGE_DECODE_ABNORMAL; + } + // set savedImage extension + if (gifPtr_->ExtensionBlocks != nullptr) { + saveImagePtr->ExtensionBlocks = gifPtr_->ExtensionBlocks; + saveImagePtr->ExtensionBlockCount = gifPtr_->ExtensionBlockCount; + gifPtr_->ExtensionBlocks = nullptr; + gifPtr_->ExtensionBlockCount = 0; + } + // set savedImage rasterBits + if (SetSavedImageRasterBits(saveImagePtr, frameIndex, imageSize, imageWidth, imageHeight) != SUCCESS) { + HiLog::Error(LABEL, "[ParseFrameDetail] set saved image data failed"); + GifFreeExtensions(&saveImagePtr->ExtensionBlockCount, &saveImagePtr->ExtensionBlocks); + return ERR_IMAGE_DECODE_ABNORMAL; + } + return SUCCESS; +} + +uint32_t GifDecoder::SetSavedImageRasterBits(SavedImage *saveImagePtr, int32_t frameIndex, uint64_t imageSize, + int32_t imageWidth, int32_t imageHeight) +{ + if (saveImagePtr->RasterBits == nullptr) { + saveImagePtr->RasterBits = static_cast(malloc(imageSize * sizeof(GifPixelType))); + if (saveImagePtr->RasterBits == nullptr) { + HiLog::Error(LABEL, "[SetSavedImageData]malloc frame %{public}d rasterBits failed", frameIndex); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + } + // if error next time will retry the rasterBits and the pointer free will be called DGifCloseFile. + if (saveImagePtr->ImageDesc.Interlace) { + for (int32_t i = 0; i < INTERLACED_PASSES; i++) { + for (int32_t j = INTERLACED_OFFSET[i]; j < imageHeight; j += INTERLACED_INTERVAL[i]) { + if (DGifGetLine(gifPtr_, saveImagePtr->RasterBits + j * imageWidth, imageWidth) == GIF_ERROR) { + HiLog::Error(LABEL, "[SetSavedImageData]interlace set frame %{public}d bits failed %{public}d", + frameIndex, gifPtr_->Error); + return ERR_IMAGE_DECODE_ABNORMAL; + } + } + } + } else { + if (DGifGetLine(gifPtr_, saveImagePtr->RasterBits, imageSize) == GIF_ERROR) { + HiLog::Error(LABEL, "[SetSavedImageData]normal set frame %{public}d bits failed %{public}d", frameIndex, + gifPtr_->Error); + return ERR_IMAGE_DECODE_ABNORMAL; + } + } + return SUCCESS; +} + +uint32_t GifDecoder::ParseFrameExtension() +{ + GifByteType *extData = nullptr; + int32_t extFunc = 0; + if (DGifGetExtension(gifPtr_, &extFunc, &extData) == GIF_ERROR) { + HiLog::Error(LABEL, "[ParseFrameExtension]get extension failed %{public}d", gifPtr_->Error); + return ERR_IMAGE_DECODE_ABNORMAL; + } + if (extData == nullptr) { + return SUCCESS; + } + + HiLog::Debug(LABEL, "[ParseFrameExtension] get extension:0x%{public}x", extFunc); + + if (GifAddExtensionBlock(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks, extFunc, + extData[EXTENSION_LEN_INDEX], &extData[EXTENSION_DATA_INDEX]) == GIF_ERROR) { + HiLog::Error(LABEL, "[ParseFrameExtension]set extension to gif pointer failed"); + // GifAddExtensionBlock will allocate memory, if error, free extension ready to retry + GifFreeExtensions(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks); + return ERR_IMAGE_DECODE_ABNORMAL; + } + while (true) { + if (DGifGetExtensionNext(gifPtr_, &extData) == GIF_ERROR) { + HiLog::Error(LABEL, "[ParseFrameExtension]get next extension failed %{public}d", gifPtr_->Error); + return ERR_IMAGE_DECODE_ABNORMAL; + } + if (extData == nullptr) { + return SUCCESS; + } + + if (GifAddExtensionBlock(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks, CONTINUE_EXT_FUNC_CODE, + extData[EXTENSION_LEN_INDEX], &extData[EXTENSION_DATA_INDEX]) == GIF_ERROR) { + HiLog::Error(LABEL, "[ParseFrameExtension]set next extension to gif pointer failed"); + GifFreeExtensions(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks); + return ERR_IMAGE_DECODE_ABNORMAL; + } + } + return SUCCESS; +} + +uint32_t GifDecoder::UpdateGifFileType(int32_t updateFrameIndex) +{ + HiLog::Debug(LABEL, "[UpdateGifFileType]update %{public}d to %{public}d", savedFrameIndex_, updateFrameIndex); + uint32_t startPosition = inputStreamPtr_->Tell(); + GifRecordType recordType; + gifPtr_->ExtensionBlocks = nullptr; + gifPtr_->ExtensionBlockCount = 0; + do { + if (DGifGetRecordType(gifPtr_, &recordType) == GIF_ERROR) { + HiLog::Error(LABEL, "[UpdateGifFileType]parse file record type failed %{public}d", gifPtr_->Error); + inputStreamPtr_->Seek(startPosition); + return ERR_IMAGE_DECODE_ABNORMAL; + } + + switch (recordType) { + case EXTENSION_RECORD_TYPE: + if (ParseFrameExtension() != SUCCESS) { + HiLog::Error(LABEL, "[UpdateGifFileType]parse frame extension failed"); + inputStreamPtr_->Seek(startPosition); + return ERR_IMAGE_DECODE_ABNORMAL; + } + break; + case IMAGE_DESC_RECORD_TYPE: + if (ParseFrameDetail() != SUCCESS) { + HiLog::Error(LABEL, "[UpdateGifFileType]parse frame detail failed"); + inputStreamPtr_->Seek(startPosition); + return ERR_IMAGE_DECODE_ABNORMAL; + } + savedFrameIndex_ = gifPtr_->ImageCount - 1; + startPosition = inputStreamPtr_->Tell(); + break; + case TERMINATE_RECORD_TYPE: + HiLog::Debug(LABEL, "[UpdateGifFileType]parse gif completed"); + isLoadAllFrame_ = true; + break; + default: + break; + } + + if (isLoadAllFrame_ || savedFrameIndex_ == updateFrameIndex) { + break; + } + } while (recordType != TERMINATE_RECORD_TYPE); + + if (gifPtr_->ImageCount <= 0) { + gifPtr_->Error = D_GIF_ERR_NO_IMAG_DSCR; + HiLog::Error(LABEL, "[UpdateGifFileType]has no frame in gif block"); + return ERR_IMAGE_DECODE_ABNORMAL; + } + return SUCCESS; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libgifplugin/src/plugin_export.cpp b/plugins/common/libs/image/libgifplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a34d5407c17b37ca08b183f40b070dfc691ccc44 --- /dev/null +++ b/plugins/common/libs/image/libgifplugin/src/plugin_export.cpp @@ -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. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "plugin_utils.h" +#include "log_tags.h" +#include "gif_decoder.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibGifPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::GifDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibGifPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/plugins/common/libs/image/libheifplugin/BUILD.gn_old b/plugins/common/libs/image/libheifplugin/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..8c720e7de674301ff6e1e6a6800565eb38005ce0 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/BUILD.gn_old @@ -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("//build/ohos.gni") + +ohos_shared_library("heifplugin") { + defines = [ "DUAL_ADAPTER" ] + DUAL_ADAPTER = true + + sources = [ +# "//foundation/multimedia/image_standard/plugins/common/libs/image/libheifplugin/src/heif_decoder.cpp", +# "//foundation/multimedia/image_standard/plugins/common/libs/image/libheifplugin/src/heif_decoder_wrapper.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libheifplugin/src/plugin_export.cpp", + ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libheifplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/adapter/frameworks/heifcodec/include", + "//third_party/flutter/skia/third_party/libjpeg-turbo", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { + deps += [ +# "//foundation/multimedia/image_standard/adapter/frameworks/heifcodec:heifadapter", + ] +# aosp_deps = [ "shared_library:libheif" ] + } + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + part_name = "multimedia_image" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("heifpluginmetadata") { + source = "heifplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/common/libs/image/libheifplugin/heifplugin.pluginmeta b/plugins/common/libs/image/libheifplugin/heifplugin.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..e5de15930693f2970bc2ead7131da9f65eb316f9 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/heifplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibHeifPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libheifplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::HeifDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/heif" + } + ] + } + ] +} diff --git a/plugins/common/libs/image/libheifplugin/include/heif_decoder.h b/plugins/common/libs/image/libheifplugin/include/heif_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..1530b035088def748a1ceea595489b8757c539a1 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/include/heif_decoder.h @@ -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. + */ + +#ifndef HEIF_DECODER_H +#define HEIF_DECODER_H + +#include +#include "abs_image_decoder.h" +#include "heif_decoder_wrapper.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "nocopyable.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class HeifDecoder : public AbsImageDecoder, public MultimediaPlugin::PluginClassBase { +public: + HeifDecoder() = default; + virtual ~HeifDecoder() override{}; + virtual void SetSource(InputDataStream &sourceStream) override; + virtual void Reset() override; + virtual uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + virtual uint32_t Decode(uint32_t index, DecodeContext &context) override; + virtual uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + virtual uint32_t GetTopLevelImageNum(uint32_t &num) override; + virtual uint32_t GetImageSize(uint32_t index, PlSize &size) override; + +private: + DISALLOW_COPY_AND_MOVE(HeifDecoder); + bool AllocHeapBuffer(DecodeContext &context); + bool IsHeifImageParaValid(PlSize heifSize, uint32_t bytesPerPixel); + std::unique_ptr heifDecoderInterface_ = nullptr; + PlSize heifSize_; + int32_t bytesPerPixel_ = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HEIF_DECODER_H diff --git a/plugins/common/libs/image/libheifplugin/include/heif_decoder_interface.h b/plugins/common/libs/image/libheifplugin/include/heif_decoder_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..659f3abf43dfc75c8e42a99a52149404700af982 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/include/heif_decoder_interface.h @@ -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. + */ + +#ifndef HEIF_DECODER_INTERFACE_H +#define HEIF_DECODER_INTERFACE_H + +#include "abs_image_decoder.h" +#include "image_plugin_type.h" +#include "input_data_stream.h" + +namespace OHOS { +namespace ImagePlugin { +class HeifDecoderInterface { +public: + HeifDecoderInterface() = default; + virtual ~HeifDecoderInterface() = default; + virtual void GetHeifSize(PlSize &size) = 0; + virtual void SetAllowPartial(const bool isAllowPartialImage) = 0; + virtual bool ConversionSupported(const PlPixelFormat &plPixelFormat, int32_t &bytesPerPixel) = 0; + virtual uint32_t OnGetPixels(const PlSize &dstSize, const uint32_t dstRowBytes, DecodeContext &context) = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HEIF_DECODER_INTERFACE_H \ No newline at end of file diff --git a/plugins/common/libs/image/libheifplugin/include/heif_decoder_wrapper.h b/plugins/common/libs/image/libheifplugin/include/heif_decoder_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..13d61dd3c53885896909e935c2dc6f047b01dbb0 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/include/heif_decoder_wrapper.h @@ -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. + */ + +#ifndef HEIF_DECODER_WRAPPER_H +#define HEIF_DECODER_WRAPPER_H + +#include +#include "heif_decoder_interface.h" +#include "input_data_stream.h" + +namespace OHOS { +namespace ImagePlugin { +class HeifDecoderWrapper { +public: + static std::unique_ptr CreateHeifDecoderInterface(InputDataStream &stream); +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // HEIF_DECODER_WRAPPER_H \ No newline at end of file diff --git a/plugins/common/libs/image/libheifplugin/src/heif_decoder.cpp b/plugins/common/libs/image/libheifplugin/src/heif_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e218476d313ef2e470e4621611e563c68ae9b521 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/src/heif_decoder.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "heif_decoder.h" +#include "media_errors.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; + +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "HeifDecoder" }; +constexpr uint32_t HEIF_IMAGE_NUM = 1; + +void HeifDecoder::SetSource(InputDataStream &sourceStream) +{ + heifDecoderInterface_ = HeifDecoderWrapper::CreateHeifDecoderInterface(sourceStream); +} + +void HeifDecoder::Reset() +{ + heifDecoderInterface_ = nullptr; + heifSize_.width = 0; + heifSize_.height = 0; + bytesPerPixel_ = 0; +} + +uint32_t HeifDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + uint32_t ret = GetImageSize(index, info.size); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "get image size failed, ret=%{public}u", ret); + return ret; + } + heifSize_ = info.size; + + if (heifDecoderInterface_->ConversionSupported(opts.desiredPixelFormat, bytesPerPixel_)) { + info.pixelFormat = opts.desiredPixelFormat; + if (info.pixelFormat == PlPixelFormat::UNKNOWN) { + info.pixelFormat = PlPixelFormat::BGRA_8888; + } + } else { + return ERR_IMAGE_COLOR_CONVERT; + } + heifDecoderInterface_->SetAllowPartial(opts.allowPartialImage); + bool hasAlpha = (info.pixelFormat == PlPixelFormat::RGB_565 || info.pixelFormat == PlPixelFormat::RGB_888 || + info.pixelFormat == PlPixelFormat::ALPHA_8); + if (hasAlpha) { + info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + } else { + info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + } + return SUCCESS; +} +uint32_t HeifDecoder::Decode(uint32_t index, DecodeContext &context) +{ + if (heifDecoderInterface_ == nullptr) { + HiLog::Error(LABEL, "create heif interface object failed!"); + return ERR_IMAGE_INIT_ABNORMAL; + } + + if (index >= HEIF_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}d.", index, HEIF_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + + if (!AllocHeapBuffer(context)) { + HiLog::Error(LABEL, "get pixels memory fail."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + return heifDecoderInterface_->OnGetPixels(heifSize_, heifSize_.width * bytesPerPixel_, context); +} + +uint32_t HeifDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= HEIF_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}d.", index, HEIF_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + + if (heifDecoderInterface_ == nullptr) { + HiLog::Error(LABEL, "create heif interface object failed!"); + return ERR_IMAGE_INIT_ABNORMAL; + } + + heifDecoderInterface_->GetHeifSize(size); + if (size.width == 0 || size.height == 0) { + HiLog::Error(LABEL, "get width and height fail, height:%{public}u, width:%{public}u.", size.height, + size.height); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + return SUCCESS; +} + +uint32_t HeifDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + // currently not support increment decode + return ERR_IMAGE_DATA_UNSUPPORT; +} +uint32_t HeifDecoder::GetTopLevelImageNum(uint32_t &num) +{ + // currently only supports single frame + num = HEIF_IMAGE_NUM; + return SUCCESS; +} + +bool HeifDecoder::AllocHeapBuffer(DecodeContext &context) +{ + if (context.pixelsBuffer.buffer == nullptr) { + if (!IsHeifImageParaValid(heifSize_, bytesPerPixel_)) { + HiLog::Error(LABEL, "check heif image para fail"); + return false; + } + uint64_t byteCount = static_cast(heifSize_.width) * heifSize_.height * bytesPerPixel_; + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { + int fd = AshmemCreate("HEIF RawData", byteCount); + if (fd < 0) { + return false; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return false; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return false; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return false; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.", + static_cast(byteCount)); + return false; + } + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + HiLog::Error(LABEL, "memset buffer failed."); + free(outputBuffer); + outputBuffer = nullptr; + return false; + } + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + } + return true; +} + +bool HeifDecoder::IsHeifImageParaValid(PlSize heifSize, uint32_t bytesPerPixel) +{ + if (heifSize.width == 0 || heifSize.height == 0 || bytesPerPixel == 0) { + HiLog::Error(LABEL, "heif image para is 0"); + return false; + } + uint64_t area = static_cast(heifSize.width) * heifSize.height; + if ((area / heifSize.width) != heifSize.height) { + HiLog::Error(LABEL, "compute width*height overflow!"); + return false; + } + uint64_t size = area * bytesPerPixel; + if ((size / bytesPerPixel) != area) { + HiLog::Error(LABEL, "compute area*bytesPerPixel overflow!"); + return false; + } + if (size > UINT32_MAX) { + HiLog::Error(LABEL, "size is too large!"); + return false; + } + return true; +} +} // namespace ImagePlugin +} // namespace OHOS \ No newline at end of file diff --git a/plugins/common/libs/image/libheifplugin/src/heif_decoder_wrapper.cpp b/plugins/common/libs/image/libheifplugin/src/heif_decoder_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fec244996286ffa30c66cc045465821315771be0 --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/src/heif_decoder_wrapper.cpp @@ -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. + */ + +#include "heif_decoder_wrapper.h" +#ifdef DUAL_ADAPTER +#include "heif_decoder_adapter.h" +#endif + +namespace OHOS { +namespace ImagePlugin { +std::unique_ptr HeifDecoderWrapper::CreateHeifDecoderInterface(InputDataStream &stream) +{ +#ifdef DUAL_ADAPTER + return Media::HeifDecoderAdapter::MakeFromStream(stream); +#else + return nullptr; +#endif +} +} // namespace ImagePlugin +}; // namespace OHOS \ No newline at end of file diff --git a/plugins/common/libs/image/libheifplugin/src/plugin_export.cpp b/plugins/common/libs/image/libheifplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7173d27abd60a27f42555a67b89ce86dad42f01d --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/src/plugin_export.cpp @@ -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. + */ + +#include "plugin_export.h" +#include "heif_decoder.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibHeifPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::HeifDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibHeifPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/plugins/common/libs/image/libjpegplugin/BUILD.gn_old b/plugins/common/libs/image/libjpegplugin/BUILD.gn_old new file mode 100644 index 0000000000000000000000000000000000000000..000d1bf1c434830f32fe9f74d66d139a40017f40 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/BUILD.gn_old @@ -0,0 +1,96 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("jpegplugin") { + sources = [ + "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/jpeg_utils.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/plugin_export.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//third_party/flutter/skia/third_party/externals/libjpeg-turbo", + "//third_party/flutter/skia/include/codec", + "//third_party/flutter/skia", + "//third_party/flutter/skia/include/core", + "//third_party/flutter/skia/third_party/libjpeg-turbo", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + + "//third_party/libjpeg-turbo", + ] + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/libjpeg-turbo:libjpeg_turbo_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//third_party/libjpeg-turbo", + ] + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/libjpeg-turbo:libjpeg_turbo_static", + ] + } else { + defines = [ "DUAL_ADAPTER" ] + DUAL_ADAPTER = true + include_dirs += [ "//utils/native/base/include" ] + sources += [ "//foundation/multimedia/image_standard/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp" ] + deps = [ + "//foundation/multimedia/image_standard/interfaces/innerkits:image", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { +# aosp_deps = [ "shared_library:libjpeg" ] + } else { + deps += [ "//third_party/libjpeg-turbo:libjpeg-turbo" ] + include_dirs += [ "//third_party/libjpeg-turbo" ] + } + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("jpegpluginmetadata") { + source = "jpegplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h b/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..9e5c2dc3ccbb8bff234154b62508a6327d643a6f --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/include/jpeg_decoder.h @@ -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. + */ + +#ifndef JPEG_DECODER_H +#define JPEG_DECODER_H + +#include +#include +#include "abs_image_decoder.h" +#include "abs_image_decompress_component.h" +#include "hilog/log.h" +#include "jpeg_utils.h" +#include "jpeglib.h" +#include "log_tags.h" +#include "plugin_class_base.h" +#include "plugin_server.h" + +namespace OHOS { +namespace ImagePlugin { +enum class JpegDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSING = 2, + BASE_INFO_PARSED = 3, + IMAGE_DECODING = 4, + IMAGE_ERROR = 5, + IMAGE_PARTIAL = 6, + IMAGE_DECODED = 7 +}; + +class JpegDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + JpegDecoder(); + ~JpegDecoder() override; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + +private: + DISALLOW_COPY_AND_MOVE(JpegDecoder); + J_COLOR_SPACE GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat); + void CreateHwDecompressor(); + uint32_t DoSwDecode(DecodeContext &context); + void FinishOldDecompress(); + uint32_t DecodeHeader(); + uint32_t StartDecompress(const PixelDecodeOptions &opts); + uint32_t GetRowBytes(); + void CreateDecoder(); + bool IsMarker(uint8_t rawPrefix, uint8_t rawMarkderCode, uint8_t markerCode); + bool FindMarker(InputDataStream &stream, uint8_t marker); + + static MultimediaPlugin::PluginServer &pluginServer_; + jpeg_decompress_struct decodeInfo_; + JpegSrcMgr srcMgr_; + ErrorMgr jerr_; + AbsImageDecompressComponent *hwJpegDecompress_ = nullptr; + JpegDecodingState state_ = JpegDecodingState::UNDECIDED; + uint32_t streamPosition_ = 0; // may be changed by other decoders, record it and restore if needed. + PlPixelFormat outputFormat_ = PlPixelFormat::UNKNOWN; + PixelDecodeOptions opts_; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // JPEG_DECODER_H diff --git a/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h b/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..63d1da005663f227a0fcde50e70edc417e8d01da --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/include/jpeg_encoder.h @@ -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. + */ + +#ifndef JPEG_ENCODER_H +#define JPEG_ENCODER_H + +#include +#include "abs_image_encoder.h" +#include "hilog/log.h" +#include "jpeg_utils.h" +#include "jpeglib.h" +#include "log_tags.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace ImagePlugin { +class JpegEncoder : public AbsImageEncoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + JpegEncoder(); + ~JpegEncoder() override; + uint32_t StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option) override; + uint32_t AddImage(Media::PixelMap &pixelMap) override; + uint32_t FinalizeEncode() override; + +private: + DISALLOW_COPY_AND_MOVE(JpegEncoder); + J_COLOR_SPACE GetEncodeFormat(Media::PixelFormat format, int32_t &componentsNum); + void Deinterweave(uint8_t *uvPlane, uint8_t *uPlane, uint8_t *vPlane, uint32_t curRow, uint32_t width, + uint32_t height); + uint32_t SetCommonConfig(); + void SetYuv420spExtraConfig(); + uint32_t SequenceEncoder(const uint8_t *data); + uint32_t Yuv420spEncoder(const uint8_t *data); + static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegEncoder" }; + jpeg_compress_struct encodeInfo_; + JpegDstMgr dstMgr_; + ErrorMgr jerr_; + std::vector pixelMaps_; + PlEncodeOptions encodeOpts_; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // JPEG_ENCODER_H \ No newline at end of file diff --git a/plugins/common/libs/image/libjpegplugin/include/jpeg_utils.h b/plugins/common/libs/image/libjpegplugin/include/jpeg_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..51ac52fe0aabb7ae3eef959e434b9e4f520f33aa --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/include/jpeg_utils.h @@ -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. + */ + +#ifndef JPEG_UTILS_H +#define JPEG_UTILS_H + +#include +#include +#include +#include "hilog/log.h" +#include "input_data_stream.h" +#include "jerror.h" +#include "jpeglib.h" +#include "log_tags.h" +#include "output_data_stream.h" + +namespace OHOS { +namespace ImagePlugin { +static constexpr uint8_t SET_JUMP_VALUE = 1; +static constexpr uint8_t RW_LINE_NUM = 1; +static constexpr uint16_t JPEG_BUFFER_SIZE = 1024; +static constexpr uint32_t JPEG_IMAGE_NUM = 1; + +// redefine jpeg error manager struct. +struct ErrorMgr : jpeg_error_mgr { + struct jpeg_error_mgr pub; // public fields + +#ifdef _WIN32 + jmp_buf setjmp_buffer = {{0}}; // for return to caller +#else + jmp_buf setjmp_buffer; // for return to caller +#endif +}; + +// redefine jpeg source manager struct. +struct JpegSrcMgr : jpeg_source_mgr { + explicit JpegSrcMgr(InputDataStream *stream); + + InputDataStream *inputStream = nullptr; + uint16_t bufferSize = JPEG_BUFFER_SIZE; + ImagePlugin::DataStreamBuffer streamData; +}; + +// redefine jpeg destination manager struct. +struct JpegDstMgr : jpeg_destination_mgr { + explicit JpegDstMgr(OutputDataStream *stream); + + OutputDataStream *outputStream = nullptr; + uint16_t bufferSize = JPEG_BUFFER_SIZE; + uint8_t buffer[JPEG_BUFFER_SIZE] = { 0 }; +}; + +// for jpeg error manager +void ErrorExit(j_common_ptr cinfo); +void OutputErrorMessage(j_common_ptr cinfo); +// for jpeg source manager +void InitSrcStream(j_decompress_ptr dinfo); +boolean FillInputBuffer(j_decompress_ptr dinfo); +void SkipInputData(j_decompress_ptr dinfo, long numBytes); +void TermSrcStream(j_decompress_ptr dinfo); +// for jpeg destination manager +void InitDstStream(j_compress_ptr cinfo); +boolean EmptyOutputBuffer(j_compress_ptr cinfo); +void TermDstStream(j_compress_ptr cinfo); +} // namespace ImagePlugin +} // namespace OHOS + +#endif // JPEG_UTILS_H diff --git a/plugins/common/libs/image/libjpegplugin/jpegplugin.pluginmeta b/plugins/common/libs/image/libjpegplugin/jpegplugin.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..991535c23f7c61dff761ddf7874da1ac32a98b97 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/jpegplugin.pluginmeta @@ -0,0 +1,42 @@ +{ + "packageName":"LibJpegPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libjpegplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::JpegDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/jpeg" + } + ] + }, + { + "className":"OHOS::ImagePlugin::JpegEncoder", + "services": [ + { + "interfaceID":3, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/jpeg" + } + ] + } + ] +} diff --git a/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp b/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2989f29a1ed1e3e5723964a109b87cac6ba11422 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/src/jpeg_decoder.cpp @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "jpeg_decoder.h" + +#include "jerror.h" +#include "media_errors.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegDecoder" }; +namespace { +constexpr uint32_t PIXEL_BYTES_RGB_565 = 2; +constexpr uint32_t MARKER_SIZE = 2; +constexpr uint32_t MARKER_LENGTH = 2; +constexpr uint8_t MARKER_LENGTH_0_OFFSET = 0; +constexpr uint8_t MARKER_LENGTH_1_OFFSET = 1; +constexpr uint32_t MARKER_LENGTH_SHIFT = 8; +constexpr uint8_t JPG_MARKER_PREFIX_OFFSET = 0; +constexpr uint8_t JPG_MARKER_CODE_OFFSET = 1; +constexpr uint8_t JPG_MARKER_PREFIX = 0XFF; +constexpr uint8_t JPG_MARKER_SOI = 0XD8; +constexpr uint8_t JPG_MARKER_SOS = 0XDA; +constexpr uint8_t JPG_MARKER_RST = 0XD0; +constexpr uint8_t JPG_MARKER_RST0 = 0XD0; +constexpr uint8_t JPG_MARKER_RSTN = 0XD7; +constexpr uint8_t JPG_MARKER_APP = 0XE0; +constexpr uint8_t JPG_MARKER_APP0 = 0XE0; +constexpr uint8_t JPG_MARKER_APPN = 0XEF; +} // namespace + +PluginServer &JpegDecoder::pluginServer_ = DelayedRefSingleton::GetInstance(); + +JpegSrcMgr::JpegSrcMgr(InputDataStream *stream) : inputStream(stream) +{ + init_source = InitSrcStream; + fill_input_buffer = FillInputBuffer; + skip_input_data = SkipInputData; + resync_to_restart = jpeg_resync_to_restart; + term_source = TermSrcStream; +} + +JpegDecoder::JpegDecoder() : srcMgr_(nullptr) +{ + CreateDecoder(); +#if !defined(_WIN32) && !defined(_APPLE) + CreateHwDecompressor(); +#endif +} + +void JpegDecoder::CreateDecoder() +{ + // create decompress struct + jpeg_create_decompress(&decodeInfo_); + + // set error output + decodeInfo_.err = jpeg_std_error(&jerr_); + jerr_.error_exit = ErrorExit; + if (decodeInfo_.err == nullptr) { + HiLog::Error(LABEL, "create jpeg decoder failed."); + return; + } + decodeInfo_.err->output_message = &OutputErrorMessage; +} + +JpegDecoder::~JpegDecoder() +{ + jpeg_destroy_decompress(&decodeInfo_); + if (hwJpegDecompress_ != nullptr) { + delete hwJpegDecompress_; + hwJpegDecompress_ = nullptr; + } +} + +void JpegDecoder::SetSource(InputDataStream &sourceStream) +{ + srcMgr_.inputStream = &sourceStream; + state_ = JpegDecodingState::SOURCE_INITED; +} + +uint32_t JpegDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= JPEG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < JpegDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= JpegDecodingState::BASE_INFO_PARSED) { + size.width = decodeInfo_.image_width; + size.height = decodeInfo_.image_height; + return Media::SUCCESS; + } + // only state JpegDecodingState::SOURCE_INITED and JpegDecodingState::BASE_INFO_PARSING can go here. + uint32_t ret = DecodeHeader(); + if (ret != Media::SUCCESS) { + HiLog::Error(LABEL, "decode header error on get image size, ret:%{public}u.", ret); + state_ = JpegDecodingState::BASE_INFO_PARSING; + return ret; + } + size.width = decodeInfo_.image_width; + size.height = decodeInfo_.image_height; + state_ = JpegDecodingState::BASE_INFO_PARSED; + return Media::SUCCESS; +} + +J_COLOR_SPACE JpegDecoder::GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat) +{ + outputFormat = format; + J_COLOR_SPACE colorSpace = JCS_UNKNOWN; + switch (format) { + case PlPixelFormat::UNKNOWN: + case PlPixelFormat::RGBA_8888: { + colorSpace = JCS_EXT_RGBA; + outputFormat = PlPixelFormat::RGBA_8888; + break; + } + case PlPixelFormat::BGRA_8888: { + colorSpace = JCS_EXT_BGRA; + outputFormat = PlPixelFormat::BGRA_8888; + break; + } + case PlPixelFormat::ARGB_8888: { + colorSpace = JCS_EXT_ARGB; + break; + } + case PlPixelFormat::ALPHA_8: { + colorSpace = JCS_GRAYSCALE; + break; + } + case PlPixelFormat::RGB_565: { + colorSpace = JCS_RGB565; + break; + } + case PlPixelFormat::RGB_888: { + colorSpace = JCS_RGB; + break; + } + default: { + colorSpace = JCS_EXT_RGBA; + outputFormat = PlPixelFormat::RGBA_8888; + break; + } + } + return colorSpace; +} + +uint32_t JpegDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + if (index >= JPEG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < JpegDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "set decode options failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= JpegDecodingState::IMAGE_DECODING) { + FinishOldDecompress(); + state_ = JpegDecodingState::SOURCE_INITED; + } + if (state_ < JpegDecodingState::BASE_INFO_PARSED) { + uint32_t ret = DecodeHeader(); + if (ret != Media::SUCCESS) { + state_ = JpegDecodingState::BASE_INFO_PARSING; + HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret); + return ret; + } + state_ = JpegDecodingState::BASE_INFO_PARSED; + } + // only state JpegDecodingState::BASE_INFO_PARSED can go here. + uint32_t ret = StartDecompress(opts); + if (ret != Media::SUCCESS) { + HiLog::Error(LABEL, "start decompress failed on set decode options:%{public}u.", ret); + return ret; + } + info.pixelFormat = outputFormat_; + info.size.width = decodeInfo_.output_width; + info.size.height = decodeInfo_.output_height; + info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + opts_ = opts; + state_ = JpegDecodingState::IMAGE_DECODING; + return Media::SUCCESS; +} + +uint32_t JpegDecoder::GetRowBytes() +{ + uint32_t pixelBytes = + (decodeInfo_.out_color_space == JCS_RGB565) ? PIXEL_BYTES_RGB_565 : decodeInfo_.out_color_components; + return decodeInfo_.output_width * pixelBytes; +} + +uint32_t JpegDecoder::DoSwDecode(DecodeContext &context) +{ + if (setjmp(jerr_.setjmp_buffer)) { + HiLog::Error(LABEL, "decode image failed."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + uint32_t rowStride = GetRowBytes(); + if (context.pixelsBuffer.buffer == nullptr) { + uint64_t byteCount = static_cast(rowStride) * decodeInfo_.output_height; + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int fd = AshmemCreate("JPEG RawData", byteCount); + if (fd < 0) { + return ERR_SHAMEM_DATA_ABNORMAL; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return ERR_SHAMEM_DATA_ABNORMAL; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return ERR_SHAMEM_DATA_ABNORMAL; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.", + static_cast(byteCount)); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.context = nullptr; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + } + uint8_t *base = static_cast(context.pixelsBuffer.buffer); + if (base == nullptr) { + HiLog::Error(LABEL, "decode image buffer is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + srcMgr_.inputStream->Seek(streamPosition_); + uint8_t *buffer = nullptr; + while (decodeInfo_.output_scanline < decodeInfo_.output_height) { + buffer = base + rowStride * decodeInfo_.output_scanline; + uint32_t readLineNum = jpeg_read_scanlines(&decodeInfo_, &buffer, RW_LINE_NUM); + if (readLineNum < RW_LINE_NUM) { + streamPosition_ = srcMgr_.inputStream->Tell(); + HiLog::Error(LABEL, "read line fail, read num:%{public}u, total read num:%{public}u.", readLineNum, + decodeInfo_.output_scanline); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + } + streamPosition_ = srcMgr_.inputStream->Tell(); + return Media::SUCCESS; +} + +uint32_t JpegDecoder::Decode(uint32_t index, DecodeContext &context) +{ + if (index >= JPEG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < JpegDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "decode failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ > JpegDecodingState::IMAGE_DECODING) { + FinishOldDecompress(); + state_ = JpegDecodingState::SOURCE_INITED; + uint32_t ret = DecodeHeader(); + if (ret != Media::SUCCESS) { + state_ = JpegDecodingState::BASE_INFO_PARSING; + HiLog::Error(LABEL, "decode header error on decode:%{public}u.", ret); + return ret; + } + state_ = JpegDecodingState::BASE_INFO_PARSED; + ret = StartDecompress(opts_); + if (ret != Media::SUCCESS) { + HiLog::Error(LABEL, "start decompress failed on decode:%{public}u.", ret); + return ret; + } + state_ = JpegDecodingState::IMAGE_DECODING; + } + // only state JpegDecodingState::IMAGE_DECODING can go here. + if (hwJpegDecompress_ != nullptr) { + srcMgr_.inputStream->Seek(streamPosition_); + uint32_t ret = hwJpegDecompress_->Decompress(&decodeInfo_, srcMgr_.inputStream, context); + if (ret == Media::SUCCESS) { + state_ = JpegDecodingState::IMAGE_DECODED; + HiLog::Debug(LABEL, "jpeg hardware decode success."); + return ret; + } + } + uint32_t ret = DoSwDecode(context); + if (ret == Media::SUCCESS) { + state_ = JpegDecodingState::IMAGE_DECODED; + HiLog::Debug(LABEL, "jpeg software decode success."); + return Media::SUCCESS; + } + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && opts_.allowPartialImage) { + state_ = JpegDecodingState::IMAGE_PARTIAL; + context.ifPartialOutput = true; + return Media::SUCCESS; + } + state_ = JpegDecodingState::IMAGE_ERROR; + return ret; +} + +void JpegDecoder::Reset() +{ + srcMgr_.inputStream = nullptr; +} + +uint32_t JpegDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &progContext) +{ + progContext.totalProcessProgress = 0; + if (index >= JPEG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ != JpegDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + + uint32_t ret = DoSwDecode(progContext.decodeContext); + if (ret == Media::SUCCESS) { + state_ = JpegDecodingState::IMAGE_DECODED; + } + // get promote decode progress, in percentage: 0~100. + progContext.totalProcessProgress = + decodeInfo_.output_height == 0 ? 0 : decodeInfo_.output_scanline * 100 / decodeInfo_.output_height; + HiLog::Debug(LABEL, "incremental decode progress %{public}u.", progContext.totalProcessProgress); + return ret; +} + +void JpegDecoder::CreateHwDecompressor() +{ + std::map capabilities; + const std::string format = "image/jpeg"; + capabilities.insert(std::map::value_type("encodeFormat", AttrData(format))); + hwJpegDecompress_ = pluginServer_.CreateObject( + AbsImageDecompressComponent::SERVICE_DEFAULT, capabilities); + if (hwJpegDecompress_ == nullptr) { + HiLog::Error(LABEL, "get hardware jpeg decompress component failed."); + return; + } +} + +void JpegDecoder::FinishOldDecompress() +{ + if (state_ < JpegDecodingState::IMAGE_DECODING) { + return; + } + jpeg_destroy_decompress(&decodeInfo_); + CreateDecoder(); +} + +bool JpegDecoder::IsMarker(uint8_t rawMarkerPrefix, uint8_t rawMarkderCode, uint8_t markerCode) +{ + if (rawMarkerPrefix != JPG_MARKER_PREFIX) { + return false; + } + + // RSTn, n from 0 to 7 + if (rawMarkderCode >= JPG_MARKER_RST0 && rawMarkderCode <= JPG_MARKER_RSTN && markerCode == JPG_MARKER_RST) { + return true; + } + + // APPn, n from 0 to 15 + if (rawMarkderCode >= JPG_MARKER_APP0 && rawMarkderCode <= JPG_MARKER_APPN && markerCode == JPG_MARKER_APP) { + return true; + } + + if (rawMarkderCode == markerCode) { + return true; + } + return false; +} + +bool JpegDecoder::FindMarker(InputDataStream &stream, uint8_t marker) +{ + uint8_t buffer[MARKER_SIZE] = { 0 }; + uint32_t readSize = 0; + stream.Seek(0); + while (true) { + uint32_t cur = stream.Tell(); + if (!stream.Seek(cur + MARKER_SIZE)) { + return false; + } + stream.Seek(cur); + + // read marker code + stream.Read(MARKER_SIZE, buffer, sizeof(buffer), readSize); + if (readSize != MARKER_SIZE) { + return false; + } + + uint8_t markerPrefix = buffer[JPG_MARKER_PREFIX_OFFSET]; + uint8_t markerCode = buffer[JPG_MARKER_CODE_OFFSET]; + if (IsMarker(markerPrefix, markerCode, JPG_MARKER_SOS)) { + return true; + } + + if (IsMarker(markerPrefix, markerCode, JPG_MARKER_SOI) || IsMarker(markerPrefix, markerCode, JPG_MARKER_RST)) { + continue; + } + + cur = stream.Tell(); + if (!stream.Seek(cur + MARKER_LENGTH)) { + return false; + } + stream.Seek(cur); + // read marker length + stream.Read(MARKER_LENGTH, buffer, sizeof(buffer), readSize); + if (readSize != MARKER_LENGTH) { + return false; + } + // skip data, length = sizeof(length) + sizeof(data) + uint32_t length = (buffer[MARKER_LENGTH_0_OFFSET] << MARKER_LENGTH_SHIFT) + buffer[MARKER_LENGTH_1_OFFSET]; + if (!stream.Seek(cur + length)) { + return false; + } + } +} + +uint32_t JpegDecoder::DecodeHeader() +{ + if (setjmp(jerr_.setjmp_buffer)) { + HiLog::Error(LABEL, "get image size failed."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + if (state_ == JpegDecodingState::SOURCE_INITED) { + srcMgr_.inputStream->Seek(0); + } else { + srcMgr_.inputStream->Seek(streamPosition_); + } + decodeInfo_.src = &srcMgr_; + + /** + * The function jpeg_read_header() shall read the JPEG datastream until the first SOS marker is encountered + * incremental decoding should have enough data(contains SOS marker) before calling jpeg_read_header. + */ + if (!srcMgr_.inputStream->IsStreamCompleted()) { + uint32_t curPos = srcMgr_.inputStream->Tell(); + while (true) { + if (!FindMarker(*srcMgr_.inputStream, JPG_MARKER_SOS)) { + srcMgr_.inputStream->Seek(curPos); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + srcMgr_.inputStream->Seek(curPos); + break; + } + } + + int32_t ret = jpeg_read_header(&decodeInfo_, false); + streamPosition_ = srcMgr_.inputStream->Tell(); + if (ret == JPEG_SUSPENDED) { + HiLog::Debug(LABEL, "image input data incomplete, decode header error:%{public}u.", ret); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } else if (ret != JPEG_HEADER_OK) { + HiLog::Error(LABEL, "image type is not jpeg, decode header error:%{public}u.", ret); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + return Media::SUCCESS; +} + +uint32_t JpegDecoder::StartDecompress(const PixelDecodeOptions &opts) +{ + if (setjmp(jerr_.setjmp_buffer)) { + HiLog::Error(LABEL, "set output image info failed."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + // set decode options + if (decodeInfo_.jpeg_color_space == JCS_CMYK || decodeInfo_.jpeg_color_space == JCS_YCCK) { + // can't support CMYK to alpha8 convert + if (opts.desiredPixelFormat == PlPixelFormat::ALPHA_8) { + HiLog::Error(LABEL, "can't support colorspace CMYK to alpha convert."); + return ERR_IMAGE_UNKNOWN_FORMAT; + } + HiLog::Debug(LABEL, "jpeg colorspace is CMYK."); + decodeInfo_.out_color_space = JCS_CMYK; + outputFormat_ = PlPixelFormat::CMYK; + } else { + decodeInfo_.out_color_space = GetDecodeFormat(opts.desiredPixelFormat, outputFormat_); + if (decodeInfo_.out_color_space == JCS_UNKNOWN) { + HiLog::Error(LABEL, "set jpeg output color space invalid."); + return ERR_IMAGE_UNKNOWN_FORMAT; + } + } + srcMgr_.inputStream->Seek(streamPosition_); + if (jpeg_start_decompress(&decodeInfo_) != TRUE) { + streamPosition_ = srcMgr_.inputStream->Tell(); + HiLog::Error(LABEL, "jpeg start decompress failed, invalid input."); + return ERR_IMAGE_INVALID_PARAMETER; + } + streamPosition_ = srcMgr_.inputStream->Tell(); + return Media::SUCCESS; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp b/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7aab2a12e4d064739143315137df9982b6508f6e --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/src/jpeg_encoder.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerror.h" +#include "jpeg_encoder.h" +#include "media_errors.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; + +constexpr uint32_t COMPONENT_NUM_ARGB = 4; +constexpr uint32_t COMPONENT_NUM_RGBA = 4; +constexpr uint32_t COMPONENT_NUM_BGRA = 4; +constexpr uint32_t COMPONENT_NUM_RGB = 3; +constexpr uint32_t COMPONENT_NUM_GRAY = 1; +// yuv format +constexpr uint8_t COMPONENT_NUM_YUV420SP = 3; +constexpr uint8_t Y_SAMPLE_ROW = 16; +constexpr uint8_t UV_SAMPLE_ROW = 8; +constexpr uint8_t SAMPLE_FACTOR_ONE = 1; +constexpr uint8_t SAMPLE_FACTOR_TWO = 2; +constexpr uint8_t INDEX_ZERO = 0; +constexpr uint8_t INDEX_ONE = 1; +constexpr uint8_t INDEX_TWO = 2; +constexpr uint8_t SHIFT_MASK = 1; + +JpegDstMgr::JpegDstMgr(OutputDataStream *stream) : outputStream(stream) +{ + init_destination = InitDstStream; + empty_output_buffer = EmptyOutputBuffer; + term_destination = TermDstStream; +} + +JpegEncoder::JpegEncoder() : dstMgr_(nullptr) +{ + // create decompress struct + jpeg_create_compress(&encodeInfo_); + + // set error output + encodeInfo_.err = jpeg_std_error(&jerr_); + jerr_.error_exit = ErrorExit; + if (encodeInfo_.err == nullptr) { + HiLog::Error(LABEL, "create jpeg encoder failed."); + return; + } + encodeInfo_.err->output_message = &OutputErrorMessage; +} + +uint32_t JpegEncoder::StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option) +{ + pixelMaps_.clear(); + dstMgr_.outputStream = &outputStream; + encodeInfo_.dest = &dstMgr_; + encodeOpts_ = option; + return SUCCESS; +} + +J_COLOR_SPACE JpegEncoder::GetEncodeFormat(PixelFormat format, int32_t &componentsNum) +{ + J_COLOR_SPACE colorSpace = JCS_UNKNOWN; + int32_t components = 0; + switch (format) { + case PixelFormat::RGBA_8888: { + colorSpace = JCS_EXT_RGBA; + components = COMPONENT_NUM_RGBA; + break; + } + case PixelFormat::BGRA_8888: { + colorSpace = JCS_EXT_BGRA; + components = COMPONENT_NUM_BGRA; + break; + } + case PixelFormat::ARGB_8888: { + colorSpace = JCS_EXT_ARGB; + components = COMPONENT_NUM_ARGB; + break; + } + case PixelFormat::ALPHA_8: { + colorSpace = JCS_GRAYSCALE; + components = COMPONENT_NUM_GRAY; + break; + } + case PixelFormat::RGB_888: { + colorSpace = JCS_RGB; + components = COMPONENT_NUM_RGB; + break; + } + case PixelFormat::NV12: + case PixelFormat::NV21: { + colorSpace = JCS_YCbCr; + components = COMPONENT_NUM_YUV420SP; + break; + } + case PixelFormat::CMYK: { + colorSpace = JCS_CMYK; + components = COMPONENT_NUM_RGBA; + break; + } + default: { + HiLog::Error(LABEL, "encode format:[%{public}d] is unsupported!", format); + break; + } + } + componentsNum = components; + return colorSpace; +} + +uint32_t JpegEncoder::AddImage(Media::PixelMap &pixelMap) +{ + if (pixelMaps_.size() >= JPEG_IMAGE_NUM) { + HiLog::Error(LABEL, "add pixel map out of range:[%{public}u].", JPEG_IMAGE_NUM); + return ERR_IMAGE_ADD_PIXEL_MAP_FAILED; + } + pixelMaps_.push_back(&pixelMap); + return SUCCESS; +} + +uint32_t JpegEncoder::FinalizeEncode() +{ + uint32_t errorCode = SetCommonConfig(); + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "set jpeg compress struct failed:%{public}u.", errorCode); + return errorCode; + } + const uint8_t *data = pixelMaps_[0]->GetPixels(); + if (data == nullptr) { + HiLog::Error(LABEL, "encode image buffer is null."); + return ERR_IMAGE_INVALID_PARAMETER; + } + PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat(); + if (pixelFormat == PixelFormat::NV21 || pixelFormat == PixelFormat::NV12) { + errorCode = Yuv420spEncoder(data); + } else { + errorCode = SequenceEncoder(data); + } + if (errorCode != SUCCESS) { + HiLog::Error(LABEL, "encode jpeg failed:%{public}u.", errorCode); + } + return errorCode; +} + +uint32_t JpegEncoder::SetCommonConfig() +{ + if (pixelMaps_.empty()) { + HiLog::Error(LABEL, "encode image failed, no pixel map input."); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (setjmp(jerr_.setjmp_buffer)) { + HiLog::Error(LABEL, "encode image error, set config failed."); + return ERR_IMAGE_ENCODE_FAILED; + } + encodeInfo_.image_width = pixelMaps_[0]->GetWidth(); + encodeInfo_.image_height = pixelMaps_[0]->GetHeight(); + PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat(); + encodeInfo_.in_color_space = GetEncodeFormat(pixelFormat, encodeInfo_.input_components); + if (encodeInfo_.in_color_space == JCS_UNKNOWN) { + HiLog::Error(LABEL, "set input jpeg color space invalid."); + return ERR_IMAGE_UNKNOWN_FORMAT; + } + HiLog::Debug(LABEL, "width=%{public}u, height=%{public}u, colorspace=%{public}d, components=%{public}d.", + encodeInfo_.image_width, encodeInfo_.image_height, encodeInfo_.in_color_space, + encodeInfo_.input_components); + jpeg_set_defaults(&encodeInfo_); + int32_t quality = encodeOpts_.quality; + jpeg_set_quality(&encodeInfo_, quality, TRUE); + return SUCCESS; +} + +uint32_t JpegEncoder::SequenceEncoder(const uint8_t *data) +{ + if (setjmp(jerr_.setjmp_buffer)) { + HiLog::Error(LABEL, "encode image error."); + return ERR_IMAGE_ENCODE_FAILED; + } + jpeg_start_compress(&encodeInfo_, TRUE); + uint8_t *base = const_cast(data); + uint32_t rowStride = encodeInfo_.image_width * encodeInfo_.input_components; + uint8_t *buffer = nullptr; + while (encodeInfo_.next_scanline < encodeInfo_.image_height) { + buffer = base + encodeInfo_.next_scanline * rowStride; + jpeg_write_scanlines(&encodeInfo_, &buffer, RW_LINE_NUM); + } + jpeg_finish_compress(&encodeInfo_); + return SUCCESS; +} + +void JpegEncoder::SetYuv420spExtraConfig() +{ + encodeInfo_.raw_data_in = TRUE; + encodeInfo_.dct_method = JDCT_IFAST; + encodeInfo_.comp_info[INDEX_ZERO].h_samp_factor = SAMPLE_FACTOR_TWO; + encodeInfo_.comp_info[INDEX_ZERO].v_samp_factor = SAMPLE_FACTOR_TWO; + encodeInfo_.comp_info[INDEX_ONE].h_samp_factor = SAMPLE_FACTOR_ONE; + encodeInfo_.comp_info[INDEX_ONE].v_samp_factor = SAMPLE_FACTOR_ONE; + encodeInfo_.comp_info[INDEX_TWO].h_samp_factor = SAMPLE_FACTOR_ONE; + encodeInfo_.comp_info[INDEX_TWO].v_samp_factor = SAMPLE_FACTOR_ONE; +} + +uint32_t JpegEncoder::Yuv420spEncoder(const uint8_t *data) +{ + SetYuv420spExtraConfig(); + jpeg_start_compress(&encodeInfo_, TRUE); + JSAMPROW y[Y_SAMPLE_ROW]; + JSAMPROW u[UV_SAMPLE_ROW]; + JSAMPROW v[UV_SAMPLE_ROW]; + JSAMPARRAY planes[COMPONENT_NUM_YUV420SP]{ y, u, v }; + uint32_t width = encodeInfo_.image_width; + uint32_t height = encodeInfo_.image_height; + uint32_t yPlaneSize = width * height; + uint8_t *yPlane = const_cast(data); + uint8_t *uvPlane = const_cast(data + yPlaneSize); + auto uPlane = std::make_unique((width >> SHIFT_MASK) * UV_SAMPLE_ROW); + if (uPlane == nullptr) { + HiLog::Error(LABEL, "allocate uPlane memory failed."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + auto vPlane = std::make_unique((width >> SHIFT_MASK) * UV_SAMPLE_ROW); + if (vPlane == nullptr) { + HiLog::Error(LABEL, "allocate vPlane memory failed."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + while (encodeInfo_.next_scanline < height) { + Deinterweave(uvPlane, uPlane.get(), vPlane.get(), encodeInfo_.next_scanline, width, height); + for (uint32_t i = 0; i < Y_SAMPLE_ROW; i++) { + y[i] = yPlane + (encodeInfo_.next_scanline + i) * width; + if ((i & SHIFT_MASK) == 0) { + uint32_t offset = (i >> SHIFT_MASK) * (width >> SHIFT_MASK); + u[i >> SHIFT_MASK] = uPlane.get() + offset; + v[i >> SHIFT_MASK] = vPlane.get() + offset; + } + } + jpeg_write_raw_data(&encodeInfo_, planes, Y_SAMPLE_ROW); + } + jpeg_finish_compress(&encodeInfo_); + return SUCCESS; +} + +void JpegEncoder::Deinterweave(uint8_t *uvPlane, uint8_t *uPlane, uint8_t *vPlane, uint32_t curRow, uint32_t width, + uint32_t height) +{ + PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat(); + uint32_t rowNum = (height - curRow) >> SHIFT_MASK; + if (rowNum > UV_SAMPLE_ROW) { + rowNum = UV_SAMPLE_ROW; + } + uint8_t indexZero = INDEX_ZERO; + uint8_t indexOne = INDEX_ONE; + if (pixelFormat != PixelFormat::NV12) { + std::swap(indexZero, indexOne); + } + + for (uint32_t row = 0; row < rowNum; row++) { + uint32_t offset = ((curRow >> SHIFT_MASK) + row) * width; + uint8_t *uv = uvPlane + offset; + uint32_t col = width >> SHIFT_MASK; + for (uint32_t i = 0; i < col; i++) { + uint32_t index = row * col + i; + uPlane[index] = uv[indexZero]; + vPlane[index] = uv[indexOne]; + uv += INDEX_TWO; + } + } +} + +JpegEncoder::~JpegEncoder() +{ + jpeg_destroy_compress(&encodeInfo_); + pixelMaps_.clear(); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libjpegplugin/src/jpeg_utils.cpp b/plugins/common/libs/image/libjpegplugin/src/jpeg_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36aeff58125d37a97ff104f0266a6e175a985cb4 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/src/jpeg_utils.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jpeg_utils.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegUtils" }; + +// these functions are called by libjpeg-turbo third_party library, no need check input parameter. +// for error manager +void ErrorExit(j_common_ptr dinfo) +{ + if ((dinfo == nullptr) || (dinfo->err == nullptr)) { + return; + } + // dinfo->err really points to a ErrorMgr struct, so coerce pointer. + ErrorMgr *err = static_cast(dinfo->err); + (*dinfo->err->output_message)(dinfo); + // return control to the setjmp point. + longjmp(err->setjmp_buffer, SET_JUMP_VALUE); +} + +void OutputErrorMessage(j_common_ptr dinfo) +{ + if ((dinfo == nullptr) || (dinfo->err == nullptr)) { + return; + } + char buffer[JMSG_LENGTH_MAX] = { 0 }; + dinfo->err->format_message(dinfo, buffer); + HiLog::Error(LABEL, "libjpeg error %{public}d <%{public}s>.", dinfo->err->msg_code, buffer); +} + +// for source manager +// this is called by jpeg_read_header() before any data is actually read. +void InitSrcStream(j_decompress_ptr dinfo) +{ + if ((dinfo == nullptr) || (dinfo->src == nullptr)) { + HiLog::Error(LABEL, "init source stream error."); + return; + } + JpegSrcMgr *src = static_cast(dinfo->src); + src->next_input_byte = src->streamData.inputStreamBuffer; + src->bytes_in_buffer = 0; +} + +// this is called whenever bytes_in_buffer has reached zero and more data is wanted. +boolean FillInputBuffer(j_decompress_ptr dinfo) +{ + if (dinfo == nullptr) { + HiLog::Error(LABEL, "fill input buffer error, decompress struct is null."); + return FALSE; + } + JpegSrcMgr *src = static_cast(dinfo->src); + if ((src == nullptr) || (src->inputStream == nullptr)) { + HiLog::Error(LABEL, "fill input buffer error, source stream is null."); + ERREXIT(dinfo, JERR_FILE_READ); + return FALSE; + } + + uint32_t preReadPos = src->inputStream->Tell(); + if (!src->inputStream->IsStreamCompleted() && !src->inputStream->Seek(preReadPos + JPEG_BUFFER_SIZE)) { + return FALSE; + } + src->inputStream->Seek(preReadPos); + if (!src->inputStream->Read(src->bufferSize, src->streamData)) { + HiLog::Error(LABEL, "fill input buffer error, read source stream failed."); + return FALSE; + } + if (!src->inputStream->IsStreamCompleted() && src->streamData.dataSize < JPEG_BUFFER_SIZE) { + uint32_t curr = src->inputStream->Tell(); + src->inputStream->Seek(curr - src->streamData.dataSize); + HiLog::Debug(LABEL, "fill input buffer seekTo=%{public}u, rewindSize=%{public}u.", + curr - src->streamData.dataSize, src->streamData.dataSize); + return FALSE; + } + src->next_input_byte = src->streamData.inputStreamBuffer; + src->bytes_in_buffer = src->streamData.dataSize; + return TRUE; +} + +// skip num_bytes worth of data. +void SkipInputData(j_decompress_ptr dinfo, long numBytes) +{ + if (dinfo == nullptr) { + HiLog::Error(LABEL, "skip input buffer error, decompress struct is null."); + return; + } + JpegSrcMgr *src = static_cast(dinfo->src); + if ((src == nullptr) || (src->inputStream == nullptr)) { + HiLog::Error(LABEL, "skip input buffer error, source stream is null."); + ERREXIT(dinfo, JERR_FILE_READ); + return; + } + size_t bytes = static_cast(numBytes); + if (bytes > src->bytes_in_buffer) { + size_t bytesToSkip = bytes - src->bytes_in_buffer; + uint32_t nowOffset = src->inputStream->Tell(); + if (bytesToSkip > src->inputStream->GetStreamSize() - nowOffset) { + HiLog::Error(LABEL, "skip data:%{public}zu larger than current offset:%{public}u.", bytesToSkip, nowOffset); + return; + } + if (!src->inputStream->Seek(nowOffset + bytesToSkip)) { + HiLog::Error(LABEL, "skip data:%{public}zu fail, current offset:%{public}u.", bytesToSkip, nowOffset); + ERREXIT(dinfo, JERR_FILE_READ); + return; + } + src->next_input_byte = src->streamData.inputStreamBuffer; + src->bytes_in_buffer = 0; + } else { + src->next_input_byte += numBytes; + src->bytes_in_buffer -= numBytes; + } +} + +// this is called by jpeg_finish_decompress() after all data has been read. Often a no-op. +void TermSrcStream(j_decompress_ptr dinfo) +{} + +// for destination manager +// this is called by jpeg_start_compress() before any data is actually written. +void InitDstStream(j_compress_ptr cinfo) +{ + if ((cinfo == nullptr) || (cinfo->dest == nullptr)) { + HiLog::Error(LABEL, "init destination stream error."); + return; + } + JpegDstMgr *dest = static_cast(cinfo->dest); + dest->next_output_byte = dest->buffer; + dest->free_in_buffer = dest->bufferSize; +} + +// this is called whenever the buffer has filled (free_in_buffer reaches zero). +boolean EmptyOutputBuffer(j_compress_ptr cinfo) +{ + if (cinfo == nullptr) { + HiLog::Error(LABEL, "write output buffer error, compress struct is null."); + return FALSE; + } + JpegDstMgr *dest = static_cast(cinfo->dest); + if ((dest == nullptr) || (dest->outputStream == nullptr)) { + HiLog::Error(LABEL, "write output buffer error, dest stream is null."); + ERREXIT(cinfo, JERR_FILE_WRITE); + return FALSE; + } + if (!dest->outputStream->Write(dest->buffer, dest->bufferSize)) { + HiLog::Error(LABEL, "write output buffer error, write dest stream failed."); + ERREXIT(cinfo, JERR_FILE_WRITE); + return FALSE; + } + dest->next_output_byte = dest->buffer; + dest->free_in_buffer = dest->bufferSize; + return TRUE; +} + +// this is called by jpeg_finish_compress() after all data has been written. +void TermDstStream(j_compress_ptr cinfo) +{ + if (cinfo == nullptr) { + HiLog::Error(LABEL, "term output buffer error, compress struct is null."); + return; + } + JpegDstMgr *dest = static_cast(cinfo->dest); + if ((dest == nullptr) || (dest->outputStream == nullptr)) { + HiLog::Error(LABEL, "term output buffer error, dest stream is null."); + ERREXIT(cinfo, JERR_FILE_WRITE); + return; + } + size_t size = dest->bufferSize - dest->free_in_buffer; + if (size > 0) { + if (!dest->outputStream->Write(dest->buffer, size)) { + HiLog::Error(LABEL, "term output buffer error, write dest stream size:%{public}zu failed.", size); + ERREXIT(cinfo, JERR_FILE_WRITE); + return; + } + } + dest->outputStream->Flush(); +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libjpegplugin/src/plugin_export.cpp b/plugins/common/libs/image/libjpegplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9677c35b766c410850c3bebe315dfbc7bab247c2 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/src/plugin_export.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "plugin_utils.h" +#include "jpeg_decoder.h" +#include "jpeg_encoder.h" +#include "log_tags.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibJpegPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::JpegDecoder) +#if !defined(_WIN32) && !defined(_APPLE) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::JpegEncoder) +#endif +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibJpegPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/plugins/common/libs/image/libpngplugin/BUILD.gn b/plugins/common/libs/image/libpngplugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..def41a2992fcb314a1f5cd03172244039edc4a7c --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/BUILD.gn @@ -0,0 +1,92 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("pngplugin") { + sources = [ + "//foundation/multimedia/image_standard/plugins/common/libs/image/libpngplugin/src/nine_patch_listener.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libpngplugin/src/plugin_export.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libpngplugin/src/png_decoder.cpp", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libpngplugin/src/png_ninepatch_res.cpp", + ] + include_dirs = [ + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libpngplugin/include", + "//third_party/zlib", + "//third_party/libpng", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//third_party/flutter/skia/third_party/libjpeg-turbo", + ] + deps = [ "//third_party/zlib:libz" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//third_party/libpng", + ] + deps += [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/libpng:png_static", + ] + + libs = [ "//prebuilts/mingw-w64/ohos/linux-x86_64/clang-mingw/x86_64-w64-mingw32/lib/libws2_32.a" ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//third_party/libpng", + "//utils/native/base/include", + ] + deps += [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager_static", + "//third_party/libpng:png_static", + "//utils/native/base:utilsecurec", + ] + } else { + defines = [ "DUAL_ADAPTER" ] + DUAL_ADAPTER = true + include_dirs += [ "//utils/native/base/include" ] + deps += [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + if (DUAL_ADAPTER) { +# aosp_deps = [ "shared_library:libpng" ] + } else { + deps += [ "//third_party/libpng:libpng" ] + include_dirs += [ "//third_party/libpng" ] + } +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("pngpluginmetadata") { + source = "pngplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/common/libs/image/libpngplugin/include/nine_patch_listener.h b/plugins/common/libs/image/libpngplugin/include/nine_patch_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..77d53a6bebd5369c032f4caa95fd16d24e731764 --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/include/nine_patch_listener.h @@ -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. + */ + +#ifndef NINE_PATCH_LISTENER_H +#define NINE_PATCH_LISTENER_H + +#include +#include +#include +#include "nocopyable.h" +#include "png_ninepatch_res.h" + +namespace OHOS { +namespace ImagePlugin { +class NinePatchListener { +public: + NinePatchListener() : patch_(nullptr), patchSize_(0) + {} + ~NinePatchListener() + { + if (patch_ != nullptr) { + free(patch_); + patch_ = nullptr; + } + } + bool ReadChunk(const std::string &tag, void *data, size_t length); + void Scale(float scaleX, float scaleY, int32_t scaledWidth, int32_t scaledHeight); + PngNinePatchRes *patch_ = nullptr; + size_t patchSize_ = 0; + +private: + DISALLOW_COPY_AND_MOVE(NinePatchListener); +}; +} // namespace ImagePlugin +} // namespace OHOS +#endif // NINE_PATCH_LISTENER_H diff --git a/plugins/common/libs/image/libpngplugin/include/png_decoder.h b/plugins/common/libs/image/libpngplugin/include/png_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..08f52e5b77bc4eec2955b5da388dfe803d492c86 --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/include/png_decoder.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PNG_DECODER_H +#define PNG_DECODER_H + +#include "abs_image_decoder.h" +#include "hilog/log.h" +#include "input_data_stream.h" +#include "log_tags.h" +#include "nine_patch_listener.h" +#include "plugin_class_base.h" +#include "png.h" + +namespace OHOS { +namespace ImagePlugin { +enum class PngDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSING = 2, + BASE_INFO_PARSED = 3, + IMAGE_DECODING = 4, + IMAGE_ERROR = 5, + IMAGE_PARTIAL = 6, + IMAGE_DECODED = 7 +}; + +struct PngImageInfo { + uint32_t width = 0; + uint32_t height = 0; + uint8_t bitDepth = 0; + uint32_t rowDataSize = 0; + int32_t numberPasses = 0; // interlace is 7 otherwise is 1. +}; + +class PngDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + PngDecoder(); + ~PngDecoder() override; + PngDecoder(const PngDecoder &) = delete; + PngDecoder &operator=(const PngDecoder &) = delete; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + bool HasProperty(std::string key) override; + +private: + uint32_t GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat, PlAlphaType &alphaType); + void ChooseFormat(PlPixelFormat format, PlPixelFormat &outputFormat, png_byte destType); + static void PngErrorExit(png_structp pngPtr, png_const_charp message); + static void PngWarning(png_structp pngPtr, png_const_charp message); + static void PngWarningMessage(png_structp pngPtr, png_const_charp message); + static void PngErrorMessage(png_structp pngPtr, png_const_charp message); + // incremental private interface + uint32_t PushCurrentToDecode(InputDataStream *stream); + uint32_t IncrementalReadRows(InputDataStream *stream); + uint32_t PushAllToDecode(InputDataStream *stream, size_t bufferSize, size_t length); + static void GetAllRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass); + static void GetInterlacedRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass); + static int32_t ReadUserChunk(png_structp png_ptr, png_unknown_chunkp chunk); + void SaveRows(png_bytep row, png_uint_32 rowNum); + void SaveInterlacedRows(png_bytep row, png_uint_32 rowNum, int pass); + uint32_t ReadIncrementalHead(InputDataStream *stream, PngImageInfo &info); + bool GetImageInfo(PngImageInfo &info); + bool IsChunk(const png_byte *chunk, const char *flag); + uint32_t ProcessData(png_structp pngPtr, png_infop infoPtr, InputDataStream *sourceStream, + DataStreamBuffer streamData, size_t bufferSize, size_t totalSize); + bool ConvertOriginalFormat(png_byte source, png_byte &destination); + uint8_t *AllocOutputHeapBuffer(DecodeContext &context); + uint32_t IncrementalRead(InputDataStream *stream, uint32_t desiredSize, DataStreamBuffer &outData); + uint32_t DecodeHeader(); + uint32_t ConfigInfo(const PixelDecodeOptions &opts); + uint32_t DoOneTimeDecode(DecodeContext &context); + bool FinishOldDecompress(); + bool InitPnglib(); + uint32_t GetImageIdatSize(InputDataStream *stream); + void DealNinePatch(const PixelDecodeOptions &opts); + // local private parameter + const std::string NINE_PATCH = "ninepatch"; + png_structp pngStructPtr_ = nullptr; + png_infop pngInfoPtr_ = nullptr; + InputDataStream *inputStreamPtr_ = nullptr; + PngImageInfo pngImageInfo_; + bool decodedIdat_ = false; + size_t idatLength_ = 0; + size_t incrementalLength_ = 0; + uint8_t *pixelsData_ = nullptr; + uint32_t outputRowsNum_ = 0; + PngDecodingState state_ = PngDecodingState::UNDECIDED; + uint32_t streamPosition_ = 0; // may be changed by other decoders, record it and restore if needed. + PlPixelFormat outputFormat_ = PlPixelFormat::UNKNOWN; + PlAlphaType alphaType_ = PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; + PixelDecodeOptions opts_; + bool decodeHeadFlag_ = false; + uint32_t firstRow_ = 0; + uint32_t lastRow_ = 0; + bool interlacedComplete_ = false; + NinePatchListener ninePatch_; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // PNG_DECODER_H diff --git a/plugins/common/libs/image/libpngplugin/include/png_ninepatch_res.h b/plugins/common/libs/image/libpngplugin/include/png_ninepatch_res.h new file mode 100644 index 0000000000000000000000000000000000000000..0945097d78203e86b0e30a300f36b932ec7a28d6 --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/include/png_ninepatch_res.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PNG_NINEPATCH_RES_H +#define PNG_NINEPATCH_RES_H + +#include +#include + +namespace OHOS { +namespace ImagePlugin { +struct alignas(uintptr_t) PngNinePatchRes { + PngNinePatchRes() : wasDeserialized(false), xDivsOffset(0), yDivsOffset(0), colorsOffset(0) + {} + ~PngNinePatchRes() = default; + void DeviceToFile(); + void FileToDevice(); + static PngNinePatchRes *Deserialize(void *data); + size_t SerializedSize() const; + inline int32_t *GetXDivs() const + { + return reinterpret_cast(reinterpret_cast(this) + xDivsOffset); + } + inline int32_t *GetYDivs() const + { + return reinterpret_cast(reinterpret_cast(this) + yDivsOffset); + } + inline uint32_t *GetColors() const + { + return reinterpret_cast(reinterpret_cast(this) + colorsOffset); + } + int8_t wasDeserialized; + uint8_t numXDivs; + uint8_t numYDivs; + uint8_t numColors; + uint32_t xDivsOffset; + uint32_t yDivsOffset; + int32_t paddingLeft; + int32_t paddingRight; + int32_t paddingTop; + int32_t paddingBottom; + // The offset (from the start of this structure) to the colors array + uint32_t colorsOffset; +} __attribute__((packed)); +} // namespace ImagePlugin +} // namespace OHOS +#endif // PNG_NINEPATCH_RES_H diff --git a/plugins/common/libs/image/libpngplugin/pngplugin.pluginmeta b/plugins/common/libs/image/libpngplugin/pngplugin.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..37af6874b84207dbc743ed161c8c7dca825ea38e --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/pngplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibPngPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libpngplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::PngDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/png" + } + ] + } + ] +} diff --git a/plugins/common/libs/image/libpngplugin/src/nine_patch_listener.cpp b/plugins/common/libs/image/libpngplugin/src/nine_patch_listener.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07ca28db626a2b9c054c91dd90d7d7618b3e9c36 --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/src/nine_patch_listener.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nine_patch_listener.h" +#include +#include +#include "hilog/log.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; + +namespace { +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "NinePatchListener" }; +const std::string CHUNK_NAME = "npTc"; +constexpr float FLOAT_NEAR_ZERO = (1.0f / (1 << 12)); +constexpr float FHALF = 0.5f; +constexpr float NO_SCALE = 1.0f; +} // namespace + +static void ScaleDivRange(int32_t *divs, int32_t count, float scale, int32_t maxValue) +{ + for (int i = 0; i < count; i++) { + divs[i] = static_cast(divs[i] * scale + FHALF); + if (i > 0 && divs[i] == divs[i - 1]) { + divs[i]++; + } + } + + if (divs[count - 1] > maxValue) { + int highestAvailable = maxValue; + for (int i = count - 1; i >= 0; i--) { + divs[i] = highestAvailable; + if (i > 0 && divs[i] <= divs[i - 1]) { + highestAvailable = divs[i] - 1; + } else { + break; + } + } + } +} + +bool NinePatchListener::ReadChunk(const std::string &tag, void *data, size_t length) +{ + if (tag == CHUNK_NAME && length >= sizeof(PngNinePatchRes)) { + if (data == nullptr) { + HiLog::Error(LABEL, "data is null"); + return false; + } + PngNinePatchRes *patch = static_cast(data); + size_t patchSize = patch->SerializedSize(); + if (length != patchSize) { + HiLog::Error(LABEL, "length(%{public}zu) ne patchSize(%{public}zu)", length, patchSize); + return false; + } + // copy the data because it is owned by the png reader + PngNinePatchRes *patchNew = static_cast(malloc(patchSize)); + if (patchNew == nullptr) { + HiLog::Error(LABEL, "malloc failed"); + return false; + } + errno_t err = memcpy_s(patchNew, patchSize, patch, patchSize); + if (err != 0) { + HiLog::Error(LABEL, "memcpy failed. errno:%{public}d", err); + free(patchNew); + patchNew = nullptr; + return false; + } + PngNinePatchRes::Deserialize(patchNew); + patchNew->FileToDevice(); + if (patch_ != nullptr) { + free(patch_); + } + patch_ = patchNew; + patchSize_ = patchSize; + } + + return true; +} + +void NinePatchListener::Scale(float scaleX, float scaleY, int32_t scaledWidth, int32_t scaledHeight) +{ + if (patch_ == nullptr) { + HiLog::Error(LABEL, "patch is null"); + return; + } + + if (fabsf(scaleX - NO_SCALE) > FLOAT_NEAR_ZERO) { + patch_->paddingLeft = static_cast(patch_->paddingLeft * scaleX + FHALF); + patch_->paddingRight = static_cast(patch_->paddingRight * scaleX + FHALF); + ScaleDivRange(patch_->GetXDivs(), patch_->numXDivs, scaleX, scaledWidth - 1); + } + + if (fabsf(scaleY - NO_SCALE) > FLOAT_NEAR_ZERO) { + patch_->paddingTop = static_cast(patch_->paddingTop * scaleY + FHALF); + patch_->paddingBottom = static_cast(patch_->paddingBottom * scaleY + FHALF); + ScaleDivRange(patch_->GetYDivs(), patch_->numYDivs, scaleY, scaledHeight - 1); + } +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libpngplugin/src/plugin_export.cpp b/plugins/common/libs/image/libpngplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed1f7697e9191b5cb72729dd7c634eeb6504268d --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/src/plugin_export.cpp @@ -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. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "png_decoder.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibPngPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::PngDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibPngPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/plugins/common/libs/image/libpngplugin/src/png_decoder.cpp b/plugins/common/libs/image/libpngplugin/src/png_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2ebaa1eae152880fb67af1b9ceda0ac18a69a3b --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/src/png_decoder.cpp @@ -0,0 +1,999 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "png_decoder.h" +#include "media_errors.h" +#include "pngpriv.h" +#include "pngstruct.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PngDecoder" }; +static constexpr uint32_t PNG_IMAGE_NUM = 1; +static constexpr int SET_JUMP_VALUE = 1; +static constexpr int BITDEPTH_VALUE_1 = 1; +static constexpr int BITDEPTH_VALUE_2 = 2; +static constexpr int BITDEPTH_VALUE_4 = 4; +static constexpr int BITDEPTH_VALUE_8 = 8; +static constexpr int BITDEPTH_VALUE_16 = 16; +static constexpr size_t DECODE_BUFFER_SIZE = 4096; +static constexpr size_t CHUNK_SIZE = 8; +static constexpr size_t CHUNK_DATA_LEN = 4; +static constexpr int PNG_HEAD_SIZE = 100; + +PngDecoder::PngDecoder() +{ + if (!InitPnglib()) { + HiLog::Error(LABEL, "Png decoder init failed!"); + } +} + +PngDecoder::~PngDecoder() +{ + Reset(); + // destroy the png decode struct + if (pngStructPtr_) { + png_infopp pngInfoPtr = pngInfoPtr_ ? &pngInfoPtr_ : nullptr; + png_destroy_read_struct(&pngStructPtr_, pngInfoPtr, nullptr); + } +} + +void PngDecoder::SetSource(InputDataStream &sourceStream) +{ + inputStreamPtr_ = &sourceStream; + state_ = PngDecodingState::SOURCE_INITED; +} + +uint32_t PngDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + // PNG format only supports one picture decoding, index in order to Compatible animation scene. + if (index >= PNG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) { + HiLog::Error(LABEL, "create Png Struct or Png Info failed!"); + return ERR_IMAGE_INIT_ABNORMAL; + } + if (state_ < PngDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= PngDecodingState::BASE_INFO_PARSED) { + size.width = png_get_image_width(pngStructPtr_, pngInfoPtr_); + size.height = png_get_image_height(pngStructPtr_, pngInfoPtr_); + return SUCCESS; + } + // only state PngDecodingState::SOURCE_INITED and PngDecodingState::BASE_INFO_PARSING can go here. + uint32_t ret = DecodeHeader(); + if (ret != SUCCESS) { + HiLog::Debug(LABEL, "decode header error on get image ret:%{public}u.", ret); + return ret; + } + size.width = png_get_image_width(pngStructPtr_, pngInfoPtr_); + size.height = png_get_image_height(pngStructPtr_, pngInfoPtr_); + return SUCCESS; +} + +uint32_t PngDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + // PNG format only supports one picture decoding, index in order to Compatible animation scene. + if (index >= PNG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) { + HiLog::Error(LABEL, "Png init fail, can't set decode option."); + return ERR_IMAGE_INIT_ABNORMAL; + } + if (state_ < PngDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "set decode options failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= PngDecodingState::IMAGE_DECODING) { + if (!FinishOldDecompress()) { + HiLog::Error(LABEL, "finish old decompress fail, can't set decode option."); + return ERR_IMAGE_INIT_ABNORMAL; + } + } + if (state_ < PngDecodingState::BASE_INFO_PARSED) { + uint32_t ret = DecodeHeader(); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret); + return ret; + } + } + + DealNinePatch(opts); + // only state PngDecodingState::BASE_INFO_PARSED can go here. + uint32_t ret = ConfigInfo(opts); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "config decoding failed on set decode options:%{public}u.", ret); + return ret; + } + info.size.width = pngImageInfo_.width; + info.size.height = pngImageInfo_.height; + info.pixelFormat = outputFormat_; + info.alphaType = alphaType_; + opts_ = opts; + state_ = PngDecodingState::IMAGE_DECODING; + return SUCCESS; +} + +bool PngDecoder::HasProperty(std::string key) +{ + if (NINE_PATCH == key) { + return static_cast(ninePatch_.patch_) != nullptr && ninePatch_.patchSize_ != 0; + } + return false; +} + +uint32_t PngDecoder::Decode(uint32_t index, DecodeContext &context) +{ + // PNG format only supports one picture decoding, index in order to Compatible animation scene. + if (index >= PNG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) { + HiLog::Error(LABEL, "Png init failed can't begin to decode."); + return ERR_IMAGE_INIT_ABNORMAL; + } + if (state_ < PngDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "decode failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ > PngDecodingState::IMAGE_DECODING) { + if (!FinishOldDecompress()) { + HiLog::Error(LABEL, "finish old decompress fail on decode."); + return ERR_IMAGE_INIT_ABNORMAL; + } + uint32_t ret = DecodeHeader(); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "decode header error on decode:%{public}u.", ret); + return ret; + } + ret = ConfigInfo(opts_); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "config decoding info failed on decode:%{public}u.", ret); + return ret; + } + state_ = PngDecodingState::IMAGE_DECODING; + } + // only state PngDecodingState::IMAGE_DECODING can go here. + context.ninePatchContext.ninePatch = static_cast(ninePatch_.patch_); + context.ninePatchContext.patchSize = ninePatch_.patchSize_; + uint32_t ret = DoOneTimeDecode(context); + if (ret == SUCCESS) { + state_ = PngDecodingState::IMAGE_DECODED; + return SUCCESS; + } + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && opts_.allowPartialImage) { + state_ = PngDecodingState::IMAGE_PARTIAL; + context.ifPartialOutput = true; + HiLog::Error(LABEL, "this is partial image data to decode, ret:%{public}u.", ret); + return SUCCESS; + } + state_ = PngDecodingState::IMAGE_ERROR; + return ret; +} + +uint8_t *PngDecoder::AllocOutputHeapBuffer(DecodeContext &context) +{ + if (context.pixelsBuffer.buffer == nullptr) { + uint64_t byteCount = static_cast(pngImageInfo_.rowDataSize) * pngImageInfo_.height; + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { +#if !defined(_WIN32) && !defined(_APPLE) + int fd = AshmemCreate("PNG RawData", byteCount); + if (fd < 0) { + return nullptr; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return nullptr; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return nullptr; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "new fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return nullptr; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.", + static_cast(byteCount)); + return nullptr; + } +#ifdef _WIN32 + memset(outputBuffer, 0, byteCount); +#else + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + HiLog::Error(LABEL, "init output buffer fail."); + free(outputBuffer); + outputBuffer = nullptr; + return nullptr; + } +#endif + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + } + return static_cast(context.pixelsBuffer.buffer); +} + +uint32_t PngDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + // PNG format only supports one picture decoding, index in order to Compatible animation scene. + context.totalProcessProgress = 0; + if (index >= PNG_IMAGE_NUM) { + HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}u.", index, PNG_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) { + HiLog::Error(LABEL, "Png init failed can't begin to decode."); + return ERR_IMAGE_INIT_ABNORMAL; + } + if (state_ != PngDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + + pixelsData_ = AllocOutputHeapBuffer(context.decodeContext); + if (pixelsData_ == nullptr) { + HiLog::Error(LABEL, "get pixels memory fail."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + inputStreamPtr_->Seek(streamPosition_); + uint32_t ret = IncrementalReadRows(inputStreamPtr_); + streamPosition_ = inputStreamPtr_->Tell(); + if (ret != SUCCESS) { + if (ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + HiLog::Error(LABEL, "Incremental decode fail, ret:%{public}u", ret); + } + } else { + if (outputRowsNum_ != pngImageInfo_.height) { + HiLog::Debug(LABEL, "Incremental decode incomplete, outputRowsNum:%{public}u, height:%{public}u", + outputRowsNum_, pngImageInfo_.height); + } + state_ = PngDecodingState::IMAGE_DECODED; + } + // get promote decode progress, in percentage: 0~100. + // DecodeHeader() has judged that pngImageInfo_.height should not be equal to 0 and returns a failure result, + // so here pngImageInfo_.height will not be equal to 0 in the PngDecodingState::IMAGE_DECODING state. + context.totalProcessProgress = + outputRowsNum_ == 0 ? 0 : outputRowsNum_ * ProgDecodeContext::FULL_PROGRESS / pngImageInfo_.height; + HiLog::Debug(LABEL, "Incremental decode progress %{public}u.", context.totalProcessProgress); + return ret; +} + +void PngDecoder::Reset() +{ + inputStreamPtr_ = nullptr; + decodedIdat_ = false; + idatLength_ = 0; + incrementalLength_ = 0; + pixelsData_ = nullptr; + outputRowsNum_ = 0; + decodeHeadFlag_ = false; + firstRow_ = 0; + lastRow_ = 0; + interlacedComplete_ = false; +} + +// private interface +bool PngDecoder::ConvertOriginalFormat(png_byte source, png_byte &destination) +{ + if (png_get_valid(pngStructPtr_, pngInfoPtr_, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(pngStructPtr_); + } + HiLog::Info(LABEL, "color type:[%{public}d]", source); + switch (source) { + case PNG_COLOR_TYPE_PALETTE: { // value is 3 + png_set_palette_to_rgb(pngStructPtr_); + destination = PNG_COLOR_TYPE_RGB; + break; + } + case PNG_COLOR_TYPE_GRAY: { // value is 0 + if (pngImageInfo_.bitDepth < 8) { // 8 is single pixel bit depth + png_set_expand_gray_1_2_4_to_8(pngStructPtr_); + } + png_set_gray_to_rgb(pngStructPtr_); + destination = PNG_COLOR_TYPE_RGB; + break; + } + case PNG_COLOR_TYPE_GRAY_ALPHA: { // value is 4 + png_set_gray_to_rgb(pngStructPtr_); + destination = PNG_COLOR_TYPE_RGB; + break; + } + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: { // value is 6 + destination = source; + break; + } + default: { + HiLog::Error(LABEL, "the color type:[%{public}d] libpng unsupported!", source); + return false; + } + } + + return true; +} + +uint32_t PngDecoder::GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat, PlAlphaType &alphaType) +{ + png_byte sourceType = png_get_color_type(pngStructPtr_, pngInfoPtr_); + if ((sourceType & PNG_COLOR_MASK_ALPHA) || png_get_valid(pngStructPtr_, pngInfoPtr_, PNG_INFO_tRNS)) { + alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL; + } else { + alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + } + png_byte destType = 0; + if (!ConvertOriginalFormat(sourceType, destType)) { + return ERR_IMAGE_DATA_UNSUPPORT; + } + if (format != PlPixelFormat::RGB_888 && destType == PNG_COLOR_TYPE_RGB) { + png_set_add_alpha(pngStructPtr_, 0xff, PNG_FILLER_AFTER); // 0xffff add the A after RGB. + } + // only support 8 bit depth for each pixel except for RGBA_F16 + if (format != PlPixelFormat::RGBA_F16 && pngImageInfo_.bitDepth == 16) { // 16bit depth + pngImageInfo_.bitDepth = 8; // 8bit depth + png_set_strip_16(pngStructPtr_); + } + ChooseFormat(format, outputFormat, destType); + return SUCCESS; +} + +void PngDecoder::ChooseFormat(PlPixelFormat format, PlPixelFormat &outputFormat, + png_byte destType) +{ + outputFormat = format; + switch (format) { + case PlPixelFormat::BGRA_8888: { + pngImageInfo_.rowDataSize = pngImageInfo_.width * 4; // 4 is BGRA size + png_set_bgr(pngStructPtr_); + break; + } + case PlPixelFormat::ARGB_8888: { + png_set_swap_alpha(pngStructPtr_); + pngImageInfo_.rowDataSize = pngImageInfo_.width * 4; // 4 is ARGB size + break; + } + case PlPixelFormat::RGB_888: { + if (destType == PNG_COLOR_TYPE_RGBA) { + png_set_strip_alpha(pngStructPtr_); + } + pngImageInfo_.rowDataSize = pngImageInfo_.width * 3; // 3 is RGB size + break; + } + case PlPixelFormat::RGBA_F16: { + png_set_scale_16(pngStructPtr_); + pngImageInfo_.rowDataSize = pngImageInfo_.width * 7; // 7 is RRGGBBA size + break; + } + case PlPixelFormat::UNKNOWN: + case PlPixelFormat::RGBA_8888: + default: { + pngImageInfo_.rowDataSize = pngImageInfo_.width * 4; // 4 is RGBA size + outputFormat = PlPixelFormat::RGBA_8888; + break; + } + } +} + +void PngDecoder::PngErrorExit(png_structp pngPtr, png_const_charp message) +{ + if ((pngPtr == nullptr) || (message == nullptr)) { + HiLog::Error(LABEL, "ErrorExit png_structp or error message is null."); + return; + } + jmp_buf *jmpBuf = &(png_jmpbuf(pngPtr)); + if (jmpBuf == nullptr) { + HiLog::Error(LABEL, "jmpBuf exception."); + return; + } + longjmp(*jmpBuf, SET_JUMP_VALUE); +} + +void PngDecoder::PngWarning(png_structp pngPtr, png_const_charp message) +{ + if (message == nullptr) { + HiLog::Error(LABEL, "WarningExit message is null."); + return; + } + HiLog::Warn(LABEL, "png warn %{public}s", message); +} + +void PngDecoder::PngErrorMessage(png_structp pngPtr, png_const_charp message) +{ + if (message == nullptr) { + HiLog::Error(LABEL, "PngErrorMessage message is null."); + return; + } + HiLog::Error(LABEL, "PngErrorMessage, message:%{public}s.", message); +} + +void PngDecoder::PngWarningMessage(png_structp pngPtr, png_const_charp message) +{ + if (message == nullptr) { + HiLog::Error(LABEL, "PngWarningMessage message is null."); + return; + } + HiLog::Error(LABEL, "PngWarningMessage, message:%{public}s.", message); +} + +// image incremental decode Interface +uint32_t PngDecoder::ProcessData(png_structp pngStructPtr, png_infop infoStructPtr, InputDataStream *sourceStream, + DataStreamBuffer streamData, size_t bufferSize, size_t totalSize) +{ + if (pngStructPtr == nullptr || infoStructPtr == nullptr || sourceStream == nullptr || totalSize == 0 || + bufferSize == 0) { + HiLog::Error(LABEL, "ProcessData input error, totalSize:%{public}zu, bufferSize:%{public}zu.", totalSize, + bufferSize); + return ERR_IMAGE_INVALID_PARAMETER; + } + while (totalSize > 0) { + size_t readSize = (bufferSize < totalSize) ? bufferSize : totalSize; + uint32_t ret = IncrementalRead(sourceStream, readSize, streamData); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "ProcessData Read from source stream fail, readSize:%{public}zu,\ + bufferSize:%{public}zu, dataSize:%{public}u, totalSize:%{public}zu.", + readSize, bufferSize, streamData.dataSize, totalSize); + return ret; + } + png_process_data(pngStructPtr, infoStructPtr, const_cast(streamData.inputStreamBuffer), + streamData.dataSize); + totalSize -= streamData.dataSize; + } + return SUCCESS; +} + +bool PngDecoder::IsChunk(const png_byte *chunk, const char *flag) +{ + if (chunk == nullptr || flag == nullptr) { + HiLog::Error(LABEL, "IsChunk input parameter exception."); + return false; + } + return memcmp(chunk + CHUNK_DATA_LEN, flag, CHUNK_DATA_LEN) == 0; +} + +bool PngDecoder::GetImageInfo(PngImageInfo &info) +{ + png_uint_32 origWidth = 0; + png_uint_32 origHeight = 0; + int32_t bitDepth = 0; + png_get_IHDR(pngStructPtr_, pngInfoPtr_, &origWidth, &origHeight, &bitDepth, nullptr, nullptr, nullptr, nullptr); + if ((origWidth == 0) || (origHeight == 0) || (origWidth > PNG_UINT_31_MAX) || (origHeight > PNG_UINT_31_MAX)) { + HiLog::Error(LABEL, "Get the png image size abnormal, width:%{public}u, height:%{public}u", origWidth, + origHeight); + return false; + } + if (bitDepth != BITDEPTH_VALUE_1 && bitDepth != BITDEPTH_VALUE_2 && bitDepth != BITDEPTH_VALUE_4 && + bitDepth != BITDEPTH_VALUE_8 && bitDepth != BITDEPTH_VALUE_16) { + HiLog::Error(LABEL, "Get the png image bit depth abnormal, bitDepth:%{public}d.", bitDepth); + return false; + } + size_t rowDataSize = png_get_rowbytes(pngStructPtr_, pngInfoPtr_); + if (rowDataSize == 0) { + HiLog::Error(LABEL, "Get the bitmap row bytes size fail."); + return false; + } + info.numberPasses = png_set_interlace_handling(pngStructPtr_); + info.width = origWidth; + info.height = origHeight; + info.bitDepth = bitDepth; + info.rowDataSize = rowDataSize; + HiLog::Info(LABEL, "GetImageInfo:width:%{public}u,height:%{public}u,bitDepth:%{public}u,numberPasses:%{public}d.", + origWidth, origHeight, info.bitDepth, info.numberPasses); + return true; +} + +uint32_t PngDecoder::IncrementalRead(InputDataStream *stream, uint32_t desiredSize, DataStreamBuffer &outData) +{ + uint32_t curPos = stream->Tell(); + if (!stream->Read(desiredSize, outData)) { + HiLog::Debug(LABEL, "read data fail."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + if (outData.inputStreamBuffer == nullptr || outData.dataSize == 0) { + HiLog::Error(LABEL, "inputStreamBuffer is null or data size is %{public}u.", outData.dataSize); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + if (outData.dataSize < desiredSize) { + stream->Seek(curPos); + HiLog::Debug(LABEL, "read outdata size[%{public}u] < data size[%{public}u] and curpos:%{public}u", + outData.dataSize, desiredSize, curPos); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + return SUCCESS; +} + +uint32_t PngDecoder::GetImageIdatSize(InputDataStream *stream) +{ + uint32_t ret = 0; + DataStreamBuffer readData; + while (true) { + uint32_t preReadPos = stream->Tell(); + ret = IncrementalRead(stream, static_cast(CHUNK_SIZE), readData); + if (ret != SUCCESS) { + break; + } + png_byte *chunk = const_cast(readData.inputStreamBuffer); + const size_t length = png_get_uint_32(chunk); + if (IsChunk(chunk, "IDAT")) { + HiLog::Debug(LABEL, "first idat Length is %{public}zu.", length); + idatLength_ = length; + return SUCCESS; + } + uint32_t afterReadPos = stream->Tell(); + if (!stream->Seek(length + afterReadPos + CHUNK_DATA_LEN)) { + HiLog::Debug(LABEL, "stream current pos is %{public}u, chunk size is %{public}zu.", preReadPos, length); + stream->Seek(preReadPos); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + stream->Seek(afterReadPos); + png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE); + ret = ProcessData(pngStructPtr_, pngInfoPtr_, stream, readData, DECODE_BUFFER_SIZE, length + CHUNK_DATA_LEN); + if (ret != SUCCESS) { + break; + } + } + return ret; +} + +uint32_t PngDecoder::ReadIncrementalHead(InputDataStream *stream, PngImageInfo &info) +{ + if (stream == nullptr) { + HiLog::Error(LABEL, "read incremental head input data is null!"); + return ERR_IMAGE_INVALID_PARAMETER; + } + uint32_t pos = stream->Tell(); + if (!stream->Seek(PNG_HEAD_SIZE)) { + HiLog::Debug(LABEL, "don't enough the data to decode the image head."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + stream->Seek(pos); + // set the exception handle + jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_)); + if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) { + HiLog::Error(LABEL, "read incremental head PNG decode head exception."); + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + + DataStreamBuffer readData; + if (!decodeHeadFlag_) { + png_set_keep_unknown_chunks(pngStructPtr_, PNG_HANDLE_CHUNK_ALWAYS, (png_byte *)"", 0); + png_set_read_user_chunk_fn(pngStructPtr_, static_cast(&ninePatch_), ReadUserChunk); + png_set_progressive_read_fn(pngStructPtr_, nullptr, nullptr, nullptr, nullptr); + uint32_t ret = IncrementalRead(stream, static_cast(CHUNK_SIZE), readData); + if (ret != SUCCESS) { + return ret; + } + png_bytep head = const_cast(readData.inputStreamBuffer); + png_process_data(pngStructPtr_, pngInfoPtr_, head, CHUNK_SIZE); + decodeHeadFlag_ = true; + } + uint32_t ret = GetImageIdatSize(stream); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "get image idat size fail, ret:%{public}u.", ret); + return ret; + } + if (!GetImageInfo(info)) { + return ERR_IMAGE_DECODE_HEAD_ABNORMAL; + } + return SUCCESS; +} + +void PngDecoder::SaveRows(png_bytep row, png_uint_32 rowNum) +{ + if (rowNum != outputRowsNum_ || pngImageInfo_.height < rowNum) { + HiLog::Error(LABEL, + "AllRowsCallback exception, rowNum:%{public}u, outputRowsNum:%{public}u, height:%{public}u.", + rowNum, outputRowsNum_, pngImageInfo_.height); + return; + } + outputRowsNum_++; + uint8_t *offset = pixelsData_ + rowNum * pngImageInfo_.rowDataSize; + uint32_t offsetSize = (pngImageInfo_.height - rowNum) * pngImageInfo_.rowDataSize; + errno_t ret = memcpy_s(offset, offsetSize, row, pngImageInfo_.rowDataSize); + if (ret != 0) { + HiLog::Error(LABEL, "copy data fail, ret:%{public}d, rowDataSize:%{public}u, offsetSize:%{public}u.", ret, + pngImageInfo_.rowDataSize, offsetSize); + return; + } +} + +void PngDecoder::SaveInterlacedRows(png_bytep row, png_uint_32 rowNum, int pass) +{ + if (row == nullptr) { + HiLog::Error(LABEL, "input row is null."); + return; + } + if (rowNum < firstRow_ || rowNum > lastRow_ || interlacedComplete_) { + HiLog::Error(LABEL, "ignore this row, rowNum:%{public}u,InterlacedComplete:%{public}u.", rowNum, + interlacedComplete_); + return; + } + png_bytep oldRow = pixelsData_ + (rowNum - firstRow_) * pngImageInfo_.rowDataSize; + uint64_t mollocByteCount = static_cast(pngImageInfo_.rowDataSize) * pngImageInfo_.height; + uint64_t needByteCount = static_cast(pngStructPtr_->width) * sizeof(*oldRow); + if (mollocByteCount < needByteCount) { + HiLog::Error(LABEL, "malloc byte size is(%{public}llu), but actual needs (%{public}llu)", + static_cast(mollocByteCount), static_cast(needByteCount)); + return; + } + png_progressive_combine_row(pngStructPtr_, oldRow, row); + if (pass == 0) { + // The first pass initializes all rows. + if (outputRowsNum_ == rowNum - firstRow_) { + HiLog::Error(LABEL, "rowNum(%{public}u) - firstRow(%{public}u) = outputRow(%{public}u)", rowNum, firstRow_, + outputRowsNum_); + return; + } + outputRowsNum_++; + } else { + if (outputRowsNum_ == lastRow_ - firstRow_ + 1) { + HiLog::Error(LABEL, "lastRow_(%{public}u) + firstRow(%{public}u) + 1 = outputRow(%{public}u)", lastRow_, + firstRow_, outputRowsNum_); + return; + } + if (pngImageInfo_.numberPasses - 1 == pass && rowNum == lastRow_) { + // Last pass, and we have read all of the rows we care about. + HiLog::Error(LABEL, "last pass:%{public}d, numberPasses:%{public}d, rowNum:%{public}d, lastRow:%{public}d.", + pass, pngImageInfo_.numberPasses, rowNum, lastRow_); + interlacedComplete_ = true; + } + } +} + +void PngDecoder::GetAllRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass) +{ + if (pngPtr == nullptr || row == nullptr) { + HiLog::Error(LABEL, "get decode rows exception, rowNum:%{public}u.", rowNum); + return; + } + PngDecoder *decoder = static_cast(png_get_progressive_ptr(pngPtr)); + if (decoder == nullptr) { + HiLog::Error(LABEL, "get all rows fail, get decoder is null."); + return; + } + decoder->SaveRows(row, rowNum); +} + +void PngDecoder::GetInterlacedRows(png_structp pngPtr, png_bytep row, png_uint_32 rowNum, int pass) +{ + if (pngPtr == nullptr || row == nullptr) { + HiLog::Debug(LABEL, "get decode rows exception, rowNum:%{public}u.", rowNum); + return; + } + PngDecoder *decoder = static_cast(png_get_progressive_ptr(pngPtr)); + if (decoder == nullptr) { + HiLog::Error(LABEL, "get all rows fail, get decoder is null."); + return; + } + decoder->SaveInterlacedRows(row, rowNum, pass); +} + +int32_t PngDecoder::ReadUserChunk(png_structp png_ptr, png_unknown_chunkp chunk) +{ + NinePatchListener *chunkReader = static_cast(png_get_user_chunk_ptr(png_ptr)); + if (chunkReader == nullptr) { + HiLog::Error(LABEL, "chunk header is null."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + return chunkReader->ReadChunk(reinterpret_cast(chunk->name), chunk->data, chunk->size) + ? SUCCESS + : ERR_IMAGE_DECODE_ABNORMAL; +} + +uint32_t PngDecoder::PushAllToDecode(InputDataStream *stream, size_t bufferSize, size_t length) +{ + if (stream == nullptr || bufferSize == 0 || length == 0) { + HiLog::Error(LABEL, "iend process input exception, bufferSize:%{public}zu, length:%{public}zu.", bufferSize, + length); + return ERR_IMAGE_INVALID_PARAMETER; + } + DataStreamBuffer ReadData; + if (ProcessData(pngStructPtr_, pngInfoPtr_, stream, ReadData, bufferSize, length) != SUCCESS) { + HiLog::Error(LABEL, "ProcessData return false, bufferSize:%{public}zu, length:%{public}zu.", bufferSize, + length); + return ERR_IMAGE_DECODE_ABNORMAL; + } + bool iend = false; + uint32_t ret = 0; + while (true) { + // Parse chunk length and type. + ret = IncrementalRead(stream, CHUNK_SIZE, ReadData); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "set iend mode Read chunk fail,ret:%{public}u", ret); + break; + } + png_byte *chunk = const_cast(ReadData.inputStreamBuffer); + png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE); + if (IsChunk(chunk, "IEND")) { + iend = true; + } + size_t chunkLength = png_get_uint_32(chunk); + // Process the full chunk + CRC + ret = ProcessData(pngStructPtr_, pngInfoPtr_, stream, ReadData, bufferSize, chunkLength + CHUNK_DATA_LEN); + if (ret != SUCCESS || iend) { + break; + } + } + return ret; +} + +uint32_t PngDecoder::IncrementalReadRows(InputDataStream *stream) +{ + if (stream == nullptr) { + HiLog::Error(LABEL, "input data is null!"); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + if (idatLength_ < incrementalLength_) { + HiLog::Error(LABEL, "incremental len:%{public}zu > idat len:%{public}zu.", incrementalLength_, idatLength_); + return ERR_IMAGE_INVALID_PARAMETER; + } + // set the exception handle + jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_)); + if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) { + HiLog::Error(LABEL, "[IncrementalReadRows]PNG decode exception."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + // set process decode state to IDAT mode. + if (!decodedIdat_) { + if (pngImageInfo_.numberPasses == 1) { + png_set_progressive_read_fn(pngStructPtr_, this, nullptr, GetAllRows, nullptr); + } else { + png_set_progressive_read_fn(pngStructPtr_, this, nullptr, GetInterlacedRows, nullptr); + lastRow_ = pngImageInfo_.height - 1; // decode begin to 0 + } + png_byte idat[] = { 0, 0, 0, 0, 'I', 'D', 'A', 'T' }; + png_save_uint_32(idat, idatLength_); + png_process_data(pngStructPtr_, pngInfoPtr_, idat, CHUNK_SIZE); + decodedIdat_ = true; + idatLength_ += CHUNK_DATA_LEN; + } + if (stream->IsStreamCompleted()) { + uint32_t ret = PushAllToDecode(stream, DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "iend set fail, ret:%{public}u, idatLen:%{public}zu, incrementalLen:%{public}zu.", ret, + idatLength_, incrementalLength_); + return ret; + } + return SUCCESS; + } + uint32_t ret = PushCurrentToDecode(stream); + if (ret != SUCCESS) { + HiLog::Error(LABEL, + "push stream to decode fail, ret:%{public}u, idatLen:%{public}zu, incrementalLen:%{public}zu.", + ret, idatLength_, incrementalLength_); + return ret; + } + return SUCCESS; +} + +uint32_t PngDecoder::PushCurrentToDecode(InputDataStream *stream) +{ + if (stream == nullptr) { + HiLog::Error(LABEL, "push current stream to decode input data is null!"); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + if (idatLength_ == 0) { + HiLog::Error(LABEL, "idat Length is zero."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + + DataStreamBuffer ReadData; + uint32_t ret = 0; + while (incrementalLength_ < idatLength_) { + const size_t targetSize = std::min(DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_); + ret = IncrementalRead(stream, targetSize, ReadData); + if (ret != SUCCESS) { + HiLog::Debug(LABEL, "push current stream read fail, ret:%{public}u", ret); + return ret; + } + incrementalLength_ += ReadData.dataSize; + png_process_data(pngStructPtr_, pngInfoPtr_, (png_bytep)ReadData.inputStreamBuffer, ReadData.dataSize); + } + + while (true) { + ret = IncrementalRead(stream, CHUNK_SIZE, ReadData); + if (ret != SUCCESS) { + HiLog::Debug(LABEL, "set iend mode Read chunk fail,ret:%{public}u", ret); + break; + } + png_byte *chunk = const_cast(ReadData.inputStreamBuffer); + png_process_data(pngStructPtr_, pngInfoPtr_, chunk, CHUNK_SIZE); + idatLength_ = png_get_uint_32(chunk) + CHUNK_DATA_LEN; + incrementalLength_ = 0; + while (incrementalLength_ < idatLength_) { + const size_t targetSize = std::min(DECODE_BUFFER_SIZE, idatLength_ - incrementalLength_); + ret = IncrementalRead(stream, targetSize, ReadData); + if (ret != SUCCESS) { + HiLog::Debug(LABEL, "push current stream read fail, ret:%{public}u", ret); + return ret; + } + incrementalLength_ += ReadData.dataSize; + png_process_data(pngStructPtr_, pngInfoPtr_, (png_bytep)ReadData.inputStreamBuffer, ReadData.dataSize); + } + } + return ret; +} + +uint32_t PngDecoder::DecodeHeader() +{ + // only state PngDecodingState::SOURCE_INITED and PngDecodingState::BASE_INFO_PARSING can go in this function. + if (inputStreamPtr_->IsStreamCompleted()) { + // decode the png image header + inputStreamPtr_->Seek(0); + } + // incremental decode the png image header + if (state_ == PngDecodingState::SOURCE_INITED) { + inputStreamPtr_->Seek(0); + } else { + inputStreamPtr_->Seek(streamPosition_); + } + uint32_t ret = ReadIncrementalHead(inputStreamPtr_, pngImageInfo_); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + streamPosition_ = inputStreamPtr_->Tell(); + state_ = PngDecodingState::BASE_INFO_PARSING; + } else { + state_ = PngDecodingState::SOURCE_INITED; + HiLog::Error(LABEL, "decode image head, ret:%{public}u.", ret); + } + return ret; + } + if (pngImageInfo_.width == 0 || pngImageInfo_.height == 0) { + HiLog::Error(LABEL, "get width and height fail, height:%{public}u, width:%{public}u.", pngImageInfo_.height, + pngImageInfo_.width); + state_ = PngDecodingState::SOURCE_INITED; + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + streamPosition_ = inputStreamPtr_->Tell(); + state_ = PngDecodingState::BASE_INFO_PARSED; + return SUCCESS; +} + +uint32_t PngDecoder::ConfigInfo(const PixelDecodeOptions &opts) +{ + uint32_t ret = SUCCESS; + bool isComeNinePatchRGB565 = false; + if (ninePatch_.patch_ != nullptr) { + // Do not allow ninepatch decodes to 565,use RGBA_8888; + if (opts.desiredPixelFormat == PlPixelFormat::RGB_565) { + ret = GetDecodeFormat(PlPixelFormat::RGBA_8888, outputFormat_, alphaType_); + isComeNinePatchRGB565 = true; + } + } + if (!isComeNinePatchRGB565) { + ret = GetDecodeFormat(opts.desiredPixelFormat, outputFormat_, alphaType_); + } + if (ret != SUCCESS) { + HiLog::Error(LABEL, "get the color type fail."); + return ERR_IMAGE_DATA_ABNORMAL; + } + + // get the libpng interface exception. + jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_)); + if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) { + HiLog::Error(LABEL, "config decoding info fail."); + return ERR_IMAGE_DATA_ABNORMAL; + } + png_read_update_info(pngStructPtr_, pngInfoPtr_); + return SUCCESS; +} + +uint32_t PngDecoder::DoOneTimeDecode(DecodeContext &context) +{ + if (idatLength_ <= 0) { + HiLog::Error(LABEL, "normal decode the image source incomplete."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + jmp_buf *jmpBuf = &(png_jmpbuf(pngStructPtr_)); + if ((jmpBuf == nullptr) || setjmp(*jmpBuf)) { + HiLog::Error(LABEL, "decode the image fail."); + return ERR_IMAGE_DECODE_ABNORMAL; + } + pixelsData_ = AllocOutputHeapBuffer(context); + if (pixelsData_ == nullptr) { + HiLog::Error(LABEL, "get pixels memory fail."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + inputStreamPtr_->Seek(streamPosition_); + uint32_t ret = IncrementalReadRows(inputStreamPtr_); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "normal decode the image fail, ret:%{public}u", ret); + return ret; + } + streamPosition_ = inputStreamPtr_->Tell(); + return SUCCESS; +} + +bool PngDecoder::FinishOldDecompress() +{ + if (state_ < PngDecodingState::IMAGE_DECODING) { + return true; + } + + InputDataStream *temp = inputStreamPtr_; + Reset(); + inputStreamPtr_ = temp; + // destroy the png decode struct + if (pngStructPtr_ != nullptr) { + png_infopp pngInfoPtr = pngInfoPtr_ ? &pngInfoPtr_ : nullptr; + png_destroy_read_struct(&pngStructPtr_, pngInfoPtr, nullptr); + HiLog::Debug(LABEL, "FinishOldDecompress png_destroy_read_struct"); + } + state_ = PngDecodingState::SOURCE_INITED; + if (InitPnglib()) { + return true; + } + return false; +} + +bool PngDecoder::InitPnglib() +{ + // create the png decode struct + pngStructPtr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PngErrorExit, PngWarning); + pngInfoPtr_ = png_create_info_struct(pngStructPtr_); + // set the libpng exception message callback function + png_set_error_fn(pngStructPtr_, nullptr, PngErrorMessage, PngWarningMessage); + if (pngStructPtr_ == nullptr || pngInfoPtr_ == nullptr) { + HiLog::Error(LABEL, "Png lib init fail."); + return false; + } + return true; +} + +void PngDecoder::DealNinePatch(const PixelDecodeOptions &opts) +{ + if (ninePatch_.patch_ != nullptr) { + if (opts.desiredSize.width > 0 && opts.desiredSize.height > 0) { + const float scaleX = static_cast(opts.desiredSize.width) / pngImageInfo_.width; + const float scaleY = static_cast(opts.desiredSize.height) / pngImageInfo_.height; + ninePatch_.Scale(scaleX, scaleY, opts.desiredSize.width, opts.desiredSize.height); + } + } +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libpngplugin/src/png_ninepatch_res.cpp b/plugins/common/libs/image/libpngplugin/src/png_ninepatch_res.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5856b003c0583c662f83fc41ced4e1a5e1c0caec --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/src/png_ninepatch_res.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "png_ninepatch_res.h" +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace OHOS { +namespace ImagePlugin { +static void Fill9patchOffsets(PngNinePatchRes *patch) +{ + patch->xDivsOffset = sizeof(PngNinePatchRes); + patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t)); + patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t)); +} + +PngNinePatchRes *PngNinePatchRes::Deserialize(void *inData) +{ + PngNinePatchRes *patch = static_cast(inData); + patch->wasDeserialized = true; + Fill9patchOffsets(patch); + + return patch; +} + +void PngNinePatchRes::DeviceToFile() +{ + int32_t *xDivs = GetXDivs(); + for (int i = 0; i < numXDivs; i++) { + xDivs[i] = htonl(xDivs[i]); + } + int32_t *yDivs = GetYDivs(); + for (int i = 0; i < numYDivs; i++) { + yDivs[i] = htonl(yDivs[i]); + } + paddingTop = htonl(paddingTop); + paddingBottom = htonl(paddingBottom); + paddingLeft = htonl(paddingLeft); + paddingRight = htonl(paddingRight); + uint32_t *colors = GetColors(); + for (int i = 0; i < numColors; i++) { + colors[i] = htonl(colors[i]); + } +} + +void PngNinePatchRes::FileToDevice() +{ + int32_t *xDivs = GetXDivs(); + for (int i = 0; i < numXDivs; i++) { + xDivs[i] = ntohl(xDivs[i]); + } + int32_t *yDivs = GetYDivs(); + for (int i = 0; i < numYDivs; i++) { + yDivs[i] = ntohl(yDivs[i]); + } + paddingTop = ntohl(paddingTop); + paddingBottom = ntohl(paddingBottom); + paddingLeft = ntohl(paddingLeft); + paddingRight = ntohl(paddingRight); + uint32_t *colors = GetColors(); + for (int i = 0; i < numColors; i++) { + colors[i] = ntohl(colors[i]); + } +} + +size_t PngNinePatchRes::SerializedSize() const +{ + // The size of this struct is 32 bytes on the 32-bit target system + return 32 + numXDivs * sizeof(int32_t) + numYDivs * sizeof(int32_t) + numColors * sizeof(uint32_t); +} +} // namespace ImagePlugin +} // namespace OHOS \ No newline at end of file diff --git a/plugins/common/libs/image/libwebpplugin/.BUILD.gn.swp b/plugins/common/libs/image/libwebpplugin/.BUILD.gn.swp new file mode 100644 index 0000000000000000000000000000000000000000..c068f13595866da2fde36e45ce1fb30ba183c1bd Binary files /dev/null and b/plugins/common/libs/image/libwebpplugin/.BUILD.gn.swp differ diff --git a/plugins/common/libs/image/libwebpplugin/BUILD.gn b/plugins/common/libs/image/libwebpplugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..f25cfd9f55fdd2593af4455251852cd5f7c69135 --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +#config("webp_public_config") { +# include_dirs = [ "${asdk_dir}/static_library/${target_os}_${target_cpu}/include/external/webp/include" ] +#} + +ohos_shared_library("webpplugin") { + sources = [ + "//foundation/multimedia/image_standard/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp", +# "//foundation/multimedia/image_standard/plugins/common/libs/image/libwebpplugin/src/webp_decoder.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/image", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/common/libs/image/libwebpplugin/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//third_party/flutter/skia/third_party/externals/libwebp/src", + ] + if (use_mingw_win) { + defines = image_decode_windows_defines +# public_configs = [ ":webp_public_config" ] + include_dirs += [ "//foundation/multimedia/image_standard/mock/native/include" ] + + deps = [ + "${asdk_dir}/static_library/${target_os}_${target_cpu}:libwebp-image_static", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + ] + } else { + defines = [ "DUAL_ADAPTER" ] + DUAL_ADAPTER = true + include_dirs += [ "//utils/native/base/include" ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { +# public_configs = [ ":webp_public_config" ] +# aosp_deps = [ "shared_library:libhwui" ] + } + +# external_deps = [ "hilog:libhilog" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("webppluginmetadata") { + source = "webpplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/common/libs/image/libwebpplugin/include/webp_decoder.h b/plugins/common/libs/image/libwebpplugin/include/webp_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..09e48b67ca05a6baf1d822d9c01ed70dd9ef5efa --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/include/webp_decoder.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WEBP_DECODER_H +#define WEBP_DECODER_H + +#include "abs_image_decoder.h" +#include "hilog/log.h" +#include "input_data_stream.h" +#include "log_tags.h" +#include "plugin_class_base.h" +#include "webp/decode.h" +#include "webp/demux.h" + +namespace OHOS { +namespace ImagePlugin { +enum class WebpDecodingState : int32_t { + UNDECIDED = 0, + SOURCE_INITED = 1, + BASE_INFO_PARSING = 2, + BASE_INFO_PARSED = 3, + IMAGE_DECODING = 4, + IMAGE_ERROR = 5, + IMAGE_PARTIAL = 6, + IMAGE_DECODED = 7 +}; + +class WebpDecoder : public AbsImageDecoder, public OHOS::MultimediaPlugin::PluginClassBase { +public: + WebpDecoder(); + ~WebpDecoder() override; + void SetSource(InputDataStream &sourceStream) override; + void Reset() override; + uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) override; + uint32_t Decode(uint32_t index, DecodeContext &context) override; + uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) override; + uint32_t GetImageSize(uint32_t index, PlSize &size) override; + +private: + // private function + DISALLOW_COPY_AND_MOVE(WebpDecoder); + WEBP_CSP_MODE GetWebpDecodeMode(const PlPixelFormat &pixelFormat, bool premul); + uint32_t ReadIncrementalHead(); + uint32_t DecodeHeader(); + bool AllocHeapBuffer(DecodeContext &context, bool isIncremental); + void InitWebpOutput(const DecodeContext &context, WebPDecBuffer &output); + bool PreDecodeProc(DecodeContext &context, WebPDecoderConfig &config, bool isIncremental); + uint32_t DoCommonDecode(DecodeContext &context); + uint32_t DoIncrementalDecode(ProgDecodeContext &context); + void FinishOldDecompress(); + bool IsDataEnough(); + // private members + InputDataStream *stream_ = nullptr; + DataStreamBuffer dataBuffer_; + PlSize webpSize_; + size_t incrementSize_ = 0; // current incremental data size + size_t lastDecodeSize_ = 0; // last decoded data size + int32_t bytesPerPixel_ = 4; // default four bytes for each pixel + WEBP_CSP_MODE webpMode_ = MODE_RGBA; + WebpDecodingState state_ = WebpDecodingState::UNDECIDED; + PixelDecodeOptions opts_; + PlPixelFormat outputFormat_ = PlPixelFormat::UNKNOWN; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // WEBP_DECODER_H diff --git a/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp b/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1b81c859cf3fabcd89496fb94bced9a444be1d9 --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/src/plugin_export.cpp @@ -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. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "webp_decoder.h" + +// plugin package name same as metadata. +PLUGIN_EXPORT_REGISTER_PACKAGE("LibWebpPlugin") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::ImagePlugin::WebpDecoder) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LibWebpPlugin" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin. +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() diff --git a/plugins/common/libs/image/libwebpplugin/src/webp_decoder.cpp b/plugins/common/libs/image/libwebpplugin/src/webp_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0edb089cbd8c26edfb7be9aa0af8deee86a435b4 --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/src/webp_decoder.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "webp_decoder.h" +#include "media_errors.h" +#include "multimedia_templates.h" +#include "securec.h" + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HiviewDFX; +using namespace MultimediaPlugin; +using namespace Media; +using namespace MultiMedia; + +namespace { +constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WebpDecoder" }; +constexpr int32_t WEBP_IMAGE_NUM = 1; +constexpr int32_t EXTERNAL_MEMORY = 1; +constexpr size_t DECODE_VP8CHUNK_MIN_SIZE = 4096; +} // namespace + +WebpDecoder::WebpDecoder() +{} + +WebpDecoder::~WebpDecoder() +{ + Reset(); +} + +void WebpDecoder::SetSource(InputDataStream &sourceStream) +{ + stream_ = &sourceStream; + state_ = WebpDecodingState::SOURCE_INITED; +} + +uint32_t WebpDecoder::GetImageSize(uint32_t index, PlSize &size) +{ + if (index >= WEBP_IMAGE_NUM) { + HiLog::Error(LABEL, "image size:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < WebpDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= WebpDecodingState::BASE_INFO_PARSED) { + size = webpSize_; + return SUCCESS; + } + + uint32_t ret = DecodeHeader(); + if (ret != SUCCESS) { + HiLog::Debug(LABEL, "decode header error on get image ret:%{public}u.", ret); + return ret; + } + size = webpSize_; + return SUCCESS; +} + +uint32_t WebpDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) +{ + if (index >= WEBP_IMAGE_NUM) { + HiLog::Error(LABEL, "set option:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < WebpDecodingState::SOURCE_INITED) { + HiLog::Error(LABEL, "set decode option failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ >= WebpDecodingState::IMAGE_DECODING) { + FinishOldDecompress(); + state_ = WebpDecodingState::SOURCE_INITED; + } + if (state_ < WebpDecodingState::BASE_INFO_PARSED) { + uint32_t ret = DecodeHeader(); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret); + state_ = WebpDecodingState::BASE_INFO_PARSING; + return ret; + } + state_ = WebpDecodingState::BASE_INFO_PARSED; + } + + bool hasAlpha = true; + if (opts.desiredPixelFormat == PlPixelFormat::RGB_565) { + hasAlpha = false; + info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + } else { + info.alphaType = opts.desireAlphaType; + } + webpMode_ = GetWebpDecodeMode(opts.desiredPixelFormat, + hasAlpha && (opts.desireAlphaType == PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL)); + info.size = webpSize_; + info.pixelFormat = outputFormat_; + opts_ = opts; + + state_ = WebpDecodingState::IMAGE_DECODING; + return SUCCESS; +} + +uint32_t WebpDecoder::Decode(uint32_t index, DecodeContext &context) +{ + if (index >= WEBP_IMAGE_NUM) { + HiLog::Error(LABEL, "decode:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + if (state_ < WebpDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "set decode option failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + if (state_ > WebpDecodingState::IMAGE_DECODING) { + FinishOldDecompress(); + uint32_t ret = DecodeHeader(); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret); + state_ = WebpDecodingState::BASE_INFO_PARSING; + return ret; + } + bool hasAlpha = true; + if (opts_.desiredPixelFormat == PlPixelFormat::RGB_565) { + hasAlpha = false; + } + webpMode_ = + GetWebpDecodeMode(opts_.desiredPixelFormat, + hasAlpha && opts_.desireAlphaType == PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL); + state_ = WebpDecodingState::IMAGE_DECODING; + } + + return DoCommonDecode(context); +} + +uint32_t WebpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) +{ + context.totalProcessProgress = 0; + if (index >= WEBP_IMAGE_NUM) { + HiLog::Error(LABEL, "incremental:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM); + return ERR_IMAGE_INVALID_PARAMETER; + } + + if (state_ != WebpDecodingState::IMAGE_DECODING) { + HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_); + return ERR_MEDIA_INVALID_OPERATION; + } + + if (!IsDataEnough()) { + HiLog::Debug(LABEL, "increment data not enough, need next data."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + return DoIncrementalDecode(context); +} + +uint32_t WebpDecoder::DecodeHeader() +{ + uint32_t ret = ReadIncrementalHead(); + if (ret != SUCCESS) { + if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { + state_ = WebpDecodingState::BASE_INFO_PARSING; + } else { + state_ = WebpDecodingState::SOURCE_INITED; + HiLog::Error(LABEL, "decode image head, ret:%{public}u.", ret); + } + return ret; + } + state_ = WebpDecodingState::BASE_INFO_PARSED; + return SUCCESS; +} + +uint32_t WebpDecoder::ReadIncrementalHead() +{ + size_t stremSize = stream_->GetStreamSize(); + if (stremSize >= DECODE_VP8CHUNK_MIN_SIZE || stream_->IsStreamCompleted()) { + stream_->Seek(0); + if (!stream_->Read(stream_->GetStreamSize(), dataBuffer_)) { + HiLog::Error(LABEL, "read data fail."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + if (dataBuffer_.inputStreamBuffer == nullptr || dataBuffer_.dataSize == 0) { + HiLog::Error(LABEL, "inputStreamBuffer is null or data size is %{public}u.", dataBuffer_.dataSize); + return ERR_IMAGE_GET_DATA_ABNORMAL; + } + + int32_t width = 0; + int32_t height = 0; + int32_t ret = WebPGetInfo(dataBuffer_.inputStreamBuffer, dataBuffer_.bufferSize, &width, &height); + if (ret == 0 || (width == 0 && height == 0)) { + // may be incomplete data + HiLog::Error(LABEL, "get width and height fail."); + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + + if (width < 0 || height < 0) { + HiLog::Error(LABEL, "width and height invalid, width:%{public}d, height:%{public}d.", width, height); + return ERR_IMAGE_INVALID_PARAMETER; + } + webpSize_.width = static_cast(width); + webpSize_.height = static_cast(height); + incrementSize_ = stremSize; + lastDecodeSize_ = stremSize; + return SUCCESS; + } + + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; +} + +bool WebpDecoder::IsDataEnough() +{ + size_t streamSize = stream_->GetStreamSize(); + if (incrementSize_ < DECODE_VP8CHUNK_MIN_SIZE && !stream_->IsStreamCompleted()) { + incrementSize_ += streamSize - lastDecodeSize_; + lastDecodeSize_ = streamSize; + return false; + } + incrementSize_ = streamSize - lastDecodeSize_; + lastDecodeSize_ = streamSize; + return true; +} + +WEBP_CSP_MODE WebpDecoder::GetWebpDecodeMode(const PlPixelFormat &pixelFormat, bool premul) +{ + WEBP_CSP_MODE webpMode = MODE_RGBA; + outputFormat_ = pixelFormat; + switch (pixelFormat) { + case PlPixelFormat::BGRA_8888: + webpMode = premul ? MODE_bgrA : MODE_BGRA; + break; + case PlPixelFormat::RGBA_8888: + webpMode = premul ? MODE_rgbA : MODE_RGBA; + break; + case PlPixelFormat::RGB_565: + bytesPerPixel_ = 2; // RGB_565 2 bytes each pixel + webpMode = MODE_RGB_565; + break; + case PlPixelFormat::UNKNOWN: + default: + outputFormat_ = PlPixelFormat::RGBA_8888; + webpMode = premul ? MODE_rgbA : MODE_RGBA; + break; + } + return webpMode; +} + +void WebpDecoder::FinishOldDecompress() +{ + if (state_ < WebpDecodingState::IMAGE_DECODING) { + return; + } + Reset(); +} + +uint32_t WebpDecoder::DoCommonDecode(DecodeContext &context) +{ + WebPDecoderConfig config; + if (!PreDecodeProc(context, config, false)) { + HiLog::Error(LABEL, "prepare common decode failed."); + state_ = WebpDecodingState::IMAGE_ERROR; + return ERR_IMAGE_MALLOC_ABNORMAL; + } + + TAutoCallProc webpOutput(&config.output); + TAutoCallProc idec(WebPINewDecoder(&config.output)); + if (idec == nullptr) { + HiLog::Error(LABEL, "common decode:idec is null."); + state_ = WebpDecodingState::IMAGE_ERROR; + return ERR_IMAGE_DECODE_FAILED; + } + + VP8StatusCode status = WebPIUpdate(idec, dataBuffer_.inputStreamBuffer, static_cast(dataBuffer_.dataSize)); + if (status == VP8_STATUS_OK) { + state_ = WebpDecodingState::IMAGE_DECODED; + return SUCCESS; + } + if (status == VP8_STATUS_SUSPENDED && opts_.allowPartialImage) { + state_ = WebpDecodingState::IMAGE_PARTIAL; + context.ifPartialOutput = true; + HiLog::Error(LABEL, "this is partial image data to decode."); + return SUCCESS; + } + + HiLog::Error(LABEL, "decode image data failed, status:%{public}d.", status); + state_ = WebpDecodingState::IMAGE_ERROR; + return ERR_IMAGE_DECODE_FAILED; +} + +uint32_t WebpDecoder::DoIncrementalDecode(ProgDecodeContext &context) +{ + WebPDecoderConfig config; + if (!PreDecodeProc(context.decodeContext, config, true)) { + HiLog::Error(LABEL, "prepare increment decode failed."); + return ERR_IMAGE_MALLOC_ABNORMAL; + } + + TAutoCallProc webpOutput(&config.output); + TAutoCallProc idec(WebPINewDecoder(&config.output)); + if (idec == nullptr) { + HiLog::Error(LABEL, "incremental code:idec is null."); + return ERR_IMAGE_DECODE_FAILED; + } + + dataBuffer_ = { nullptr, 0, 0 }; + stream_->Seek(0); + if (!stream_->Read(stream_->GetStreamSize(), dataBuffer_)) { + HiLog::Error(LABEL, "incremental:read data failed."); + return ERR_IMAGE_DECODE_FAILED; + } + if (dataBuffer_.inputStreamBuffer == nullptr || dataBuffer_.dataSize == 0) { + HiLog::Error(LABEL, "incremental:data is null."); + return ERR_IMAGE_DECODE_FAILED; + } + + VP8StatusCode status = WebPIUpdate(idec, dataBuffer_.inputStreamBuffer, static_cast(dataBuffer_.dataSize)); + if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { + HiLog::Error(LABEL, "incremental:webp status exception,status:%{public}d.", status); + return ERR_IMAGE_DECODE_FAILED; + } + if (status == VP8_STATUS_SUSPENDED) { + int32_t curHeight = 0; + if (WebPIDecGetRGB(idec, &curHeight, nullptr, nullptr, nullptr) == nullptr) { + HiLog::Debug(LABEL, "refresh image failed, current height:%{public}d.", curHeight); + } + if (curHeight > 0 && webpSize_.height != 0) { + context.totalProcessProgress = + static_cast(curHeight) * ProgDecodeContext::FULL_PROGRESS / webpSize_.height; + } + return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; + } + if (status == VP8_STATUS_OK) { + context.totalProcessProgress = context.FULL_PROGRESS; + state_ = WebpDecodingState::IMAGE_DECODED; + } + return SUCCESS; +} + +void WebpDecoder::InitWebpOutput(const DecodeContext &context, WebPDecBuffer &output) +{ + output.is_external_memory = EXTERNAL_MEMORY; // external allocated space + output.u.RGBA.rgba = static_cast(context.pixelsBuffer.buffer); + output.u.RGBA.stride = webpSize_.width * bytesPerPixel_; + output.u.RGBA.size = context.pixelsBuffer.bufferSize; + output.colorspace = webpMode_; +} + +bool WebpDecoder::PreDecodeProc(DecodeContext &context, WebPDecoderConfig &config, bool isIncremental) +{ + if (WebPInitDecoderConfig(&config) == 0) { + HiLog::Error(LABEL, "init config failed."); + return false; + } + if (!AllocHeapBuffer(context, isIncremental)) { + HiLog::Error(LABEL, "get pixels memory failed."); + return false; + } + + InitWebpOutput(context, config.output); + return true; +} + +void WebpDecoder::Reset() +{ + stream_->Seek(0); + dataBuffer_ = { nullptr, 0, 0 }; + webpSize_ = { 0, 0 }; +} + +bool WebpDecoder::AllocHeapBuffer(DecodeContext &context, bool isIncremental) +{ + if (isIncremental) { + if (context.pixelsBuffer.buffer != nullptr && context.allocatorType == AllocatorType::HEAP_ALLOC) { + free(context.pixelsBuffer.buffer); + context.pixelsBuffer.buffer = nullptr; + } + } + + if (context.pixelsBuffer.buffer == nullptr) { + uint64_t byteCount = static_cast(webpSize_.width) * webpSize_.height * bytesPerPixel_; + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { +#ifndef _WIN32 + int fd = AshmemCreate("WEBP RawData", byteCount); + if (fd < 0) { + return false; + } + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + if (result < 0) { + ::close(fd); + return false; + } + void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + return false; + } + context.pixelsBuffer.buffer = ptr; + void *fdBuffer = new int32_t(); + if (fdBuffer == nullptr) { + HiLog::Error(LABEL, "malloc fdBuffer fail"); + ::munmap(ptr, byteCount); + ::close(fd); + context.pixelsBuffer.buffer = nullptr; + return false; + } + *static_cast(fdBuffer) = fd; + context.pixelsBuffer.context = fdBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.allocatorType = AllocatorType::SHARE_MEM_ALLOC; + context.freeFunc = nullptr; +#endif + } else { + void *outputBuffer = malloc(byteCount); + if (outputBuffer == nullptr) { + HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.", + static_cast(byteCount)); + return false; + } +#ifdef _WIN32 + memset(outputBuffer, 0, byteCount); +#else + if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) { + HiLog::Error(LABEL, "memset buffer failed."); + free(outputBuffer); + outputBuffer = nullptr; + return false; + } +#endif + context.pixelsBuffer.buffer = outputBuffer; + context.pixelsBuffer.bufferSize = byteCount; + context.pixelsBuffer.context = nullptr; + context.allocatorType = AllocatorType::HEAP_ALLOC; + context.freeFunc = nullptr; + } + } + return true; +} +} // namespace ImagePlugin +} // namespace OHOS diff --git a/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta b/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta new file mode 100644 index 0000000000000000000000000000000000000000..9a2fa908791ccc1d91b3b31cd665d6cb354de480 --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/webpplugin.pluginmeta @@ -0,0 +1,25 @@ +{ + "packageName":"LibWebpPlugin", + "version":"1.0.0.0", + "targetVersion":"1.0.0.0", + "libraryPath":"libwebpplugin.z.so", + "classes": [ + { + "className":"OHOS::ImagePlugin::WebpDecoder", + "services": [ + { + "interfaceID":2, + "serviceType":0 + } + ], + "priority":100, + "capabilities": [ + { + "name":"encodeFormat", + "type":"string", + "value": "image/webp" + } + ] + } + ] +} diff --git a/plugins/manager/BUILD.gn b/plugins/manager/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..021436aa2efa63acb38a308251cf5292898c2af5 --- /dev/null +++ b/plugins/manager/BUILD.gn @@ -0,0 +1,149 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +ohos_shared_library("pluginmanager") { + sources = [ + "//foundation/multimedia/image_standard/plugins/manager/src/common/attr_data.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/common/platform_adp.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/capability.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/impl_class.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/impl_class_key.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/impl_class_mgr.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/json_helper.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin_fw.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin_info_lock.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin_mgr.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/plugin_server.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/pluginbase/plugin_class_base.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/include/utils", + "//foundation/multimedia/image_standard/plugins/manager/src/common", + "//foundation/multimedia/image_standard/plugins/manager/src/framework", + "//foundation/multimedia/image_standard/plugins/manager/src/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/src/thirdpartyadp/gstreamer", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//third_party/json/single_include/nlohmann", + "//third_party/boost/tools/build/src/engine", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + #"//foundation/multimedia/image_standard/mock/native/include/secure", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//utils/native/base:utilsecurec", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + + ldflags = [ "-Wl,-Bsymbolic" ] + + deps = [ "//utils/native/base:utils" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + subsystem_name = "multimedia" + part_name = "multimedia_image" +} + +ohos_static_library("pluginmanager_static") { + sources = [ + "//foundation/multimedia/image_standard/plugins/manager/src/common/attr_data.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/common/platform_adp.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/capability.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/impl_class.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/impl_class_key.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/impl_class_mgr.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/json_helper.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin_fw.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin_info_lock.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/framework/plugin_mgr.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/plugin_server.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/pluginbase/plugin_class_base.cpp", + "//foundation/multimedia/image_standard/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.cpp", + ] + + include_dirs = [ + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/include/utils", + "//foundation/multimedia/image_standard/plugins/manager/src/common", + "//foundation/multimedia/image_standard/plugins/manager/src/framework", + "//foundation/multimedia/image_standard/plugins/manager/src/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/src/thirdpartyadp/gstreamer", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//third_party/json/single_include/nlohmann", + "//third_party/boost/tools/build/src/engine", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + #"//foundation/multimedia/image_standard/mock/native/include/secure", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//utils/native/base/include", + ] + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//foundation/multimedia/image_standard/mock/native:utils_mock_static", + "//utils/native/base:utilsecurec", + ] + } else { + include_dirs += [ "//utils/native/base/include" ] + + ldflags = [ "-Wl,-Bsymbolic" ] + + deps = [ "//utils/native/base:utils" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } +} diff --git a/plugins/manager/include/attr_data.h b/plugins/manager/include/attr_data.h new file mode 100644 index 0000000000000000000000000000000000000000..90a85bf536473ddd805b9df0a78201a1a4c8d7b8 --- /dev/null +++ b/plugins/manager/include/attr_data.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ATTR_DATA_H +#define ATTR_DATA_H + +#include +#include +#include "plugin_errors.h" + +namespace OHOS { +namespace MultimediaPlugin { +enum class AttrDataType : int32_t { + ATTR_DATA_NULL = 0, + ATTR_DATA_BOOL, + ATTR_DATA_UINT32, + ATTR_DATA_STRING, + ATTR_DATA_UINT32_SET, + ATTR_DATA_STRING_SET, + ATTR_DATA_UINT32_RANGE, + ATTR_DATA_TYPE_INVALID +}; + +class AttrData final { +public: + AttrData(); + explicit AttrData(bool value); + explicit AttrData(uint32_t value); + explicit AttrData(const std::string &value); + explicit AttrData(std::string &&value); + AttrData(uint32_t lowerBound, uint32_t upperBound); + AttrData(const AttrData &data); + AttrData(AttrData &&data) noexcept; + ~AttrData(); + + AttrData &operator=(const AttrData &data); + AttrData &operator=(AttrData &&data) noexcept; + + void SetData(bool value); + void SetData(uint32_t value); + uint32_t SetData(const std::string &value); + uint32_t SetData(std::string &&value); + uint32_t SetData(uint32_t lowerBound, uint32_t upperBound); + void ClearData(); + + uint32_t InsertSet(uint32_t value); + uint32_t InsertSet(const std::string &value); + uint32_t InsertSet(std::string &&value); + + bool InRange(bool value) const; + bool InRange(uint32_t value) const; + bool InRange(const std::string &value) const; + bool InRange(const AttrData &data) const; + + AttrDataType GetType() const; + uint32_t GetMinValue(uint32_t &value) const; + uint32_t GetMaxValue(uint32_t &value) const; + uint32_t GetMinValue(const std::string *&value) const; + uint32_t GetMaxValue(const std::string *&value) const; + + uint32_t GetValue(bool &value) const; + uint32_t GetValue(uint32_t &value) const; + uint32_t GetValue(std::string &value) const; + uint32_t GetValue(const std::string *&value) const; + + static constexpr uint8_t RANGE_ARRAY_SIZE = 2; + static constexpr uint8_t LOWER_BOUND_INDEX = 0; + static constexpr uint8_t UPPER_BOUND_INDEX = 1; + +private: + uint32_t InitStringAttrData(const AttrData &data); + uint32_t InitUint32SetAttrData(const AttrData &data); + uint32_t InitStringSetAttrData(const AttrData &data); + bool InRangeUint32Range(uint32_t value) const; + bool InRange(const std::set &uint32Set) const; + bool InRange(const std::set &stringSet) const; + bool InRange(const uint32_t (&uint32Rang)[RANGE_ARRAY_SIZE]) const; + + AttrDataType type_; + union AttrDataUnion { + bool boolValue; + uint32_t uint32Value; + uint32_t uint32Rang[RANGE_ARRAY_SIZE]; + std::set *uint32Set; + std::string *stringValue; + std::set *stringSet; + }; + AttrDataUnion value_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // ATTR_DATA_H diff --git a/plugins/manager/include/image/abs_image_decoder.h b/plugins/manager/include/image/abs_image_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..801719b8b13b841bb362d566f7fc8aa983d86f98 --- /dev/null +++ b/plugins/manager/include/image/abs_image_decoder.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ABS_IMAGE_DECODER_H +#define ABS_IMAGE_DECODER_H + +#include +#include +#include +#include +#include +#if !defined(_WIN32) && !defined(_APPLE) +#include +#include "ashmem.h" +#endif +#include "image_plugin_type.h" +#include "input_data_stream.h" +#include "media_errors.h" +#include "pixel_map.h" +#include "plugin_service.h" + +namespace OHOS { +namespace ImagePlugin { +const std::string ACTUAL_IMAGE_ENCODED_FORMAT = "actual_encoded_format"; + +struct NinePatchContext { + // png nine patch info + void *ninePatch = nullptr; + // png nine patch info size; + size_t patchSize = 0; +}; +struct DecodeContext { + // In: input the image head info. + PlImageInfo info; + // InOut: input the buffer and bufferSize, output pixels data and dataSize. + PlImageBuffer pixelsBuffer; + // In: whether the source data is completed. + // data incomplete may occur when it is in incremental data source. + // when this state is false, data incomplete is not an exception, + // so the decoding cannot be failed because data incomplete, + // but should decode as much as possible based on the existing data. + bool ifSourceCompleted = true; + // Out: output the PixelFormat. + PlPixelFormat pixelFormat = PlPixelFormat::RGBA_8888; + // Out: output the ColorSpace. + PlColorSpace colorSpace = PlColorSpace::UNKNOWN; + // Out: output if a partial image output. + bool ifPartialOutput = false; + // Out: output allocator type. + Media::AllocatorType allocatorType = Media::AllocatorType::HEAP_ALLOC; + // Out: output allocator release function. + Media::CustomFreePixelMap freeFunc = nullptr; + // Out: png nine patch context; + NinePatchContext ninePatchContext; +}; + +struct ProgDecodeContext { + DecodeContext decodeContext; + + static constexpr uint8_t DEFAULT_STEP = 10; + static constexpr uint8_t FULL_PROGRESS = 100; + // In: step size requesting advancement, in percentage, 1-100. + // if it is an incremental data source and the remaining image data does not + // reach the required amount, try to decode to the maximum possible number. + uint8_t desiredStep = DEFAULT_STEP; + + // InOut: in percentage, 1-100. + // input total process progress after last decoding step, + // output total process progress after current decoding step. + uint8_t totalProcessProgress = 0; +}; + +struct PixelDecodeOptions { + PlRect CropRect; + PlSize desiredSize; + float rotateDegrees = 0; + static constexpr uint32_t DEFAULT_SAMPLE_SIZE = 1; + uint32_t sampleSize = DEFAULT_SAMPLE_SIZE; + PlPixelFormat desiredPixelFormat = PlPixelFormat::RGBA_8888; + PlColorSpace desiredColorSpace = PlColorSpace::UNKNOWN; + PlAlphaType desireAlphaType = PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL; + bool allowPartialImage = true; + bool editable = false; +}; + +class AbsImageDecoder { +public: + static constexpr uint32_t DEFAULT_IMAGE_NUM = 1; + + AbsImageDecoder() = default; + + virtual ~AbsImageDecoder() = default; + + // set image file source, start a new picture decoding process. + // the InputDataStream points to the beginning of the image file. + virtual void SetSource(InputDataStream &sourceStream) = 0; + + // reset the decoder, clear all the decoder's status data cache. + virtual void Reset() = 0; + + // judge a image source has a property or not. + virtual bool HasProperty(std::string key) + { + return false; + } + + // set decode options before decode and get target decoded image info. + virtual uint32_t SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info) = 0; + + // One-time decoding. + virtual uint32_t Decode(uint32_t index, DecodeContext &context) = 0; + + // incremental decoding. + virtual uint32_t PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context) = 0; + + // get the number of top level images in the image file. + virtual uint32_t GetTopLevelImageNum(uint32_t &num) + { + num = DEFAULT_IMAGE_NUM; + return Media::SUCCESS; + } + + // get image size without decoding image data. + virtual uint32_t GetImageSize(uint32_t index, PlSize &size) = 0; + + // get image property. + virtual uint32_t GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) + { + return Media::ERR_MEDIA_INVALID_OPERATION; + } + + // get image property. + virtual uint32_t GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) + { + return Media::ERR_MEDIA_INVALID_OPERATION; + } + + // define multiple subservices for this interface + static constexpr uint16_t SERVICE_DEFAULT = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +DECLARE_INTERFACE(OHOS::ImagePlugin::AbsImageDecoder, IMAGE_DECODER_IID) + +#endif // ABS_IMAGE_DECODER_H diff --git a/plugins/manager/include/image/abs_image_decompress_component.h b/plugins/manager/include/image/abs_image_decompress_component.h new file mode 100644 index 0000000000000000000000000000000000000000..5ffc3ee08210f78b29d4a5f1a9cc8a11f828528a --- /dev/null +++ b/plugins/manager/include/image/abs_image_decompress_component.h @@ -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. + */ + +#ifndef ABS_IMAGE_DECOMPRESS_H +#define ABS_IMAGE_DECOMPRESS_H + +#include "image_plugin_type.h" +#include "input_data_stream.h" +#include "plugin_service.h" +#include "media_errors.h" +#include "pixel_map.h" + +namespace OHOS { +namespace ImagePlugin { +class AbsImageDecompressComponent { +public: + + AbsImageDecompressComponent() = default; + virtual ~AbsImageDecompressComponent() = default; + virtual uint32_t Decompress(void *decompressInfo, InputDataStream *stream, DecodeContext &context) = 0; + // define multiple subservices for this interface + static constexpr uint16_t SERVICE_DEFAULT = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +DECLARE_INTERFACE(OHOS::ImagePlugin::AbsImageDecompressComponent, IMAGE_DECOMPRESS_COMP_IID) + +#endif // ABS_IMAGE_DECOMPRESS_H diff --git a/plugins/manager/include/image/abs_image_encoder.h b/plugins/manager/include/image/abs_image_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..9692e0f02f861733196fed27de85bb0b897d4239 --- /dev/null +++ b/plugins/manager/include/image/abs_image_encoder.h @@ -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. + */ + +#ifndef ABS_IMAGE_ENCODER_H +#define ABS_IMAGE_ENCODER_H + +#include "pixel_map.h" +#include "image_plugin_type.h" +#include "output_data_stream.h" +#include "plugin_service.h" + +namespace OHOS { +namespace ImagePlugin { +struct PlEncodeOptions { + uint8_t quality = 100; + uint32_t numberHint = 1; +}; + +class AbsImageEncoder { +public: + AbsImageEncoder() = default; + virtual ~AbsImageEncoder() = default; + virtual uint32_t StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option) = 0; + virtual uint32_t AddImage(Media::PixelMap &pixelMap) = 0; + virtual uint32_t FinalizeEncode() = 0; + + // define multiple subservices for this interface + static constexpr uint16_t SERVICE_DEFAULT = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +DECLARE_INTERFACE(OHOS::ImagePlugin::AbsImageEncoder, IMAGE_ENCODER_IID) + +#endif // ABS_IMAGE_ENCODER_H diff --git a/plugins/manager/include/image/abs_image_format_agent.h b/plugins/manager/include/image/abs_image_format_agent.h new file mode 100644 index 0000000000000000000000000000000000000000..f7f2aeedf9bc9e9780df18578ef6ae6ab9eb5a98 --- /dev/null +++ b/plugins/manager/include/image/abs_image_format_agent.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ABS_IMAGE_FORMAT_AGENT_H +#define ABS_IMAGE_FORMAT_AGENT_H + +#include +#include "image_plugin_type.h" +#include "plugin_service.h" + +namespace OHOS { +namespace ImagePlugin { +class AbsImageFormatAgent { +public: + // get the image encoded format supported by this class. + virtual std::string GetFormatType() = 0; + + // get the header size of the encoded format. + // it is used to determine the size of the image data that + // needs to be passed to the function of CheckFormat(). + virtual uint32_t GetHeaderSize() = 0; + + // check if the image is in this encoded format, if it returns true. + virtual bool CheckFormat(const void *headerData, uint32_t dataSize) = 0; + + // define multiple subservices for this interface. + static constexpr uint16_t SERVICE_DEFAULT = 0; +}; +} // namespace ImagePlugin +} // namespace OHOS + +DECLARE_INTERFACE(OHOS::ImagePlugin::AbsImageFormatAgent, IMAGE_FORMAT_AGENT_IID) + +#endif // ABS_IMAGE_FORMAT_AGENT_H diff --git a/plugins/manager/include/image/image_plugin_type.h b/plugins/manager/include/image/image_plugin_type.h new file mode 100644 index 0000000000000000000000000000000000000000..a1f4d95c79e101d2b61de8201637aefd3c43505c --- /dev/null +++ b/plugins/manager/include/image/image_plugin_type.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_PLUGIN_TYPE_H +#define IMAGE_PLUGIN_TYPE_H + +#include + +namespace OHOS { +namespace ImagePlugin { +enum class PlColorSpace { + // unknown color space. + UNKNOWN = 0, + + // based on SMPTE RP 431-2-2007 & IEC 61966-2.1:1999. + DISPLAY_P3 = 1, + + // standard Red Green Blue based on IEC 61966-2.1:1999. + SRGB = 2, + + // SRGB with a linear transfer function based on IEC 61966-2.1:1999. + LINEAR_SRGB = 3, + + // based on IEC 61966-2-2:2003. + EXTENDED_SRGB = 4, + + // based on IEC 61966-2-2:2003. + LINEAR_EXTENDED_SRGB = 5, + + // based on standard illuminant D50 as the white point. + GENERIC_XYZ = 6, + + // based on CIE XYZ D50 as the profile conversion space. + GENERIC_LAB = 7, + + // based on SMPTE ST 2065-1:2012. + ACES = 8, + + // based on Academy S-2014-004. + ACES_CG = 9, + + // based on Adobe RGB (1998). + ADOBE_RGB_1998 = 10, + + // based on SMPTE RP 431-2-2007. + DCI_P3 = 11, + + // based on Rec. ITU-R BT.709-5. + ITU_709 = 12, + + // based on Rec. ITU-R BT.2020-1. + ITU_2020 = 13, + + // based on ROMM RGB ISO 22028-2:2013. + ROMM_RGB = 14, + + // based on 1953 standard. + NTSC_1953 = 15, + + // based on SMPTE C. + SMPTE_C = 16 +}; + +enum class PlEncodedFormat { + UNKNOWN = 0, + JPEG = 1, + PNG = 2, + GIF = 3, + HEIF = 4 +}; + +enum class PlPixelFormat { + UNKNOWN = 0, + ARGB_8888 = 1, + RGB_565 = 2, + RGBA_8888 = 3, + BGRA_8888 = 4, + RGB_888 = 5, + ALPHA_8 = 6, + RGBA_F16 = 7, + NV21 = 8, + NV12 = 9, + CMYK = 10, +}; + +enum class PlAlphaType : int32_t { + IMAGE_ALPHA_TYPE_UNKNOWN = 0, + IMAGE_ALPHA_TYPE_OPAQUE = 1, + IMAGE_ALPHA_TYPE_PREMUL = 2, + IMAGE_ALPHA_TYPE_UNPREMUL = 3, +}; + +struct PlPosition { + uint32_t x = 0; + uint32_t y = 0; +}; + +struct PlRect { + uint32_t left = 0; + uint32_t top = 0; + uint32_t width = 0; + uint32_t height = 0; +}; + +struct PlSize { + uint32_t width = 0; + uint32_t height = 0; +}; + +struct PlImageInfo { + PlSize size; + PlPixelFormat pixelFormat = PlPixelFormat::UNKNOWN; + PlColorSpace colorSpace = PlColorSpace::UNKNOWN; + PlAlphaType alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; +}; + +struct PlImageBuffer { + void *buffer = nullptr; + uint32_t bufferSize = 0; + uint32_t dataSize = 0; + void *context = nullptr; +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // IMAGE_PLUGIN_TYPE_H \ No newline at end of file diff --git a/plugins/manager/include/image/input_data_stream.h b/plugins/manager/include/image/input_data_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..a2f6f514e8b434d788ea76d522e752c7d0daddba --- /dev/null +++ b/plugins/manager/include/image/input_data_stream.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INPUT_DATA_STREAM_H +#define INPUT_DATA_STREAM_H + +#include +#include "nocopyable.h" + +namespace OHOS { +namespace ImagePlugin { +enum { + BUFFER_SOURCE_TYPE, + INPUT_STREAM_TYPE, + FILE_STREAM_TYPE, +}; + +struct DataStreamBuffer { + // Out: output a pointer containing a data buffer. + // the buffer is managed by SourceStream, and the user does not need to alloc for a buffer himself. + // and the buffer is guaranteed to remain valid until the next operation on the SourceStream object. + const uint8_t *inputStreamBuffer = nullptr; + // Out: output buffer size. + uint32_t bufferSize = 0; + // Out: output actual valid data size in the buffer. + uint32_t dataSize = 0; +}; + +class InputDataStream : NoCopyable { +public: + // extracts desiredSize bytes from the InputDataStream. + virtual bool Read(uint32_t desiredSize, DataStreamBuffer &outData) = 0; + + // need to copy desiredSize bytes from the InputDataStream to outBuffer. + virtual bool Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) = 0; + + // output the remaining data in the InputDataStream, without extracting it. + virtual bool Peek(uint32_t desiredSize, DataStreamBuffer &outData) = 0; + + // need to copy desiredSize bytes from the InputDataStream to outBuffer and without extracting it. + virtual bool Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize) = 0; + + // get the position of the current byte in the InputDataStream. + virtual uint32_t Tell() = 0; + + // sets the position of the next byte to be extracted from the input stream. + virtual bool Seek(uint32_t position) = 0; + + // get inherited class type + virtual uint32_t GetStreamType() { return -1; } + + // get raw pointer for BUFFER TYPE + virtual uint8_t *GetDataPtr() { return nullptr; } + + // whether the stream data is completed or not. + virtual bool IsStreamCompleted() { return true; } + + // get stream size + virtual size_t GetStreamSize() { return 0; } + + virtual ~InputDataStream() {} +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // INPUT_DATA_STREAM_H \ No newline at end of file diff --git a/plugins/manager/include/image/output_data_stream.h b/plugins/manager/include/image/output_data_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..a9dc40b913c02073ea6adbb8e9cdb1e0c603cc37 --- /dev/null +++ b/plugins/manager/include/image/output_data_stream.h @@ -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. + */ + +#ifndef OUTPUT_DATA_STREAM_H +#define OUTPUT_DATA_STREAM_H + +#include + +namespace OHOS { +namespace ImagePlugin { +class OutputDataStream { +public: + virtual ~OutputDataStream() {} + virtual bool Write(const uint8_t *buffer, uint32_t size) = 0; + virtual void Flush() {} +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // OUTPUT_DATA_STREAM_H \ No newline at end of file diff --git a/plugins/manager/include/plugin_class_base.h b/plugins/manager/include/plugin_class_base.h new file mode 100644 index 0000000000000000000000000000000000000000..2c83d388c7ad72eea5e5bf4a37afbd1dab789360 --- /dev/null +++ b/plugins/manager/include/plugin_class_base.h @@ -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. + */ + +#ifndef PLUGIN_CLASS_BASE_H +#define PLUGIN_CLASS_BASE_H + +#include + +namespace OHOS { +namespace MultimediaPlugin { +class AbsImplClassKey; + +class PluginClassBase { +public: + PluginClassBase() = default; + virtual ~PluginClassBase(); + static constexpr uint32_t MAGIC_CODE = 0x1122CCFF; + +private: + friend class ImplClass; + // the plugin manager guarantees that the key object continue to be valid until the plugin object is destroyed. + // return MAGIC_CODE used to check if the plugin class correctly inherits the PluginClassBase class. + uint32_t SetImplClassKey(AbsImplClassKey &key); + AbsImplClassKey *implClassKey_ = nullptr; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_CLASS_BASE_H diff --git a/plugins/manager/include/plugin_common_type.h b/plugins/manager/include/plugin_common_type.h new file mode 100644 index 0000000000000000000000000000000000000000..3b540caec37b415505550b6bb4fda6556cf58026 --- /dev/null +++ b/plugins/manager/include/plugin_common_type.h @@ -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. + */ + +#ifndef PLUGIN_COMMON_TYPE_H +#define PLUGIN_COMMON_TYPE_H + +#include +#include +#include "attr_data.h" + +namespace OHOS { +namespace MultimediaPlugin { +struct ClassInfo { + std::string packageName; + std::string className; + uint16_t priority; + std::map capabilities; +}; + +constexpr uint32_t UINT16_MAX_VALUE = 0xFFFFUL; +constexpr uint32_t UINT32_MAX_VALUE = 0xFFFFFFFFUL; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_COMMON_TYPE_H diff --git a/plugins/manager/include/plugin_errors.h b/plugins/manager/include/plugin_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..e82be276e86758b7a6a057ee64d69af938b29560 --- /dev/null +++ b/plugins/manager/include/plugin_errors.h @@ -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. + */ + +#ifndef PLUGIN_ERRORS_H +#define PLUGIN_ERRORS_H + +#include "errors.h" +#include "modules.h" + +namespace OHOS { +namespace MultimediaPlugin { +constexpr uint32_t BASE_PLUGIN_ERR_OFFSET = ErrCodeOffset(SUBSYS_MULTIMEDIA, MODULE_PLUGIN); + +constexpr uint32_t SUCCESS = 0; // Operation succeed +constexpr uint32_t ERR_GENERAL = BASE_PLUGIN_ERR_OFFSET; // General error +constexpr uint32_t ERR_INTERNAL = BASE_PLUGIN_ERR_OFFSET + 1; +constexpr uint32_t ERR_INVALID_PARAMETER = BASE_PLUGIN_ERR_OFFSET + 2; +constexpr uint32_t ERR_UNSUPPORTED = BASE_PLUGIN_ERR_OFFSET + 3; +constexpr uint32_t ERR_MATCHING_PLUGIN = BASE_PLUGIN_ERR_OFFSET + 4; +constexpr uint32_t ERR_INSTANCE_LIMIT = BASE_PLUGIN_ERR_OFFSET + 5; +constexpr uint32_t ERR_COMP_EQUAL = BASE_PLUGIN_ERR_OFFSET + 6; +constexpr uint32_t ERR_COMP_ERROR = BASE_PLUGIN_ERR_OFFSET + 7; +constexpr uint32_t ERR_COMP_LOWER = BASE_PLUGIN_ERR_OFFSET + 8; +constexpr uint32_t ERR_COMP_HIGHER = BASE_PLUGIN_ERR_OFFSET + 9; +constexpr uint32_t ERR_NO_TARGET = BASE_PLUGIN_ERR_OFFSET + 10; +constexpr uint32_t ERR_DATA_TYPE = BASE_PLUGIN_ERR_OFFSET + 11; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_ERRORS_H diff --git a/plugins/manager/include/plugin_server.h b/plugins/manager/include/plugin_server.h new file mode 100644 index 0000000000000000000000000000000000000000..465a7576c3fff2802996c7a27441d3efa768a587 --- /dev/null +++ b/plugins/manager/include/plugin_server.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_SERVER_H +#define PLUGIN_SERVER_H + +#include +#include +#include +#include +#include "singleton.h" +#include "attr_data.h" +#include "plugin_class_base.h" +#include "plugin_common_type.h" +#include "plugin_errors.h" +#include "plugin_service.h" +#include "priority_scheme.h" + +namespace OHOS { +namespace MultimediaPlugin { +class PlatformAdp; +class PluginFw; +class GstPluginFw; + +enum class PluginFWType : int32_t { + PLUGIN_FW_GENERAL = 0, + PLUGIN_FW_GSTREAMER +}; + +class PluginServer final : public NoCopyable { +public: + uint32_t Register(std::vector &&pluginPaths); + + template + inline T *CreateObject(const std::string &className, uint32_t &errorCode) + { + uint16_t interfaceID = GetInterfaceId(); + return ConvertToServiceInterface(CreateObject(interfaceID, className, errorCode)); + } + + template + inline T *CreateObject(const std::string &className) + { + uint16_t interfaceID = GetInterfaceId(); + uint32_t errorCode = 0; + return ConvertToServiceInterface(CreateObject(interfaceID, className, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, uint32_t &errorCode) + { + uint16_t interfaceID = GetInterfaceId(); + std::map emptyCapabilities; + PriorityScheme emptyPriScheme; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, emptyCapabilities, + emptyPriScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType) + { + uint16_t interfaceID = GetInterfaceId(); + std::map emptyCapabilities; + PriorityScheme emptyPriScheme; + uint32_t errorCode = 0; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, emptyCapabilities, + emptyPriScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, const PriorityScheme &priorityScheme, uint32_t &errorCode) + { + uint16_t interfaceID = GetInterfaceId(); + std::map emptyCapabilities; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, emptyCapabilities, + priorityScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, const PriorityScheme &priorityScheme) + { + uint16_t interfaceID = GetInterfaceId(); + std::map emptyCapabilities; + uint32_t errorCode = 0; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, emptyCapabilities, + priorityScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, const std::map &capabilities, + uint32_t &errorCode) + { + uint16_t interfaceID = GetInterfaceId(); + PriorityScheme emptyPriScheme; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, capabilities, + emptyPriScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, const std::map &capabilities) + { + uint16_t interfaceID = GetInterfaceId(); + PriorityScheme emptyPriScheme; + uint32_t errorCode = 0; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, capabilities, + emptyPriScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, const std::map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode) + { + uint16_t interfaceID = GetInterfaceId(); + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, capabilities, + priorityScheme, errorCode)); + } + + template + inline T *CreateObject(uint16_t serviceType, const std::map &capabilities, + const PriorityScheme &priorityScheme) + { + uint16_t interfaceID = GetInterfaceId(); + uint32_t errorCode = 0; + return ConvertToServiceInterface(CreateObject(interfaceID, serviceType, capabilities, + priorityScheme, errorCode)); + } + + template + inline uint32_t PluginServerGetClassInfo(uint16_t serviceType, std::vector &classesInfo) + { + uint16_t interfaceID = GetInterfaceId(); + std::map emptyCapabilities; + return PluginServerGetClassInfo(interfaceID, serviceType, emptyCapabilities, classesInfo); + } + + template + inline uint32_t PluginServerGetClassInfo(uint16_t serviceType, const std::map &capabilities, + std::vector &classesInfo) + { + uint16_t interfaceID = GetInterfaceId(); + return PluginServerGetClassInfo(interfaceID, serviceType, capabilities, classesInfo); + } + + DECLARE_DELAYED_REF_SINGLETON(PluginServer); + +private: + template + inline T *ConvertToServiceInterface(PluginClassBase *pluginBase) + { +#ifdef PLUGIN_FLAG_RTTI_ENABLE + // when -frtti is enable, we use dynamic cast directly + // to achieve the correct base class side-to-side conversion. + T *serviceObj = dynamic_cast(pluginBase); + if (serviceObj == nullptr && pluginBase != nullptr) { + // type mismatch. + delete pluginBase; + } +#else + // adjust pointer position when multiple inheritance. + void *obj = dynamic_cast(pluginBase); + // when -frtti is not enable, we use static cast. + // static cast is not safe enough, but we have checked before we get here. + T *serviceObj = static_cast(obj); +#endif + return serviceObj; + } + + PluginClassBase *CreateObject(uint16_t interfaceID, const std::string &className, uint32_t &errorCode); + PluginClassBase *CreateObject(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode); + uint32_t PluginServerGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + std::vector &classesInfo); + PluginFWType AnalyzeFWType(const std::string &canonicalPath); + + PlatformAdp &platformAdp_; + PluginFw &pluginFw_; + GstPluginFw &gstPluginFw_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_SERVER_H diff --git a/plugins/manager/include/plugin_service.h b/plugins/manager/include/plugin_service.h new file mode 100644 index 0000000000000000000000000000000000000000..d17422738c11424ee8906d051810038f0a01c5fb --- /dev/null +++ b/plugins/manager/include/plugin_service.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_SERVICE_H +#define PLUGIN_SERVICE_H + +namespace OHOS { +namespace MultimediaPlugin { +constexpr uint8_t SUBID_BIT_NUM = 12; +constexpr uint16_t INVALID_IID = 0xFFFF; + +constexpr uint16_t IID_TYPE_GENERAL = 0; +constexpr uint16_t IID_TYPE_PIPELINE = 1; + +constexpr uint16_t MakeInterfaceID(uint16_t interfaceIDType, uint16_t subID) +{ + return ((interfaceIDType << SUBID_BIT_NUM) | subID); +} + +constexpr uint16_t GetInterfaceIDType(uint16_t interfaceID) +{ + return (interfaceID >> SUBID_BIT_NUM); +} + +constexpr uint16_t PLUGIN_EXAMPLE_IID = MakeInterfaceID(IID_TYPE_GENERAL, 0); +constexpr uint16_t IMAGE_FORMAT_AGENT_IID = MakeInterfaceID(IID_TYPE_GENERAL, 1); +constexpr uint16_t IMAGE_DECODER_IID = MakeInterfaceID(IID_TYPE_GENERAL, 2); +constexpr uint16_t IMAGE_ENCODER_IID = MakeInterfaceID(IID_TYPE_GENERAL, 3); +constexpr uint16_t IMAGE_DECOMPRESS_COMP_IID = MakeInterfaceID(IID_TYPE_GENERAL, 4); +constexpr uint16_t IMAGE_EXIF_IID = MakeInterfaceID(IID_TYPE_GENERAL, 5); + +template inline uint16_t GetInterfaceId() +{ + return INVALID_IID; +} + +#define DECLARE_INTERFACE(InterfaceType, interfaceID) \ + template <> \ + inline uint16_t OHOS::MultimediaPlugin::GetInterfaceId() \ + { \ + return interfaceID; \ + } +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_SERVICE_H diff --git a/plugins/manager/include/pluginbase/plugin_export.h b/plugins/manager/include/pluginbase/plugin_export.h new file mode 100644 index 0000000000000000000000000000000000000000..a63941e45addcb2e22d435b844f8c5e85da5824a --- /dev/null +++ b/plugins/manager/include/pluginbase/plugin_export.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_EXPORT_H +#define PLUGIN_EXPORT_H + +#include +#include "plugin_class_base.h" +#include "image_type.h" + +// The .so of plugin exports C form interface, so we use extern "C" here for consistent +#ifdef __cplusplus +extern "C" { +#endif + +NATIVEEXPORT bool PluginExternalStart(); +NATIVEEXPORT void PluginExternalStop(); +NATIVEEXPORT OHOS::MultimediaPlugin::PluginClassBase *PluginExternalCreate(const std::string &className); + +// function pointer for plugin interface "PluginExternalStart" +typedef decltype(PluginExternalStart) *PluginStartFunc; + +// function pointer for plugin interface "PluginExternalStop" +typedef decltype(PluginExternalStop) *PluginStopFunc; + +// function pointer for plugin interface "PluginExternalCreate" +typedef decltype(PluginExternalCreate) *PluginCreateFunc; + +#ifdef __cplusplus +} +#endif + +#endif // PLUGIN_EXPORT_H diff --git a/plugins/manager/include/pluginbase/plugin_utils.h b/plugins/manager/include/pluginbase/plugin_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..75cd7311495f85623eb9011d2e72ee1aa860f5db --- /dev/null +++ b/plugins/manager/include/pluginbase/plugin_utils.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_UTILS_H +#define PLUGIN_UTILS_H + +#include +#include +#include "plugin_class_base.h" + +namespace OHOS { +namespace MultimediaPlugin { +template +PluginClassBase *CreatePluginObject() +{ + return static_cast(new (std::nothrow) ImplClassType()); // upward conversion. +} +} // namespace MultimediaPlugin +} // namespace OHOS + +#define PLUGIN_OBJECT_CREATOR(ImplClassType) OHOS::MultimediaPlugin::CreatePluginObject + +#define IMPL_CLASS_NAME_STRING(ImplClassType) (#ImplClassType) + +using PluginObjectCreatorFunc = OHOS::MultimediaPlugin::PluginClassBase *(*)(); + +// --------- a set of code fragments that helps define a simple plugin_export.cpp file ---------- +#define PLUGIN_EXPORT_REGISTER_PACKAGE(packageName) \ +static const std::string PACKAGE_NAME = (packageName); + +#define PLUGIN_EXPORT_REGISTER_CLASS_BEGIN \ +using ImplClassMap = std::map; \ +static ImplClassMap implClassMap = { + +#define PLUGIN_EXPORT_REGISTER_CLASS(ImplClassType) \ +{ IMPL_CLASS_NAME_STRING(ImplClassType), PLUGIN_OBJECT_CREATOR(ImplClassType) }, + +#define PLUGIN_EXPORT_REGISTER_CLASS_END \ +}; + +#define PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() \ +bool PluginExternalStart() \ +{ \ + PLUGIN_LOG_D("call PluginExternalStart() in package: %{public}s.", PACKAGE_NAME.c_str()); \ + return true; \ +} + +#define PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() \ +void PluginExternalStop() \ +{ \ + PLUGIN_LOG_D("call PluginExternalStop() in package: %{public}s.", PACKAGE_NAME.c_str()); \ + return; \ +} + +#define PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() \ +OHOS::MultimediaPlugin::PluginClassBase *PluginExternalCreate(const std::string &className) \ +{ \ + PLUGIN_LOG_D("PluginExternalCreate: create object for package: %{public}s, class: %{public}s.", \ + PACKAGE_NAME.c_str(), className.c_str()); \ + \ + auto iter = implClassMap.find(className); \ + if (iter == implClassMap.end()) { \ + PLUGIN_LOG_E("PluginExternalCreate: failed to find class: %{public}s, in package: %{public}s.", \ + className.c_str(), PACKAGE_NAME.c_str()); \ + return nullptr; \ + } \ + \ + auto creator = iter->second; \ + if (creator == nullptr) { \ + PLUGIN_LOG_E("PluginExternalCreate: null creator for class: %{public}s, in package: %{public}s.", \ + className.c_str(), PACKAGE_NAME.c_str()); \ + return nullptr; \ + } \ + \ + return creator(); \ +} + +#endif // PLUGIN_UTILS_H diff --git a/plugins/manager/include/priority_scheme.h b/plugins/manager/include/priority_scheme.h new file mode 100644 index 0000000000000000000000000000000000000000..8d591e27443a70a6949d942f1ddf67da0448c42e --- /dev/null +++ b/plugins/manager/include/priority_scheme.h @@ -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. + */ + +#ifndef PRIORITY_SCHEME_H +#define PRIORITY_SCHEME_H + +#include + +namespace OHOS { +namespace MultimediaPlugin { +enum class PriorityType : int32_t { + PRIORITY_TYPE_NULL, + PRIORITY_ORDER_BY_ATTR_ASCENDING, + PRIORITY_ORDER_BY_ATTR_DESCENDING +}; + +class PriorityScheme final { +public: + PriorityScheme() : type_(PriorityType::PRIORITY_TYPE_NULL) {} + PriorityScheme(PriorityType type, const std::string &attrKey) : type_(type), attrKey_(attrKey) {} + PriorityScheme(PriorityType type, std::string &&attrKey) : type_(type), attrKey_(std::move(attrKey)) {} + ~PriorityScheme() = default; + + PriorityType GetPriorityType() const + { + return type_; + } + + const std::string &GetAttrKey() const + { + return attrKey_; + } + +private: + PriorityType type_; + std::string attrKey_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PRIORITY_SCHEME_H diff --git a/plugins/manager/include/utils/pointer_key_map.h b/plugins/manager/include/utils/pointer_key_map.h new file mode 100644 index 0000000000000000000000000000000000000000..9043d0a074edf117f409b866850d6de9dbb89a28 --- /dev/null +++ b/plugins/manager/include/utils/pointer_key_map.h @@ -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. + */ + +#ifndef POINTER_KEY_MAP_H +#define POINTER_KEY_MAP_H + +#include + +namespace OHOS { +namespace MultimediaPlugin { +template +struct PointerComparator { + bool operator()(K *lhs, K *rhs) const + { + if (lhs == nullptr || rhs == nullptr) { + return false; + } + + return *lhs < *rhs; + } +}; + +template using PointerKeyMap = std::map>; + +template using PointerKeyMultimap = std::multimap>; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // POINTER_KEY_MAP_H \ No newline at end of file diff --git a/plugins/manager/src/common/attr_data.cpp b/plugins/manager/src/common/attr_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bf8069da9beb8b24cdc3e92dffcba3d3a11ef9e --- /dev/null +++ b/plugins/manager/src/common/attr_data.cpp @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "attr_data.h" +#include "hilog/log.h" +#include "log_tags.h" +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif + +namespace OHOS { +namespace MultimediaPlugin { +using std::set; +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "AttrData" }; + +AttrData::AttrData() : type_(AttrDataType::ATTR_DATA_NULL) +{} + +AttrData::AttrData(bool value) : type_(AttrDataType::ATTR_DATA_BOOL) +{ + value_.boolValue = value; +} + +AttrData::AttrData(uint32_t value) : type_(AttrDataType::ATTR_DATA_UINT32) +{ + value_.uint32Value = value; +} + +AttrData::AttrData(const string &value) : type_(AttrDataType::ATTR_DATA_STRING) +{ + value_.stringValue = new (std::nothrow) string(value); + if (value_.stringValue == nullptr) { + HiLog::Error(LABEL, "AttrData: alloc stringValue result null!"); + type_ = AttrDataType::ATTR_DATA_NULL; + } +} + +AttrData::AttrData(string &&value) : type_(AttrDataType::ATTR_DATA_STRING) +{ + value_.stringValue = new (std::nothrow) string(std::move(value)); + if (value_.stringValue == nullptr) { + HiLog::Error(LABEL, "AttrData: alloc stringValue result null!"); + type_ = AttrDataType::ATTR_DATA_NULL; + } +} + +AttrData::AttrData(uint32_t lowerBound, uint32_t upperBound) : type_(AttrDataType::ATTR_DATA_UINT32_RANGE) +{ + if (lowerBound > upperBound) { + type_ = AttrDataType::ATTR_DATA_NULL; + } + + value_.uint32Rang[LOWER_BOUND_INDEX] = lowerBound; + value_.uint32Rang[UPPER_BOUND_INDEX] = upperBound; +} + +AttrData::AttrData(const AttrData &data) +{ + switch (data.type_) { + case AttrDataType::ATTR_DATA_BOOL: { + value_.boolValue = data.value_.boolValue; + type_ = AttrDataType::ATTR_DATA_BOOL; + break; + } + case AttrDataType::ATTR_DATA_UINT32: { + value_.uint32Value = data.value_.uint32Value; + type_ = AttrDataType::ATTR_DATA_UINT32; + break; + } + case AttrDataType::ATTR_DATA_STRING: { + (void)InitStringAttrData(data); + break; + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + (void)InitUint32SetAttrData(data); + break; + } + case AttrDataType::ATTR_DATA_STRING_SET: { + (void)InitStringSetAttrData(data); + break; + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + value_.uint32Rang[LOWER_BOUND_INDEX] = data.value_.uint32Rang[LOWER_BOUND_INDEX]; + value_.uint32Rang[UPPER_BOUND_INDEX] = data.value_.uint32Rang[UPPER_BOUND_INDEX]; + type_ = AttrDataType::ATTR_DATA_UINT32_RANGE; + break; + } + default: { + HiLog::Debug(LABEL, "AttrData: null or unexpected type in copy constructor: %{public}d.", data.type_); + type_ = AttrDataType::ATTR_DATA_NULL; + } + } +} + +AttrData::AttrData(AttrData &&data) noexcept +{ + if (memcpy_s(&value_, sizeof(value_), &data.value_, sizeof(data.value_)) == 0) { + type_ = data.type_; + data.type_ = AttrDataType::ATTR_DATA_NULL; + } else { + type_ = AttrDataType::ATTR_DATA_NULL; + HiLog::Error(LABEL, "memcpy error in assignment operator!"); + } +} + +AttrData::~AttrData() +{ + ClearData(); +} + +AttrData &AttrData::operator=(const AttrData &data) +{ + // make a copy, avoid self-assignment problems. + AttrData temp(data); + ClearData(); + if (memcpy_s(&value_, sizeof(value_), &temp.value_, sizeof(temp.value_)) == 0) { + type_ = temp.type_; + temp.type_ = AttrDataType::ATTR_DATA_NULL; + } else { + type_ = AttrDataType::ATTR_DATA_NULL; + HiLog::Error(LABEL, "memcpy error in assignment operator!"); + } + + return *this; +} + +AttrData &AttrData::operator=(AttrData &&data) noexcept +{ + // case if self-assignment. + if (&data == this) { + return *this; + } + + ClearData(); + if (memcpy_s(&value_, sizeof(value_), &data.value_, sizeof(data.value_)) == 0) { + type_ = data.type_; + data.type_ = AttrDataType::ATTR_DATA_NULL; + } else { + type_ = AttrDataType::ATTR_DATA_NULL; + HiLog::Error(LABEL, "memcpy error in assignment operator!"); + } + + return *this; +} + +void AttrData::SetData(bool value) +{ + ClearData(); + value_.boolValue = value; + type_ = AttrDataType::ATTR_DATA_BOOL; +} + +void AttrData::SetData(uint32_t value) +{ + ClearData(); + value_.uint32Value = value; + type_ = AttrDataType::ATTR_DATA_UINT32; +} + +uint32_t AttrData::SetData(const string &value) +{ + if (type_ == AttrDataType::ATTR_DATA_STRING) { + *(value_.stringValue) = value; + return SUCCESS; + } + + string *newValue = new (std::nothrow) string(value); + if (newValue == nullptr) { + HiLog::Error(LABEL, "SetData: alloc string result null!"); + return ERR_INTERNAL; + } + + ClearData(); + value_.stringValue = newValue; + type_ = AttrDataType::ATTR_DATA_STRING; + return SUCCESS; +} + +uint32_t AttrData::SetData(string &&value) +{ + if (type_ == AttrDataType::ATTR_DATA_STRING) { + *(value_.stringValue) = std::move(value); + return SUCCESS; + } + + string *newValue = new (std::nothrow) string(std::move(value)); + if (newValue == nullptr) { + HiLog::Error(LABEL, "SetData: alloc string result null!"); + return ERR_INTERNAL; + } + + ClearData(); + value_.stringValue = newValue; + type_ = AttrDataType::ATTR_DATA_STRING; + return SUCCESS; +} + +uint32_t AttrData::SetData(uint32_t lowerBound, uint32_t upperBound) +{ + if (lowerBound > upperBound) { + HiLog::Error(LABEL, "SetData: lowerBound is upper than upperBound, lower: %{public}u, upper: %{public}u.", + lowerBound, upperBound); + return ERR_INVALID_PARAMETER; + } + + ClearData(); + value_.uint32Rang[LOWER_BOUND_INDEX] = lowerBound; + value_.uint32Rang[UPPER_BOUND_INDEX] = upperBound; + type_ = AttrDataType::ATTR_DATA_UINT32_RANGE; + return SUCCESS; +} + +void AttrData::ClearData() +{ + switch (type_) { + case AttrDataType::ATTR_DATA_STRING: { + if (value_.stringValue != nullptr) { + delete value_.stringValue; + value_.stringValue = nullptr; + } + break; + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + if (value_.uint32Set != nullptr) { + delete value_.uint32Set; + value_.uint32Set = nullptr; + } + break; + } + case AttrDataType::ATTR_DATA_STRING_SET: { + if (value_.stringSet != nullptr) { + delete value_.stringSet; + value_.stringSet = nullptr; + } + break; + } + default: { + // do nothing + HiLog::Debug(LABEL, "ClearData: do nothing for type %{public}d.", type_); + } + } + + type_ = AttrDataType::ATTR_DATA_NULL; +} + +uint32_t AttrData::InsertSet(uint32_t value) +{ + if (type_ == AttrDataType::ATTR_DATA_NULL) { + value_.uint32Set = new (std::nothrow) set({ value }); + if (value_.uint32Set == nullptr) { + HiLog::Error(LABEL, "InsertSet: alloc uint32Set result null!"); + return ERR_INTERNAL; + } + + type_ = AttrDataType::ATTR_DATA_UINT32_SET; + return SUCCESS; + } + + if (type_ != AttrDataType::ATTR_DATA_UINT32_SET) { + HiLog::Error(LABEL, "InsertSet: AttrData type is not uint32Set or null, type: %{public}d.", type_); + return ERR_UNSUPPORTED; + } + + auto result = value_.uint32Set->insert(value); + if (!result.second) { + HiLog::Error(LABEL, "InsertSet: set insert error!"); + return ERR_GENERAL; + } + + return SUCCESS; +} + +uint32_t AttrData::InsertSet(const string &value) +{ + if (type_ == AttrDataType::ATTR_DATA_NULL) { + value_.stringSet = new (std::nothrow) set({ value }); + if (value_.stringSet == nullptr) { + HiLog::Error(LABEL, "InsertSet: alloc stringSet result null!"); + return ERR_INTERNAL; + } + + type_ = AttrDataType::ATTR_DATA_STRING_SET; + return SUCCESS; + } + + if (type_ != AttrDataType::ATTR_DATA_STRING_SET) { + HiLog::Error(LABEL, "InsertSet: AttrData type is not stringSet or null, type: %{public}d.", type_); + return ERR_UNSUPPORTED; + } + + auto result = value_.stringSet->insert(value); + if (!result.second) { + HiLog::Error(LABEL, "InsertSet: set insert error!"); + return ERR_INTERNAL; + } + + return SUCCESS; +} + +uint32_t AttrData::InsertSet(string &&value) +{ + if (type_ == AttrDataType::ATTR_DATA_NULL) { + value_.stringSet = new (std::nothrow) set; + if (value_.stringSet == nullptr) { + HiLog::Error(LABEL, "InsertSet: alloc stringSet result null!"); + return ERR_INTERNAL; + } + + auto result = value_.stringSet->insert(std::move(value)); + if (!result.second) { + delete value_.stringSet; + value_.stringSet = nullptr; + HiLog::Error(LABEL, "InsertSet: set insert error!"); + return ERR_INTERNAL; + } + + type_ = AttrDataType::ATTR_DATA_STRING_SET; + return SUCCESS; + } + + if (type_ != AttrDataType::ATTR_DATA_STRING_SET) { + HiLog::Error(LABEL, "InsertSet: AttrData type is not stringSet or null, type: %{public}d.", type_); + return ERR_UNSUPPORTED; + } + + auto result = value_.stringSet->insert(std::move(value)); + if (!result.second) { + HiLog::Error(LABEL, "InsertSet: set insert error!"); + return ERR_INTERNAL; + } + + return SUCCESS; +} + +bool AttrData::InRange(bool value) const +{ + if (type_ != AttrDataType::ATTR_DATA_BOOL) { + HiLog::Error(LABEL, "InRange: comparison of bool type with non-bool type: %{public}d.", type_); + return false; + } + + return value == value_.boolValue; +} + +bool AttrData::InRange(uint32_t value) const +{ + switch (type_) { + case AttrDataType::ATTR_DATA_UINT32: { + return value == value_.uint32Value; + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + return value_.uint32Set->find(value) != value_.uint32Set->end(); + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + return InRangeUint32Range(value); + } + default: { + HiLog::Error(LABEL, "InRange: comparison of uint32 type with non-uint32 type: %{public}d.", type_); + return false; + } + } +} + +bool AttrData::InRange(const string &value) const +{ + switch (type_) { + case AttrDataType::ATTR_DATA_STRING: { + return value == *(value_.stringValue); + } + case AttrDataType::ATTR_DATA_STRING_SET: { + return value_.stringSet->find(value) != value_.stringSet->end(); + } + default: { + HiLog::Error(LABEL, "InRange: comparison of string type with non-string type: %{public}d.", type_); + return false; + } + } +} + +bool AttrData::InRange(const AttrData &data) const +{ + switch (data.type_) { + case AttrDataType::ATTR_DATA_NULL: { + return type_ == AttrDataType::ATTR_DATA_NULL; + } + case AttrDataType::ATTR_DATA_BOOL: { + return InRange(data.value_.boolValue); + } + case AttrDataType::ATTR_DATA_UINT32: { + return InRange(data.value_.uint32Value); + } + case AttrDataType::ATTR_DATA_STRING: { + return InRange(*(data.value_.stringValue)); + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + return InRange(*(data.value_.uint32Set)); + } + case AttrDataType::ATTR_DATA_STRING_SET: { + return InRange(*(data.value_.stringSet)); + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + return InRange(data.value_.uint32Rang); + } + default: { + HiLog::Error(LABEL, "InRange: unexpected AttrData type: %{public}d.", data.type_); + return false; + } + } +} + +AttrDataType AttrData::GetType() const +{ + return type_; +} + +uint32_t AttrData::GetMinValue(uint32_t &value) const +{ + switch (type_) { + case AttrDataType::ATTR_DATA_UINT32: { + value = value_.uint32Value; + return SUCCESS; + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + auto iter = value_.uint32Set->begin(); + if (iter == value_.uint32Set->end()) { + HiLog::Error(LABEL, "GetMinValue: uint32Set is empty."); + return ERR_GENERAL; + } + value = *iter; + return SUCCESS; + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + value = value_.uint32Rang[LOWER_BOUND_INDEX]; + return SUCCESS; + } + default: { + HiLog::Error(LABEL, "GetMinValue: invalid data type for uint32: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + } +} + +uint32_t AttrData::GetMaxValue(uint32_t &value) const +{ + switch (type_) { + case AttrDataType::ATTR_DATA_UINT32: { + value = value_.uint32Value; + return SUCCESS; + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + auto iter = value_.uint32Set->rbegin(); + if (iter == value_.uint32Set->rend()) { + HiLog::Error(LABEL, "GetMaxValue: GetMaxValue: uint32Set is empty."); + return ERR_GENERAL; + } + + value = *iter; + return SUCCESS; + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + value = value_.uint32Rang[UPPER_BOUND_INDEX]; + return SUCCESS; + } + default: { + HiLog::Error(LABEL, "GetMaxValue: invalid data type for uint32: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + } +} + +uint32_t AttrData::GetMinValue(const string *&value) const +{ + switch (type_) { + case AttrDataType::ATTR_DATA_STRING: { + value = value_.stringValue; + return SUCCESS; + } + case AttrDataType::ATTR_DATA_STRING_SET: { + auto iter = value_.stringSet->begin(); + if (iter == value_.stringSet->end()) { + HiLog::Error(LABEL, "GetMinValue: stringSet is empty."); + return ERR_GENERAL; + } + + value = (&(*iter)); + return SUCCESS; + } + default: { + HiLog::Error(LABEL, "GetMinValue: invalid data type for string: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + } +} + +uint32_t AttrData::GetMaxValue(const string *&value) const +{ + switch (type_) { + case AttrDataType::ATTR_DATA_STRING: { + value = value_.stringValue; + return SUCCESS; + } + case AttrDataType::ATTR_DATA_STRING_SET: { + auto iter = value_.stringSet->rbegin(); + if (iter == value_.stringSet->rend()) { + HiLog::Error(LABEL, "GetMaxValue: stringSet is empty."); + return ERR_GENERAL; + } + + value = (&(*iter)); + return SUCCESS; + } + default: { + HiLog::Error(LABEL, "GetMaxValue: invalid data type for string: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + } +} + +uint32_t AttrData::GetValue(bool &value) const +{ + if (type_ != AttrDataType::ATTR_DATA_BOOL) { + HiLog::Error(LABEL, "Get uint32 value: not a bool AttrData type: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + + value = value_.boolValue; + return SUCCESS; +} + +uint32_t AttrData::GetValue(uint32_t &value) const +{ + if (type_ != AttrDataType::ATTR_DATA_UINT32) { + HiLog::Error(LABEL, "Get uint32 value: not a uint32 AttrData type: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + + value = value_.uint32Value; + return SUCCESS; +} + +uint32_t AttrData::GetValue(string &value) const +{ + if (type_ != AttrDataType::ATTR_DATA_STRING) { + HiLog::Error(LABEL, "Get string value by reference: not a string AttrData type: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + + value = *(value_.stringValue); + return SUCCESS; +} + +uint32_t AttrData::GetValue(const string *&value) const +{ + if (type_ != AttrDataType::ATTR_DATA_STRING) { + HiLog::Error(LABEL, "Get string value: not a string AttrData type: %{public}d.", type_); + return ERR_INVALID_PARAMETER; + } + + value = value_.stringValue; + return SUCCESS; +} + +// ------------------------------- private method ------------------------------- +uint32_t AttrData::InitStringAttrData(const AttrData &data) +{ + value_.stringValue = new (std::nothrow) string(*(data.value_.stringValue)); + if (value_.stringValue == nullptr) { + HiLog::Error(LABEL, "InitStringAttrData: alloc stringValue result null!"); + type_ = AttrDataType::ATTR_DATA_NULL; + return ERR_INTERNAL; + } + type_ = AttrDataType::ATTR_DATA_STRING; + return SUCCESS; +} + +uint32_t AttrData::InitUint32SetAttrData(const AttrData &data) +{ + value_.uint32Set = new (std::nothrow) set(*(data.value_.uint32Set)); + if (value_.uint32Set == nullptr) { + HiLog::Error(LABEL, "InitUint32SetAttrData: alloc uint32Set result null!"); + type_ = AttrDataType::ATTR_DATA_NULL; + return ERR_INTERNAL; + } + type_ = AttrDataType::ATTR_DATA_UINT32_SET; + return SUCCESS; +} + +uint32_t AttrData::InitStringSetAttrData(const AttrData &data) +{ + value_.stringSet = new (std::nothrow) set(*(data.value_.stringSet)); + if (value_.stringSet == nullptr) { + HiLog::Error(LABEL, "InitStringSetAttrData: alloc stringSet result null!"); + type_ = AttrDataType::ATTR_DATA_NULL; + return ERR_INTERNAL; + } + type_ = AttrDataType::ATTR_DATA_STRING_SET; + return SUCCESS; +} + +bool AttrData::InRangeUint32Range(uint32_t value) const +{ + return value >= value_.uint32Rang[LOWER_BOUND_INDEX] && value <= value_.uint32Rang[UPPER_BOUND_INDEX]; +} + +bool AttrData::InRange(const set &uint32Set) const +{ + if (uint32Set.empty()) { + return false; + } + + for (uint32_t value : uint32Set) { + if (!InRange(value)) { + return false; + } + } + + return true; +} + +bool AttrData::InRange(const set &stringSet) const +{ + if (stringSet.empty()) { + HiLog::Debug(LABEL, "InRange: empty set of parameter."); + return false; + } + + for (const string &value : stringSet) { + if (!InRange(value)) { + return false; + } + } + + return true; +} + +bool AttrData::InRange(const uint32_t (&uint32Rang)[RANGE_ARRAY_SIZE]) const +{ + if (uint32Rang[LOWER_BOUND_INDEX] > uint32Rang[UPPER_BOUND_INDEX]) { + return false; + } + + switch (type_) { + case AttrDataType::ATTR_DATA_UINT32: { + return uint32Rang[LOWER_BOUND_INDEX] == uint32Rang[UPPER_BOUND_INDEX] && + uint32Rang[UPPER_BOUND_INDEX] == value_.uint32Value; + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + auto lowerIter = value_.uint32Set->find(uint32Rang[LOWER_BOUND_INDEX]); + if (lowerIter == value_.uint32Set->end()) { + return false; + } + + auto upperIter = value_.uint32Set->find(uint32Rang[UPPER_BOUND_INDEX]); + if (upperIter == value_.uint32Set->end()) { + return false; + } + + uint32_t count = 0; + for (auto tmpIter = lowerIter; tmpIter != upperIter; ++tmpIter) { + count++; + } + + if (count != (uint32Rang[UPPER_BOUND_INDEX] - uint32Rang[LOWER_BOUND_INDEX])) { + return false; + } + + return true; + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + return (uint32Rang[LOWER_BOUND_INDEX] >= value_.uint32Rang[LOWER_BOUND_INDEX]) && + (uint32Rang[UPPER_BOUND_INDEX] <= value_.uint32Rang[UPPER_BOUND_INDEX]); + } + default: { + return false; + } + } +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/common/platform_adp.cpp b/plugins/manager/src/common/platform_adp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3245d952de6a2940aafe0391fae2748d22f7e35d --- /dev/null +++ b/plugins/manager/src/common/platform_adp.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "platform_adp.h" +#ifndef _WIN32 +#include +#endif +#include "directory_ex.h" +#include "hilog/log.h" +#include "log_tags.h" + +namespace OHOS { +namespace MultimediaPlugin { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PlatformAdp" }; + +const string PlatformAdp::DIR_SEPARATOR = "/"; +const string PlatformAdp::LIBRARY_FILE_SUFFIX = "so"; + +#ifdef _WIN32 +HMODULE PlatformAdp::AdpLoadLibrary(const string &packageName) +{ + return LoadLibrary(packageName.c_str()); +} + +void PlatformAdp::AdpFreeLibrary(HMODULE handle) +{ + FreeLibrary(handle); +} + +FARPROC PlatformAdp::AdpGetSymAddress(HMODULE handle, const string &symbol) +{ + return GetProcAddress(handle, symbol.c_str()); +} +#else +void *PlatformAdp::LoadLibrary(const string &packageName) +{ + return dlopen(packageName.c_str(), RTLD_LAZY); +} + +void PlatformAdp::FreeLibrary(void *handle) +{ + dlclose(handle); +} + +void *PlatformAdp::GetSymAddress(void *handle, const string &symbol) +{ + return dlsym(handle, symbol.c_str()); +} +#endif + +uint32_t PlatformAdp::CheckAndNormalizePath(string &path) +{ +#if !defined(_WIN32) && !defined(_APPLE) + if (path.empty()) { + HiLog::Error(LABEL, "check path empty."); + return ERR_GENERAL; + } +#endif + + string realPath; + if (!PathToRealPath(path, realPath)) { + HiLog::Error(LABEL, "path to real path error."); + return ERR_GENERAL; + } + + path = std::move(realPath); + + return SUCCESS; +} + +// ------------------------------- private method ------------------------------- +PlatformAdp::PlatformAdp() {} + +PlatformAdp::~PlatformAdp() {} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/common/platform_adp.h b/plugins/manager/src/common/platform_adp.h new file mode 100644 index 0000000000000000000000000000000000000000..73dc55dc6c603f253d74f2ee812cd76449a6bdba --- /dev/null +++ b/plugins/manager/src/common/platform_adp.h @@ -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. + */ + +#ifndef PLATFORM_ADP_H +#define PLATFORM_ADP_H + +#include +#include "nocopyable.h" +#include "singleton.h" +#include "plugin_errors.h" +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace OHOS { +namespace MultimediaPlugin { +class PlatformAdp final : public NoCopyable { +public: +#ifdef _WIN32 + HMODULE AdpLoadLibrary(const std::string &packageName); + void AdpFreeLibrary(HMODULE handle); + FARPROC AdpGetSymAddress(HMODULE handle, const std::string &symbol); +#else + void *LoadLibrary(const std::string &packageName); + void FreeLibrary(void *handle); + void *GetSymAddress(void *handle, const std::string &symbol); +#endif + + uint32_t CheckAndNormalizePath(std::string &path); + DECLARE_DELAYED_REF_SINGLETON(PlatformAdp); + +public: + static const std::string DIR_SEPARATOR; + static const std::string LIBRARY_FILE_SUFFIX; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLATFORM_ADP_H diff --git a/plugins/manager/src/framework/capability.cpp b/plugins/manager/src/framework/capability.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1516465991eb00818a4044575ce5703df7e4d441 --- /dev/null +++ b/plugins/manager/src/framework/capability.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "capability.h" +#include "hilog/log.h" +#include "json_helper.h" +#include "log_tags.h" +#include "plugin_common_type.h" + +namespace OHOS { +namespace MultimediaPlugin { +using nlohmann::json; +using std::map; +using std::size_t; +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "Capability" }; +const string Capability::CAPABILITY_BOOL_TRUE = "true"; +const string Capability::CAPABILITY_BOOL_FALSE = "false"; + +Capability::Capability(const map &caps) : caps_(caps) +{} + +Capability::Capability(map &&caps) : caps_(std::move(caps)) +{} + +uint32_t Capability::SetCapability(const json &capsInfo) +{ + if (!capsInfo.is_array()) { + HiLog::Error(LABEL, "not a array type value."); + return ERR_INVALID_PARAMETER; + } + + if (!caps_.empty()) { + caps_.clear(); + } + + size_t capNum = capsInfo.size(); + HiLog::Debug(LABEL, "class cap num: %{public}zu.", capNum); + string name; + for (size_t i = 0; i < capNum; i++) { + const json &capabilityInfo = capsInfo[i]; + if (JsonHelper::GetStringValue(capabilityInfo, "name", name) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis cap name."); + continue; + } + + HiLog::Debug(LABEL, "get new cap, name: %{public}s.", name.c_str()); + AttrData attrData; + if (AnalyzeAttrData(capabilityInfo, attrData) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis cap value."); + continue; + } + + caps_.emplace(std::move(name), std::move(attrData)); + } + + return SUCCESS; +} + +bool Capability::IsCompatible(const map &caps) const +{ + for (const auto &capability : caps) { + auto iter = caps_.find(capability.first); + if (iter == caps_.end()) { + return false; + } + + if (!iter->second.InRange(capability.second)) { + return false; + } + } + + return true; +} + +const AttrData *Capability::GetCapability(const string &key) const +{ + auto iter = caps_.find(key); + if (iter == caps_.end()) { + return nullptr; + } + + return &(iter->second); +} + +const std::map &Capability::GetCapability() const +{ + return caps_; +} + +// ------------------------------- private method ------------------------------- +uint32_t Capability::AnalyzeAttrData(const json &capInfo, AttrData &attrData) +{ + string type; + if (JsonHelper::GetStringValue(capInfo, "type", type) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis data type."); + return ERR_INVALID_PARAMETER; + } + + std::map typeMap_ = { + { "bool", AttrDataType::ATTR_DATA_BOOL }, + { "uint32", AttrDataType::ATTR_DATA_UINT32 }, + { "string", AttrDataType::ATTR_DATA_STRING }, + { "uint32Set", AttrDataType::ATTR_DATA_UINT32_SET }, + { "stringSet", AttrDataType::ATTR_DATA_STRING_SET }, + { "uint32Range", AttrDataType::ATTR_DATA_UINT32_RANGE } + }; + + auto iter = typeMap_.find(type); + if (iter == typeMap_.end()) { + HiLog::Error(LABEL, "unknown cap value type: %{public}s.", type.c_str()); + return ERR_INVALID_PARAMETER; + } + + switch (iter->second) { + case AttrDataType::ATTR_DATA_BOOL: { + return AnalyzeBool(capInfo, attrData); + } + case AttrDataType::ATTR_DATA_UINT32: { + return AnalyzeUint32(capInfo, attrData); + } + case AttrDataType::ATTR_DATA_STRING: { + return AnalyzeString(capInfo, attrData); + } + case AttrDataType::ATTR_DATA_UINT32_SET: { + return AnalyzeUint32Set(capInfo, attrData); + } + case AttrDataType::ATTR_DATA_STRING_SET: { + return AnalyzeStringSet(capInfo, attrData); + } + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + return AnalyzeUint32Range(capInfo, attrData); + } + default: { + HiLog::Error(LABEL, "unexpected cap value type: %{public}d.", iter->second); + return ERR_INTERNAL; + } + } + + return SUCCESS; +} + +uint32_t Capability::AnalyzeBool(const json &capInfo, AttrData &attrData) +{ + string value; + if (JsonHelper::GetStringValue(capInfo, "value", value) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis bool value."); + return ERR_INVALID_PARAMETER; + } + + bool attrValue = false; + if (value == CAPABILITY_BOOL_TRUE) { + attrValue = true; + } else if (value == CAPABILITY_BOOL_FALSE) { + attrValue = false; + } else { + HiLog::Error(LABEL, "failed to analyze bool value: %{public}s.", value.c_str()); + return ERR_INVALID_PARAMETER; + } + + HiLog::Debug(LABEL, "get bool AttrData: %{public}s.", value.c_str()); + attrData.SetData(attrValue); + + return SUCCESS; +} + +uint32_t Capability::AnalyzeUint32(const json &capInfo, AttrData &attrData) +{ + uint32_t value; + if (JsonHelper::GetUint32Value(capInfo, "value", value) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis uint32 value."); + return ERR_INVALID_PARAMETER; + } + + HiLog::Debug(LABEL, "get uint32 AttrData: %{public}u.", value); + attrData.SetData(value); + + return SUCCESS; +} + +uint32_t Capability::AnalyzeString(const json &capInfo, AttrData &attrData) +{ + string value; + if (JsonHelper::GetStringValue(capInfo, "value", value) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis string value."); + return ERR_INVALID_PARAMETER; + } + + if (value.empty()) { + HiLog::Error(LABEL, "failed to analyze string value."); + return ERR_INVALID_PARAMETER; + } + + HiLog::Debug(LABEL, "get string AttrData: %{public}s.", value.c_str()); + if (attrData.SetData(std::move(value)) != SUCCESS) { + HiLog::Error(LABEL, "AnalyzeString: failed to call SetData for string type."); + return ERR_INTERNAL; + } + + return SUCCESS; +} + +uint32_t Capability::AnalyzeUint32Set(const json &capInfo, AttrData &attrData) +{ + size_t arraySize; + if (JsonHelper::GetArraySize(capInfo, "value", arraySize) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis uint32Set value."); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "uint32Set size: %{public}zu.", arraySize); + + if (arraySize < SET_MIN_VALUE_NUM) { + HiLog::Error(LABEL, "invalid uint32Set size: %{public}zu.", arraySize); + return ERR_INVALID_PARAMETER; + } + + uint32_t value; + const json &valueArray = capInfo["value"]; + for (size_t i = 0; i < arraySize; i++) { + if (JsonHelper::GetUint32Value(valueArray[i], value) != SUCCESS) { + HiLog::Error(LABEL, "fail to analyze uint32Set[%{public}zu]: %{public}u.", i, value); + attrData.ClearData(); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "get uint32Set[%{public}zu]: %{public}u.", i, value); + if (attrData.InsertSet(value) != SUCCESS) { + HiLog::Error(LABEL, "AnalyzeUint32Set: failed to call InsertSet."); + attrData.ClearData(); + return ERR_INTERNAL; + } + } + + return SUCCESS; +} + +uint32_t Capability::AnalyzeUint32Range(const json &capInfo, AttrData &attrData) +{ + size_t arraySize; + if (JsonHelper::GetArraySize(capInfo, "value", arraySize) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis uint32Range value."); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "uint32Range size: %{public}zu.", arraySize); + + if (arraySize != AttrData::RANGE_ARRAY_SIZE) { + HiLog::Error(LABEL, "invalid uint32Range size: %{public}zu.", arraySize); + return ERR_INVALID_PARAMETER; + } + + const json &valueArray = capInfo["value"]; + uint32_t lowerBound = 0; + if (JsonHelper::GetUint32Value(valueArray[AttrData::LOWER_BOUND_INDEX], lowerBound) != SUCCESS) { + HiLog::Error(LABEL, "fail to analyze uint32 value of lowerBound: %{public}u.", lowerBound); + return ERR_INVALID_PARAMETER; + } + + uint32_t upperBound = 0; + if (JsonHelper::GetUint32Value(valueArray[AttrData::UPPER_BOUND_INDEX], upperBound) != SUCCESS) { + HiLog::Error(LABEL, "fail to analyze uint32 value of upperBound: %{public}u.", upperBound); + return ERR_INVALID_PARAMETER; + } + + HiLog::Debug(LABEL, "AnalyzeUint32Range: get lowerBound: %{public}u, upperBound: %{public}u.", lowerBound, + upperBound); + if (attrData.SetData(lowerBound, upperBound) != SUCCESS) { + HiLog::Error(LABEL, "AnalyzeUint32Range: failed to call SetData."); + return ERR_INTERNAL; + } + + return SUCCESS; +} + +uint32_t Capability::AnalyzeStringSet(const json &capInfo, AttrData &attrData) +{ + size_t arraySize; + if (JsonHelper::GetArraySize(capInfo, "value", arraySize) != SUCCESS) { + HiLog::Error(LABEL, "failed to analysis stringSet value."); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "stringSet size: %{public}zu.", arraySize); + + if (arraySize < SET_MIN_VALUE_NUM) { + HiLog::Error(LABEL, "invalid stringSet size: %{public}zu.", arraySize); + return ERR_INVALID_PARAMETER; + } + + const json &valueArray = capInfo["value"]; + string value; + for (size_t i = 0; i < arraySize; i++) { + if (JsonHelper::GetStringValue(valueArray[i], value) != SUCCESS) { + HiLog::Error(LABEL, "failed to analyze string value in stringSet[%{public}zu].", i); + attrData.ClearData(); + return ERR_INVALID_PARAMETER; + } + + HiLog::Debug(LABEL, "AnalyzeStringSet: get stringSet[%{public}zu]: %{public}s.", i, value.c_str()); + if (attrData.InsertSet(std::move(value)) != SUCCESS) { + HiLog::Error(LABEL, "AnalyzeStringSet: failed to call InsertSet."); + attrData.ClearData(); + return ERR_INTERNAL; + } + } + + return SUCCESS; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/capability.h b/plugins/manager/src/framework/capability.h new file mode 100644 index 0000000000000000000000000000000000000000..a060729109304ec76ff575005a04f53165576727 --- /dev/null +++ b/plugins/manager/src/framework/capability.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CAPABILITY_H +#define CAPABILITY_H + +#include +#include +#include "json.hpp" +#include "attr_data.h" +#include "plugin_errors.h" + +namespace OHOS { +namespace MultimediaPlugin { +class Capability final { +public: + Capability() = default; + explicit Capability(const std::map &caps); + explicit Capability(std::map &&caps); + ~Capability() = default; + uint32_t SetCapability(const nlohmann::json &capsInfo); + bool IsCompatible(const std::map &caps) const; + const AttrData *GetCapability(const std::string &key) const; + const std::map &GetCapability() const; + +private: + uint32_t AnalyzeAttrData(const nlohmann::json &capInfo, AttrData &attrData); + uint32_t AnalyzeBool(const nlohmann::json &capInfo, AttrData &attrData); + uint32_t AnalyzeUint32(const nlohmann::json &capInfo, AttrData &attrData); + uint32_t AnalyzeString(const nlohmann::json &capInfo, AttrData &attrData); + uint32_t AnalyzeUint32Set(const nlohmann::json &capInfo, AttrData &attrData); + uint32_t AnalyzeUint32Range(const nlohmann::json &capInfo, AttrData &attrData); + uint32_t AnalyzeStringSet(const nlohmann::json &capInfo, AttrData &attrData); + + static constexpr uint32_t SET_MIN_VALUE_NUM = 1; + static const std::string CAPABILITY_BOOL_TRUE; + static const std::string CAPABILITY_BOOL_FALSE; + static std::map typeMap_; + using CapsMap = std::map; + CapsMap caps_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // CAPABILITY_H diff --git a/plugins/manager/src/framework/impl_class.cpp b/plugins/manager/src/framework/impl_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e96ff57118035f2234b0c80708e93cf18201a26 --- /dev/null +++ b/plugins/manager/src/framework/impl_class.cpp @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "impl_class.h" +#include +#include "hilog/log.h" +#include "impl_class_key.h" +#include "json_helper.h" +#include "log_tags.h" +#include "plugin.h" +#include "plugin_class_base.h" +#include "plugin_common_type.h" +#include "plugin_export.h" + +namespace OHOS { +namespace MultimediaPlugin { +using nlohmann::json; +using std::map; +using std::recursive_mutex; +using std::set; +using std::shared_ptr; +using std::size_t; +using std::string; +using std::weak_ptr; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "ImplClass" }; +string ImplClass::emptyString_; + +ImplClass::ImplClass() : selfKey_(*this) +{} + +uint32_t ImplClass::Register(weak_ptr &plugin, const json &classInfo) +{ + if (state_ != ClassState::CLASS_STATE_UNREGISTER) { + // repeat registration + HiLog::Error(LABEL, "repeat registration."); + return ERR_INTERNAL; + } + + if (JsonHelper::GetStringValue(classInfo, "className", className_) != SUCCESS) { + HiLog::Error(LABEL, "read className failed."); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "register class: %{public}s.", className_.c_str()); + + if (!AnalysisServices(classInfo)) { + HiLog::Error(LABEL, "failed to analysis services for class %{public}s.", className_.c_str()); + return ERR_INVALID_PARAMETER; + } + + uint32_t result = JsonHelper::GetUint16Value(classInfo, "priority", priority_); + if (result != SUCCESS) { + if (result != ERR_NO_TARGET) { + HiLog::Error(LABEL, "read priority failed, result: %{public}u.", result); + return ERR_INVALID_PARAMETER; + } + // priority is optional, and default zero. + priority_ = 0; + } + HiLog::Debug(LABEL, "get class priority: %{public}u.", priority_); + + if (!AnalysisMaxInstance(classInfo)) { + HiLog::Error(LABEL, "failed to analysis maxInstance for class %{public}s.", className_.c_str()); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "get class maxInstance: %{public}u.", maxInstance_); + + if (JsonHelper::CheckElementExistence(classInfo, "capabilities") == SUCCESS) { + capability_.SetCapability(classInfo["capabilities"]); + } + pluginRef_ = plugin; + state_ = ClassState::CLASS_STATE_REGISTERED; + return SUCCESS; +} + +PluginClassBase *ImplClass::CreateObject(uint32_t &errorCode) +{ + errorCode = ERR_INTERNAL; + if (state_ != ClassState::CLASS_STATE_REGISTERED) { + HiLog::Error(LABEL, "failed to create for unregistered, className: %{public}s.", className_.c_str()); + return nullptr; + } + + auto sharedPlugin = pluginRef_.lock(); + if (sharedPlugin == nullptr) { + HiLog::Error(LABEL, "failed to dereference Plugin, className: %{public}s.", className_.c_str()); + return nullptr; + } + + HiLog::Debug(LABEL, "create object, className: %{public}s.", className_.c_str()); + + std::unique_lock guard(dynDataLock_); + if (maxInstance_ != INSTANCE_NO_LIMIT_NUM && instanceNum_ >= maxInstance_) { + HiLog::Error(LABEL, "failed to create for limit, currentNum: %{public}u, maxNum: %{public}u, \ + className: %{public}s.", + instanceNum_, maxInstance_, className_.c_str()); + guard.unlock(); + errorCode = ERR_INSTANCE_LIMIT; + return nullptr; + } + + if (instanceNum_ == 0) { + if (sharedPlugin->Ref() != SUCCESS) { + return nullptr; + } + } + + PluginClassBase *object = DoCreateObject(sharedPlugin); + if (object == nullptr) { + HiLog::Error(LABEL, "create object result null, className: %{public}s.", className_.c_str()); + goto CREATE_INTERNAL_ERROR_EXIT; + } + + ++instanceNum_; + HiLog::Debug(LABEL, "create object success, InstanceNum: %{public}u.", instanceNum_); + guard.unlock(); + + errorCode = SUCCESS; + return object; + +CREATE_INTERNAL_ERROR_EXIT: + if (instanceNum_ == 0) { + sharedPlugin->DeRef(); + } + return nullptr; +} + +weak_ptr ImplClass::GetPluginRef() const +{ + if (state_ != ClassState::CLASS_STATE_REGISTERED) { + return weak_ptr(); + } + + return pluginRef_; +} + +const string &ImplClass::GetClassName() const +{ + return className_; +} + +const string &ImplClass::GetPackageName() const +{ + if (state_ != ClassState::CLASS_STATE_REGISTERED) { + HiLog::Error(LABEL, "get package name, className: %{public}s, state error: %{public}d.", className_.c_str(), + state_); + return emptyString_; + } + + auto sharedPlugin = pluginRef_.lock(); + if (sharedPlugin == nullptr) { + HiLog::Error(LABEL, "get package name, failed to dereference Plugin, className: %{public}s.", + className_.c_str()); + return emptyString_; + } + + return sharedPlugin->GetPackageName(); +} + +bool ImplClass::IsSupport(uint16_t interfaceID) const +{ + HiLog::Debug(LABEL, "search for support iid: %{public}u, className: %{public}s.", interfaceID, className_.c_str()); + for (uint32_t serviceFlag : services_) { + if (MakeIID(serviceFlag) == interfaceID) { + return true; + } + } + + HiLog::Debug(LABEL, "there is no matching interfaceID"); + return false; +} + +void ImplClass::OnObjectDestroy() +{ + // this situation does not happen in design. + // the process context can guarantee that this will not happen. + // the judgment statement here is for protection and positioning purposes only. + if (state_ != ClassState::CLASS_STATE_REGISTERED) { + HiLog::Error(LABEL, "failed to destroy object because class unregistered, className: %{public}s.", + className_.c_str()); + return; + } + + std::unique_lock guard(dynDataLock_); + // this situation does not happen in design. + if (instanceNum_ == 0) { + guard.unlock(); + HiLog::Error(LABEL, "destroy object while instanceNum is zero."); + return; + } + + --instanceNum_; + + auto sharedPlugin = pluginRef_.lock(); + // this situation does not happen in design. + if (sharedPlugin == nullptr) { + guard.unlock(); + HiLog::Error(LABEL, "destroy object failed because failed to dereference Plugin, className: %{public}s.", + className_.c_str()); + return; + } + + HiLog::Debug(LABEL, "destroy object: className: %{public}s", className_.c_str()); + if (instanceNum_ == 0) { + sharedPlugin->DeRef(); + } + + HiLog::Debug(LABEL, "destroy object success, InstanceNum: %{public}u.", instanceNum_); +} + +const set &ImplClass::GetServices() const +{ + return services_; +} + +bool ImplClass::IsCompatible(const map &caps) const +{ + return capability_.IsCompatible(caps); +} + +const AttrData *ImplClass::GetCapability(const string &key) const +{ + if (state_ != ClassState::CLASS_STATE_REGISTERED) { + return nullptr; + } + + return capability_.GetCapability(key); +} + +const std::map &ImplClass::GetCapability() const +{ + return capability_.GetCapability(); +} + +// ------------------------------- private method ------------------------------- +bool ImplClass::AnalysisServices(const json &classInfo) +{ + size_t serviceNum; + if (JsonHelper::GetArraySize(classInfo, "services", serviceNum) != SUCCESS) { + HiLog::Error(LABEL, "read array size of services failed."); + return false; + } + HiLog::Debug(LABEL, "class service num: %{public}zu.", serviceNum); + + uint16_t interfaceID; +#ifndef PLUGIN_FLAG_RTTI_ENABLE + uint32_t lastInterfaceID = UINT32_MAX_VALUE; +#endif + uint16_t serviceType; + uint32_t result; + bool serviceAdded = false; + const json &servicesInfo = classInfo["services"]; + for (size_t i = 0; i < serviceNum; i++) { + const json &serviceInfo = servicesInfo[i]; + if (JsonHelper::GetUint16Value(serviceInfo, "interfaceID", interfaceID) != SUCCESS) { + HiLog::Error(LABEL, "read interfaceID failed at %{public}zu.", i); +#ifndef PLUGIN_FLAG_RTTI_ENABLE + // when -frtti is not enable, to ensure correct base class side-to-side conversion, we require that + // the plugin class inherit only one service interface class and the PluginClassBase class, + // while the location of the service interface class is in front of the PluginClassBase. + // below, we check only one business interface class is allowed to inherit. + HiLog::Error(LABEL, "no valid service info or encounter the risk of more than one business \ + interface base class."); + return false; +#else + continue; +#endif + } + +#ifndef PLUGIN_FLAG_RTTI_ENABLE + // check only one business interface class is allowed to inherit. + if (lastInterfaceID != UINT32_MAX_VALUE && lastInterfaceID != interfaceID) { + HiLog::Error(LABEL, "more than one business interface base class."); + return false; + } + lastInterfaceID = interfaceID; +#endif + result = JsonHelper::GetUint16Value(serviceInfo, "serviceType", serviceType); + if (result != SUCCESS) { + if (result != ERR_NO_TARGET) { + HiLog::Error(LABEL, "read serviceType failed at %{public}zu.", i); + continue; + } + // serviceType is optional, and default zero. + serviceType = 0; + } + + HiLog::Debug(LABEL, "insert class service iid: %{public}u, serviceType: %{public}u.", interfaceID, serviceType); + services_.insert(MakeServiceFlag(interfaceID, serviceType)); + serviceAdded = true; + } + + return serviceAdded; +} + +bool ImplClass::AnalysisMaxInstance(const json &classInfo) +{ + uint32_t result = JsonHelper::GetUint16Value(classInfo, "maxInstance", maxInstance_); + if (result == SUCCESS) { + HiLog::Debug(LABEL, "class maxInstance num: %{public}u.", maxInstance_); + if (maxInstance_ == 0) { + HiLog::Error(LABEL, "class maxInstance num is invalid zero."); + return false; + } + return true; + } + + if (result != ERR_NO_TARGET) { + HiLog::Error(LABEL, "read maxInstance failed."); + return false; + } + + // maxInstance is optional, and value for this case is not limited. + maxInstance_ = INSTANCE_NO_LIMIT_NUM; + return true; +} + +PluginClassBase *ImplClass::DoCreateObject(shared_ptr &plugin) +{ + // since the plugin library may be unloaded and reloaded, the pointer cannot guarantee a constant value, + // so it is reread every time here. + PluginCreateFunc factory = plugin->GetCreateFunc(); + if (factory == nullptr) { + HiLog::Error(LABEL, "failed to get create func, className: %{public}s.", className_.c_str()); + return nullptr; + } + + PluginClassBase *pluginBaseObj = factory(className_); + if (pluginBaseObj == nullptr) { + HiLog::Error(LABEL, "create object result null, className: %{public}s.", className_.c_str()); + return nullptr; + } + +#ifndef PLUGIN_FLAG_RTTI_ENABLE + // when -frtti is not enable, to ensure correct base class side-to-side conversion, + // we require that the plugin class inherit only one service interface class and the PluginClassBase class, + // while the location of the service interface class is in front of the PluginClassBase. + // below, we check the inherited position constraint. + void *obj = dynamic_cast(pluginBaseObj); // adjust pointer position when multiple inheritance. + if (obj == pluginBaseObj) { + // PluginClassBase is the first base class, not allowed. + HiLog::Error(LABEL, "service interface class is not the first base class. className: %{public}s.", + className_.c_str()); + delete pluginBaseObj; + return nullptr; + } +#endif + + if (pluginBaseObj->SetImplClassKey(selfKey_) != PluginClassBase::MAGIC_CODE) { + HiLog::Error(LABEL, "failed to set key, className: %{public}s.", className_.c_str()); + delete pluginBaseObj; + return nullptr; + } + + return pluginBaseObj; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/impl_class.h b/plugins/manager/src/framework/impl_class.h new file mode 100644 index 0000000000000000000000000000000000000000..5f732635526017d89af4d3159af4c16ff2fb7006 --- /dev/null +++ b/plugins/manager/src/framework/impl_class.h @@ -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. + */ + +#ifndef IMPL_CLASS_H +#define IMPL_CLASS_H + +#include +#include +#include +#include +#include "json.hpp" +#include "attr_data.h" +#include "capability.h" +#include "impl_class_key.h" +#include "plugin_errors.h" + +namespace OHOS { +namespace MultimediaPlugin { +class Plugin; +class PluginClassBase; + +enum class ClassState : int32_t { + CLASS_STATE_UNREGISTER = 0, + CLASS_STATE_REGISTERED +}; + +class ImplClass final { +public: + ImplClass(); + ~ImplClass() = default; + static uint32_t MakeServiceFlag(uint16_t interfaceID, uint16_t serviceType) + { + return (((static_cast(interfaceID)) << SERVICETYPE_BIT_NUM) | serviceType); + } + static uint16_t MakeIID(uint32_t serviceFlag) + { + return ((serviceFlag >> SERVICETYPE_BIT_NUM) & IID_MASK); + } + uint32_t Register(std::weak_ptr &plugin, const nlohmann::json &classInfo); + PluginClassBase *CreateObject(uint32_t &errorCode); + std::weak_ptr GetPluginRef() const; + const std::string &GetClassName() const; + const std::string &GetPackageName() const; + bool IsSupport(uint16_t interfaceID) const; + void OnObjectDestroy(); + const std::set &GetServices() const; + bool IsCompatible(const std::map &caps) const; + + uint16_t GetPriority() const + { + return priority_; + } + + const AttrData *GetCapability(const std::string &key) const; + const std::map &GetCapability() const; + + static constexpr uint8_t SERVICETYPE_BIT_NUM = 16; + static constexpr uint32_t IID_MASK = 0xFFFF; + +private: + bool AnalysisServices(const nlohmann::json &classInfo); + bool AnalysisMaxInstance(const nlohmann::json &classInfo); + PluginClassBase *DoCreateObject(std::shared_ptr &plugin); + static constexpr uint16_t INSTANCE_NO_LIMIT_NUM = 0; + static std::string emptyString_; + // dynDataLock_: + // for data that only changes in the register, we don't call it dynamic data. + // non-dynamic data are protected by other means, that is: mutual exclusion between + // the register and createObject processes. + // current dynamic data includes: + // instanceNum_. + std::recursive_mutex dynDataLock_; + ClassState state_ = ClassState::CLASS_STATE_UNREGISTER; + std::string className_; + std::set services_; + uint16_t priority_ = 0; + uint16_t maxInstance_ = 0; + Capability capability_; + std::weak_ptr pluginRef_; + ImplClassKey selfKey_; + uint16_t instanceNum_ = 0; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // IMPL_CLASS_H diff --git a/plugins/manager/src/framework/impl_class_key.cpp b/plugins/manager/src/framework/impl_class_key.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efa1842be8627a6af2ee398874abd10fe6505599 --- /dev/null +++ b/plugins/manager/src/framework/impl_class_key.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "impl_class_key.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "impl_class.h" + +namespace OHOS { +namespace MultimediaPlugin { +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "ImplClassKey" }; + +void ImplClassKey::OnObjectDestroy() +{ + HiLog::Debug(LABEL, "destroy object: className: %{public}s, packageName: %{public}s,", + implClass_.GetClassName().c_str(), implClass_.GetPackageName().c_str()); + + implClass_.OnObjectDestroy(); +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/impl_class_key.h b/plugins/manager/src/framework/impl_class_key.h new file mode 100644 index 0000000000000000000000000000000000000000..4aa8669aaae2314e3f9149cc9f43d45b48b4356b --- /dev/null +++ b/plugins/manager/src/framework/impl_class_key.h @@ -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. + */ + +#ifndef IMPL_CLASS_KEY_H +#define IMPL_CLASS_KEY_H + +#include "abs_impl_class_key.h" + +namespace OHOS { +namespace MultimediaPlugin { +class ImplClass; + +class ImplClassKey final : public AbsImplClassKey { +public: + // must guarantee that the key object continue to be valid until all corresponding instances are destroyed. + explicit ImplClassKey(ImplClass &key) : implClass_(key) {}; + ~ImplClassKey() = default; + void OnObjectDestroy() override; + +private: + ImplClass &implClass_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // IMPL_CLASS_KEY_H \ No newline at end of file diff --git a/plugins/manager/src/framework/impl_class_mgr.cpp b/plugins/manager/src/framework/impl_class_mgr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9209fa099688ab460e5edaae81a7b118a63aa940 --- /dev/null +++ b/plugins/manager/src/framework/impl_class_mgr.cpp @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "impl_class_mgr.h" +#include "hilog/log.h" +#include "impl_class.h" +#include "log_tags.h" +#include "plugin.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace MultimediaPlugin { +using nlohmann::json; +using std::list; +using std::map; +using std::multimap; +using std::mutex; +using std::set; +using std::shared_ptr; +using std::string; +using std::weak_ptr; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "ImplClassMgr" }; + +uint32_t ImplClassMgr::AddClass(weak_ptr &plugin, const json &classInfo) +{ + shared_ptr implClass = std::make_shared(); + if (implClass == nullptr) { + HiLog::Error(LABEL, "AddClass: failed to create ImplClass."); + return ERR_INTERNAL; + } + + auto ret = implClass->Register(plugin, classInfo); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "AddClass: failed to register impClass.ERRNO: %{public}u.", ret); + return ret; + } + + const string &key = implClass->GetClassName(); + if (key.empty()) { + HiLog::Error(LABEL, "AddClass: empty className."); + return ERR_INTERNAL; + } + + HiLog::Debug(LABEL, "AddClass: insert Class: %{public}s.", key.c_str()); + classMultimap_.insert(NameClassMultimap::value_type(&key, implClass)); + + // for fast search by service flag + const set &services = implClass->GetServices(); + for (const uint32_t &srv : services) { + HiLog::Debug(LABEL, "AddClass: insert service: %{public}u.", srv); + srvSearchMultimap_.insert(ServiceClassMultimap::value_type(srv, implClass)); + } + + return SUCCESS; +} + +void ImplClassMgr::DeleteClass(const weak_ptr &plugin) +{ + // delete all ImplClass under the specified plugin. + auto targetPlugin = plugin.lock(); + + for (auto iter = srvSearchMultimap_.begin(); iter != srvSearchMultimap_.end();) { + auto tmpPlugin = iter->second->GetPluginRef().lock(); + if (tmpPlugin != targetPlugin) { + ++iter; + continue; + } + iter = srvSearchMultimap_.erase(iter); + } + + for (auto iter = classMultimap_.begin(); iter != classMultimap_.end();) { + auto tmpPlugin = iter->second->GetPluginRef().lock(); + if (tmpPlugin != targetPlugin) { + ++iter; + continue; + } + iter = classMultimap_.erase(iter); + } +} + +PluginClassBase *ImplClassMgr::CreateObject(uint16_t interfaceID, const string &className, uint32_t &errorCode) +{ + HiLog::Debug(LABEL, "create object iid: %{public}u, className: %{public}s.", interfaceID, className.c_str()); + + NameClassMultimap::iterator iter = classMultimap_.lower_bound(&className); + NameClassMultimap::iterator endIter = classMultimap_.upper_bound(&className); + if (iter == endIter) { + HiLog::Error(LABEL, "failed to find matching class by className: %{public}s.", className.c_str()); + errorCode = ERR_MATCHING_PLUGIN; + return nullptr; + } + + for (; iter != endIter; ++iter) { + if (iter->second->IsSupport(interfaceID)) { + return iter->second->CreateObject(errorCode); + } + } + + // no this class + HiLog::Error(LABEL, "failed to find matching class for iid: %{public}u, className: %{public}s.", interfaceID, + className.c_str()); + errorCode = ERR_MATCHING_PLUGIN; + return nullptr; +} + +PluginClassBase *ImplClassMgr::CreateObject(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode) +{ + uint32_t serviceFlag = ImplClass::MakeServiceFlag(interfaceID, serviceType); + list> candidates; + + HiLog::Debug(LABEL, "create object iid: %{public}u, serviceType: %{public}u.", interfaceID, serviceType); + + auto iter = srvSearchMultimap_.lower_bound(serviceFlag); + auto endIter = srvSearchMultimap_.upper_bound(serviceFlag); + for (; iter != endIter; ++iter) { + shared_ptr &temp = iter->second; + if ((!capabilities.empty()) && (!temp->IsCompatible(capabilities))) { + continue; + } + candidates.push_back(temp); + } + + shared_ptr target = SearchByPriority(candidates, priorityScheme); + if (target == nullptr) { + HiLog::Error(LABEL, "failed to find class by priority."); + errorCode = ERR_MATCHING_PLUGIN; + return nullptr; + } + + HiLog::Debug(LABEL, "search by priority result, className: %{public}s.", target->GetClassName().c_str()); + return target->CreateObject(errorCode); +} + +uint32_t ImplClassMgr::ImplClassMgrGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + std::vector &classesInfo) +{ + // get service flag by interfaceID and serviceType + uint32_t serviceFlag = ImplClass::MakeServiceFlag(interfaceID, serviceType); + + HiLog::Debug(LABEL, "get classinfo iid: %{public}u, serviceType: %{public}u.", interfaceID, serviceType); + auto iter = srvSearchMultimap_.lower_bound(serviceFlag); + auto endIter = srvSearchMultimap_.upper_bound(serviceFlag); + if (iter == endIter) { + HiLog::Error(LABEL, "failed to get class by serviceFlag, iid: %{public}u, serviceType: %{public}u.", + interfaceID, serviceType); + return ERR_MATCHING_PLUGIN; + } + + for (; iter != endIter; ++iter) { + shared_ptr &temp = iter->second; + if ((capabilities.size() != 0) && (!temp->IsCompatible(capabilities))) { + continue; + } + // after multiple filtering, there are only a few instances here, which will not cause massive logs. + HiLog::Debug(LABEL, "found by serviceFlag & capabilities, className: %{public}s.", + temp->GetClassName().c_str()); + ClassInfo classInfo; + classInfo.packageName = temp->GetPackageName(); + classInfo.className = temp->GetClassName(); + classInfo.priority = temp->GetPriority(); + classInfo.capabilities = temp->GetCapability(); + classesInfo.emplace_back(std::move(classInfo)); + } + + if (classesInfo.empty()) { + HiLog::Error(LABEL, "failed to get class by capabilities, iid: %{public}u, serviceType: %{public}u.", + interfaceID, serviceType); + return ERR_MATCHING_PLUGIN; + } + + return SUCCESS; +} + +shared_ptr ImplClassMgr::GetImplClass(const string &packageName, const string &className) +{ + HiLog::Debug(LABEL, "search ImplClass, className: %{public}s.", className.c_str()); + shared_ptr implClass = nullptr; + auto iter = classMultimap_.lower_bound(&className); + auto endIter = classMultimap_.upper_bound(&className); + for (; iter != endIter; ++iter) { + if (packageName == iter->second->GetPackageName()) { + implClass = iter->second; + break; + } + } + + if (implClass == nullptr) { + HiLog::Error(LABEL, "failed to get ImplClass, className: %{public}s.", className.c_str()); + } + + return implClass; +} + +// ------------------------------- private method ------------------------------- +ImplClassMgr::ImplClassMgr() +{} + +ImplClassMgr::~ImplClassMgr() +{} + +shared_ptr ImplClassMgr::SearchByPriority(const list> &candidates, + const PriorityScheme &priorityScheme) +{ + auto size = candidates.size(); + if (size == 0) { // 0 means class no candidate, return empty directly. + HiLog::Error(LABEL, "SearchByPriority: candidates size is zero."); + return nullptr; + } + + if (size == 1) { // 1 means class only one candidate, no need to handle priority, return directly. + return candidates.front(); + } + + if (priorityScheme.GetPriorityType() == PriorityType::PRIORITY_TYPE_NULL) { + // no attribute priority policy, we only compare static priority + return SearchSimplePriority(candidates); + } + + PriorityType priorityType = priorityScheme.GetPriorityType(); + const string &attrKey = priorityScheme.GetAttrKey(); + + auto targetIter = candidates.begin(); + // targetAttr is allowed to be empty. + // when the target ImplClass does not have this attribute, the value of targetAttr is null, + // and the subsequent priority comparison process will judge and handle this situation. + const AttrData *targetAttr = ((*targetIter)->GetCapability)(attrKey); + + auto tempIter = targetIter; + for (++tempIter; tempIter != candidates.end(); ++tempIter) { + const AttrData *attrData = ((*tempIter)->GetCapability)(attrKey); + if (attrData == nullptr) { + continue; + } + + if (targetAttr == nullptr) { + targetIter = tempIter; + targetAttr = attrData; + continue; + } + + // the result value is used later, the targetIter and targetAttr assignment structures cannot be merged, + // and the the merged logic will not understand well. + uint32_t result = ComparePriority(*attrData, *targetAttr, priorityType); + if (result == ERR_COMP_HIGHER) { + targetIter = tempIter; + targetAttr = attrData; + continue; + } + + // if the priority attribute are equal, we further compare the static priority. + if (result == ERR_COMP_EQUAL) { + if (((*tempIter)->GetPriority()) > ((*targetIter)->GetPriority())) { + targetIter = tempIter; + targetAttr = attrData; + } + } + } + + return *targetIter; +} + +shared_ptr ImplClassMgr::SearchSimplePriority(const list> &candidates) +{ + if (candidates.size() == 0) { + HiLog::Error(LABEL, "SearchSimplePriority: candidates size is zero."); + return nullptr; + } + auto targetIter = candidates.begin(); + auto tempIter = targetIter; + + for (++tempIter; tempIter != candidates.end(); ++tempIter) { + if (((*tempIter)->GetPriority()) > ((*targetIter)->GetPriority())) { + targetIter = tempIter; + } + } + + return *targetIter; +} + +uint32_t ImplClassMgr::ComparePriority(const AttrData &lhs, const AttrData &rhs, PriorityType type) +{ + if (lhs.GetType() != rhs.GetType()) { + HiLog::Error(LABEL, "compare between different types, %{public}d and %{public}d.", lhs.GetType(), + rhs.GetType()); + return ERR_COMP_ERROR; + } + + switch (lhs.GetType()) { + case AttrDataType::ATTR_DATA_NULL: { + return ERR_COMP_EQUAL; + } + case AttrDataType::ATTR_DATA_BOOL: { + return CompareBoolPriority(lhs, rhs, type); + } + case AttrDataType::ATTR_DATA_UINT32: + case AttrDataType::ATTR_DATA_UINT32_SET: + case AttrDataType::ATTR_DATA_UINT32_RANGE: { + return CompareUint32Priority(lhs, rhs, type); + } + case AttrDataType::ATTR_DATA_STRING: + case AttrDataType::ATTR_DATA_STRING_SET: { + return CompareStringPriority(lhs, rhs, type); + } + default: { + HiLog::Error(LABEL, "invalid data type: %{public}d.", lhs.GetType()); + return ERR_COMP_ERROR; + } + } +} + +// for the bool type, the meaning of the size is unknown. we artificially define true greater than false here. +uint32_t ImplClassMgr::CompareBoolPriority(const AttrData &lhs, const AttrData &rhs, PriorityType type) +{ + bool lhsValue = false; + bool rhsValue = false; + + if ((lhs.GetValue(lhsValue) != SUCCESS) || (rhs.GetValue(rhsValue) != SUCCESS)) { + HiLog::Error(LABEL, "CompareBoolPriority: failed to get attrubute value."); + return ERR_COMP_ERROR; + } + + if (type == PriorityType::PRIORITY_ORDER_BY_ATTR_ASCENDING) { + if (lhsValue) { + if (!rhsValue) { + return ERR_COMP_LOWER; + } + return ERR_COMP_EQUAL; + } + + if (rhsValue) { + return ERR_COMP_HIGHER; + } + + return ERR_COMP_EQUAL; + } + + if (lhsValue) { + if (!rhsValue) { + return ERR_COMP_HIGHER; + } + return ERR_COMP_EQUAL; + } + + if (rhsValue) { + return ERR_COMP_LOWER; + } + + return ERR_COMP_EQUAL; +} + +uint32_t ImplClassMgr::CompareUint32Priority(const AttrData &lhs, const AttrData &rhs, PriorityType type) +{ + uint32_t lhsValue = 0; + uint32_t rhsValue = 0; + + if (type == PriorityType::PRIORITY_ORDER_BY_ATTR_ASCENDING) { + if ((lhs.GetMinValue(lhsValue) != SUCCESS) || (rhs.GetMinValue(rhsValue) != SUCCESS)) { + HiLog::Error(LABEL, "CompareUint32Priority: failed to get attrubute min value."); + return ERR_COMP_ERROR; + } + + if (lhsValue < rhsValue) { + return ERR_COMP_HIGHER; + } + + if (lhsValue == rhsValue) { + return ERR_COMP_EQUAL; + } + + return ERR_COMP_LOWER; + } + + if ((lhs.GetMaxValue(lhsValue) != SUCCESS) || (rhs.GetMaxValue(rhsValue) != SUCCESS)) { + HiLog::Error(LABEL, "CompareUint32Priority: failed to get attrubute max value."); + return ERR_COMP_ERROR; + } + + if (lhsValue < rhsValue) { + return ERR_COMP_LOWER; + } + + if (lhsValue == rhsValue) { + return ERR_COMP_EQUAL; + } + + return ERR_COMP_HIGHER; +} + +uint32_t ImplClassMgr::CompareStringPriority(const AttrData &lhs, const AttrData &rhs, PriorityType type) +{ + const string *lhsValue = nullptr; + const string *rhsValue = nullptr; + + if (type == PriorityType::PRIORITY_ORDER_BY_ATTR_ASCENDING) { + if ((lhs.GetMinValue(lhsValue) != SUCCESS) || (rhs.GetMinValue(rhsValue) != SUCCESS)) { + HiLog::Error(LABEL, "CompareStringPriority: failed to get attrubute min value."); + return ERR_COMP_ERROR; + } + + if (*lhsValue < *rhsValue) { + return ERR_COMP_HIGHER; + } + + if (*lhsValue == *rhsValue) { + return ERR_COMP_EQUAL; + } + + return ERR_COMP_LOWER; + } + + if ((lhs.GetMaxValue(lhsValue) != SUCCESS) || (rhs.GetMaxValue(rhsValue) != SUCCESS)) { + HiLog::Error(LABEL, "CompareStringPriority: failed to get attrubute max value."); + + return ERR_COMP_ERROR; + } + + if (*lhsValue < *rhsValue) { + return ERR_COMP_LOWER; + } + + if (*lhsValue == *rhsValue) { + return ERR_COMP_EQUAL; + } + + return ERR_COMP_HIGHER; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/impl_class_mgr.h b/plugins/manager/src/framework/impl_class_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..f36fa1c7041b86a4f87d5528accb509b279fe2ae --- /dev/null +++ b/plugins/manager/src/framework/impl_class_mgr.h @@ -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. + */ + +#ifndef IMPL_CLASS_MGR_H +#define IMPL_CLASS_MGR_H + +#include +#include +#include "json.hpp" +#include "nocopyable.h" +#include "plugin_common_type.h" +#include "plugin_errors.h" +#include "pointer_key_map.h" +#include "priority_scheme.h" +#include "singleton.h" + +namespace OHOS { +namespace MultimediaPlugin { +class ImplClass; +class Plugin; +class PluginClassBase; + +class ImplClassMgr final : public NoCopyable { +public: + uint32_t AddClass(std::weak_ptr &plugin, const nlohmann::json &classInfo); + void DeleteClass(const std::weak_ptr &plugin); + PluginClassBase *CreateObject(uint16_t interfaceID, const std::string &className, uint32_t &errorCode); + PluginClassBase *CreateObject(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode); + uint32_t ImplClassMgrGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, std::vector &classesInfo); + std::shared_ptr GetImplClass(const std::string &packageName, const std::string &className); + DECLARE_DELAYED_REF_SINGLETON(ImplClassMgr); + +private: + std::shared_ptr SearchByPriority(const std::list> &candidates, + const PriorityScheme &priorityScheme); + std::shared_ptr SearchSimplePriority(const std::list> &candidates); + uint32_t ComparePriority(const AttrData &lhs, const AttrData &rhs, PriorityType type); + uint32_t CompareBoolPriority(const AttrData &lhs, const AttrData &rhs, PriorityType type); + uint32_t CompareUint32Priority(const AttrData &lhs, const AttrData &rhs, PriorityType type); + uint32_t CompareStringPriority(const AttrData &lhs, const AttrData &rhs, PriorityType type); + + using NameClassMultimap = PointerKeyMultimap>; + using ServiceClassMultimap = std::multimap>; + NameClassMultimap classMultimap_; + ServiceClassMultimap srvSearchMultimap_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // IMPL_CLASS_MGR_H diff --git a/plugins/manager/src/framework/json_helper.cpp b/plugins/manager/src/framework/json_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e295adbed10c0f2853abde65a3620e66707be343 --- /dev/null +++ b/plugins/manager/src/framework/json_helper.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "json_helper.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_common_type.h" + +namespace OHOS { +namespace MultimediaPlugin { +using nlohmann::json; +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JsonHelper" }; +json JsonHelper::nullJson_; + +uint32_t JsonHelper::CheckElementExistence(const json &jsonObject, const string &key) +{ + uint32_t errorCode; + GetJsonElement(jsonObject, key, errorCode); + return errorCode; +} + +uint32_t JsonHelper::GetStringValue(const json &jsonString, string &value) +{ + if (!jsonString.is_string()) { + HiLog::Error(LABEL, "GetStringValue: not a string type value."); + return ERR_DATA_TYPE; + } + + value = jsonString; + return SUCCESS; +} + +uint32_t JsonHelper::GetStringValue(const json &jsonObject, const string &key, string &value) +{ + uint32_t result; + const json &jsonString = GetJsonElement(jsonObject, key, result); + if (result != SUCCESS) { + PrintElementMissingLog("GetStringValue", key, result); + return result; + } + + return GetStringValue(jsonString, value); +} + +uint32_t JsonHelper::GetUint32Value(const json &jsonNum, uint32_t &value) +{ + if (!jsonNum.is_number_integer()) { + HiLog::Error(LABEL, "GetUint32Value: not a integer type value."); + return ERR_DATA_TYPE; + } + + if (jsonNum < 0) { + HiLog::Error(LABEL, "GetUint32Value: not a unsigned integer type value, num: %{public}lld.", + static_cast(jsonNum)); + return ERR_DATA_TYPE; + } + + if (jsonNum > UINT32_MAX_VALUE) { + HiLog::Error(LABEL, "GetUint32Value: out of range value, num: %{public}llu.", + static_cast(jsonNum)); + return ERR_DATA_TYPE; + } + + value = jsonNum; + return SUCCESS; +} + +uint32_t JsonHelper::GetUint32Value(const json &jsonObject, const string &key, uint32_t &value) +{ + uint32_t result; + const json &jsonNum = GetJsonElement(jsonObject, key, result); + if (result != SUCCESS) { + PrintElementMissingLog("GetUint32Value", key, result); + return result; + } + + return GetUint32Value(jsonNum, value); +} + +uint32_t JsonHelper::GetUint16Value(const json &jsonObject, const string &key, uint16_t &value) +{ + uint32_t result; + const json &jsonNum = GetJsonElement(jsonObject, key, result); + if (result != SUCCESS) { + PrintElementMissingLog("GetUint16Value", key, result); + return result; + } + + if (!jsonNum.is_number_integer()) { + HiLog::Error(LABEL, "GetUint16Value: not a integer type value for key %{public}s.", key.c_str()); + return ERR_DATA_TYPE; + } + + if (jsonNum < 0) { + HiLog::Error(LABEL, "GetUint16Value: not a unsigned integer type value for key %{public}s, num: %{public}lld.", + key.c_str(), static_cast(jsonNum)); + return ERR_DATA_TYPE; + } + + if (jsonNum > UINT16_MAX_VALUE) { + HiLog::Error(LABEL, "GetUint16Value: out of range value for key %{public}s, num: %{public}llu.", key.c_str(), + static_cast(jsonNum)); + return ERR_DATA_TYPE; + } + + value = jsonNum; + return SUCCESS; +} + +uint32_t JsonHelper::GetArraySize(const json &jsonObject, const string &key, size_t &size) +{ + uint32_t result; + const json &jsonArray = GetJsonElement(jsonObject, key, result); + if (result != SUCCESS) { + PrintElementMissingLog("GetArraySize", key, result); + return result; + } + + if (!jsonArray.is_array()) { + HiLog::Error(LABEL, "GetArraySize: not a array type value for key %{public}s.", key.c_str()); + return ERR_DATA_TYPE; + } + + size = jsonArray.size(); + return SUCCESS; +} + +// ------------------------------- private method ------------------------------- +const json &JsonHelper::GetJsonElement(const json &jsonObject, const string &key, uint32_t &errorCode) +{ + if (!jsonObject.is_object()) { + HiLog::Error(LABEL, "GetJsonElement: not a object type json for key %{public}s.", key.c_str()); + errorCode = ERR_DATA_TYPE; + return nullJson_; + } + + auto iter = jsonObject.find(key); + if (iter == jsonObject.end()) { + // some elements are optional, it is normal to miss them, so do not use error level here. + HiLog::Debug(LABEL, "GetJsonElement: failed to find key %{public}s.", key.c_str()); + errorCode = ERR_NO_TARGET; + return nullJson_; + } + + errorCode = SUCCESS; + return *iter; +} + +void JsonHelper::PrintElementMissingLog(const std::string &identifier, const std::string &key, uint32_t errorCode) +{ + if (errorCode == ERR_NO_TARGET) { + // some elements are optional, it is normal to miss them, so do not use error level here. + HiLog::Debug(LABEL, "%{public}s: failed to find key %{public}s, ERRNO: %{public}u.", identifier.c_str(), + key.c_str(), errorCode); + } else { + HiLog::Error(LABEL, "%{public}s: failed to find key %{public}s, ERRNO: %{public}u.", identifier.c_str(), + key.c_str(), errorCode); + } +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/json_helper.h b/plugins/manager/src/framework/json_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..b6c8c64d4a7b3a0848b1520af6850b5accf6d4c2 --- /dev/null +++ b/plugins/manager/src/framework/json_helper.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JSON_HELPER_H +#define JSON_HELPER_H + +#include +#include "json.hpp" + +namespace OHOS { +namespace MultimediaPlugin { +class JsonHelper final { +public: + static uint32_t CheckElementExistence(const nlohmann::json &jsonObject, const std::string &key); + static uint32_t GetStringValue(const nlohmann::json &jsonString, std::string &value); + static uint32_t GetStringValue(const nlohmann::json &jsonObject, const std::string &key, std::string &value); + static uint32_t GetUint32Value(const nlohmann::json &jsonNum, uint32_t &value); + static uint32_t GetUint32Value(const nlohmann::json &jsonObject, const std::string &key, uint32_t &value); + static uint32_t GetUint16Value(const nlohmann::json &jsonObject, const std::string &key, uint16_t &value); + static uint32_t GetArraySize(const nlohmann::json &jsonObject, const std::string &key, size_t &size); + +private: + static const nlohmann::json &GetJsonElement(const nlohmann::json &jsonObject, + const std::string &key, + uint32_t &errorCode); + static void PrintElementMissingLog(const std::string &identifier, const std::string &key, uint32_t errorCode); + static nlohmann::json nullJson_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // JSON_HELPER_H \ No newline at end of file diff --git a/plugins/manager/src/framework/plugin.cpp b/plugins/manager/src/framework/plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ebb32a30afbe1666ba60e344e6ad661b2f548a00 --- /dev/null +++ b/plugins/manager/src/framework/plugin.cpp @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin.h" +#include +#include "hilog/log.h" +#include "impl_class_mgr.h" +#include "json.hpp" +#include "json_helper.h" +#include "log_tags.h" +#include "platform_adp.h" +#include "singleton.h" +#ifdef _WIN32 +#include +HMODULE hDll = NULL; +#endif + +namespace OHOS { +namespace MultimediaPlugin { +using nlohmann::json; +using std::istream; +using std::istringstream; +using std::recursive_mutex; +using std::size_t; +using std::string; +using std::weak_ptr; +using namespace OHOS::HiviewDFX; + +enum class VersionParseStep : int32_t { STEP_MAJOR = 0, STEP_MINOR, STEP_MICRO, STEP_NANO, STEP_FINISHED }; + +struct VersionNum { + uint16_t major = 0; + uint16_t minor = 0; + uint16_t micro = 0; + uint16_t nano = 0; +}; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "Plugin" }; + +Plugin::Plugin() + : platformAdp_(DelayedRefSingleton::GetInstance()), + implClassMgr_(DelayedRefSingleton::GetInstance()) {} + +Plugin::~Plugin() +{ + std::unique_lock guard(dynDataLock_); + if (refNum_ != 0) { + // this situation does not happen in design. + // the process context can guarantee that this will not happen. + // the judgment statement here is for protection and positioning purposes only. + HiLog::Error(LABEL, "release plugin: refNum: %{public}u.", refNum_); + } + + implClassMgr_.DeleteClass(plugin_); + FreeLibrary(); +} + +uint32_t Plugin::Register(istream &metadata, string &&libraryPath, weak_ptr &plugin) +{ + std::unique_lock guard(dynDataLock_); + if (state_ != PluginState::PLUGIN_STATE_UNREGISTER) { + guard.unlock(); + HiLog::Error(LABEL, "repeat registration."); + return ERR_INTERNAL; + } + + auto ret = RegisterMetadata(metadata, plugin); + if (ret != SUCCESS) { + guard.unlock(); + HiLog::Error(LABEL, "failed to register metadata, ERRNO: %{public}u.", ret); + return ret; + } + + libraryPath_ = std::move(libraryPath); + plugin_ = plugin; + state_ = PluginState::PLUGIN_STATE_REGISTERED; + return SUCCESS; +} + +uint32_t Plugin::Ref() +{ + // once the client make a ref, it can use the plugin at any time, + // so we do the necessary preparations here. + std::unique_lock guard(dynDataLock_); + if (state_ == PluginState::PLUGIN_STATE_REGISTERED) { + if (ResolveLibrary() != SUCCESS) { + guard.unlock(); + HiLog::Error(LABEL, "failed to resolve library."); + return ERR_GENERAL; + } + state_ = PluginState::PLUGIN_STATE_RESOLVED; + } + + if (state_ == PluginState::PLUGIN_STATE_RESOLVED) { + // maybe asynchronous, or for reduce the locking time + state_ = PluginState::PLUGIN_STATE_STARTING; + if (!startFunc_()) { + HiLog::Error(LABEL, "failed to start plugin."); + FreeLibrary(); + state_ = PluginState::PLUGIN_STATE_REGISTERED; + return ERR_GENERAL; + } + state_ = PluginState::PLUGIN_STATE_ACTIVE; + } + + if (state_ != PluginState::PLUGIN_STATE_ACTIVE) { + HiLog::Error(LABEL, "plugin ref: state error, state: %{public}d.", state_); + return ERR_GENERAL; + } + + ++refNum_; + HiLog::Debug(LABEL, "plugin refNum: %{public}d.", refNum_); + return SUCCESS; +} + +void Plugin::DeRef() +{ + std::unique_lock guard(dynDataLock_); + if (refNum_ == 0) { + // this situation does not happen in design. + // the process context can guarantee that this will not happen. + // the judgment statement here is for protection and positioning purposes only. + guard.unlock(); + HiLog::Error(LABEL, "DeRef while RefNum is zero."); + return; + } + + --refNum_; + HiLog::Debug(LABEL, "plugin refNum: %{public}d.", refNum_); +} + +void Plugin::Block() +{ + // used to protect against business interruptions during plugin upgrades. + // after the plugin is upgraded, if the original .so is being used, + // it cannot be released immediately and should be locked, + // and the subsequent requests are migrated to the new .so. + std::unique_lock guard(dynDataLock_); + blocked_ = true; +} + +void Plugin::Unblock() +{ + std::unique_lock guard(dynDataLock_); + blocked_ = false; +} + +PluginCreateFunc Plugin::GetCreateFunc() +{ + std::unique_lock guard(dynDataLock_); + if ((state_ != PluginState::PLUGIN_STATE_ACTIVE) || (refNum_ == 0)) { + // In this case, we can't guarantee that the pointer is lasting valid. + HiLog::Error(LABEL, "failed to get create func, State: %{public}d, RefNum: %{public}u.", state_, refNum_); + return nullptr; + } + + return createFunc_; +} + +const string &Plugin::GetLibraryPath() const +{ + return libraryPath_; +} + +const string &Plugin::GetPackageName() const +{ + return packageName_; +} + +// ------------------------------- private method ------------------------------- +uint32_t Plugin::ResolveLibrary() +{ + std::string pluginStartSymbol = "PluginExternalStart"; + std::string pluginStopSymbol = "PluginExternalStop"; + std::string pluginCreateSymbol = "PluginExternalCreate"; + +#ifdef _WIN32 + hDll = platformAdp_.AdpLoadLibrary(libraryPath_); + if (hDll == NULL) { + HiLog::Error(LABEL, "failed to load library."); + return ERR_GENERAL; + } + + startFunc_ = (PluginStartFunc)platformAdp_.AdpGetSymAddress(hDll, pluginStartSymbol); + stopFunc_ = (PluginStopFunc)platformAdp_.AdpGetSymAddress(hDll, pluginStopSymbol); + createFunc_ = (PluginCreateFunc)platformAdp_.AdpGetSymAddress(hDll, pluginCreateSymbol); + if (startFunc_ == NULL || stopFunc_ == NULL || createFunc_ == NULL) { + HiLog::Error(LABEL, "failed to get export symbol for the plugin."); + FreeLibrary(); + return ERR_GENERAL; + } + + return SUCCESS; +#else + handle_ = platformAdp_.LoadLibrary(libraryPath_); + if (handle_ == nullptr) { + HiLog::Error(LABEL, "failed to load library."); + return ERR_GENERAL; + } + + startFunc_ = (PluginStartFunc)platformAdp_.GetSymAddress(handle_, pluginStartSymbol); + stopFunc_ = (PluginStopFunc)platformAdp_.GetSymAddress(handle_, pluginStopSymbol); + createFunc_ = (PluginCreateFunc)platformAdp_.GetSymAddress(handle_, pluginCreateSymbol); + if (startFunc_ == nullptr || stopFunc_ == nullptr || createFunc_ == nullptr) { + HiLog::Error(LABEL, "failed to get export symbol for the plugin."); + FreeLibrary(); + return ERR_GENERAL; + } + + return SUCCESS; +#endif +} + +void Plugin::FreeLibrary() +{ +#ifdef _WIN32 + if (state_ == PluginState::PLUGIN_STATE_STARTING || state_ == PluginState::PLUGIN_STATE_ACTIVE) { + if (stopFunc_ != NULL) { + stopFunc_(); + } + } + if (handle_ == NULL) { + return; + } + platformAdp_.AdpFreeLibrary(hDll); + hDll = NULL; + startFunc_ = NULL; + stopFunc_ = NULL; + createFunc_ = NULL; +#else + if (state_ == PluginState::PLUGIN_STATE_STARTING || state_ == PluginState::PLUGIN_STATE_ACTIVE) { + if (stopFunc_ != nullptr) { + stopFunc_(); + } + } + + if (handle_ == nullptr) { + return; + } + + platformAdp_.FreeLibrary(handle_); + handle_ = nullptr; + startFunc_ = nullptr; + stopFunc_ = nullptr; + createFunc_ = nullptr; +#endif +} + +uint32_t Plugin::RegisterMetadata(istream &metadata, weak_ptr &plugin) +{ + json root; + metadata >> root; + if (JsonHelper::GetStringValue(root, "packageName", packageName_) != SUCCESS) { + HiLog::Error(LABEL, "read packageName failed."); + return ERR_INVALID_PARAMETER; + } + + string targetVersion; + if (JsonHelper::GetStringValue(root, "targetVersion", targetVersion) != SUCCESS) { + HiLog::Error(LABEL, "read targetVersion failed."); + return ERR_INVALID_PARAMETER; + } + uint32_t ret = CheckTargetVersion(targetVersion); + if (ret != SUCCESS) { + // target version is not compatible + HiLog::Error(LABEL, "check targetVersion failed, Version: %{public}s, ERRNO: %{public}u.", + targetVersion.c_str(), ret); + return ret; + } + + if (JsonHelper::GetStringValue(root, "version", version_) != SUCCESS) { + HiLog::Error(LABEL, "read version failed."); + return ERR_INVALID_PARAMETER; + } + VersionNum versionNum; + ret = AnalyzeVersion(version_, versionNum); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "check version failed, Version: %{public}s, ERRNO: %{public}u.", version_.c_str(), ret); + return ret; + } + + size_t classNum; + if (JsonHelper::GetArraySize(root, "classes", classNum) != SUCCESS) { + HiLog::Error(LABEL, "get array size of classes failed."); + return ERR_INVALID_PARAMETER; + } + HiLog::Debug(LABEL, "parse class num: %{public}zu.", classNum); + for (size_t i = 0; i < classNum; i++) { + const json &classInfo = root["classes"][i]; + if (implClassMgr_.AddClass(plugin, classInfo) != SUCCESS) { + HiLog::Error(LABEL, "failed to add class, index: %{public}zu.", i); + continue; + } + } + + return SUCCESS; +} + +uint32_t Plugin::CheckTargetVersion(const string &targetVersion) +{ + VersionNum versionNum; + auto ret = AnalyzeVersion(targetVersion, versionNum); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "failed to analyze version, ERRNO: %{public}u.", ret); + return ret; + } + + return SUCCESS; +} + +uint32_t Plugin::AnalyzeVersion(const string &versionInfo, VersionNum &versionNum) +{ + VersionParseStep step = VersionParseStep::STEP_MAJOR; + istringstream versionInput(versionInfo); + uint16_t versionArray[VERSION_ARRAY_SIZE] = { 0 }; // major, minor, micro, nano. + string tmp; + + while (getline(versionInput, tmp, '.')) { + auto ret = ExecuteVersionAnalysis(tmp, step, versionArray); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "failed to execute version analysis, ERRNO: %{public}u.", ret); + return ret; + } + } + + if (step == VersionParseStep::STEP_NANO) { + // we treat nano version as optional, and default 0. + HiLog::Debug(LABEL, "default nano version 0."); + versionArray[VERSION_NANO_INDEX] = 0; + step = VersionParseStep::STEP_FINISHED; + } + + if (step != VersionParseStep::STEP_FINISHED) { + HiLog::Error(LABEL, "analysis version failed, step = %{public}d.", step); + return ERR_INVALID_PARAMETER; + } + + versionNum.major = versionArray[VERSION_MAJOR_INDEX]; + versionNum.minor = versionArray[VERSION_MINOR_INDEX]; + versionNum.micro = versionArray[VERSION_MICRO_INDEX]; + versionNum.nano = versionArray[VERSION_NANO_INDEX]; + + HiLog::Debug(LABEL, "analysis result: %{public}u.%{public}u.%{public}u.%{public}u.", versionNum.major, + versionNum.minor, versionNum.micro, versionNum.nano); + + return SUCCESS; +} + +uint32_t Plugin::ExecuteVersionAnalysis(const string &input, VersionParseStep &step, + uint16_t (&versionNum)[VERSION_ARRAY_SIZE]) +{ + switch (step) { + case VersionParseStep::STEP_MAJOR: { + auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MAJOR_INDEX]); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "read major version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), + ret); + return ret; + } + step = VersionParseStep::STEP_MINOR; + break; + } + case VersionParseStep::STEP_MINOR: { + auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MINOR_INDEX]); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "read minor version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), + ret); + return ret; + } + step = VersionParseStep::STEP_MICRO; + break; + } + case VersionParseStep::STEP_MICRO: { + auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MICRO_INDEX]); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "read micro version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), + ret); + return ret; + } + step = VersionParseStep::STEP_NANO; + break; + } + case VersionParseStep::STEP_NANO: { + auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_NANO_INDEX]); + if (ret != SUCCESS) { + HiLog::Error(LABEL, "read nano version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), + ret); + return ret; + } + step = VersionParseStep::STEP_FINISHED; + break; + } + default: { + HiLog::Error(LABEL, "read redundant version data, input: %{public}s.", input.c_str()); + return ERR_INVALID_PARAMETER; + } + } + + return SUCCESS; +} + +uint32_t Plugin::GetUint16ValueFromDecimal(const string &source, uint16_t &result) +{ + if (source.empty() || source.size() > UINT16_MAX_DECIMAL_DIGITS) { + HiLog::Error(LABEL, "invalid string of uint16: %{public}s.", source.c_str()); + return ERR_INVALID_PARAMETER; + } + + // determine if all characters are numbers. + for (auto &character : source) { + if (character < '0' || character > '9') { + HiLog::Error(LABEL, "character out of the range of digital: %{public}s.", source.c_str()); + return ERR_INVALID_PARAMETER; + } + } + + unsigned long tmp = stoul(source); + if (tmp > UINT16_MAX_VALUE) { + HiLog::Error(LABEL, "result out of the range of uint16: %{public}s.", source.c_str()); + return ERR_INVALID_PARAMETER; + } + + result = static_cast(tmp); + return SUCCESS; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/plugin.h b/plugins/manager/src/framework/plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..906a49ad54cbdd18f98b0659a7f422b1d3cb4ecc --- /dev/null +++ b/plugins/manager/src/framework/plugin.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include +#include +#include +#include "nocopyable.h" +#include "plugin_errors.h" +#include "plugin_export.h" + +namespace OHOS { +namespace MultimediaPlugin { +enum class PluginState : int32_t { + PLUGIN_STATE_UNREGISTER = 0, + PLUGIN_STATE_REGISTERED, + PLUGIN_STATE_RESOLVED, + PLUGIN_STATE_STARTING, + PLUGIN_STATE_ACTIVE, + PLUGIN_STATE_STOPPING +}; + +enum class VersionParseStep; +class ImplClassMgr; +class PlatformAdp; +struct VersionNum; + +class Plugin final : public NoCopyable { +public: + Plugin(); + ~Plugin(); + uint32_t Register(std::istream &metadata, std::string &&libraryPath, std::weak_ptr &plugin); + uint32_t Ref(); + void DeRef(); + void Block(); + void Unblock(); + PluginCreateFunc GetCreateFunc(); + const std::string &GetLibraryPath() const; + const std::string &GetPackageName() const; + +private: + static constexpr uint8_t VERSION_MAJOR_INDEX = 0; + static constexpr uint8_t VERSION_MINOR_INDEX = 1; + static constexpr uint8_t VERSION_MICRO_INDEX = 2; + static constexpr uint8_t VERSION_NANO_INDEX = 3; + static constexpr uint8_t VERSION_ARRAY_SIZE = 4; + static constexpr uint8_t UINT16_MAX_DECIMAL_DIGITS = 5; // uint16_t max number 65535, 5 digits. + + uint32_t ResolveLibrary(); + void FreeLibrary(); + uint32_t RegisterMetadata(std::istream &metadata, std::weak_ptr &plugin); + uint32_t CheckTargetVersion(const std::string &targetVersion); + uint32_t AnalyzeVersion(const std::string &versionInfo, VersionNum &versionNum); + uint32_t ExecuteVersionAnalysis(const std::string &input, VersionParseStep &step, + uint16_t (&versionNum)[VERSION_ARRAY_SIZE]); + uint32_t GetUint16ValueFromDecimal(const std::string &source, uint16_t &result); + + PlatformAdp &platformAdp_; + ImplClassMgr &implClassMgr_; + // dynDataLock_: + // for data that only changes in the register, we don't call it dynamic data. + // non-dynamic data are protected by other means, that is: mutual exclusion between + // the register and createObject processes. + // current dynamic data includes: + // state_, handle_, refNum_, startFunc_, stopFunc_, createFunc_, blocked_. + std::recursive_mutex dynDataLock_; + PluginState state_ = PluginState::PLUGIN_STATE_UNREGISTER; + std::weak_ptr plugin_; + void *handle_ = nullptr; + uint32_t refNum_ = 0; + std::string libraryPath_; + std::string packageName_; + std::string version_; + PluginStartFunc startFunc_ = nullptr; + PluginStopFunc stopFunc_ = nullptr; + PluginCreateFunc createFunc_ = nullptr; + bool blocked_ = false; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_H diff --git a/plugins/manager/src/framework/plugin_fw.cpp b/plugins/manager/src/framework/plugin_fw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b440a6f0fd2e6002978eceea2fa1762b3902e315 --- /dev/null +++ b/plugins/manager/src/framework/plugin_fw.cpp @@ -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. + */ + +#include "plugin_fw.h" +#include "hilog/log.h" +#include "singleton.h" +#include "log_tags.h" +#include "impl_class_mgr.h" +#include "plugin_info_lock.h" +#include "plugin_mgr.h" + +namespace OHOS { +namespace MultimediaPlugin { +using std::map; +using std::string; +using std::vector; +using OHOS::Utils::RWLock; +using OHOS::Utils::UniqueReadGuard; +using OHOS::Utils::UniqueWriteGuard; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PluginFw" }; + +uint32_t PluginFw::Register(const vector &canonicalPaths) +{ + HiLog::Debug(LABEL, "plugin register."); + // Use the read-write lock to mutually exclusive write plugin information and read plugin information operations, + // where Register() plays the write role. + UniqueWriteGuard lk(DelayedRefSingleton::GetInstance().rwLock_); + return pluginMgr_.Register(canonicalPaths); +} + +PluginClassBase *PluginFw::CreateObject(uint16_t interfaceID, const string &className, uint32_t &errorCode) +{ + // Use the read-write lock to mutually exclusive write plugin information and read plugin information operations, + // where CreateObject() plays the read role. + UniqueReadGuard lk(DelayedRefSingleton::GetInstance().rwLock_); + return implClassMgr_.CreateObject(interfaceID, className, errorCode); +} + +PluginClassBase *PluginFw::CreateObject(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode) +{ + // Use the read-write lock to mutually exclusive write plugin information and read plugin information operations, + // where CreateObject() plays the read role. + UniqueReadGuard lk(DelayedRefSingleton::GetInstance().rwLock_); + return implClassMgr_.CreateObject(interfaceID, serviceType, capabilities, priorityScheme, errorCode); +} + +uint32_t PluginFw::PluginFwGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + vector &classesInfo) +{ + // Use the read-write lock to mutually exclusive write plugin information and read plugin information operations, + // where GetClassInfo() plays the read role. + UniqueReadGuard lk(DelayedRefSingleton::GetInstance().rwLock_); + return implClassMgr_.ImplClassMgrGetClassInfo(interfaceID, serviceType, capabilities, classesInfo); +} + +// ------------------------------- private method ------------------------------- +PluginFw::PluginFw() + : pluginMgr_(DelayedRefSingleton::GetInstance()), + implClassMgr_(DelayedRefSingleton::GetInstance()) {} + +PluginFw::~PluginFw() {} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/plugin_fw.h b/plugins/manager/src/framework/plugin_fw.h new file mode 100644 index 0000000000000000000000000000000000000000..63a5b2ae1b2553c23ce5d5614aa5d674acc738bc --- /dev/null +++ b/plugins/manager/src/framework/plugin_fw.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_FW_H +#define PLUGIN_FW_H + +#include +#include +#include +#include "nocopyable.h" +#include "singleton.h" +#include "attr_data.h" +#include "plugin_class_base.h" +#include "plugin_common_type.h" +#include "plugin_errors.h" +#include "priority_scheme.h" + +namespace OHOS { +namespace MultimediaPlugin { +class PluginMgr; +class ImplClassMgr; + +class PluginFw final : public NoCopyable { +public: + uint32_t Register(const std::vector &canonicalPaths); + PluginClassBase *CreateObject(uint16_t interfaceID, const std::string &className, uint32_t &errorCode); + PluginClassBase *CreateObject(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode); + uint32_t PluginFwGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + std::vector &classesInfo); + DECLARE_DELAYED_REF_SINGLETON(PluginFw); + +private: + PluginMgr &pluginMgr_; + ImplClassMgr &implClassMgr_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_FW_H diff --git a/plugins/manager/src/framework/plugin_info_lock.cpp b/plugins/manager/src/framework/plugin_info_lock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1414b899c2e4be849f8444d515e43a64ec857d40 --- /dev/null +++ b/plugins/manager/src/framework/plugin_info_lock.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_info_lock.h" + +namespace OHOS { +namespace MultimediaPlugin { +using OHOS::Utils::RWLock; + +// ------------------------------- private method ------------------------------- +PluginInfoLock::PluginInfoLock() {} + +PluginInfoLock::~PluginInfoLock() {} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/plugin_info_lock.h b/plugins/manager/src/framework/plugin_info_lock.h new file mode 100644 index 0000000000000000000000000000000000000000..c69832dc9e87fcf3ffe72aa127333042063b8b79 --- /dev/null +++ b/plugins/manager/src/framework/plugin_info_lock.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_INFO_LOCK_H +#define PLUGIN_INFO_LOCK_H + +#include "nocopyable.h" +#include "rwlock.h" +#include "singleton.h" + +namespace OHOS { +namespace MultimediaPlugin { +class PluginInfoLock final : public NoCopyable { +public: + // Use the read-write lock to mutually exclusive write plugin information and read plugin information operations, + // where Register() plays the write role, CreateObject() and GetClassInfo() play the read role. + OHOS::Utils::RWLock rwLock_; + DECLARE_DELAYED_REF_SINGLETON(PluginInfoLock); +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_INFO_LOCK_H \ No newline at end of file diff --git a/plugins/manager/src/framework/plugin_mgr.cpp b/plugins/manager/src/framework/plugin_mgr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4cb0dc76feb829a267145801afcee4993b23ff3 --- /dev/null +++ b/plugins/manager/src/framework/plugin_mgr.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_mgr.h" +#include +#include "directory_ex.h" +#include "hilog/log.h" +#include "json.hpp" +#include "json_helper.h" +#include "log_tags.h" +#include "platform_adp.h" +#include "plugin.h" + +namespace OHOS { +namespace MultimediaPlugin { +using nlohmann::json; +using std::ifstream; +using std::size_t; +using std::string; +using std::vector; +using std::weak_ptr; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PluginMgr" }; +PlatformAdp &PluginMgr::platformAdp_ = DelayedRefSingleton::GetInstance(); + +uint32_t PluginMgr::Register(const vector &canonicalPaths) +{ + bool pathTraversed = false; + uint32_t errorCode = SUCCESS; + for (const string &path : canonicalPaths) { + uint32_t result = TraverseFiles(path); + if (result == SUCCESS) { + pathTraversed = true; + } else { + // no target is not a critical error type, giving priority to more serious errors. + if ((errorCode == SUCCESS) || (errorCode == ERR_NO_TARGET)) { + errorCode = result; + } + } + } + + if (!pathTraversed) { + return errorCode; + } + + return SUCCESS; +} + +// ------------------------------- private method ------------------------------- +PluginMgr::PluginMgr() +{} + +PluginMgr::~PluginMgr() +{} + +uint32_t PluginMgr::TraverseFiles(const string &canonicalPath) +{ + bool noTarget = true; + vector strFiles; + GetDirFiles(canonicalPath, strFiles); + if (strFiles.empty()) { + HiLog::Error(LABEL, "failed to get dir files."); + return ERR_GENERAL; + } + + string libraryPath; + for (const auto &file : strFiles) { + if (!CheckPluginMetaFile(file, libraryPath)) { + continue; + } + noTarget = false; + RegisterPlugin(file, std::move(libraryPath)); + } + + if (noTarget) { + HiLog::Warn(LABEL, "there is no plugin meta file in path."); + return ERR_NO_TARGET; + } + + return SUCCESS; +} + +bool PluginMgr::CheckPluginMetaFile(const string &candidateFile, string &libraryPath) +{ + const string meatedataFileSuffix = "pluginmeta"; + const string dirSeparator = "/"; + +#ifdef _WIN32 + const string libraryFileSuffix = "dll"; +#elif defined _APPLE + const string libraryFileSuffix = "dylib"; +#else + const string libraryFileSuffix = "so"; +#endif + + string fileExt = ExtractFileExt(candidateFile); + if (fileExt != meatedataFileSuffix) { + // not a plugin metadata file, quietly skip this item. + return false; + } + + ifstream metadata(candidateFile); + if (!metadata) { + HiLog::Error(LABEL, "failed to open metadata file."); + return false; + } + + json root; + metadata >> root; + if (JsonHelper::GetStringValue(root, "libraryPath", libraryPath) != SUCCESS) { + HiLog::Error(LABEL, "read libraryPath failed."); + return false; + } + +#if defined(_WIN32) || defined(_APPLE) + libraryPath = TransformFileName(libraryPath); +#endif + + fileExt = ExtractFileExt(libraryPath); + if (fileExt != libraryFileSuffix) { + HiLog::Error(LABEL, "invalid library suffix."); + return false; + } + +#if !defined(_WIN32) && !defined(_APPLE) + if (libraryPath.substr(0, 1) != dirSeparator) { + // relative path to absolute path. + // just keep original library name + return true; + } +#endif + + string realPath; + if (!PathToRealPath(libraryPath, realPath)) { + HiLog::Error(LABEL, "library path to real path error."); + return false; + } + + libraryPath = std::move(realPath); + return true; +} + +uint32_t PluginMgr::RegisterPlugin(const string &metadataPath, string &&libraryPath) +{ + auto iter = plugins_.find(&libraryPath); + if (iter != plugins_.end()) { + // already registered before, just skip it. + HiLog::Debug(LABEL, "the libraryPath has already been registered before."); + return ERR_GENERAL; + } + + ifstream metadata(metadataPath); + if (!metadata) { + HiLog::Error(LABEL, "failed to open metadata file."); + return ERR_GENERAL; + } + + auto plugin = std::make_shared(); + if (plugin == nullptr) { + HiLog::Error(LABEL, "failed to create Plugin."); + return ERR_INTERNAL; + } + + weak_ptr weakPtr = plugin; + auto regRet = plugin->Register(metadata, std::move(libraryPath), weakPtr); + if (regRet != SUCCESS) { + HiLog::Error(LABEL, "failed to register plugin,ERRNO: %{public}u.", regRet); + return regRet; + } + + const std::string &key = plugin->GetLibraryPath(); + if (key.empty()) { + HiLog::Error(LABEL, "get empty libraryPath."); + return ERR_INTERNAL; + } + + auto insertRet = plugins_.insert(PluginMap::value_type(&key, std::move(plugin))); + if (!insertRet.second) { + HiLog::Error(LABEL, "failed to insert Plugin"); + return ERR_INTERNAL; + } + + return SUCCESS; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/framework/plugin_mgr.h b/plugins/manager/src/framework/plugin_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..a78ea7aee89833bbb89e72cca1c31a577225de47 --- /dev/null +++ b/plugins/manager/src/framework/plugin_mgr.h @@ -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. + */ + +#ifndef PLUGIN_MGR_H +#define PLUGIN_MGR_H + +#include +#include +#include "nocopyable.h" +#include "singleton.h" +#include "plugin_errors.h" +#include "pointer_key_map.h" + +namespace OHOS { +namespace MultimediaPlugin { +class PlatformAdp; +class Plugin; + +class PluginMgr final : public NoCopyable { +public: + uint32_t Register(const std::vector &canonicalPaths); + DECLARE_DELAYED_REF_SINGLETON(PluginMgr); + +private: + uint32_t TraverseFiles(const std::string &canonicalPath); + bool CheckPluginMetaFile(const std::string &candidateFile, std::string &libraryPath); + uint32_t RegisterPlugin(const std::string &metadataPath, std::string &&libraryPath); + + static PlatformAdp &platformAdp_; + using PluginMap = PointerKeyMap>; + PluginMap plugins_; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // PLUGIN_MGR_H diff --git a/plugins/manager/src/plugin_server.cpp b/plugins/manager/src/plugin_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c04a8ef38a2d4ddc52f8b93b1d74125f3b7c523d --- /dev/null +++ b/plugins/manager/src/plugin_server.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "plugin_server.h" +#include "hilog/log.h" +#include "singleton.h" +#include "log_tags.h" +#include "gst_plugin_fw.h" +#include "platform_adp.h" +#include "plugin_fw.h" + +namespace OHOS { +namespace MultimediaPlugin { +using std::map; +using std::string; +using std::vector; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PluginServer" }; + +uint32_t PluginServer::Register(vector &&pluginPaths) +{ + vector canonicalPaths; + vector gstCanonicalPaths; + for (string &path : pluginPaths) { + if (platformAdp_.CheckAndNormalizePath(path) != SUCCESS) { + HiLog::Error(LABEL, "failed to check and normalize path: %{public}s.", path.c_str()); + continue; + } + + PluginFWType fwType = AnalyzeFWType(path); + switch (fwType) { + case PluginFWType::PLUGIN_FW_GENERAL: { + // directory path parameters, usually not too much, will not cause massive logs. + HiLog::Debug(LABEL, "PluginFW path: %{public}s.", path.c_str()); + canonicalPaths.push_back(std::move(path)); + break; + } + case PluginFWType::PLUGIN_FW_GSTREAMER: { + // directory path parameters, usually not too much, will not cause massive logs. + HiLog::Debug(LABEL, "GstPluginFW path: %{public}s.", path.c_str()); + gstCanonicalPaths.push_back(std::move(path)); + break; + } + default: { + HiLog::Error(LABEL, "unknown FWType: %{public}d.", fwType); + } + } + } + + if (canonicalPaths.empty() && gstCanonicalPaths.empty()) { + HiLog::Error(LABEL, "failed to find any valid plugin path."); + return ERR_INVALID_PARAMETER; + } + + if (!gstCanonicalPaths.empty()) { + uint32_t result = gstPluginFw_.Register(gstCanonicalPaths); + if (result != SUCCESS) { + HiLog::Error(LABEL, "failed to register gst plugin path, ERRNO: %{public}u.", result); + return result; + } + } + + if (!canonicalPaths.empty()) { + uint32_t result = pluginFw_.Register(canonicalPaths); + if (result != SUCCESS) { + HiLog::Error(LABEL, "failed to register plugin path, ERRNO: %{public}u.", result); + return result; + } + } + + return SUCCESS; +} + +// ------------------------------- private method ------------------------------- +PluginServer::PluginServer() + : platformAdp_(DelayedRefSingleton::GetInstance()), + pluginFw_(DelayedRefSingleton::GetInstance()), + gstPluginFw_(DelayedRefSingleton::GetInstance()) {} + +PluginServer::~PluginServer() {} + +PluginClassBase *PluginServer::CreateObject(uint16_t interfaceID, const string &className, uint32_t &errorCode) +{ + HiLog::Debug(LABEL, "create object iid: %{public}u, className: %{public}s.", interfaceID, className.c_str()); + PluginClassBase *obj = nullptr; + // if it is a pipeline service, use the gstreamer framework first. + if (GetInterfaceIDType(interfaceID) == IID_TYPE_PIPELINE) { + HiLog::Debug(LABEL, "it is a pipeline interface type."); + obj = gstPluginFw_.CreateObject(interfaceID, className, errorCode); + if (obj != nullptr) { + return obj; + } + } + + obj = pluginFw_.CreateObject(interfaceID, className, errorCode); + return obj; +} + +PluginClassBase *PluginServer::CreateObject(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode) +{ + HiLog::Debug(LABEL, "create object iid: %{public}u, service Type: %{public}u.", interfaceID, serviceType); + PluginClassBase *obj = nullptr; + // if it is a pipeline service, use the gstreamer framework first. + if (GetInterfaceIDType(interfaceID) == IID_TYPE_PIPELINE) { + HiLog::Debug(LABEL, "it is a pipeline interface type."); + obj = gstPluginFw_.CreateObject(interfaceID, serviceType, capabilities, priorityScheme, errorCode); + if (obj != nullptr) { + return obj; + } + } + + obj = pluginFw_.CreateObject(interfaceID, serviceType, capabilities, priorityScheme, errorCode); + return obj; +} + +uint32_t PluginServer::PluginServerGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + vector &classesInfo) +{ + if (!classesInfo.empty()) { + classesInfo.clear(); + } + + uint32_t resultGst = ERR_MATCHING_PLUGIN; + // if it is a pipeline service, use the gstreamer framework first. + if (GetInterfaceIDType(interfaceID) == IID_TYPE_PIPELINE) { + resultGst = gstPluginFw_.GstPluginFwGetClassInfo(interfaceID, serviceType, capabilities, classesInfo); + } + + // if the previous process has added classesInfo, the effect here is to append some other classesInfo. + uint32_t resultFw = pluginFw_.PluginFwGetClassInfo(interfaceID, serviceType, capabilities, classesInfo); + + // if both gstreamer and self-developing plugin can not get class information, then considered fail. + if ((resultGst != SUCCESS) && (resultFw != SUCCESS)) { + HiLog::Error(LABEL, "failed to get class by serviceType, resultGst: %{public}u, resultFw: %{public}u.", + resultGst, resultFw); + return resultFw; + } + + return SUCCESS; +} + +PluginFWType PluginServer::AnalyzeFWType(const string &canonicalPath) +{ + // for the current rule, contains the word "/gstreamer" is considered to be the gstreamer plugin directory. + if (canonicalPath.find(platformAdp_.DIR_SEPARATOR + "gstreamer") != string::npos) { + return PluginFWType::PLUGIN_FW_GSTREAMER; + } + + return PluginFWType::PLUGIN_FW_GENERAL; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/pluginbase/abs_impl_class_key.h b/plugins/manager/src/pluginbase/abs_impl_class_key.h new file mode 100644 index 0000000000000000000000000000000000000000..93bdbbe1ce363f9edf96a2db064e6649602f4159 --- /dev/null +++ b/plugins/manager/src/pluginbase/abs_impl_class_key.h @@ -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. + */ + +#ifndef ABS_IMPL_CLASS_KEY_H +#define ABS_IMPL_CLASS_KEY_H + +namespace OHOS { +namespace MultimediaPlugin { +class AbsImplClassKey { +public: + AbsImplClassKey() = default; + virtual ~AbsImplClassKey() = default; + virtual void OnObjectDestroy() = 0; +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // ABS_IMPL_CLASS_KEY_H \ No newline at end of file diff --git a/plugins/manager/src/pluginbase/plugin_class_base.cpp b/plugins/manager/src/pluginbase/plugin_class_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f7fb5951f0953f463e324a41e0c985346962ccf --- /dev/null +++ b/plugins/manager/src/pluginbase/plugin_class_base.cpp @@ -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. + */ + +#include "plugin_class_base.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "abs_impl_class_key.h" + +namespace OHOS { +namespace MultimediaPlugin { +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PluginClassBase" }; + +PluginClassBase::~PluginClassBase() +{ + // this situation does not happen in design. + // the process context can guarantee that this will not happen. + // the judgment statement here is for protection and positioning purposes only. + if (implClassKey_ == nullptr) { + HiLog::Error(LABEL, "release class base, null implClassKey."); + return; + } + + implClassKey_->OnObjectDestroy(); +} + +// ------------------------------- private method ------------------------------- +uint32_t PluginClassBase::SetImplClassKey(AbsImplClassKey &key) +{ + implClassKey_ = &key; + return MAGIC_CODE; +} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.cpp b/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d4fd38d0c66c1d51a73a8284f50dcd24ff3baa3 --- /dev/null +++ b/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gst_plugin_fw.h" +#include "hilog/log.h" +#include "log_tags.h" + +namespace OHOS { +namespace MultimediaPlugin { +using std::map; +using std::mutex; +using std::string; +using std::vector; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "GstPluginFw" }; + +uint32_t GstPluginFw::Register(const vector &canonicalPaths) +{ + (void) canonicalPaths; + HiLog::Debug(LABEL, "register called."); + return SUCCESS; +} + +PluginClassBase *GstPluginFw::CreateObject(uint16_t interfaceID, const string &className, uint32_t &errorCode) +{ + (void) interfaceID; + (void) className; + HiLog::Debug(LABEL, "CreateObject by name called."); + errorCode = ERR_MATCHING_PLUGIN; + + return nullptr; +} + +PluginClassBase *GstPluginFw::CreateObject(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode) +{ + (void) interfaceID; + (void) serviceType; + (void) capabilities; + (void) priorityScheme; + HiLog::Debug(LABEL, "CreateObject by serviceType called."); + errorCode = ERR_MATCHING_PLUGIN; + + return nullptr; +} + +uint32_t GstPluginFw::GstPluginFwGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const map &capabilities, + vector &classesInfo) +{ + (void) interfaceID; + (void) serviceType; + (void) capabilities; + (void) classesInfo; + HiLog::Debug(LABEL, "GetClassInfo by serviceType called."); + return ERR_MATCHING_PLUGIN; +} + +// ------------------------------- private method ------------------------------- +GstPluginFw::GstPluginFw() {} +GstPluginFw::~GstPluginFw() {} +} // namespace MultimediaPlugin +} // namespace OHOS diff --git a/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.h b/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.h new file mode 100644 index 0000000000000000000000000000000000000000..5eab8f334ff1966276ffe09bdfad1a09c0c69731 --- /dev/null +++ b/plugins/manager/src/thirdpartyadp/gstreamer/gst_plugin_fw.h @@ -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. + */ + +#ifndef GST_PLUGIN_FW_H +#define GST_PLUGIN_FW_H + +#include +#include +#include +#include +#include "nocopyable.h" +#include "singleton.h" +#include "attr_data.h" +#include "plugin_class_base.h" +#include "plugin_common_type.h" + +namespace OHOS { +namespace MultimediaPlugin { +class PriorityScheme; + +class GstPluginFw final : public NoCopyable { +public: + uint32_t Register(const std::vector &canonicalPaths); + PluginClassBase *CreateObject(uint16_t interfaceID, const std::string &className, uint32_t &errorCode); + PluginClassBase *CreateObject(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + const PriorityScheme &priorityScheme, uint32_t &errorCode); + uint32_t GstPluginFwGetClassInfo(uint16_t interfaceID, uint16_t serviceType, + const std::map &capabilities, + std::vector &classesInfo); + DECLARE_DELAYED_REF_SINGLETON(GstPluginFw); +}; +} // namespace MultimediaPlugin +} // namespace OHOS + +#endif // GST_PLUGIN_FW_H diff --git a/plugins/manager/test/BUILD.gn b/plugins/manager/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2f8ba7196835bf21a7c2397f59aac11d1fe61260 --- /dev/null +++ b/plugins/manager/test/BUILD.gn @@ -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. + +import("//build/test.gni") + +#################################group######################################### +group("unittest") { + testonly = true + deps = [] + + deps += [ "unittest/common:unittest" ] +} +############################################################################### diff --git a/plugins/manager/test/unittest/common/BUILD.gn b/plugins/manager/test/unittest/common/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..96a8034f613e3a8056a6e43dbde82c0e6b96425f --- /dev/null +++ b/plugins/manager/test/unittest/common/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "multimedia_image/plugins" + +############################################################################### +config("module_private_config") { + visibility = [ ":*" ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/interface/vision", + ] +} + +##############################unittest########################################## +ohos_unittest("PluginManagerTest") { + module_out_path = module_output_path + + sources = [ "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_manager_test.cpp" ] + + configs = [ ":module_private_config" ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example1:pluginexample1", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example2:pluginexample2", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example3:pluginexample3", + "//third_party/googletest:gtest_main", + ] + +# external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + resource_config_file = + "//foundation/multimedia/image_standard/test/resource/plugins/ohos_test.xml" +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":PluginManagerTest" ] +} +############################################################################### diff --git a/plugins/manager/test/unittest/common/plugin_example/interface/vision/abs_image_detector.h b/plugins/manager/test/unittest/common/plugin_example/interface/vision/abs_image_detector.h new file mode 100644 index 0000000000000000000000000000000000000000..313c0cec3c1427bd8b4ec2a7b07ae26aaca4a374 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/interface/vision/abs_image_detector.h @@ -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. + */ +#ifndef ABS_IMAGE_DETECT_H +#define ABS_IMAGE_DETECT_H + +#include +#include +#include "plugin_service.h" + +namespace OHOS { +namespace PluginExample { +class AbsImageDetector { +public: + virtual bool Prepare() = 0; + virtual std::string Process() = 0; + virtual ~AbsImageDetector() {} + + // define multiple subservices for this interface + static constexpr uint16_t SERVICE_LABEL = 0; + static constexpr uint16_t SERVICE_LANDMARK = 1; + static constexpr uint16_t SERVICE_FACE = 2; + static constexpr uint16_t SERVICE_TEXT = 3; + static constexpr uint16_t SERVICE_FLOWER = 4; +}; +} // namespace PluginExample +} // namespace OHOS + +DECLARE_INTERFACE(OHOS::PluginExample::AbsImageDetector, PLUGIN_EXAMPLE_IID) + +#endif // ABS_IMAGE_DETECT_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example1/BUILD.gn b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..33059964bc33edbd85b3b73ee0320d0a1570b026 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/BUILD.gn @@ -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("//build/ohos.gni") + +ohos_shared_library("pluginexample1") { + sources = [ + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.cpp", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.cpp", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example1/plugin_export.cpp", + ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/interface/vision", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + ] + + +# external_deps = [ "hilog:libhilog" ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c233ca01bb3a26d8256def56a86c26793a264f5 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cloud_label_detector.h" +#include "hilog/log.h" +#include "log_tags.h" + +namespace OHOS { +namespace PluginExample { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "CloudLabelDetector" }; +const string CloudLabelDetector::RESULT_STR = "CloudLabelDetector"; + +CloudLabelDetector::CloudLabelDetector() +{ + HiLog::Debug(LABEL, "call CloudLabelDetector()."); +} + +CloudLabelDetector::~CloudLabelDetector() +{ + HiLog::Debug(LABEL, "call ~CloudLabelDetector()."); +} + +bool CloudLabelDetector::Prepare() +{ + HiLog::Debug(LABEL, "call Prepare()."); + return true; +} + +string CloudLabelDetector::Process() +{ + HiLog::Debug(LABEL, "call Process()."); + return RESULT_STR; +} +} // namespace PluginExample +} // namespace OHOS diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.h b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.h new file mode 100644 index 0000000000000000000000000000000000000000..33ea8f58cd3540eece61679994b3a2e47f34d7f2 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/cloud_label_detector.h @@ -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. + */ + +#ifndef CLOUD_LABEL_DETECTOR_H +#define CLOUD_LABEL_DETECTOR_H + +#include "abs_image_detector.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace PluginExample { +class CloudLabelDetector final: public AbsImageDetector, public OHOS::MultimediaPlugin::PluginClassBase { +public: + CloudLabelDetector(); + ~CloudLabelDetector(); + + bool Prepare() override; + std::string Process() override; + +private: + static const std::string RESULT_STR; +}; +} // namespace PluginExample +} // namespace OHOS + +#endif // CLOUD_LABEL_DETECTOR_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d6467427cef66ddbe3db2877d5b56295ddff0cd --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "label_detector.h" +#include "hilog/log.h" +#include "log_tags.h" + +namespace OHOS { +namespace PluginExample { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LabelDetector" }; +const string LabelDetector::RESULT_STR = "LabelDetector"; + +LabelDetector::LabelDetector() +{ + HiLog::Debug(LABEL, "call LabelDetector()."); +} + +LabelDetector::~LabelDetector() +{ + HiLog::Debug(LABEL, "call ~LabelDetector()."); +} + +bool LabelDetector::Prepare() +{ + HiLog::Debug(LABEL, "call Prepare()."); + return true; +} + +string LabelDetector::Process() +{ + HiLog::Debug(LABEL, "call Process()."); + return RESULT_STR; +} +} // namespace PluginExample +} // namespace OHOS diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.h b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.h new file mode 100644 index 0000000000000000000000000000000000000000..1ea51f2af6528b636d8c45602e302c99938f91bc --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/label_detector.h @@ -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. + */ + +#ifndef LABEL_DETECTOR_H +#define LABEL_DETECTOR_H + +#include "abs_image_detector.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace PluginExample { +class LabelDetector final : public AbsImageDetector, public OHOS::MultimediaPlugin::PluginClassBase { +public: + LabelDetector(); + ~LabelDetector(); + + bool Prepare() override; + std::string Process() override; + +private: + static const std::string RESULT_STR; +}; +} // namespace PluginExample +} // namespace OHOS + +#endif // LABEL_DETECTOR_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example1/plugin_export.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..854ed723511a6a6ed6d95ab2a8b22895b740b1d3 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/plugin_export.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_export.h" +#include +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_class_base.h" +#include "plugin_utils.h" +#include "cloud_label_detector.h" +#include "label_detector.h" + +// this file shows how to write plugin_export.cpp file directly. +// but this file can also be simplified using the code elements provided by plugin_utils.h, +// see plugin_example2 and plugin_example3. +using std::map; +using std::string; +using namespace OHOS::HiviewDFX; + +static const string PACKAGE_NAME = "plugin_example1"; +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "plugin_example1" }; +using ImplClassMap = map; + +static ImplClassMap implClassMap = { + PLUGIN_EXPORT_REGISTER_CLASS(OHOS::PluginExample::LabelDetector) + PLUGIN_EXPORT_REGISTER_CLASS(OHOS::PluginExample::CloudLabelDetector) +}; + +bool PluginExternalStart() +{ + HiLog::Debug(LABEL, "call PluginExternalStart() in package: %{public}s.", PACKAGE_NAME.c_str()); + // in this example we don't have to do anything, + // but you may need to do some preparations below for your plugin... + return true; +} + +void PluginExternalStop() +{ + HiLog::Debug(LABEL, "call PluginExternalStop() in package: %{public}s.", PACKAGE_NAME.c_str()); + // in this example we don't have to do anything, + // but you may need to do some cleaning work below for your plugin... + return; +} + +OHOS::MultimediaPlugin::PluginClassBase *PluginExternalCreate(const string &className) +{ + HiLog::Debug(LABEL, "PluginExternalCreate: create object for package: %{public}s, class: %{public}s.", + PACKAGE_NAME.c_str(), className.c_str()); + + auto iter = implClassMap.find(className); + if (iter == implClassMap.end()) { + HiLog::Error(LABEL, "PluginExternalCreate: failed to find class: %{public}s, in package: %{public}s.", + className.c_str(), PACKAGE_NAME.c_str()); + return nullptr; + } + + auto creator = iter->second; + if (creator == nullptr) { + HiLog::Error(LABEL, "PluginExternalCreate: null creator for class: %{public}s, in package: %{public}s.", + className.c_str(), PACKAGE_NAME.c_str()); + return nullptr; + } + + return creator(); +} diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example2/BUILD.gn b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..449c283a38614f50c09f8ac27a4dd5dffc71ea80 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/BUILD.gn @@ -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("//build/ohos.gni") + +ohos_shared_library("pluginexample2") { + sources = [ + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.cpp", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.cpp", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example2/plugin_export.cpp", + ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/interface/vision", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + ] + +# external_deps = [ "hilog:libhilog" ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdd0266b1430f5817c07aa38c578eedd2e323d3e --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cloud_label_detector2.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" + +namespace OHOS { +namespace PluginExample { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "CloudLabelDetector2" }; +const string CloudLabelDetector2::RESULT_STR = "CloudLabelDetector2"; + +CloudLabelDetector2::CloudLabelDetector2() +{ + HiLog::Debug(LABEL, "call CloudLabelDetector2()."); +} + +CloudLabelDetector2::~CloudLabelDetector2() +{ + HiLog::Debug(LABEL, "call ~CloudLabelDetector2()."); +} + +bool CloudLabelDetector2::Prepare() +{ + HiLog::Debug(LABEL, "call Prepare()."); + return true; +} + +string CloudLabelDetector2::Process() +{ + HiLog::Debug(LABEL, "call Process()."); + return RESULT_STR; +} +} // namespace PluginExample +} // namespace OHOS diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.h b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.h new file mode 100644 index 0000000000000000000000000000000000000000..14fc691cfe52d15d42fb278e211e19b30fdcbc41 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/cloud_label_detector2.h @@ -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. + */ + +#ifndef CLOUD_LABEL_DETECTOR2_H +#define CLOUD_LABEL_DETECTOR2_H + +#include "abs_image_detector.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace PluginExample { +class CloudLabelDetector2 final : public AbsImageDetector, public OHOS::MultimediaPlugin::PluginClassBase { +public: + CloudLabelDetector2(); + ~CloudLabelDetector2(); + + bool Prepare() override; + std::string Process() override; + +private: + static const std::string RESULT_STR; +}; +} // namespace PluginExample +} // namespace OHOS + +#endif // CLOUD_LABEL_DETECTOR2_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da94d4d3aba2522cf39c685edcc79b22ae3a82c9 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "label_detector2.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" + +namespace OHOS { +namespace PluginExample { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LabelDetector2" }; +const string LabelDetector2::RESULT_STR = "LabelDetector2"; + +LabelDetector2::LabelDetector2() +{ + HiLog::Debug(LABEL, "call LabelDetector2()."); +} + +LabelDetector2::~LabelDetector2() +{ + HiLog::Debug(LABEL, "call ~LabelDetector2()."); +} + +bool LabelDetector2::Prepare() +{ + HiLog::Debug(LABEL, "call Prepare()."); + return true; +} + +string LabelDetector2::Process() +{ + HiLog::Debug(LABEL, "call Process()."); + return RESULT_STR; +} +} // namespace PluginExample +} // namespace OHOS diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.h b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.h new file mode 100644 index 0000000000000000000000000000000000000000..0fd1ed2b461734b71b543a989fab371c1a658580 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/label_detector2.h @@ -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. + */ + +#ifndef LABEL_DETECTOR2_H +#define LABEL_DETECTOR2_H + +#include "abs_image_detector.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace PluginExample { +class LabelDetector2 final : public AbsImageDetector, public OHOS::MultimediaPlugin::PluginClassBase { +public: + LabelDetector2(); + ~LabelDetector2(); + + bool Prepare() override; + std::string Process() override; + +private: + static const std::string RESULT_STR; +}; +} // namespace PluginExample +} // namespace OHOS + +#endif // LABEL_DETECTOR2_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example2/plugin_export.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e61101123d563f3bb2ea5befe4849a9674d2419 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example2/plugin_export.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "cloud_label_detector2.h" +#include "label_detector2.h" + +// this file shows how to easily write the plugin_export.cpp file using the code elements provided by plugin_utils.h. +// but sometimes you may need to write this file directly, see plugin_example1. +PLUGIN_EXPORT_REGISTER_PACKAGE("plugin_example2") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::PluginExample::LabelDetector2) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::PluginExample::CloudLabelDetector2) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "plugin_example2" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() + diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example3/BUILD.gn b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..19d3951bf37c1fdf59bb7a70b35fff24ca1db5e6 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/BUILD.gn @@ -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("//build/ohos.gni") + +ohos_shared_library("pluginexample3") { + sources = [ + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.cpp", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.cpp", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/plugin_example3/plugin_export.cpp", + ] + + include_dirs = [ + "//utils/native/base/include", + "//foundation/multimedia/image_standard/interfaces/innerkits/include", + "//foundation/multimedia/utils/include", + "//foundation/multimedia/image_standard/plugins/manager/include", + "//foundation/multimedia/image_standard/plugins/manager/include/pluginbase", + "//foundation/multimedia/image_standard/plugins/manager/test/unittest/common/plugin_example/interface/vision", + ] + + deps = [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + ] + +# external_deps = [ "hilog:libhilog" ] + + subsystem_name = "multimedia" + part_name = "multimedia_image" +} diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ee17a3131e4a1f2c0e6a699f6c30c84b44f896f --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cloud_label_detector3.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" + +namespace OHOS { +namespace PluginExample { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "CloudLabelDetector3" }; +const string CloudLabelDetector3::RESULT_STR = "CloudLabelDetector3"; + +CloudLabelDetector3::CloudLabelDetector3() +{ + HiLog::Debug(LABEL, "call CloudLabelDetector3()."); +} + +CloudLabelDetector3::~CloudLabelDetector3() +{ + HiLog::Debug(LABEL, "call ~CloudLabelDetector3()."); +} + +bool CloudLabelDetector3::Prepare() +{ + HiLog::Debug(LABEL, "call Prepare()."); + return true; +} + +string CloudLabelDetector3::Process() +{ + HiLog::Debug(LABEL, "call Process()."); + return RESULT_STR; +} +} // namespace PluginExample +} // namespace OHOS diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.h b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.h new file mode 100644 index 0000000000000000000000000000000000000000..ef70031e75f1d6d01ab6265a7e6b39ea1db85bf2 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/cloud_label_detector3.h @@ -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. + */ + +#ifndef CLOUD_LABEL_DETECTOR3_H +#define CLOUD_LABEL_DETECTOR3_H + +#include "abs_image_detector.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace PluginExample { +class CloudLabelDetector3 final : public AbsImageDetector, public OHOS::MultimediaPlugin::PluginClassBase { +public: + CloudLabelDetector3(); + ~CloudLabelDetector3(); + + bool Prepare() override; + std::string Process() override; + +private: + static const std::string RESULT_STR; +}; +} // namespace PluginExample +} // namespace OHOS + +#endif // CLOUD_LABEL_DETECTOR3_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be201a687cb497802dfa09b98c80ac95f795fc33 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "label_detector3.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" + +namespace OHOS { +namespace PluginExample { +using std::string; +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "LabelDetector3" }; +const string LabelDetector3::RESULT_STR = "LabelDetector3"; + +LabelDetector3::LabelDetector3() +{ + HiLog::Debug(LABEL, "call LabelDetector3()."); +} + +LabelDetector3::~LabelDetector3() +{ + HiLog::Debug(LABEL, "call ~LabelDetector3()."); +} + +bool LabelDetector3::Prepare() +{ + HiLog::Debug(LABEL, "call Prepare()."); + return true; +} + +string LabelDetector3::Process() +{ + HiLog::Debug(LABEL, "call Process()."); + return RESULT_STR; +} +} // namespace PluginExample +} // namespace OHOS diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.h b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.h new file mode 100644 index 0000000000000000000000000000000000000000..54e0ae7d17ab83570f2a77ac026ad6586e845548 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/label_detector3.h @@ -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. + */ + +#ifndef LABEL_DETECTOR3_H +#define LABEL_DETECTOR3_H + +#include "abs_image_detector.h" +#include "plugin_class_base.h" + +namespace OHOS { +namespace PluginExample { +class LabelDetector3 final : public AbsImageDetector, public OHOS::MultimediaPlugin::PluginClassBase { +public: + LabelDetector3(); + ~LabelDetector3(); + + bool Prepare() override; + std::string Process() override; + +private: + static const std::string RESULT_STR; +}; +} // namespace PluginExample +} // namespace OHOS + +#endif // LABEL_DETECTOR3_H diff --git a/plugins/manager/test/unittest/common/plugin_example/plugin_example3/plugin_export.cpp b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/plugin_export.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db149a35bafe6e7f26ee5d24a77b7e2ad0f9aa75 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example3/plugin_export.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_export.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_utils.h" +#include "cloud_label_detector3.h" +#include "label_detector3.h" + +// this file shows how to easily write the plugin_export.cpp file using the code elements provided by plugin_utils.h. +// but sometimes you may need to write this file directly, see plugin_example1. +PLUGIN_EXPORT_REGISTER_PACKAGE("plugin_example3") + +// register implement classes of this plugin. +PLUGIN_EXPORT_REGISTER_CLASS_BEGIN +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::PluginExample::LabelDetector3) +PLUGIN_EXPORT_REGISTER_CLASS(OHOS::PluginExample::CloudLabelDetector3) +PLUGIN_EXPORT_REGISTER_CLASS_END + +using namespace OHOS::HiviewDFX; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "plugin_example3" }; + +#define PLUGIN_LOG_D(...) HiLog::Debug(LABEL, __VA_ARGS__); +#define PLUGIN_LOG_E(...) HiLog::Error(LABEL, __VA_ARGS__); + +// define the external interface of this plugin +PLUGIN_EXPORT_DEFAULT_EXTERNAL_START() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_STOP() +PLUGIN_EXPORT_DEFAULT_EXTERNAL_CREATE() + diff --git a/plugins/manager/test/unittest/common/plugin_manager_test.cpp b/plugins/manager/test/unittest/common/plugin_manager_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73ccc5d17a45f3d7ae5dd82ec1016b2322506015 --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_manager_test.cpp @@ -0,0 +1,989 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "abs_image_detector.h" +#include "hilog/log.h" +#include "log_tags.h" +#include "plugin_server.h" + +using OHOS::DelayedRefSingleton; +using std::string; +using std::vector; +using namespace testing::ext; +using namespace OHOS::HiviewDFX; +using namespace OHOS::MultimediaPlugin; +using namespace OHOS::PluginExample; + +static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PluginManagerTest" }; + +class PluginManagerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static uint32_t DoTestRegister003(OHOS::MultimediaPlugin::PluginServer &pluginServer); + static uint32_t DoTestRegister004(OHOS::MultimediaPlugin::PluginServer &pluginServer); + static uint32_t DoTestInstanceLimit001(OHOS::MultimediaPlugin::PluginServer &pluginServer); + static uint32_t DoTestInstanceLimit003(OHOS::MultimediaPlugin::PluginServer &pluginServer); +}; + +void PluginManagerTest::SetUpTestCase(void) +{} + +void PluginManagerTest::TearDownTestCase(void) +{} + +void PluginManagerTest::SetUp(void) +{} + +void PluginManagerTest::TearDown(void) +{} + +/** + * @tc.name: TestRegister001 + * @tc.desc: Verify that the plugin management module supports the basic scenario of + * registering and managing one plugin package in one directory. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestRegister001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register one directory with one plugin package. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by class name from the plugin package. + * @tc.expected: step2. The plugin object was created successfully. + */ + uint32_t errorCode; + string implClassName = "OHOS::PluginExample::CloudLabelDetector"; + AbsImageDetector *cLabelDetector = pluginServer.CreateObject(implClassName, errorCode); + ASSERT_NE(cLabelDetector, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object. + * @tc.expected: step3. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + cLabelDetector->Prepare(); + string result = cLabelDetector->Process(); + delete cLabelDetector; + EXPECT_EQ(result, "CloudLabelDetector"); +} + +/** + * @tc.name: TestRegister002 + * @tc.desc: Verify that the plugin management module supports the basic scenario of + * registering and managing multiple plugins in one directory. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestRegister002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register one directory with two plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by class name from the first plugin package. + * @tc.expected: step2. The plugin object was created successfully. + */ + string implClassName = "OHOS::PluginExample::CloudLabelDetector2"; + uint32_t errorCode; + AbsImageDetector *cLabelDetector2 = pluginServer.CreateObject(implClassName, errorCode); + ASSERT_NE(cLabelDetector2, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object from the first plugin package. + * @tc.expected: step3. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + cLabelDetector2->Prepare(); + string result = cLabelDetector2->Process(); + delete cLabelDetector2; + EXPECT_EQ(result, "CloudLabelDetector2"); + + /** + * @tc.steps: step4. Create a plugin object by class name from the second plugin package. + * @tc.expected: step4. The plugin object was created successfully. + */ + implClassName = "OHOS::PluginExample::LabelDetector3"; + AbsImageDetector *labelDetector3 = pluginServer.CreateObject(implClassName, errorCode); + ASSERT_NE(labelDetector3, nullptr); + + /** + * @tc.steps: step5. Call the member function of the plugin object from the second plugin package. + * @tc.expected: step5. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + labelDetector3->Prepare(); + result = labelDetector3->Process(); + delete labelDetector3; + EXPECT_EQ(result, "LabelDetector3"); +} + +/** + * @tc.name: TestRegister003 + * @tc.desc: Verify that the plugin management module supports registration of + * multiple directories not contain each other. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestRegister003, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register two non-inclusive directories that contain a total of three plugin packages. + * @tc.expected: step1. The directories were registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins", + "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Test registered plugin packages can be used normally. + * @tc.expected: step2. Plugin objects can be created correctly from the three registered plugin packages. + */ + ASSERT_EQ(DoTestRegister003(pluginServer), SUCCESS); +} + +/** + * @tc.name: TestRegister004 + * @tc.desc: Verify that the plugin management module supports the registration of + * multiple directories with duplicate relationships. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestRegister004, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register three directories with duplicate relationships. + * @tc.expected: step1. The directories were registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2", "/system/etc/multimediaplugin", + "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Test registered plugin packages can be used normally. + * @tc.expected: step2. Plugin objects can be created correctly from registered plugin packages. + */ + ASSERT_EQ(DoTestRegister004(pluginServer), SUCCESS); +} + +/** + * @tc.name: TestRegister005 + * @tc.desc: Verify that the plugin management module supports managing + * multiple plugin classes in a plugin package. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestRegister005, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register one plugin packages with two plugin classes. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by class name from the first plugin class. + * @tc.expected: step2. The plugin object was created successfully. + */ + uint32_t errorCode; + string implClassName = "OHOS::PluginExample::LabelDetector"; + AbsImageDetector *labelDetector = pluginServer.CreateObject(implClassName, errorCode); + ASSERT_NE(labelDetector, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object from the first plugin class. + * @tc.expected: step3. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + labelDetector->Prepare(); + string result = labelDetector->Process(); + delete labelDetector; + EXPECT_EQ(result, "LabelDetector"); + + /** + * @tc.steps: step4. Create a plugin object by class name from the second plugin class. + * @tc.expected: step4. The plugin object was created successfully. + */ + implClassName = "OHOS::PluginExample::CloudLabelDetector"; + AbsImageDetector *cLabelDetector = pluginServer.CreateObject(implClassName, errorCode); + ASSERT_NE(cLabelDetector, nullptr); + + /** + * @tc.steps: step5. Call the member function of the plugin object from the second plugin class. + * @tc.expected: step5. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + cLabelDetector->Prepare(); + result = cLabelDetector->Process(); + delete cLabelDetector; + EXPECT_EQ(result, "CloudLabelDetector"); +} + +/** + * @tc.name: TestCreateByName001 + * @tc.desc: Verify that the object is not able to be created and + * returns the correct error code when the class is not found by class name. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestCreateByName001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object with a non-existing class name parameter. + * @tc.expected: step2. Creation failed and correctly returned error code indicating the reason. + */ + uint32_t errorCode; + // "UnknownDetector" means non-existing detector object. + AbsImageDetector *unknownDetector = pluginServer.CreateObject("UnknownDetector", errorCode); + EXPECT_EQ(unknownDetector, nullptr); + + delete unknownDetector; + EXPECT_EQ(errorCode, ERR_MATCHING_PLUGIN); +} + +/** + * @tc.name: TestCreateByService001 + * @tc.desc: Verify that the plugin object can be found and created correctly by service + * type id. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestCreateByService001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by servicer type id of face detector. + * @tc.expected: step2. The plugin object was created successfully. + */ + uint32_t errorCode; + AbsImageDetector *labelDetector = + pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + ASSERT_NE(labelDetector, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object of face detector. + * @tc.expected: step3. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + labelDetector->Prepare(); + string result = labelDetector->Process(); + delete labelDetector; + ASSERT_EQ(result, "LabelDetector3"); + + /** + * @tc.steps: step4. Create a plugin object by servicer type id of text detector. + * @tc.expected: step4. The plugin object was created successfully. + */ + AbsImageDetector *cLabelDetector = + pluginServer.CreateObject(AbsImageDetector::SERVICE_TEXT, errorCode); + ASSERT_NE(cLabelDetector, nullptr); + + /** + * @tc.steps: step5. Call the member function of the plugin object of text detector. + * @tc.expected: step5. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + cLabelDetector->Prepare(); + result = cLabelDetector->Process(); + delete cLabelDetector; + ASSERT_EQ(result, "CloudLabelDetector3"); +} + +/** + * @tc.name: TestCreateByService002 + * @tc.desc: Verify that the object is not able to be created and return the correct error code + * when the matching class is not found by the service type id parameter. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestCreateByService002, TestSize.Level3) +{ + AbsImageDetector *unknownDetector = nullptr; + HiLog::Debug(LABEL, "[PluginManager_TestCreateByService_002] Start."); + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object with a non-existing service type id parameter. + * @tc.expected: step2. Creation failed and correctly returned error code indicating the reason. + */ + uint32_t errorCode; + unknownDetector = pluginServer.CreateObject(AbsImageDetector::SERVICE_FLOWER, errorCode); + EXPECT_EQ(unknownDetector, nullptr); + + delete unknownDetector; + EXPECT_EQ(errorCode, ERR_MATCHING_PLUGIN); +} + +/** + * @tc.name: TestCreateByCapabilities001 + * @tc.desc: Verify that the plugin object can be found and created correctly by capabilities. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestCreateByCapabilities001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register multiple plugin directories with multiple valid plugin packages. + * @tc.expected: step1. The directories were registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by servicer type id and capabilities. + * @tc.expected: step2. The plugin object was created successfully. + */ + uint32_t errorCode; + // "labelNum" means capability name, 10000 means capability value, exist in metadata. + map capabilities = { { "labelNum", AttrData(static_cast(10000)) } }; + AbsImageDetector *labelDetector = + pluginServer.CreateObject(AbsImageDetector::SERVICE_LABEL, capabilities, errorCode); + ASSERT_NE(labelDetector, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object. + * @tc.expected: step4. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + labelDetector->Prepare(); + string result = labelDetector->Process(); + delete labelDetector; + ASSERT_EQ(result, "CloudLabelDetector"); +} + +/** + * @tc.name: TestCreateByCapabilities002 + * @tc.desc: Verify that the object is not able to be created and return the correct error code + * when the matching class is not found by the capabilities. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestCreateByCapabilities002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register multiple plugin directories with multiple valid plugin packages. + * @tc.expected: step1. The directories were registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2", "/system/etc/multimediaplugin", + "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object with a non-existing service type id and capabilities parameter. + * @tc.expected: step2. Creation failed and correctly returned error code indicating the reason. + */ + uint32_t errorCode; + // "labelNum" means capability name, 128 means capability value, not exist in metadata. + map capabilities = { { "labelNum", AttrData(static_cast(128)) } }; + AbsImageDetector *unknownDetector = + pluginServer.CreateObject(AbsImageDetector::SERVICE_LABEL, capabilities, errorCode); + EXPECT_EQ(unknownDetector, nullptr); + delete unknownDetector; + EXPECT_EQ(errorCode, ERR_MATCHING_PLUGIN); +} + +/** + * @tc.name: TestPluginPriority001 + * @tc.desc: Verify that the plugin class static priority function is correct. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestPluginPriority001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register multiple plugin directories with multiple valid plugin packages. + * @tc.expected: step1. The directories were registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by servicer type id and there are multiple classes + * that can match the id. + * @tc.expected: step2. The highest priority matching plugin object was created successfully. + */ + uint32_t errorCode; + AbsImageDetector *labelDetector = + pluginServer.CreateObject(AbsImageDetector::SERVICE_LABEL, errorCode); + ASSERT_NE(labelDetector, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object. + * @tc.expected: step4. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + labelDetector->Prepare(); + string result = labelDetector->Process(); + delete labelDetector; + // here, the higher target is LabelDetector and is not CloudLabelDetector. + ASSERT_EQ(result, "LabelDetector"); +} + +/** + * @tc.name: TestPluginPriority002 + * @tc.desc: Verify that the plugin class dynamic priority is correct and + * takes precedence over static priority. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestPluginPriority002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register multiple plugin directories with multiple valid plugin packages. + * @tc.expected: step1. The directories were registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create a plugin object by servicer type id and priorityScheme, and there are multiple classes + * that can match the id. + * @tc.expected: step2. The highest priority matching plugin object was created successfully. + */ + uint32_t errorCode; + // "labelNum" means attrdata key, exist in metedata. + PriorityScheme priorityScheme = { PriorityType::PRIORITY_ORDER_BY_ATTR_DESCENDING, "labelNum" }; + AbsImageDetector *labelDetector = + pluginServer.CreateObject(AbsImageDetector::SERVICE_LABEL, priorityScheme, errorCode); + ASSERT_NE(labelDetector, nullptr); + + /** + * @tc.steps: step3. Call the member function of the plugin object. + * @tc.expected: step4. The member function of the plugin object can be called normally, + * and the execution result is correct. + */ + labelDetector->Prepare(); + string result = labelDetector->Process(); + delete labelDetector; + // here, the higher target is CloudLabelDetector and is not LabelDetector. + ASSERT_EQ(result, "CloudLabelDetector"); +} + +/** + * @tc.name: TestGetClassByService001 + * @tc.desc: Verify that the plugin object can be found and get classes info correctly by service + * type id. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestGetClassByService001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. get classes information list by servicer type id of face detector. + * @tc.expected: step2. The getclass info result successfully. + */ + vector classInfo; + uint32_t errorCode = + pluginServer.PluginServerGetClassInfo(AbsImageDetector::SERVICE_FACE, classInfo); + EXPECT_NE(classInfo.size(), 0UL); // existing service type id, get class success, size should not be zero. + EXPECT_EQ(errorCode, SUCCESS); + + /** + * @tc.steps: step3. get classes information list by servicer type id of text detector. + * @tc.expected: step3. The getclass info result successfully. + */ + errorCode = pluginServer.PluginServerGetClassInfo(AbsImageDetector::SERVICE_TEXT, classInfo); + EXPECT_NE(classInfo.size(), 0UL); // existing service type id, get class success, size should not be zero. + EXPECT_EQ(errorCode, SUCCESS); +} + +/** + * @tc.name: TestGetClassByService002 + * @tc.desc: Verify that the plugin classes can not be found by non-existing service type id. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestGetClassByService002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. get classes information with non-existing service type id parameter. + * @tc.expected: step2. The getclass info result fail. + */ + vector classInfo; + uint32_t errorCode = + pluginServer.PluginServerGetClassInfo(AbsImageDetector::SERVICE_FLOWER, classInfo); + ASSERT_EQ(classInfo.size(), 0UL); // non-existing service type id, get class success, size should be zero. + ASSERT_NE(errorCode, SUCCESS); +} + +/** + * @tc.name: TestGetClassByCapbility001 + * @tc.desc: Verify that the plugin classes can be found and get classes info correctly by service + * type id. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestGetClassByCapbility001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. get classes information list by servicer type id of face detector and capbilities. + * @tc.expected: step2. The getclass info result successfully. + */ + vector classInfo; + // "labelNum" means capability name, 256 means capability value, exist in metedata. + map capabilities = { { "labelNum", AttrData(static_cast(256)) } }; + uint32_t errorCode = + pluginServer.PluginServerGetClassInfo(AbsImageDetector::SERVICE_FACE, capabilities, classInfo); + ASSERT_NE(classInfo.size(), 0UL); // existing service type id, get class success, size should not be zero. + ASSERT_EQ(errorCode, SUCCESS); +} + +/** + * @tc.name: TestGetClassByCapbility002 + * @tc.desc: Verify that the plugin classes can not be found by the correct service type id + * but the non-existing capbility. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestGetClassByCapbility002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin", "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. get classes information list by servicer type id of face detector and capbilities. + * @tc.expected: step2. The getclass info result successfully. + */ + vector classInfo; + // "labelNum1" means capability name, 1000 means capability value, not exist in metedata. + map capabilities = { { "labelNum1", AttrData(static_cast(1000)) } }; + uint32_t errorCode = + pluginServer.PluginServerGetClassInfo(AbsImageDetector::SERVICE_FACE, capabilities, classInfo); + ASSERT_EQ(classInfo.size(), 0UL); // non-existing service type id, get class success, size should be zero. + ASSERT_NE(errorCode, SUCCESS); +} + +/** + * @tc.name: TestInstanceLimit001 + * @tc.desc: Verify cross-create multiple plugin objects within the limit of the number of instances. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestInstanceLimit001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Cross-create multiple plugin objects within the limit of the number of instances. + * @tc.expected: step2. The plugin objects were created successfully. + */ + ASSERT_EQ(DoTestInstanceLimit001(pluginServer), SUCCESS); +} + +/** + * @tc.name: TestInstanceLimit002 + * @tc.desc: Verify create multiple plugin objects belonging to the same class, up to the + * maximum number of instances. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestInstanceLimit002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + /** + * @tc.steps: step2. Create multiple plugin objects belonging to the same class, + * up to the maximum number of instances. + * @tc.expected: step2. The plugin objects were created successfully. + */ + uint32_t errorCode; + AbsImageDetector *labelDetectorIns1 = + pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + EXPECT_NE(labelDetectorIns1, nullptr); + delete labelDetectorIns1; + + AbsImageDetector *labelDetectorIns2 = + pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + EXPECT_NE(labelDetectorIns2, nullptr); + delete labelDetectorIns2; + + AbsImageDetector *labelDetectorIns3 = + pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + EXPECT_NE(labelDetectorIns3, nullptr); + delete labelDetectorIns3; +} + +/** + * @tc.name: TestInstanceLimit003 + * @tc.desc: Verify that the number of instances limit mechanism is correct. + * @tc.type: FUNC + */ +HWTEST_F(PluginManagerTest, TestInstanceLimit003, TestSize.Level3) +{ + /** + * @tc.steps: step1. Register a directory with some valid plugin packages. + * @tc.expected: step1. The directory was registered successfully. + */ + PluginServer &pluginServer = DelayedRefSingleton::GetInstance(); + vector pluginPaths = { "/system/etc/multimediaplugin/testplugins2" }; + uint32_t ret = pluginServer.Register(std::move(pluginPaths)); + ASSERT_EQ(ret, SUCCESS); + + ASSERT_EQ(DoTestInstanceLimit003(pluginServer), SUCCESS); +} + +// ------------------------------- private method ------------------------------- +/* + * Feature: MultiMedia + * Function: Plugins + * SubFunction: Plugins Manager + * FunctionPoints: Registering and managing multiple Plugins + * EnvConditions: NA + * CaseDescription: Verify that the plugin management module supports registration of + * multiple directories not contain each other. + */ +uint32_t PluginManagerTest::DoTestRegister003(PluginServer &pluginServer) +{ + uint32_t testRet = ERR_GENERAL; + uint32_t errorCode; + AbsImageDetector *labelDetector3 = nullptr; + AbsImageDetector *cLabelDetector = nullptr; + string result; + string implClassName = "OHOS::PluginExample::CloudLabelDetector2"; + AbsImageDetector *cLabelDetector2 = pluginServer.CreateObject(implClassName, errorCode); + if (cLabelDetector2 == nullptr) { + HiLog::Error(LABEL, "[DoTestRegister003] cLabelDetector2 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::LabelDetector3"; + labelDetector3 = pluginServer.CreateObject(implClassName, errorCode); + if (labelDetector3 == nullptr) { + HiLog::Error(LABEL, "[DoTestRegister003] labelDetector3 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::CloudLabelDetector"; + cLabelDetector = pluginServer.CreateObject(implClassName, errorCode); + if (cLabelDetector == nullptr) { + HiLog::Error(LABEL, "[DoTestRegister003] cLabelDetector null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + result = cLabelDetector2->Process(); + if (result != "CloudLabelDetector2") { + HiLog::Error(LABEL, "[DoTestRegister003] result1 check fail, result: %{public}s.", result.c_str()); + goto TEST_END; + } + + result = labelDetector3->Process(); + if (result != "LabelDetector3") { + HiLog::Error(LABEL, "[DoTestRegister003] result2 check fail, result: %{public}s.", result.c_str()); + goto TEST_END; + } + + result = cLabelDetector->Process(); + if (result != "CloudLabelDetector") { + HiLog::Error(LABEL, "[DoTestRegister003] result3 check fail, result: %{public}s.", result.c_str()); + goto TEST_END; + } + testRet = SUCCESS; + +TEST_END: + delete cLabelDetector; + delete cLabelDetector2; + delete labelDetector3; + + return testRet; +} + +/* + * Feature: MultiMedia + * Function: Plugins + * SubFunction: Plugins Manager + * FunctionPoints: Registering and managing multiple Plugins + * EnvConditions: NA + * CaseDescription: Verify that the plugin management module supports the registration of + * multiple directories with duplicate relationships. + */ +uint32_t PluginManagerTest::DoTestRegister004(PluginServer &pluginServer) +{ + uint32_t testRet = ERR_GENERAL; + uint32_t errorCode; + AbsImageDetector *cLabelDetector2 = nullptr; + AbsImageDetector *labelDetector3 = nullptr; + string result; + string implClassName = "OHOS::PluginExample::CloudLabelDetector"; + AbsImageDetector *cLabelDetector = pluginServer.CreateObject(implClassName, errorCode); + if (cLabelDetector == nullptr) { + HiLog::Error(LABEL, "[DoTestRegister004] cLabelDetector null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::CloudLabelDetector2"; + cLabelDetector2 = pluginServer.CreateObject(implClassName, errorCode); + if (cLabelDetector2 == nullptr) { + HiLog::Error(LABEL, "[DoTestRegister004] cLabelDetector2 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::LabelDetector3"; + labelDetector3 = pluginServer.CreateObject(implClassName, errorCode); + if (labelDetector3 == nullptr) { + HiLog::Error(LABEL, "[DoTestRegister004] labelDetector3 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + result = cLabelDetector->Process(); + if (result != "CloudLabelDetector") { + HiLog::Error(LABEL, "[DoTestRegister004] result1 check fail, result: %{public}s.", result.c_str()); + goto TEST_END; + } + + result = cLabelDetector2->Process(); + if (result != "CloudLabelDetector2") { + HiLog::Error(LABEL, "[DoTestRegister004] result2 check fail, result: %{public}s.", result.c_str()); + goto TEST_END; + } + + result = labelDetector3->Process(); + if (result != "LabelDetector3") { + HiLog::Error(LABEL, "[DoTestRegister004] result3 check fail, result: %{public}s.", result.c_str()); + return ERR_GENERAL; + } + testRet = SUCCESS; + +TEST_END: + delete cLabelDetector; + delete cLabelDetector2; + delete labelDetector3; + + return testRet; +} + +/* + * Feature: MultiMedia + * Function: Plugins + * SubFunction: Reference count + * FunctionPoints: Registering and managing multiple Plugins + * EnvConditions: NA + * CaseDescription: Verify cross-create multiple plugin objects within the limit of the number of instances. + */ +uint32_t PluginManagerTest::DoTestInstanceLimit001(PluginServer &pluginServer) +{ + uint32_t testRet = ERR_GENERAL; + uint32_t errorCode; + AbsImageDetector *labelDetectorIns1 = nullptr; + AbsImageDetector *cLabelDetectorIns1 = nullptr; + AbsImageDetector *labelDetectorIns2 = nullptr; + AbsImageDetector *cLabelDetectorIns2 = nullptr; + string implClassName = "OHOS::PluginExample::LabelDetector"; + labelDetectorIns1 = pluginServer.CreateObject(implClassName, errorCode); + if (labelDetectorIns1 == nullptr) { + HiLog::Error(LABEL, "[PluginManager_TestInstanceLimit_001] labelDetectorIns1 null. ERRNO: %{public}u.", + errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::CloudLabelDetector"; + cLabelDetectorIns1 = pluginServer.CreateObject(implClassName, errorCode); + if (cLabelDetectorIns1 == nullptr) { + HiLog::Error(LABEL, "[PluginManager_TestInstanceLimit_001] cLabelDetectorIns1 null. ERRNO: %{public}u.", + errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::LabelDetector"; + labelDetectorIns2 = pluginServer.CreateObject(implClassName, errorCode); + if (labelDetectorIns2 == nullptr) { + HiLog::Error(LABEL, "[PluginManager_TestInstanceLimit_001] labelDetectorIns2 null. ERRNO: %{public}u.", + errorCode); + goto TEST_END; + } + + implClassName = "OHOS::PluginExample::CloudLabelDetector"; + cLabelDetectorIns2 = pluginServer.CreateObject(implClassName, errorCode); + if (cLabelDetectorIns2 == nullptr) { + HiLog::Error(LABEL, "[PluginManager_TestInstanceLimit_001] cLabelDetectorIns2 null. ERRNO: %{public}u.", + errorCode); + goto TEST_END; + } + testRet = SUCCESS; + +TEST_END: + delete labelDetectorIns1; + delete cLabelDetectorIns1; + delete labelDetectorIns2; + delete cLabelDetectorIns2; + + return testRet; +} + +/* + * Feature: MultiMedia + * Function: Plugins + * SubFunction: Plugins Manager + * FunctionPoints: Instance number + * EnvConditions: NA + * CaseDescription: Verify that the number of instances limit mechanism is correct. + */ +uint32_t PluginManagerTest::DoTestInstanceLimit003(PluginServer &pluginServer) +{ + uint32_t testRet = ERR_GENERAL; + uint32_t errorCode; + AbsImageDetector *labelDetectorIns2 = nullptr; + AbsImageDetector *labelDetectorIns3 = nullptr; + AbsImageDetector *labelDetectorIns4 = nullptr; + AbsImageDetector *labelDetectorIns5 = nullptr; + + /** + * @tc.steps: step2. Create multiple plugin objects belonging to the same class, + * the number of which exceeds the maximum number of instances. + * @tc.expected: step2. The part that did not exceed the number of instances was created successfully, + * the excess part was created failed and an error code indicating the reason for + * the name was returned. + */ + AbsImageDetector *labelDetectorIns1 = + pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + if (labelDetectorIns1 == nullptr) { + HiLog::Error(LABEL, "[DoTestInstanceLimit003] labelDetectorIns1 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + labelDetectorIns2 = pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + if (labelDetectorIns1 == nullptr) { + HiLog::Error(LABEL, "[DoTestInstanceLimit003] labelDetectorIns2 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + labelDetectorIns3 = pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + if (labelDetectorIns1 == nullptr) { + HiLog::Error(LABEL, "[DoTestInstanceLimit003] labelDetectorIns3 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + labelDetectorIns4 = pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + if (labelDetectorIns4 != nullptr) { + HiLog::Error(LABEL, "[DoTestInstanceLimit003] labelDetectorIns4 not null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + + if (errorCode != ERR_INSTANCE_LIMIT) { + HiLog::Error(LABEL, "[DoTestInstanceLimit003] unexpected errorCode: %{public}u.", errorCode); + goto TEST_END; + } + + /** + * @tc.steps: step3. Release a plugin object, making the number of instances below the limit, + * then request to create a new plugin object. + * @tc.expected: step3. The new plugin object was created successfully. + */ + delete labelDetectorIns2; + labelDetectorIns2 = nullptr; + + labelDetectorIns5 = pluginServer.CreateObject(AbsImageDetector::SERVICE_FACE, errorCode); + if (labelDetectorIns1 == nullptr) { + HiLog::Error(LABEL, "[DoTestInstanceLimit003] labelDetectorIns5 null. ERRNO: %{public}u.", errorCode); + goto TEST_END; + } + testRet = SUCCESS; + +TEST_END: + delete labelDetectorIns1; + delete labelDetectorIns2; + delete labelDetectorIns3; + delete labelDetectorIns4; + delete labelDetectorIns5; + + return testRet; +} diff --git a/test/resource/image/images/hasNoExif.jpg b/test/resource/image/images/hasNoExif.jpg new file mode 100755 index 0000000000000000000000000000000000000000..e09e9fa50455263369cb0ae4f7990948ff45b3db Binary files /dev/null and b/test/resource/image/images/hasNoExif.jpg differ diff --git a/test/resource/image/images/moving_test.gif b/test/resource/image/images/moving_test.gif new file mode 100755 index 0000000000000000000000000000000000000000..6643f465ae71b561e337349063f9fa13500ad4bf Binary files /dev/null and b/test/resource/image/images/moving_test.gif differ diff --git a/test/resource/image/images/test.9.png b/test/resource/image/images/test.9.png new file mode 100755 index 0000000000000000000000000000000000000000..c8494568bf7eb0f2a0f53824eb6a3011a22b1026 Binary files /dev/null and b/test/resource/image/images/test.9.png differ diff --git a/test/resource/image/images/test.arw b/test/resource/image/images/test.arw new file mode 100755 index 0000000000000000000000000000000000000000..0ef1f2360c1749b6171c994b591891fc29bb499b Binary files /dev/null and b/test/resource/image/images/test.arw differ diff --git a/test/resource/image/images/test.bmp b/test/resource/image/images/test.bmp new file mode 100755 index 0000000000000000000000000000000000000000..a93ddb8c8f1e7967c9be33af57c1aff40eb96027 Binary files /dev/null and b/test/resource/image/images/test.bmp differ diff --git a/test/resource/image/images/test.cr2 b/test/resource/image/images/test.cr2 new file mode 100755 index 0000000000000000000000000000000000000000..9982c2fef9bc50f8910fbf6a3804bfde6807f8ba Binary files /dev/null and b/test/resource/image/images/test.cr2 differ diff --git a/test/resource/image/images/test.dng b/test/resource/image/images/test.dng new file mode 100755 index 0000000000000000000000000000000000000000..aaedd536c90368f293939bc45f0215d01128e9bd Binary files /dev/null and b/test/resource/image/images/test.dng differ diff --git a/test/resource/image/images/test.gif b/test/resource/image/images/test.gif new file mode 100755 index 0000000000000000000000000000000000000000..dfd33b993d159549a1900684e18be89605eab8ad Binary files /dev/null and b/test/resource/image/images/test.gif differ diff --git a/test/resource/image/images/test.jpg b/test/resource/image/images/test.jpg new file mode 100755 index 0000000000000000000000000000000000000000..e09e9fa50455263369cb0ae4f7990948ff45b3db Binary files /dev/null and b/test/resource/image/images/test.jpg differ diff --git a/test/resource/image/images/test.nrw b/test/resource/image/images/test.nrw new file mode 100755 index 0000000000000000000000000000000000000000..f91eff415cd83b322aeba18ee60e34a72292a09d Binary files /dev/null and b/test/resource/image/images/test.nrw differ diff --git a/test/resource/image/images/test.pef b/test/resource/image/images/test.pef new file mode 100755 index 0000000000000000000000000000000000000000..d4f6d48831974001081eb5a7093f4d45237098b5 Binary files /dev/null and b/test/resource/image/images/test.pef differ diff --git a/test/resource/image/images/test.png b/test/resource/image/images/test.png new file mode 100755 index 0000000000000000000000000000000000000000..39eebcce552f0059a8253eb71188d6534e92c00e Binary files /dev/null and b/test/resource/image/images/test.png differ diff --git a/test/resource/image/images/test.raf b/test/resource/image/images/test.raf new file mode 100755 index 0000000000000000000000000000000000000000..edb23b4abfe3e30de5b598bc033399ab6c0dddf7 Binary files /dev/null and b/test/resource/image/images/test.raf differ diff --git a/test/resource/image/images/test.rw2 b/test/resource/image/images/test.rw2 new file mode 100755 index 0000000000000000000000000000000000000000..9db5b45bda2206ea4a08e80512dfbb943bf39e27 Binary files /dev/null and b/test/resource/image/images/test.rw2 differ diff --git a/test/resource/image/images/test.wbmp b/test/resource/image/images/test.wbmp new file mode 100755 index 0000000000000000000000000000000000000000..3d1c0609afbe8172bbdd4ee69df14996bdad03ee Binary files /dev/null and b/test/resource/image/images/test.wbmp differ diff --git a/test/resource/image/images/test.webp b/test/resource/image/images/test.webp new file mode 100755 index 0000000000000000000000000000000000000000..a8f6ed69c46dab3f3b439f9238ff8714910fc0b8 Binary files /dev/null and b/test/resource/image/images/test.webp differ diff --git a/test/resource/image/images/test_exif.jpg b/test/resource/image/images/test_exif.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b1bf612dd4b771edc35ef4d8c03db52c56475723 Binary files /dev/null and b/test/resource/image/images/test_exif.jpg differ diff --git a/test/resource/image/images/test_hw.jpg b/test/resource/image/images/test_hw.jpg new file mode 100755 index 0000000000000000000000000000000000000000..542fadfcc6698b621beb6cd056e4176fd128ba91 Binary files /dev/null and b/test/resource/image/images/test_hw.jpg differ diff --git a/test/resource/image/images/test_large.webp b/test/resource/image/images/test_large.webp new file mode 100755 index 0000000000000000000000000000000000000000..b041fd99d1262537724cfd0a6123058cf7e8e1e5 Binary files /dev/null and b/test/resource/image/images/test_large.webp differ diff --git a/test/resource/image/ohos_test.xml b/test/resource/image/ohos_test.xml new file mode 100644 index 0000000000000000000000000000000000000000..9834418d1af85b5b33f55d355b0b83d5eb49b2f8 --- /dev/null +++ b/test/resource/image/ohos_test.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resource/image/perftest/ImagePerformanceTest_baseline.xml b/test/resource/image/perftest/ImagePerformanceTest_baseline.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d731242fc1ebac5715c279b1031170e3e13f167 --- /dev/null +++ b/test/resource/image/perftest/ImagePerformanceTest_baseline.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resource/image/txts/colors.txt b/test/resource/image/txts/colors.txt new file mode 100755 index 0000000000000000000000000000000000000000..b7d409bd49bdee2e82766dc3749b647f3b66df78 --- /dev/null +++ b/test/resource/image/txts/colors.txt @@ -0,0 +1 @@ +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -16777216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 \ No newline at end of file diff --git a/test/resource/plugins/ohos_test.xml b/test/resource/plugins/ohos_test.xml new file mode 100644 index 0000000000000000000000000000000000000000..fb4dadc3affbbf4e5be61a799ea6380d1abe8a96 --- /dev/null +++ b/test/resource/plugins/ohos_test.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/test/resource/plugins/plugin_example1/plugin_example1.pluginmeta b/test/resource/plugins/plugin_example1/plugin_example1.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..ab0d5b9fb8efc1212b40fc3dc118041025d47f3a --- /dev/null +++ b/test/resource/plugins/plugin_example1/plugin_example1.pluginmeta @@ -0,0 +1,44 @@ +{ + "packageName":"plugin_example1", + "version":"1.0.0.10", + "targetVersion":"10.0.0.0", + "libraryPath":"libpluginexample1.z.so", + "classes": [ + { + "className":"OHOS::PluginExample::LabelDetector", + "services": [ + { + "interfaceID":0, + "serviceType":0 + } + ], + "priority":10, + "maxInstance":2, + "capabilities": [ + { + "name":"labelNum", + "type":"uint32", + "value": 256 + } + ] + }, + { + "className":"OHOS::PluginExample::CloudLabelDetector", + "services": [ + { + "interfaceID":0, + "serviceType":0 + } + ], + "priority":5, + "maxInstance":3, + "capabilities": [ + { + "name":"labelNum", + "type":"uint32", + "value": 10000 + } + ] + } + ] +} diff --git a/test/resource/plugins/plugin_example2/plugin_example2.pluginmeta b/test/resource/plugins/plugin_example2/plugin_example2.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..13fc07047950d6e0fdfe8fcd15c3b5061df64782 --- /dev/null +++ b/test/resource/plugins/plugin_example2/plugin_example2.pluginmeta @@ -0,0 +1,44 @@ +{ + "packageName":"plugin_example2", + "version":"1.0.0.10", + "targetVersion":"10.0.0.0", + "libraryPath":"libpluginexample2.z.so", + "classes": [ + { + "className":"OHOS::PluginExample::LabelDetector2", + "services": [ + { + "interfaceID":0, + "serviceType":1 + } + ], + "priority":10, + "maxInstance":1, + "capabilities": [ + { + "name":"labelNum", + "type":"string", + "value": "256" + } + ] + }, + { + "className":"OHOS::PluginExample::CloudLabelDetector2", + "services": [ + { + "interfaceID":0, + "serviceType":1 + } + ], + "priority":5, + "maxInstance":3, + "capabilities": [ + { + "name":"labelNum", + "type":"stringSet", + "value": [ "256", "512", "1024" ] + } + ] + } + ] +} diff --git a/test/resource/plugins/plugin_example3/plugin_example3.pluginmeta b/test/resource/plugins/plugin_example3/plugin_example3.pluginmeta new file mode 100755 index 0000000000000000000000000000000000000000..16de862fafb353c16858973f754b3de45fdd4e36 --- /dev/null +++ b/test/resource/plugins/plugin_example3/plugin_example3.pluginmeta @@ -0,0 +1,44 @@ +{ + "packageName":"plugin_example3", + "version":"1.0.0.10", + "targetVersion":"10.0.0.0", + "libraryPath":"libpluginexample3.z.so", + "classes": [ + { + "className":"OHOS::PluginExample::LabelDetector3", + "services": [ + { + "interfaceID":0, + "serviceType":2 + } + ], + "priority":10, + "maxInstance":3, + "capabilities": [ + { + "name":"labelNum", + "type":"uint32Set", + "value": [ 256, 512, 1024 ] + } + ] + }, + { + "className":"OHOS::PluginExample::CloudLabelDetector3", + "services": [ + { + "interfaceID":0, + "serviceType":3 + } + ], + "priority":5, + "maxInstance":3, + "capabilities": [ + { + "name":"labelNum", + "type":"uint32Range", + "value": [ 100, 200 ] + } + ] + } + ] +}