1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ans_image_util.h"
16 #include "ans_log_wrapper.h"
17 #include "image_packer.h"
18 #include "image_source.h"
19 
20 namespace OHOS {
21 namespace Notification {
22 const std::string AnsImageUtil::IMAGE_FORMAT_PNG {"image/png"};
23 const uint8_t AnsImageUtil::IMAGE_QUALITY {100};
24 const uint8_t AnsImageUtil::SHIFT_FOUR {4};
25 const uint8_t AnsImageUtil::NUM_TEN {10};
26 const size_t  AnsImageUtil::TWO_TIMES {2};
27 const uint32_t AnsImageUtil::DEFAULT_SIZE {25 * 1024 * 1024};
28 
PackImage(const std::shared_ptr<Media::PixelMap> & pixelMap,const std::string & format)29 std::string AnsImageUtil::PackImage(const std::shared_ptr<Media::PixelMap> &pixelMap, const std::string &format)
30 {
31     if (!pixelMap || format.empty()) {
32         ANS_LOGW("invalid parameters");
33         return {};
34     }
35 
36     Media::ImagePacker imagePacker;
37     Media::PackOption option;
38     option.format     = format;
39     option.quality    = IMAGE_QUALITY;
40     option.numberHint = 1;
41 
42     std::set<std::string> formats;
43     auto ret = imagePacker.GetSupportedFormats(formats);
44     if (ret) {
45         ANS_LOGE("Failed to GetSupportedFormats, ret : %{public}u", ret);
46         return {};
47     }
48 
49     auto size = static_cast<uint32_t>(pixelMap->GetByteCount());
50     ANS_LOGD("size of pixelMap : %{public}u", size);
51     if (size < DEFAULT_SIZE) {
52         size = DEFAULT_SIZE;
53     }
54     auto pbuf = new (std::nothrow) uint8_t [size];
55     if (pbuf == nullptr) {
56         ANS_LOGE("create buffer failed");
57         return {};
58     }
59 
60     imagePacker.StartPacking(pbuf, size, option);
61     imagePacker.AddImage(*pixelMap);
62     int64_t packedSize {0};
63     imagePacker.FinalizePacking(packedSize);
64     ANS_LOGD("packed size : %{public}" PRId64, packedSize);
65 
66     std::string pixelMapStr(reinterpret_cast<char*>(pbuf), static_cast<size_t>(packedSize));
67     delete [] pbuf;
68     pbuf = nullptr;
69 
70     return BinToHex(pixelMapStr);
71 }
72 
UnPackImage(const std::string & pixelMapStr,const std::string & format)73 std::shared_ptr<Media::PixelMap> AnsImageUtil::UnPackImage(const std::string &pixelMapStr, const std::string &format)
74 {
75     if (pixelMapStr.empty()) {
76         return {};
77     }
78 
79     auto binStr = HexToBin(pixelMapStr);
80 
81     uint32_t errorCode {0};
82     Media::SourceOptions opts;
83     opts.formatHint = format;
84     auto imageSource = Media::ImageSource::CreateImageSource(
85         reinterpret_cast<const uint8_t*>(binStr.data()),
86         static_cast<uint32_t>(binStr.length()),
87         opts, errorCode);
88     if (errorCode || !imageSource) {
89         ANS_LOGE("create imageSource failed");
90         return {};
91     }
92 
93     Media::DecodeOptions decodeOpts;
94     auto pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
95     if (errorCode || !pixelMap) {
96         ANS_LOGE("Failed to create pixelMap.");
97         return {};
98     }
99 
100     return pixelMap;
101 }
102 
PackImage2File(const std::shared_ptr<Media::PixelMap> & pixelMap,const std::string & outFilePath,const std::string & format)103 bool AnsImageUtil::PackImage2File(
104     const std::shared_ptr<Media::PixelMap> &pixelMap,
105     const std::string &outFilePath,
106     const std::string &format)
107 {
108     if (!pixelMap || outFilePath.empty() || format.empty()) {
109         ANS_LOGW("invalid parameters");
110         return false;
111     }
112 
113     Media::ImagePacker imagePacker;
114     Media::PackOption option;
115     option.format     = format;
116     option.quality    = IMAGE_QUALITY;
117     option.numberHint = 1;
118 
119     std::set<std::string> formats;
120     auto ret = imagePacker.GetSupportedFormats(formats);
121     if (ret) {
122         ANS_LOGE("image packer get supported format failed, ret : %{public}u", ret);
123         return false;
124     }
125 
126     imagePacker.StartPacking(outFilePath, option);
127     imagePacker.AddImage(*pixelMap);
128     int64_t packedSize {0};
129     imagePacker.FinalizePacking(packedSize);
130     ANS_LOGI("packed size : %{public}" PRId64, packedSize);
131     return true;
132 }
133 
CreatePixelMap(const std::string & inFilePath,const std::string & format)134 std::shared_ptr<Media::PixelMap> AnsImageUtil::CreatePixelMap(const std::string &inFilePath, const std::string &format)
135 {
136     if (inFilePath.empty() || format.empty()) {
137         ANS_LOGW("invalid parameters");
138         return {};
139     }
140 
141     uint32_t errorCode {0};
142     Media::SourceOptions opts;
143     opts.formatHint = format;
144     auto imageSource = Media::ImageSource::CreateImageSource(inFilePath, opts, errorCode);
145     if (errorCode || !imageSource) {
146         ANS_LOGE("create imageSource failed");
147         return {};
148     }
149 
150     std::set<std::string> formats;
151     auto ret = imageSource->GetSupportedFormats(formats);
152     if (ret) {
153         ANS_LOGE("image packer get supported format failed, ret : %{public}u", ret);
154         return {};
155     }
156 
157     Media::DecodeOptions decodeOpts;
158     auto pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
159     if (errorCode || !pixelMap) {
160         ANS_LOGE("create pixelMap failed");
161         return {};
162     }
163 
164     return pixelMap;
165 }
166 
BinToHex(const std::string & strBin)167 std::string AnsImageUtil::BinToHex(const std::string &strBin)
168 {
169     if (strBin.empty()) {
170         return {};
171     }
172 
173     std::string strHex;
174     strHex.resize(strBin.size() * TWO_TIMES);
175     for (size_t i = 0; i < strBin.size(); i++) {
176         uint8_t cTemp = strBin[i];
177         for (size_t j = 0; j < TWO_TIMES; j++) {
178             uint8_t cCur = (cTemp & 0x0f);
179             if (cCur < NUM_TEN) {
180                 cCur += '0';
181             } else {
182                 cCur += ('a' - NUM_TEN);
183             }
184             strHex[TWO_TIMES * i + 1 - j] = cCur;
185             cTemp >>= SHIFT_FOUR;
186         }
187     }
188 
189     return strHex;
190 }
191 
HexToBin(const std::string & strHex)192 std::string AnsImageUtil::HexToBin(const std::string &strHex)
193 {
194     if (strHex.size() % TWO_TIMES != 0) {
195         return {};
196     }
197 
198     std::string strBin;
199     strBin.resize(strHex.size() / TWO_TIMES);
200     for (size_t i = 0; i < strBin.size(); i++) {
201         uint8_t cTemp = 0;
202         for (size_t j = 0; j < TWO_TIMES; j++) {
203             char cCur = strHex[TWO_TIMES * i + j];
204             uint8_t value = static_cast<uint8_t>(cTemp << SHIFT_FOUR);
205             if (cCur >= '0' && cCur <= '9') {
206                 value += (cCur - '0');
207             } else if (cCur >= 'a' && cCur <= 'f') {
208                 value += (cCur - 'a' + NUM_TEN);
209             } else if (cCur >= 'A' && cCur <= 'F') {
210                 value += (cCur - 'A' + NUM_TEN);
211             } else {
212                 return {};
213             }
214             cTemp = static_cast<uint8_t>(value);
215         }
216         strBin[i] = cTemp;
217     }
218 
219     return strBin;
220 }
221 }  // namespace Notification
222 }  // namespace OHOS
223