diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..58107d32149036f6163784f29d8601c2faa3c101 --- /dev/null +++ b/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/config/ohos/rules.gni") +import("//build/ohos.gni") +group("image_framework") { + deps = [ + "frameworks/innerkitsimpl/utils:image_utils", + "interfaces/innerkits:image_native", + "interfaces/innerkits:image", + ] +} + +group("plugins") { + deps = [ + "plugins/common/libs:multimediaplugin", + "plugins/manager:pluginmanager", + ] +} + +group("image_test_list") { + testonly = true + + # image + deps = [ "frameworks/innerkitsimpl/test:unittest" ] +} + +config("media_config") { + defines = [] + + if (current_cpu == "arm64" || current_cpu == "arm") { + defines += [ "USE_NEON" ] + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 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 100644 index 0000000000000000000000000000000000000000..c539a5da957017db6a31ef2e4c956b632e9b509d --- /dev/null +++ b/OAT.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + diff --git a/README.en.md b/README.en.md deleted file mode 100644 index ff3f83f3b1abacc7e6aa8ef670621db303c716bb..0000000000000000000000000000000000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# multimedia_image_standard - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 0781a0f05b76db30b991282c699ec17b295b624b..9a073adac028c11893f685b06cbc4def7f7ef510 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,36 @@ -# multimedia_image_standard +# Image -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +- [Introduction](#section11660541593) +- [Directory Structure](#section161941989596) +- [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. -#### 安装教程 +**Figure 1** Image architecture +![](figures/image-architecture.png "image-architecture") -1. xxxx -2. xxxx -3. xxxx +## Directory Structure -#### 使用说明 +The structure of the repository directory is as follows: -1. xxxx -2. xxxx -3. xxxx +``` +/foundation/multimedia/image +├── 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 +├── plugins # Image plug-in implementation +│ ├── common # Common image plug-ins +│ ├── manager # Image plug-in manager +├── test # Test resources +``` -#### 参与贡献 +## Repositories Involved -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +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 100644 index 0000000000000000000000000000000000000000..95818005869392128ad7fed28c13b11ec187dc3c --- /dev/null +++ b/README_zh.md @@ -0,0 +1,36 @@ +# Image组件 + +- [简介](#section11660541593) +- [目录](#section161941989596) +- [相关仓](#section1533973044317) + +## 简介 + +Image组件提供了简单易用的接口用于开发图像的编解码功能,目前支持主流的如下图片格式:JPEG、PNG、BMP + +**图 1** Image组件架构图 +![](figures/Image组件架构图.png "Image组件架构图") + +## 目录 + +仓目录结构如下: + +``` +/foundation/multimedia/image # Image组件业务代码 +├── frameworks # 框架代码 +│ ├── innerkitsimpl # 框架native层业务实现 +│ └── jni # jni层实现 +├── ohos.build # 编译配置 +├── interfaces # 外部接口层 +│ ├── innerkits # 内部其他子系统接口 +│ └── kits # java接口层 +├── plugins # 图像插件实现 +│ ├── common # 图像通用插件 +│ └── manager # 图像插件管理模块 +├── test # 测试资源目录 +``` + +## 相关仓 + +hmf/multimedia/image + 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 100644 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 100644 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 100644 index 0000000000000000000000000000000000000000..8fe091414a9b2433c615392c4b22a9e8f7000747 --- /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/pixelconverter/BUILD.gn b/frameworks/innerkitsimpl/pixelconverter/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2389606bbac1bbfc4d8bf630433c891e5b4a81e3 --- /dev/null +++ b/frameworks/innerkitsimpl/pixelconverter/BUILD.gn @@ -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. + +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/frameworks/innerkitsimpl/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", + ] + + if (use_mingw_win) { + include_dirs += [ + "//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 += [ + "//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/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp" ] + + public_configs = [ ":pixelconvertadapter_public_config" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + deps = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/communication/ipc/utils/include", + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontmgr_windows", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + "//utils/jni:utils_jnikit_win", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontmgr_mac", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + ] + } else { + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontconfig.json", + "//third_party/flutter:ace_fontmgr_ohos", + "//third_party/flutter:ace_fontmgr_standard", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_jsoncpp", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libsfntly_ohos", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + "//utils/native/base:utils", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + relative_install_dir = "module/multimedia" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} + +ohos_static_library("pixelconvertadapter_static") { + sources = [ "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp" ] + public_configs = [ ":pixelconvertadapter_public_config" ] + + if (use_mingw_win) { + defines = image_decode_windows_defines + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontmgr_windows", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_skia_windows", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontmgr_mac", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skia_mac", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + ] + } else { + deps = [ + "//foundation/multimedia/image_standard/mock/native:log_mock_static", + "//third_party/flutter:ace_fontconfig.json", + "//third_party/flutter:ace_fontmgr_ohos", + "//third_party/flutter:ace_fontmgr_standard", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_jsoncpp", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skia_ohos", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + "//utils/native/base:utils", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } +} diff --git a/frameworks/innerkitsimpl/pixelconverter/include/pixel_convert_adapter.h b/frameworks/innerkitsimpl/pixelconverter/include/pixel_convert_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..c2958f5b1b2b1f7c2e89e7e25a432c0a2f876b87 --- /dev/null +++ b/frameworks/innerkitsimpl/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/frameworks/innerkitsimpl/pixelconverter/include/pixel_map_jni_utils.h b/frameworks/innerkitsimpl/pixelconverter/include/pixel_map_jni_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..2f344a8fa691036c184d2db6d01ef65177e13806 --- /dev/null +++ b/frameworks/innerkitsimpl/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/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp b/frameworks/innerkitsimpl/pixelconverter/src/pixel_convert_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8395dda723a23e865190369a725b7153ae377d9c --- /dev/null +++ b/frameworks/innerkitsimpl/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/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 b/frameworks/innerkitsimpl/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..826809b7e1a94d7805166d18deba87adcc4595a6 --- /dev/null +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -0,0 +1,175 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES 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_native", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + # 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", +# "//foundation/multimedia/image_standard/mock/native/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", +# "//foundation/multimedia/image_standard/mock/native:utils_mock_static", +# "//foundation/multimedia/image_standard/mock/native:log_mock_static", +# ] +# 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 = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/interfaces/innerkits:image_native", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + # 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_native", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + # 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_native", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + # 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 100644 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..c9906841482da40260ca97717113a36540ed7166 --- /dev/null +++ b/frameworks/innerkitsimpl/test/unittest/image_pixel_map_test.cpp @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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(){}; +}; + + 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: 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"; +} +/** +* @tc.name: ImagePixelMap010 +* @tc.desc: test WriteToParcel +* @tc.type: FUNC +* @tc.require: AR000FTAMO +*/ +HWTEST_F(ImagePixelMapTest, ImagePixelMap010, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap010 start"; + + Parcel data; + + std::unique_ptr pixelmap = ConstructPixmap(); + + bool ret = pixelmap.get()->Marshalling(data); + + EXPECT_EQ(true, ret); + + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap010 end"; +} + +/** +* @tc.name: ImagePixelMap011 +* @tc.desc: test CreateFromParcel +* @tc.type: FUNC +* @tc.require: AR000FTAMO +*/ +HWTEST_F(ImagePixelMapTest, ImagePixelMap011, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap011 start"; + + Parcel data; + + std::unique_ptr pixelmap1 = ConstructPixmap(); + + bool ret = pixelmap1.get()->Marshalling(data); + + EXPECT_EQ(true, ret); + + PixelMap *pixelmap2 = PixelMap::Unmarshalling(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) << "ImagePixelMapTest: ImagePixelMap011 end"; +} +/** + * @tc.name: ImagePixelMap012 + * @tc.desc: create pixelmap with color,colorlength,offset,width and initialization options + * @tc.type: FUNC + */ +HWTEST_F(ImagePixelMapTest, ImagePixelMap012, TestSize.Level3) +{ + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap012 start"; + /** + * @tc.steps: step1. set color,colorlength,offset,width and initialization options + * @tc.expected: step1. The new pixelmap is not null. + */ + const uint32_t color[8] = { 0x80, 0x02, 0x04, 0x08, 0x40, 0x02, 0x04, 0x08 }; + uint32_t colorlength = sizeof(color) / sizeof(color[0]); + const int32_t offset = 1; + InitializationOptions opts; + opts.size.width = 200; + opts.size.height = 300; + opts.pixelFormat = PixelFormat::ARGB_8888; + opts.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; + int32_t width = opts.size.width; + + std::unique_ptr newPixelMap = PixelMap::Create(color, colorlength, offset, width, opts); + EXPECT_EQ(newPixelMap, nullptr); + GTEST_LOG_(INFO) << "ImagePixelMapTest: ImagePixelMap012 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..8063de5be2a4b0235db681a0952f2a6b2f6a1576 --- /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..e0fc358d76eb2a86ee096d025f87605411b34b35 --- /dev/null +++ b/frameworks/innerkitsimpl/utils/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/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", + ] + } + #relative_install_dir = "module/multimedia" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} + +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_standard" +} 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..3a789246a1da0dded21372481da574ac11bcf374 --- /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..f4ab3bfc668cef596c70d0eaac830591e2cdfd63 --- /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/kits/js/common/image_napi_utils.cpp b/frameworks/kits/js/common/image_napi_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f906348bda6534ae5c498484fab288f5b42182a --- /dev/null +++ b/frameworks/kits/js/common/image_napi_utils.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_napi_utils.h" + +namespace OHOS { +namespace Media { + +bool ImageNapiUtils::GetBufferByName(napi_env env, napi_value root, const char* name, void **res, size_t* len) +{ + napi_value tempValue = nullptr; + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_named_property(env, root, name, &tempValue)), false); + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_arraybuffer_info(env, tempValue, res, len)), false); + + return true; +} + +bool ImageNapiUtils::GetUint32ByName(napi_env env, napi_value root, const char* name, uint32_t *res) +{ + napi_value tempValue = nullptr; + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_named_property(env, root, name, &tempValue)), false); + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_value_uint32(env, tempValue, res)), false); + + return true; +} + +bool ImageNapiUtils::GetInt32ByName(napi_env env, napi_value root, const char* name, int32_t *res) +{ + napi_value tempValue = nullptr; + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_named_property(env, root, name, &tempValue)), false); + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_value_int32(env, tempValue, res)), false); + + return true; +} + +bool ImageNapiUtils::GetBoolByName(napi_env env, napi_value root, const char* name, bool *res) +{ + napi_value tempValue = nullptr; + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_named_property(env, root, name, &tempValue)), false); + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_value_bool(env, tempValue, res)), false); + + return true; +} + +bool ImageNapiUtils::GetNodeByName(napi_env env, napi_value root, const char* name, napi_value *res) +{ + + IMG_NAPI_CHECK_RET(IMG_IS_OK(napi_get_named_property(env, root, name, res)), false); + + return true; +} + +napi_valuetype ImageNapiUtils::getType(napi_env env, napi_value root) +{ + napi_valuetype res = napi_undefined; + napi_typeof(env, root, &res); + return res; +} + +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb103556917d0dab1e1da51c387893b89ab73615 --- /dev/null +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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_source_napi.h" +#include "media_errors.h" + +using OHOS::HiviewDFX::HiLog; +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "ImageSourceNapi"}; +} + +namespace OHOS { +namespace Media { +napi_ref ImageSourceNapi::sConstructor_ = nullptr; +static const std::string CLASS_NAME = "PixelMap"; + +struct ImageSourceAsyncContext { + napi_env env; + napi_async_work work; + napi_deferred deferred; + napi_ref callbackRef = nullptr; + ImageSourceNapi *constructor_; +}; + +ImageSourceNapi::ImageSourceNapi() +{ + +} + +ImageSourceNapi::~ImageSourceNapi() +{ + if (wrapper_ != nullptr) + { + napi_delete_reference(env_, wrapper_); + } +} + +napi_value ImageSourceNapi::Init(napi_env env, napi_value exports) +{ + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo), + DECLARE_NAPI_FUNCTION("getImagePropertyInt", GetImagePropertyInt), + DECLARE_NAPI_FUNCTION("getImagePropertyString", GetImagePropertyString), + DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap), + DECLARE_NAPI_FUNCTION("updateData", UpdateData), + DECLARE_NAPI_FUNCTION("release", Release), + DECLARE_NAPI_GETTER("supportedFormats", GetSupportedFormats), + }; + + napi_property_descriptor static_prop[] = { + DECLARE_NAPI_STATIC_FUNCTION("createImageSource", CreateImageSource), + DECLARE_NAPI_STATIC_FUNCTION("createIncrementalSource", CreateIncrementalSource), + }; + + napi_value constructor = nullptr; + napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr, + sizeof(properties) / sizeof(properties[0]), properties, &constructor); + + if (status != napi_ok) + { + HiLog::Error(LABEL, "define class fail"); + return nullptr; + } + + status = napi_create_reference(env, constructor, 1, &sConstructor_); + if (status != napi_ok) + { + HiLog::Error(LABEL, "create reference fail"); + return nullptr; + } + + status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor); + if (status != napi_ok) + { + HiLog::Error(LABEL, "set named property fail"); + return nullptr; + } + + status = napi_define_properties(env, exports, sizeof(static_prop) / sizeof(static_prop[0]), static_prop); + if (status != napi_ok) + { + HiLog::Error(LABEL, "define properties fail"); + return nullptr; + } + HiLog::Debug(LABEL, "Init success"); + return exports; +} + +napi_value ImageSourceNapi::Constructor(napi_env env, napi_callback_info info) +{ + napi_value undefineValue = nullptr; + napi_get_undefined(env, &undefineValue); + + napi_status status; + napi_value thisVar = nullptr; + + status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + + if (status == napi_ok && thisVar != nullptr) + { + std::unique_ptr pImgSrcNapi = std::make_unique(); + if (pImgSrcNapi != nullptr) + { + pImgSrcNapi->env_ = env; + pImgSrcNapi->nativeImgSrc = sImgSrc_; + + status = napi_wrap(env, thisVar, reinterpret_cast(pImgSrcNapi.get()), + ImageSourceNapi::Destructor, nullptr, &(pImgSrcNapi->wrapper_)); + if (status == napi_ok) + { + pImgSrcNapi.release(); + return thisVar; + } + else + { + HiLog::Error(LABEL, "Failure wrapping js to native napi"); + } + } + } + + return undefineValue; +} + +void ImageSourceNapi::Destructor(napi_env env, void *nativeObject, void *finalize) +{ + ImageSourceNapi *pImgSrcNapi = reinterpret_cast(nativeObject); + if (pImgSrcNapi != nullptr) + { + pImgSrcNapi->~ImageSourceNapi(); + } +} + +static void GetSupportedFormatsExecute(napi_env env, void *data) +{ + +} + +static void GetSupportedFormatsComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::GetSupportedFormats(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info info) +{ + + return nullptr; +} + +napi_value ImageSourceNapi::CreateIncrementalSource(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +static void GetImageInfoExecute(napi_env env, void *data) +{ + +} + +static void GetImageInfoComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::GetImageInfo(napi_env env, napi_callback_info info) +{ + return nullptr; + +} + +static void CreatePixelMapExecute(napi_env env, void *data) +{ + +} + +static void CreatePixelMapComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::CreatePixelMap(napi_env env, napi_callback_info info) +{ + return nullptr; + +} + +static void GetImagePropertyIntExecute(napi_env env, void *data) +{ + +} + +static void GetImagePropertyIntComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::GetImagePropertyInt(napi_env env, napi_callback_info info) +{ + return nullptr; + +} + +static void GetImagePropertyStringExecute(napi_env env, void *data) +{ + +} + +static void GetImagePropertyStringComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::GetImagePropertyString(napi_env env, napi_callback_info info) +{ + return nullptr; + +} + +static void UpdateDataExecute(napi_env env, void *data) +{ + +} + +static void UpdateDataComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info) +{ + return nullptr; + +} + +static void ReleaseExecute(napi_env env, void *data) +{ + +} + +static void ReleaseComplete(napi_env env, napi_status status, void *data) +{ + +} + +napi_value ImageSourceNapi::Release(napi_env env, napi_callback_info info) +{ + return nullptr; + +} + + +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/kits/js/common/include/image_napi_utils.h b/frameworks/kits/js/common/include/image_napi_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..f5d8e062fdbfaf845690c68ce484e2a3457ac1fc --- /dev/null +++ b/frameworks/kits/js/common/include/image_napi_utils.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMAGE_NAPI_UTILS_H +#define IMAGE_NAPI_UTILS_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#define IMG_IS_OK(x) ((x) == napi_ok) +#define IMG_NOT_NULL(p) ((p) != nullptr) +#define IMG_IS_READY(x, p) (IMG_IS_OK(x) && IMG_NOT_NULL(p)) + +#define IMG_NAPI_CHECK_RET_D(x, res, msg) \ +do \ +{ \ + if(!(x)) \ + { \ + msg; \ + return (res); \ + } \ +} while (0) + +#define IMG_NAPI_CHECK_RET(x, res) \ +do \ +{ \ + if(!(x)) \ + { \ + return (res); \ + } \ +} while (0) + +#define IMG_JS_ARGS(env, info, status, argc, argv, thisVar) \ +do \ +{ \ + status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); \ +} while (0) + +#define IMG_JS_NO_ARGS(env, info, status, thisVar) \ +do \ +{ \ + status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); \ +} while (0) + +#define IMG_CREATE_CREATE_ASYNC_WORK(env, status, workName, exec, complete, aContext, work) \ +do \ +{ \ + napi_value _resource = nullptr; \ + napi_create_string_utf8((env), (workName), NAPI_AUTO_LENGTH, &_resource); \ + (status) = napi_create_async_work(env, nullptr, _resource, (exec), \ + (complete), static_cast((aContext).get()), &(work)); \ + if ((status) == napi_ok) { \ + (status) = napi_queue_async_work((env), (work)); \ + if ((status) == napi_ok) { \ + (aContext).release(); \ + } \ + } \ +} while (0) + +#define IMG_ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0])) + +#define GET_BUFFER_BY_NAME(root, name, res, len) ImageNapiUtils::GetBufferByName(env, (root), (name), &(res), &(len)) +#define GET_UINT32_BY_NAME(root, name, res) ImageNapiUtils::GetUint32ByName(env, (root), (name), &(res)) +#define GET_INT32_BY_NAME(root, name, res) ImageNapiUtils::GetInt32ByName(env, (root), (name), &(res)) +#define GET_BOOL_BY_NAME(root, name, res) ImageNapiUtils::GetBoolByName(env, (root), (name), &(res)) +#define GET_NODE_BY_NAME(root, name, res) ImageNapiUtils::GetNodeByName(env, (root), (name), &(res)) + +#define STATIC_EXEC_FUNC(name) static void name ## Exec(napi_env env, void *data) +#define STATIC_COMPLETE_FUNC(name) static void name ## Complete(napi_env env, napi_status status, void *data) + +namespace OHOS { +namespace Media { + +class ImageNapiUtils { +public: + static bool GetBufferByName(napi_env env, napi_value root, const char* name, void **res, size_t* len); + static bool GetUint32ByName(napi_env env, napi_value root, const char* name, uint32_t *res); + static bool GetInt32ByName(napi_env env, napi_value root, const char* name, int32_t *res); + static bool GetBoolByName(napi_env env, napi_value root, const char* name, bool *res); + static bool GetNodeByName(napi_env env, napi_value root, const char* name, napi_value *res); + static napi_valuetype getType(napi_env env, napi_value root); +}; +} // namespace Media +} // namespace OHOS +#endif // IMAGE_NAPI_UTILS_H \ No newline at end of file diff --git a/frameworks/kits/js/common/native_module_ohos_image.cpp b/frameworks/kits/js/common/native_module_ohos_image.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e62211bee444435af78be7614d2d1acbb9d8b01 --- /dev/null +++ b/frameworks/kits/js/common/native_module_ohos_image.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 "native_module_ohos_image.h" + +namespace OHOS { +namespace Media{ +/* + * Function registering all props and functions of ohos.medialibrary module + */ +static napi_value Export(napi_env env, napi_value exports) +{ + + PixelMapNapi::Init(env, exports); + return exports; +} + +/* + * module define + */ +static napi_module g_module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Export, + .nm_modname = "multimedia.image", + .nm_priv = ((void*)0), + .reserved = {0} +}; + +/* + * module register + */ +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&g_module); +} + +} // namespace Media +} // namespace OHOS diff --git a/frameworks/kits/js/common/pixel_map_napi.cpp b/frameworks/kits/js/common/pixel_map_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7eb75e2a1c71be51fe6c4981f20217271f56919f --- /dev/null +++ b/frameworks/kits/js/common/pixel_map_napi.cpp @@ -0,0 +1,907 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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_napi.h" +#include "media_errors.h" +#include "hilog/log.h" +#include "image_napi_utils.h" + +using OHOS::HiviewDFX::HiLog; +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PixelMapNapi"}; +} + +namespace OHOS { +namespace Media { + +static const std::string CLASS_NAME = "PixelMap"; +napi_ref PixelMapNapi::sConstructor_ = nullptr; +std::shared_ptr PixelMapNapi::sPixelMap_ = nullptr; + +struct PositionArea { + void* pixels; + size_t size; + uint32_t offset; + uint32_t stride; + Rect region; +}; + +struct PixelMapAsyncContext { + napi_env env; + napi_async_work work; + napi_deferred deferred; + napi_ref callbackRef; + uint32_t status; + PixelMapNapi *nConstructor; + void* colorsBuffer; + size_t colorsBufferSize; + InitializationOptions opts; + PositionArea area; + std::shared_ptr rPixelMap; + uint32_t resultUint32; +}; + +static PixelFormat ParsePixlForamt(int32_t val) +{ + if(val <= static_cast(PixelFormat::CMYK)) + { + return PixelFormat(val); + } + + return PixelFormat::UNKNOWN; +} + +static AlphaType ParseAlphaType(int32_t val) +{ + if(val <= static_cast(AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL)) + { + return AlphaType(val); + } + + return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN; + +} + +static ScaleMode ParseScaleMode(int32_t val) +{ + if(val <= static_cast(ScaleMode::CENTER_CROP)) + { + return ScaleMode(val); + } + + return ScaleMode::FIT_TARGET_SIZE; +} + +static bool parseSize(napi_env env, napi_value root, Size* size) +{ + if(!GET_INT32_BY_NAME(root, "height", size->height)) + { + return false; + } + + if(!GET_INT32_BY_NAME(root, "width", size->width)) + { + return false; + } + + return true; +} + +static bool parseInitializationOptions(napi_env env, napi_value root, InitializationOptions* opts) +{ + uint32_t tmpNumber = 0; + napi_value tmpValue = nullptr; + + if(!GET_BOOL_BY_NAME(root, "editable", opts->editable)) + { + return false; + } + + if(!GET_UINT32_BY_NAME(root, "alphaType", tmpNumber)) + { + return false; + } + opts->alphaType = ParseAlphaType(tmpNumber); + + tmpNumber = 0; + if(!GET_UINT32_BY_NAME(root, "pixelFormat", tmpNumber)) + { + return false; + } + opts->pixelFormat = ParsePixlForamt(tmpNumber); + + + tmpNumber = 0; + if(!GET_UINT32_BY_NAME(root, "scaleMode", tmpNumber)) + { + return false; + } + opts->scaleMode = ParseScaleMode(tmpNumber); + + if(!GET_NODE_BY_NAME(root, "size", tmpValue)) + { + return false; + } + + if(!parseSize(env, tmpValue, &(opts->size))) + { + return false; + } + return true; +} + +static bool parseRegion(napi_env env, napi_value root, Rect* region) +{ + napi_value tmpValue = nullptr; + + if(!GET_INT32_BY_NAME(root, "x", region->left)) + { + return false; + } + + if(!GET_INT32_BY_NAME(root, "y", region->top)) + { + return false; + } + + if(!GET_NODE_BY_NAME(root, "size", tmpValue)) + { + return false; + } + + if(!GET_INT32_BY_NAME(tmpValue, "height", region->height)) + { + return false; + } + + if(!GET_INT32_BY_NAME(tmpValue, "width", region->width)) + { + return false; + } + + return true; +} + +static bool parsePositionArea(napi_env env, napi_value root, PositionArea* area) +{ + napi_value tmpValue = nullptr; + + if(!GET_BUFFER_BY_NAME(root, "pixels", area->pixels, area->size)) + { + return false; + } + + if(!GET_UINT32_BY_NAME(root, "offset", area->offset)) + { + return false; + } + + if(!GET_UINT32_BY_NAME(root, "stride", area->stride)) + { + return false; + } + + if(!GET_NODE_BY_NAME(root, "region", tmpValue)) + { + return false; + } + + if(!parseRegion(env, tmpValue, &(area->region))) + { + return false; + } + return true; +} + +static void CommonCallbackRoutine(napi_env env, PixelMapAsyncContext* &asyncContext, const napi_value &valueParam) +{ + napi_value result[2] = {0}; + napi_value retVal; + napi_value callback = nullptr; + + napi_get_undefined(env, &result[0]); + napi_get_undefined(env, &result[1]); + + if (asyncContext->status == SUCCESS) { + result[1] = valueParam; + } + + if (asyncContext->deferred) { + if (asyncContext->status == SUCCESS) { + napi_resolve_deferred(env, asyncContext->deferred, result[1]); + } else { + napi_reject_deferred(env, asyncContext->deferred, result[0]); + } + } else { + napi_get_reference_value(env, asyncContext->callbackRef, &callback); + napi_call_function(env, nullptr, callback, 2, result, &retVal); + napi_delete_reference(env, asyncContext->callbackRef); + } + + napi_delete_async_work(env, asyncContext->work); + + delete asyncContext; + asyncContext = nullptr; +} + +STATIC_COMPLETE_FUNC(EmptyResult) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + auto context = static_cast(data); + + CommonCallbackRoutine(env, context, result); +} + + +STATIC_COMPLETE_FUNC(Uint32Result) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + auto context = static_cast(data); + + status = napi_create_int32(env, context->resultUint32, &result); + + if(!IMG_IS_OK(status)) + { + context->status = ERROR; + HiLog::Error(LABEL, "napi_create_int32 failed!"); + napi_get_undefined(env, &result); + } + else + { + context->status = SUCCESS; + } + + CommonCallbackRoutine(env, context, result); +} + +PixelMapNapi::PixelMapNapi() + :env_(nullptr), wrapper_(nullptr) +{ + +} + +PixelMapNapi::~PixelMapNapi() +{ + if(nativePixelMap_ != nullptr) + { + nativePixelMap_ = nullptr; + } + + if (wrapper_ != nullptr) + { + napi_delete_reference(env_, wrapper_); + } +} + +napi_value PixelMapNapi::Init(napi_env env, napi_value exports) +{ + napi_property_descriptor props[] = { + DECLARE_NAPI_FUNCTION("readPixelsToBuffer", ReadPixelsToBuffer), + DECLARE_NAPI_FUNCTION("readPixels", ReadPixels), + DECLARE_NAPI_FUNCTION("writePixels", WritePixels), + DECLARE_NAPI_FUNCTION("writeBufferToPixels", WriteBufferToPixels), + DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo), + DECLARE_NAPI_FUNCTION("getBytesNumberPerRow", GetBytesNumberPerRow), + DECLARE_NAPI_FUNCTION("getPixelBytesNumber", GetPixelBytesNumber), + DECLARE_NAPI_FUNCTION("Release", Release), + + DECLARE_NAPI_GETTER("isEditable", GetIsEditable), + }; + + napi_property_descriptor static_prop[] = { + DECLARE_NAPI_STATIC_FUNCTION("createPixelMap", CreatePixelMap), + }; + + napi_value constructor = nullptr; + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, + Constructor, nullptr, IMG_ARRAY_SIZE(props), + props, &constructor)), + nullptr, + HiLog::Error(LABEL, "define class fail") + ); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_create_reference(env, constructor, 1, &sConstructor_)), + nullptr, + HiLog::Error(LABEL, "create reference fail") + ); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)), + nullptr, + HiLog::Error(LABEL, "set named property fail") + ); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK( + napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)), + nullptr, + HiLog::Error(LABEL, "define properties fail") + ); + + HiLog::Debug(LABEL, "Init success"); + return exports; +} + +std::shared_ptr PixelMapNapi::GetPixelMap(napi_env env, napi_value pixelmap) +{ + std::unique_ptr pixelMapNapi = std::make_unique(); + + napi_status status = napi_unwrap(env, pixelmap, reinterpret_cast(&pixelMapNapi)); + + if(IMG_IS_OK(status)) + { + return pixelMapNapi->nativePixelMap_; + } + + return nullptr; +} + +napi_value PixelMapNapi::Constructor(napi_env env, napi_callback_info info) +{ + napi_value undefineVar = nullptr; + napi_get_undefined(env, &undefineVar); + + napi_status status; + napi_value thisVar = nullptr; + napi_get_undefined(env, &thisVar); + + HiLog::Debug(LABEL, "Constructor IN"); + IMG_JS_NO_ARGS(env, info, status, thisVar); + + IMG_NAPI_CHECK_RET(IMG_IS_READY(status, thisVar), undefineVar); + std::unique_ptr pPixelMapNapi = std::make_unique(); + + IMG_NAPI_CHECK_RET(IMG_NOT_NULL(pPixelMapNapi), undefineVar); + + pPixelMapNapi->env_ = env; + pPixelMapNapi->nativePixelMap_ = sPixelMap_; + + status = napi_wrap(env, thisVar, reinterpret_cast(pPixelMapNapi.get()), + PixelMapNapi::Destructor, nullptr, &(pPixelMapNapi->wrapper_)); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), undefineVar, HiLog::Error(LABEL, "Failure wrapping js to native napi")); + + pPixelMapNapi.release(); + sPixelMap_ = nullptr; + + return thisVar; +} + +void PixelMapNapi::Destructor(napi_env env, void *nativeObject, void *finalize) +{ + PixelMapNapi *pixelMapNapi = reinterpret_cast(nativeObject); + + if (IMG_NOT_NULL(pixelMapNapi)) + { + pixelMapNapi->~PixelMapNapi(); + } +} + +STATIC_EXEC_FUNC(CreatePixelMap) +{ + auto context = static_cast(data); + auto colors = static_cast(context->colorsBuffer); + auto pixelmap = PixelMap::Create(colors, context->colorsBufferSize, context->opts); + + context->rPixelMap = std::move(pixelmap); + + if(IMG_NOT_NULL(context->rPixelMap)) + { + context->status = SUCCESS; + } + else + { + context->status = ERROR; + } +} + +void PixelMapNapi::CreatePixelMapComplete(napi_env env, napi_status status, void *data) +{ + napi_value constructor = nullptr; + napi_value result = nullptr; + + HiLog::Debug(LABEL, "CreatePixelMapComplete IN"); + auto context = static_cast(data); + + status = napi_get_reference_value(env, sConstructor_, &constructor); + + if (IMG_IS_OK(status)) { + sPixelMap_ = context->rPixelMap; + status = napi_new_instance(env, constructor, 0, nullptr, &result); + } + + if(!IMG_IS_OK(status)) + { + context->status = ERROR; + HiLog::Error(LABEL, "New instance could not be obtained"); + napi_get_undefined(env, &result); + } + + CommonCallbackRoutine(env, context, result); + +} + +napi_value PixelMapNapi::CreatePixelMap(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[4] = {0}; + size_t argCount = 4; + HiLog::Debug(LABEL, "CreatePixelMap IN"); + + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + //we are static method! + //thisVar is nullptr here + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + //IMG_NAPI_CHECK_RET_D(argCount >= 2, nullptr, HiLog::Error(LABEL, "CreatePixelMap args count mismatch %{public}d", argCount)); + + std::unique_ptr asyncContext = std::make_unique(); +// status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + +// IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), +// nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + status = napi_get_arraybuffer_info(env, argValue[0], &(asyncContext->colorsBuffer), &(asyncContext->colorsBufferSize)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "colors mismatch")); + + IMG_NAPI_CHECK_RET_D(parseInitializationOptions(env, argValue[1], &(asyncContext->opts)), + nullptr, HiLog::Error(LABEL, "InitializationOptions mismatch")); + + if(argCount == 3 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "CreatePixelMap", + CreatePixelMapExec, CreatePixelMapComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; +} + +napi_value PixelMapNapi::CreatePixelMap(napi_env env, std::shared_ptr pixelmap) +{ + + napi_value constructor = nullptr; + napi_value result = nullptr; + napi_status status; + + HiLog::Debug(LABEL, "CreatePixelMap IN"); + status = napi_get_reference_value(env, sConstructor_, &constructor); + + if (IMG_IS_OK(status)) { + sPixelMap_ = pixelmap; + status = napi_new_instance(env, constructor, 0, nullptr, &result); + } + + if(!IMG_IS_OK(status)) + { + HiLog::Error(LABEL, "CreatePixelMap | New instance could not be obtained"); + napi_get_undefined(env, &result); + } + + return result; +} + +napi_value PixelMapNapi::GetIsEditable(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + size_t argCount = 0; + HiLog::Debug(LABEL, "GetIsEditable IN"); + + IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr pixelMapNapi = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&pixelMapNapi)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pixelMapNapi), result, HiLog::Error(LABEL, "fail to unwrap context")); + + bool isEditable = pixelMapNapi->nativePixelMap_->IsEditable(); + + napi_get_boolean(env, isEditable, &result); + + return result; +} + +napi_value PixelMapNapi::ReadPixelsToBuffer(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[2] = {0}; + size_t argCount = 2; + + HiLog::Debug(LABEL, "ReadPixelsToBuffer IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + //IMG_NAPI_CHECK_RET_D(argCount >= 1, nullptr, HiLog::Error(LABEL, "ReadPixelsToBuffer args count mismatch %{public}d", argCount)); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + + status = napi_get_arraybuffer_info(env, argValue[0], + &(asyncContext->colorsBuffer), &(asyncContext->colorsBufferSize)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "colors mismatch")); + + if(argCount == 2 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ReadPixelsToBuffer", + [](napi_env env, void *data) + { + auto context = static_cast(data); + context->status = context->rPixelMap->ReadPixels( + context->colorsBufferSize, static_cast(context->colorsBuffer)); + } + , EmptyResultComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; + +} + +napi_value PixelMapNapi::ReadPixels(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[2] = {0}; + size_t argCount = 2; + + HiLog::Debug(LABEL, "ReadPixels IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + //IMG_NAPI_CHECK_RET_D(argCount >= 1, nullptr, HiLog::Error(LABEL, "ReadPixels args count mismatch %{public}d", argCount)); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + + IMG_NAPI_CHECK_RET_D(parsePositionArea(env, argValue[0], &(asyncContext->area)), + nullptr, HiLog::Error(LABEL, "fail to parse position area")); + + if(argCount == 2 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ReadPixels", + [](napi_env env, void *data) + { + auto context = static_cast(data); + auto area = context->area; + context->status = context->rPixelMap->ReadPixels( + area.size, area.offset, area.stride, area.region, static_cast(area.pixels)); + }, EmptyResultComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; +} + +napi_value PixelMapNapi::WritePixels(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[2] = {0}; + size_t argCount = 2; + + HiLog::Debug(LABEL, "WritePixels IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + //IMG_NAPI_CHECK_RET_D(argCount >= 1, nullptr, HiLog::Error(LABEL, "WritePixels args count mismatch %{public}d", argCount)); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + + IMG_NAPI_CHECK_RET_D(parsePositionArea(env, argValue[0], &(asyncContext->area)), + nullptr, HiLog::Error(LABEL, "fail to parse position area")); + + if(argCount == 2 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "WritePixels", + [](napi_env env, void *data) + { + auto context = static_cast(data); + auto area = context->area; + context->status = context->rPixelMap->WritePixels( + static_cast(area.pixels), area.size, area.offset, area.stride, area.region); + }, EmptyResultComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; + +} + +napi_value PixelMapNapi::WriteBufferToPixels(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[2] = {0}; + size_t argCount = 2; + + HiLog::Debug(LABEL, "WriteBufferToPixels IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + //IMG_NAPI_CHECK_RET_D(argCount >= 1, nullptr, HiLog::Error(LABEL, "WriteBufferToPixels args count mismatch %{public}d", argCount)); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + status = napi_get_arraybuffer_info(env, argValue[0], + &(asyncContext->colorsBuffer), &(asyncContext->colorsBufferSize)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to get buffer info")); + + if(argCount == 2 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "WriteBufferToPixels", + [](napi_env env, void *data) + { + auto context = static_cast(data); + context->status = context->rPixelMap->WritePixels(static_cast(context->colorsBuffer), context->colorsBufferSize); + + }, EmptyResultComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; +} + +napi_value PixelMapNapi::GetImageInfo(napi_env env, napi_callback_info info) +{ + HiLog::Debug(LABEL, "GetImageInfo IN"); + return nullptr; +} + +napi_value PixelMapNapi::GetBytesNumberPerRow(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[1] = {0}; + size_t argCount = 1; + + HiLog::Debug(LABEL, "GetBytesNumberPerRow IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + + if(argCount == 1 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetBytesNumberPerRow", + [](napi_env env, void *data) + { + auto context = static_cast(data); + context->resultUint32 = context->rPixelMap->GetRowBytes(); + context->status = SUCCESS; + + }, Uint32ResultComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; +} + +napi_value PixelMapNapi::GetPixelBytesNumber(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + int32_t refCount = 1; + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[1] = {0}; + size_t argCount = 1; + + HiLog::Debug(LABEL, "GetPixelBytesNumber IN"); + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->nConstructor)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), + nullptr, HiLog::Error(LABEL, "fail to unwrap context")); + + asyncContext->rPixelMap = asyncContext->nConstructor->nativePixelMap_; + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPixelMap), + nullptr, HiLog::Error(LABEL, "empty native pixelmap")); + + if(argCount == 1 && ImageNapiUtils::getType(env, argValue[argCount -1]) == napi_function) + { + napi_create_reference(env, argValue[argCount -1], refCount, &asyncContext->callbackRef); + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &(asyncContext->deferred), &result); + } else { + napi_get_undefined(env, &result); + } + + IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetPixelBytesNumber", + [](napi_env env, void *data) + { + auto context = static_cast(data); + context->resultUint32 = context->rPixelMap->GetByteCount(); + context->status = SUCCESS; + + }, Uint32ResultComplete, asyncContext, asyncContext->work); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), + nullptr, HiLog::Error(LABEL, "fail to create async work")); + return result; +} + +napi_value PixelMapNapi::Release(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + size_t argCount = 0; + + IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info")); + + std::unique_ptr pixelMapNapi = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&pixelMapNapi)); + + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pixelMapNapi), result, HiLog::Error(LABEL, "fail to unwrap context")); + + pixelMapNapi->nativePixelMap_= nullptr; + + return result; +} + +} // namespace Media +} // namespace OHOS 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..b1bf81329d0eb56ac4b1c4e96cbeceeef1fbd16c --- /dev/null +++ b/interfaces/innerkits/BUILD.gn @@ -0,0 +1,325 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("//foundation/multimedia/image_standard/ide/image_decode_config.gni") + +config("image_external_config") { + include_dirs = [ + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/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/image_standard/frameworks/kits/js/common/include", + "//foundation/multimedia/image_standard/interfaces/kits/js/common/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", + ] + } +} + +js_declaration("image_js") { + part_name = "multimedia_image_standard" + sources = [ + "//foundation/multimedia/image_standard/interfaces/kits/js/@ohos.multimedia.image.d.ts", + ] +} + +ohos_copy("image_declaration") { + sources = [ + "//foundation/multimedia/image_standard/interfaces/kits/js/@ohos.multimedia.image.d.ts", + ] + outputs = [ target_out_dir + "/$target_name/" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" +} + +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", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/native_module_ohos_image.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/pixel_map_napi.cpp", + #"//foundation/multimedia/image_standard/frameworks/kits/js/common/image_source_napi.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/image_napi_utils.cpp", + + ] + deps = [ + "//foundation/ace/napi:ace_napi", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + + external_deps = [ + "bytrace_standard:bytrace_core", + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + + ] + relative_install_dir = "module/multimedia" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} + + + +ohos_shared_library("image_native") { + 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", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/native_module_ohos_image.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/pixel_map_napi.cpp", + #"//foundation/multimedia/image_standard/frameworks/kits/js/common/image_source_napi.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/image_napi_utils.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/frameworks/innerkitsimpl/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/frameworks/innerkitsimpl/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/ace/napi:ace_napi", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/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) { + } else { + deps += [ + "//third_party/libjpeg-turbo:libjpeg-turbo", + "//third_party/libpng:libpng", + ] + } + external_deps = [ + "bytrace_standard:bytrace_core", + "ipc:ipc_core", + "hiviewdfx_hilog_native:libhilog", + + ] + } +# relative_install_dir = "module/multimedia" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} +ohos_static_library("image_static_napi"){ + 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", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/native_module_ohos_image.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/pixel_map_napi.cpp", + #"//foundation/multimedia/image_standard/frameworks/kits/js/common/image_source_napi.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/image_napi_utils.cpp", + ] + deps = [ + "//foundation/ace/napi:ace_napi", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/utils:image_utils", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//utils/native/base:utils", + ] + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} + +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", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/native_module_ohos_image.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/pixel_map_napi.cpp", + #"//foundation/multimedia/image_standard/frameworks/kits/js/common/image_source_napi.cpp", + "//foundation/multimedia/image_standard/frameworks/kits/js/common/image_napi_utils.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/frameworks/innerkitsimpl/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/frameworks/innerkitsimpl/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/ace/napi:ace_napi", + "//foundation/multimedia/image_standard/frameworks/innerkitsimpl/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) { + } else { + deps += [ + "//third_party/libjpeg-turbo:libjpeg-turbo", + "//third_party/libpng:libpng", + ] + } + } + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} 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 100644 index 0000000000000000000000000000000000000000..9e91c1d6afa65b38129c56e253f2e7f73577e4d3 --- /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/js/@ohos.multimedia.image.d.ts b/interfaces/kits/js/@ohos.multimedia.image.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec3d6ef73bf80b9c1f9787058f6e718eeb7079ae --- /dev/null +++ b/interfaces/kits/js/@ohos.multimedia.image.d.ts @@ -0,0 +1,385 @@ +/* +* Copyright (C) 2021 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { AsyncCallback } from './basic'; + +declare namespace image { + + /** + * Enumerates pixel map formats. + */ + enum PixelMapFormat { + /** + * Indicates an unknown pixel map 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 + } + + /** + * Enumerates color spaces. + */ + 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 + } + + /** + * Enumerates alpha types. + */ + enum AlphaType { + /** + * Indicates an unknown alpha type. + */ + UNKNOWN = 0, + + /** + * Indicates that the image has no alpha channel, or all pixels in the image are fully opaque. + */ + OPAQUE = 1, + + /** + * Indicates that RGB components of each pixel in the image are premultiplied by alpha. + */ + PREMUL = 2, + + /** + * Indicates that RGB components of each pixel in the image are independent of alpha and are not premultiplied by alpha. + */ + UNPREMUL = 3 + } + + /** + * Describes the size of an image. + */ + interface Size { + height: number; + width: number; + } + + interface Region { + size: Size; + x: number; + y: number; + } + + interface PositionArea { + pixels: ArrayBuffer; + offset: number; + stride: number; + region: Region; + } + + /** + * Describes image information. + */ + interface ImageInfo { + size: Size; + pixelFormat: PixelMapFormat; + colorSpace: ColorSpace; + alphaType: AlphaType; + } + + /** + * Describes the option for image packing. + */ + interface PackingOption { + /** + * Multipurpose Internet Mail Extensions (MIME) format of the target image, for example, image/jpeg. + */ + format: string; + + /** + * Quality of the target image. The value is an integer ranging from 0 to 100. A larger value indicates better + */ + quality: number; + } + + interface DecodingOptions { + // Indicates the sampling size based on which an image is scaled down. + sampleSize: number; + + // Indicates the rotation angle, ranging from 0 to 360 + rotateDegrees: number; + + // Specifies whether pixel values of the pixel map to be decoded can be edited. + editable: boolean; + + // Indicates the expected output size + desiredSize: Size; + + // Indicates an image area to be decoded. + desiredRegion: Region; + + // Indicates the pixel format of a decoded image, which is defined by PixelFormat. + desiredPixelFormat: PixelMapFormat; + + // reused current pixelmap buffer address for a new created pixelmap + reusedPixelMap: PixelMap; + } + + enum ScaleMode { + CENTER_CROP = 1, // Indicates the effect that scales an image to fill the target image area and center-crops the part outside the area. + FIT_TARGET_SIZE = 2, // Indicates the effect that fits the image into the target size. + } + + interface InitializationOptions { + // Indicates the expected alpha type of the pixel map to be created + alphaType: AlphaType; + + // Specifies whether pixel values of the pixel map to be created can be edited + editable: boolean; + + // Indicates the expected format of the pixel map to be created + pixelFormat: PixelMapFormat; + + // Indicates the scaling effect used when the aspect ratio of the original image is different from that of the target image + scaleMode: ScaleMode; + + // Indicates the expected size of the pixel map to be created + size: Size; + } + + /** + * Creates an ImageSource instance. + */ + function createImageSource(uri: string): ImageSource; + + // create a imagesource based on fd + function createImageSource(fd: number): ImageSource; + + // Creates an ImageSource based on a ArrayBuffer and source options. + function createImageSource(data: ArrayBuffer): ImageSource; + + // 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. + function createPixelMap(colors: ArrayBuffer, opts: InitializationOptions): Promise; + function createPixelMap(colors: ArrayBuffer, opts: InitializationOptions, callback: AsyncCallback): void; + + + function createIncrementalSource(data: ArrayBuffer): ImageSource; + + /** + * Creates an ImagePacker instance. + */ + function createImagePacker(): ImagePacker; + + interface PixelMap { + // read all pixels to an buffer + readPixelsToBuffer(dst: ArrayBuffer): Promise; + readPixelsToBuffer(dst: ArrayBuffer, callback: AsyncCallback): void; + + // read pixels from a specified area into an buffer + readPixels(area: PositionArea): Promise>; + readPixels(area: PositionArea, callback: AsyncCallback>): void; + + // write pixels to a specified area + writePixels(area: PositionArea): Promise; + writePixels(area: PositionArea, callback: AsyncCallback): void; + + // write array buffer to pixelmap + writeBufferToPixels(src: ArrayBuffer): Promise; + writeBufferToPixels(src: ArrayBuffer, callback: AsyncCallback): void; + + // obtains basic image information. + getImageInfo(): Promise; + getImageInfo(callback: AsyncCallback): void; + + // get bytes number per row. + getBytesNumberPerRow(): Promise; + getBytesNumberPerRow(callback: AsyncCallback): void; + + // get bytes buffer for a pixelmap. + getPixelBytesNumber(): Promise; + getPixelBytesNumber(callback: AsyncCallback): void; + + // release pixelmap + release(): void; + + readonly isEditable: boolean; + } + + interface ImageSource { + /** + * Obtains information about an image with the specified sequence number and uses a callback to return the result. + */ + getImageInfo(index: number, callback: AsyncCallback): void; + + /** + * Obtains information about this image and uses a callback to return the result. + */ + getImageInfo(callback: AsyncCallback): void; + + /** + * Get image information from image source. + */ + getImageInfo(index?: number): Promise; + + // Obtains the integer value of a specified property key for an image at the given index in the ImageSource. + getImagePropertyInt(index:number, key: string, defaultValue: number): Promise; + getImagePropertyInt(index:number, key: string, defaultValue: number, callback: AsyncCallback): void; + + // Obtains the string value of a specified image property key. + getImagePropertyString(key: string): Promise; + getImagePropertyString(key: string, callback: AsyncCallback): void; + + // Decodes source image data based on a specified index location in the ImageSource and creates a pixel map. + createPixelMap(index: number, options: DecodingOptions, callback: AsyncCallback): void; + createPixelMap(opts: DecodingOptions, callback: AsyncCallback): void; + + // Updates incremental data to an image data source using a byte array with specified offset and length. + updateData(data: Array, isFinal: boolean, offset?: number, length?: number): Promise; + updateData(data: Array, isFinal: boolean, offset: number, length: number, callback: AsyncCallback): void; + updateData(data: Array, isFinal: boolean, callback: AsyncCallback): void; + + /** + * Releases an ImageSource instance and uses a callback to return the result. + */ + release(callback: AsyncCallback): void; + + /** + * Releases an ImageSource instance and uses a promise to return the result. + */ + release(): Promise; + + /** + * Supported image formats. + */ + readonly supportedFormats: Array; + } + + interface ImagePacker { + /** + * Compresses or packs an image and uses a callback to return the result. + */ + packing(source: ImageSource, option: PackingOption, callback: AsyncCallback>): void; + + /** + * Compresses or packs an image and uses a promise to return the result. + */ + packing(source: ImageSource, option: PackingOption): Promise>; + + /** + * Releases an ImagePacker instance and uses a callback to return the result. + */ + release(callback: AsyncCallback): void; + + /** + * Releases an ImagePacker instance and uses a promise to return the result. + */ + release(): Promise; + + /** + * Supported image formats. + */ + readonly supportedFormats: Array; + } +} + +export default image; \ No newline at end of file diff --git a/interfaces/kits/js/common/include/image_source_napi.h b/interfaces/kits/js/common/include/image_source_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..561ea51431f1edfabb53cbcc68fab3c85dc65272 --- /dev/null +++ b/interfaces/kits/js/common/include/image_source_napi.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 IMAGE_SOURCE_NAPI_H_ +#define IMAGE_SOURCE_NAPI_H_ + +#include "pixel_map.h" +#include "image_type.h" +#include "image_source.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace Media { +class ImageSourceNapi { +public: + ImageSourceNapi(); + ~ImageSourceNapi(); + + static napi_value Init(napi_env env, napi_value exports); + +private: + static napi_value Constructor(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *nativeObject, void *finalize); + + //readonly property + static napi_value GetSupportedFormats(napi_env env, napi_callback_info info); + + //static methods + static napi_value CreateImageSource(napi_env env, napi_callback_info info); + static napi_value CreateIncrementalSource(napi_env env, napi_callback_info info); + + //methods + static napi_value GetImageInfo(napi_env env, napi_callback_info info); + static napi_value CreatePixelMap(napi_env env, napi_callback_info info); + static napi_value GetImagePropertyInt(napi_env env, napi_callback_info info); + static napi_value GetImagePropertyString(napi_env env, napi_callback_info info); + static napi_value UpdateData(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + static napi_ref sConstructor_; + static std::shared_ptr sImgSrc_; + + napi_env env_ = nullptr; + napi_ref wrapper_ = nullptr; + std::shared_ptr nativeImgSrc = nullptr; + bool isRelease = false; +}; + +} // namespace Media +} // namespace OHOS +#endif /* PIXEL_MAP_NAPI_H_ */ diff --git a/interfaces/kits/js/common/include/native_module_ohos_image.h b/interfaces/kits/js/common/include/native_module_ohos_image.h new file mode 100644 index 0000000000000000000000000000000000000000..a7370598fc5f698f37f9068db6405a3ade380d4f --- /dev/null +++ b/interfaces/kits/js/common/include/native_module_ohos_image.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 NATIVE_MODULE_OHOS_IMAGE_H_ +#define NATIVE_MODULE_OHOS_IMAGE_H_ + +#include "napi/native_node_api.h" +#include "image_source_napi.h" +#include "pixel_map_napi.h" + +#endif /* NATIVE_MODULE_OHOS_IMAGE_H_ */ diff --git a/interfaces/kits/js/common/include/pixel_map_napi.h b/interfaces/kits/js/common/include/pixel_map_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..065fe38ea1771c72079266e51b086a897a735c2d --- /dev/null +++ b/interfaces/kits/js/common/include/pixel_map_napi.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 PIXEL_MAP_NAPI_H_ +#define PIXEL_MAP_NAPI_H_ + +#include "pixel_map.h" +#include "image_type.h" +#include "image_source.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace Media { +class PixelMapNapi { +public: + PixelMapNapi(); + ~PixelMapNapi(); + + static napi_value Init(napi_env env, napi_value exports); + + static napi_value CreatePixelMap(napi_env env, std::shared_ptr pixelmap); + static std::shared_ptr GetPixelMap(napi_env env, napi_value pixelmap); + +private: + static napi_value Constructor(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *nativeObject, void *finalize); + + //readonly property + static napi_value GetIsEditable(napi_env env, napi_callback_info info); + + //static mothod + static napi_value CreatePixelMap(napi_env env, napi_callback_info info); + static void CreatePixelMapComplete(napi_env env, napi_status status, void *data); + + //methods + static napi_value ReadPixelsToBuffer(napi_env env, napi_callback_info info); + static napi_value ReadPixels(napi_env env, napi_callback_info info); + static napi_value WritePixels(napi_env env, napi_callback_info info); + static napi_value WriteBufferToPixels(napi_env env, napi_callback_info info); + static napi_value GetImageInfo(napi_env env, napi_callback_info info); + static napi_value GetBytesNumberPerRow(napi_env env, napi_callback_info info); + static napi_value GetPixelBytesNumber(napi_env env, napi_callback_info info); + static napi_value getPixelBytesCount(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + + static napi_ref sConstructor_; + static std::shared_ptr sPixelMap_; + + napi_env env_ = nullptr; + napi_ref wrapper_ = nullptr; + std::shared_ptr nativePixelMap_; + bool isRelease = false; +}; + +} // namespace Media +} // namespace OHOS +#endif /* PIXEL_MAP_NAPI_H_ */ 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..c93f3572e58b1e9a35f344a5801cbb2377ead55d --- /dev/null +++ b/interfaces/kits/native/ndk_test_example/BUILD.gn @@ -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. + +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 = [ + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + "//foundation/multimedia/image_standard/interfaces/kits/native:multimedia_target", + + # "//utils/jni:utils_jnikit", + "//utils/native/base:utils", + ] + + # 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..44d70663fb9ba9ba55b04f82009719715aa99b34 --- /dev/null +++ b/interfaces/kits/native/test/BUILD.gn @@ -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. + +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_native", + "//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/native/BUILD.gn b/mock/native/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..fd4a55749b4bbe2a6b5aa028586bea3b888bc325 --- /dev/null +++ b/mock/native/BUILD.gn @@ -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/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", + "//foundation/multimedia/image_standard/interfaces/innerkits/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..b6b7add593c188524ddb6d97f0ea95fec0b2d2a8 --- /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..0545bd2f5206581dff0f017675feeea33309ea81 --- /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..ac800da9080d723cc41c2672ca624c8c900e3a5d --- /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..917684f4f26150866964527c0a10b1daf2bf173c --- /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..7a39fe5cdeabeb0d8ed03a9037bd252186fc74f5 --- /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..9a8a3f33ae1cb821765adc3659b7aed0dc25b2b2 --- /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 100644 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..3e705a6be24c459cafafad3d11bd085f699d0d6c --- /dev/null +++ b/plugins/common/libs/BUILD.gn @@ -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") +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..8aab9f27b32e4544f75ff9d2ecf3104bcdfb0e0e --- /dev/null +++ b/plugins/common/libs/image/formatagentplugin/BUILD.gn @@ -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. + +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_standard" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("formatagentmetadata") { + source = "imageformatagent.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} 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..fd6fbe76387a0b81ea7ea3b5991872e9578b0148 --- /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..399b3e611a968fefcf6d636e012a3facee9c0c74 --- /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..e4aea4c76126e89d192779039cc2580e100666dc --- /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..6f80dd3227f3fa2427918e55127e30e9fc689dad --- /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..b47b7824cefa9adda17801de4360a71e661be533 --- /dev/null +++ b/plugins/common/libs/image/libgifplugin/BUILD.gn @@ -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. + +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_standard" + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("gifpluginmetadata") { + source = "gifplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} 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..fd60e23f14cf346d381c6707d32cae2b5f94d3be --- /dev/null +++ b/plugins/common/libs/image/libheifplugin/BUILD.gn_old @@ -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") + +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", + ] + } + + 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..dae913b7205591a4b724005000e431ebd7fe33de --- /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 b/plugins/common/libs/image/libjpegplugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..593d55dbec497da7bbcf3601f7b3ce4533c712a3 --- /dev/null +++ b/plugins/common/libs/image/libjpegplugin/BUILD.gn @@ -0,0 +1,95 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//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", + ] + 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:libjpeg_static", + ] + } else if (use_clang_mac) { + defines = image_decode_mac_defines + include_dirs += [ + "//foundation/multimedia/image_standard/mock/native/include", + "//third_party/libjpeg", + ] + 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:libjpeg_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_native", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//third_party/libjpeg:libjpeg_static", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { + } else { + deps += [ "//third_party/libjpeg:libjpeg_static" ] + include_dirs += [ "//third_party/libjpeg" ] + } + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image_standard" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("jpegpluginmetadata") { + source = "jpegplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} 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..1af11e211ba4a3588f77aafdd6c01c06bf8414b8 --- /dev/null +++ b/plugins/common/libs/image/libpngplugin/BUILD.gn @@ -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("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", + "//third_party/libpng", + ] + deps += [ + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + "//third_party/libpng:png_static", + "//utils/native/base:utils", + ] + if (DUAL_ADAPTER) { + } else { + deps += [ "//third_party/libpng:libpng" ] + include_dirs += [ "//third_party/libpng" ] + } + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image_standard" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("pngpluginmetadata") { + source = "pngplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} 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..e870129c931832c3f8fe8dcaea95d9772f7f12a3 --- /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 b/plugins/common/libs/image/libwebpplugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c5634875a8037c242a2d2e72f5353a9430c11cad --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/BUILD.gn @@ -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("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", + "//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", + ] + if (use_mingw_win) { + defines = image_decode_windows_defines + 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", + "//third_party/flutter:ace_fontconfig.json", + "//third_party/flutter:ace_fontmgr_ohos", + "//third_party/flutter:ace_fontmgr_standard", + "//third_party/flutter:ace_jpeg", + "//third_party/flutter:ace_jsoncpp", + "//third_party/flutter:ace_libfreetype2", + "//third_party/flutter:ace_libjpeg", + "//third_party/flutter:ace_libpng", + "//third_party/flutter:ace_libwebp", + "//third_party/flutter:ace_png", + "//third_party/flutter:ace_skcms", + "//third_party/flutter:ace_skia_core", + "//third_party/flutter:ace_skia_ohos", + "//third_party/flutter:ace_skia_opts", + "//third_party/flutter:ace_typeface_freetype", + "//third_party/flutter:ace_webp", + "//utils/native/base:utils", + "//utils/native/base:utils", + ] + + if (DUAL_ADAPTER) { + } + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + part_name = "multimedia_image_standard" + + subsystem_name = "multimedia" +} + +ohos_prebuilt_etc("webppluginmetadata") { + source = "webpplugin.pluginmeta" + relative_install_dir = "multimediaplugin/image" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} diff --git a/plugins/common/libs/image/libwebpplugin/include/multimedia_templates.h b/plugins/common/libs/image/libwebpplugin/include/multimedia_templates.h new file mode 100644 index 0000000000000000000000000000000000000000..4f269712cfc55626fbb9cc6b65e7256489cc3233 --- /dev/null +++ b/plugins/common/libs/image/libwebpplugin/include/multimedia_templates.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 MULTIMEDIA_TEMPLATES_H +#define MULTIMEDIA_TEMPLATES_H + +#include +#include +#include + +namespace OHOS { +namespace MultiMedia { +/* call a function when this goes out of scope. The template uses two + * parameters, the object, and a function that is to be called in the destructor + */ +template +using remove_pointer_t = typename std::remove_pointer::type; + +template +struct FunctionWrapper { + template + auto operator()(Args &&... args) const -> decltype(P(std::forward(args)...)) + { + return P(std::forward(args)...); + } +}; + +template +class TAutoCallProc : public std::unique_ptr, P>> { +public: + TAutoCallProc(T *obj) : std::unique_ptr, P>>(obj) + {} + + operator T *() const + { + return this->get(); + } + ~TAutoCallProc() = default; +}; +} // namespace MultiMedia +} // namespace OHOS +#endif // MULTIMEDIA_TEMPLATES_H 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..fbbffeaf2caef3e9a4505b1dd2d07cb15748f607 --- /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..b5b0040905a3372d708ecfd279da026b0af00cab --- /dev/null +++ b/plugins/manager/BUILD.gn @@ -0,0 +1,146 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//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" ] + 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" ] + } + relative_install_dir = "module/multimedia" + subsystem_name = "multimedia" + part_name = "multimedia_image_standard" +} + +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" ] + 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..8d83640ebe0db2de0fa0973ee71e3eeb9e400bce --- /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..806c4123a07a1826bd5b5578b17986581fff2410 --- /dev/null +++ b/plugins/manager/test/unittest/common/BUILD.gn @@ -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/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..070e1ce38f051d8cee4ce6802c5da48bb720b3ca --- /dev/null +++ b/plugins/manager/test/unittest/common/plugin_example/plugin_example1/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("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 = [ + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + ] + + # 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..d1684b99794e77d20a3279226c4ae65dd797aa2a --- /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 = [ + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + ] + + # 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..a1d9d792ec218aebf2f3202e4d62c1c8bab9cc13 --- /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 = [ + "//base/hiviewdfx/hilog/frameworks/native:libhilogutil", + "//foundation/multimedia/image_standard/plugins/manager:pluginmanager", + ] + + # 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 100644 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 ] + } + ] + } + ] +}