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
+
-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组件架构图
+
+
+## 目录
+
+仓目录结构如下:
+
+```
+/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