• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #include "drawable_descriptor.h"
17 
18 #include <cstddef>
19 #include <memory>
20 #include <string>
21 
22 #include "base/utils/string_utils.h"
23 
24 #ifdef NEW_SKIA
25 #include "include/core/SkSamplingOptions.h"
26 #endif
27 #include "cJSON.h"
28 #ifndef PREVIEW
29 #include "image_source.h"
30 #endif
31 #include "include/core/SkImage.h"
32 #include "include/core/SkRect.h"
33 
34 // 区分此函数是在Windows环境调用还是Linux/mac环境调用
35 #ifdef PREVIEW
36 #ifdef WINDOWS_PLATFORM
37 #include <windows.h>
38 #include <direct.h>
39 #elif defined(MAC_PLATFORM)
40 #include <mach-o/dyld.h>
41 #else
42 #include <unistd.h>
43 #endif
44 #endif
45 
46 namespace OHOS::Ace::Napi {
47 namespace {
48 #ifndef PREVIEW
49 const char DRAWABLEDESCRIPTOR_JSON_KEY_BACKGROUND[] = "background";
50 const char DRAWABLEDESCRIPTOR_JSON_KEY_FOREGROUND[] = "foreground";
51 #endif
52 constexpr float SIDE = 192.0;
53 
54 // define for get resource path in preview scenes
55 const static char PREVIEW_LOAD_RESOURCE_ID[] = "ohos_drawable_descriptor_path";
56 #ifdef PREVIEW
57 #ifdef WINDOWS_PLATFORM
58 constexpr static char PREVIEW_LOAD_RESOURCE_PATH[] = "\\resources\\entry\\resources.index";
59 #else
60 constexpr static char PREVIEW_LOAD_RESOURCE_PATH[] = "/resources/entry/resources.index";
61 #endif
62 
63 #ifdef LINUX_PLATFORM
64 const static size_t MAX_PATH_LEN = 255;
65 #endif
66 #endif
67 } // namespace
68 
GetPixelMapFromBuffer()69 bool DrawableDescriptor::GetPixelMapFromBuffer()
70 {
71     Media::SourceOptions opts;
72     uint32_t errorCode = 0;
73     std::unique_ptr<Media::ImageSource> imageSource =
74         Media::ImageSource::CreateImageSource(mediaData_.get(), len_, opts, errorCode);
75     if (errorCode != 0) {
76         HILOG_ERROR("CreateImageSource from buffer failed");
77         return false;
78     }
79     mediaData_.reset();
80     Media::DecodeOptions decodeOpts;
81     decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
82     if (imageSource) {
83         auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
84         pixelMap_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
85     }
86     if (errorCode != 0 || !pixelMap_) {
87         HILOG_ERROR("Get PixelMap from buffer failed");
88         return false;
89     }
90     return true;
91 }
92 
GetPixelMap()93 std::shared_ptr<Media::PixelMap> DrawableDescriptor::GetPixelMap()
94 {
95     if (pixelMap_.has_value()) {
96         return pixelMap_.value();
97     }
98     if (GetPixelMapFromBuffer()) {
99         return pixelMap_.value();
100     }
101     HILOG_ERROR("Failed to GetPixelMap!");
102     return nullptr;
103 }
104 
CreateImageSource(const char * item,uint32_t & errorCode)105 std::unique_ptr<Media::ImageSource> LayeredDrawableDescriptor::CreateImageSource(const char* item, uint32_t& errorCode)
106 {
107     std::string itemStr = item;
108     std::string idStr = itemStr.substr(itemStr.find(':') + 1);
109     if (!StringUtils::IsNumber(idStr)) {
110         return nullptr;
111     }
112 
113     size_t len = 0;
114     std::unique_ptr<uint8_t[]> data;
115     auto state = resourceMgr_->GetMediaDataById(static_cast<uint32_t>(std::stoul(idStr)), len, data);
116     if (state != Global::Resource::SUCCESS) {
117         HILOG_ERROR("GetMediaDataById failed");
118         return nullptr;
119     }
120 
121     Media::SourceOptions opts;
122     return Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
123 }
124 
GetPixelMapFromJsonBuf(bool isBackground)125 bool LayeredDrawableDescriptor::GetPixelMapFromJsonBuf(bool isBackground)
126 {
127 #ifndef PREVIEW
128     cJSON* roots = cJSON_ParseWithLength(reinterpret_cast<const char*>(jsonBuf_.get()), len_);
129 
130     if (roots == nullptr) {
131         return false;
132     }
133 
134     uint32_t errorCode = 0;
135     cJSON* item = nullptr;
136     if (isBackground) {
137         item = cJSON_GetObjectItem(roots->child, DRAWABLEDESCRIPTOR_JSON_KEY_BACKGROUND);
138     } else {
139         item = cJSON_GetObjectItem(roots->child, DRAWABLEDESCRIPTOR_JSON_KEY_FOREGROUND);
140     }
141     if (item == nullptr) {
142         cJSON_Delete(roots);
143         HILOG_ERROR("GetObjectItem from json buffer failed");
144         return false;
145     }
146 
147     if (cJSON_IsString(item)) {
148         std::unique_ptr<Media::ImageSource> imageSource =
149             LayeredDrawableDescriptor::CreateImageSource(item->valuestring, errorCode);
150         if (errorCode != 0) {
151             cJSON_Delete(roots);
152             HILOG_ERROR("CreateImageSource from json buffer failed");
153             return false;
154         }
155         Media::DecodeOptions decodeOpts;
156         decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
157         auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
158         if (errorCode != 0) {
159             cJSON_Delete(roots);
160             HILOG_ERROR("Get PixelMap from json buffer failed");
161             return false;
162         }
163 
164         if (isBackground) {
165             background_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
166         } else {
167             foreground_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
168         }
169     } else {
170         cJSON_Delete(roots);
171         HILOG_ERROR("Get background from json buffer failed");
172         return false;
173     }
174     cJSON_Delete(roots);
175     return true;
176 #else
177     return false;
178 #endif
179 }
180 
GetDefaultMask()181 bool LayeredDrawableDescriptor::GetDefaultMask()
182 {
183     const std::string name = "ohos_icon_mask";
184     size_t len = 0;
185     std::unique_ptr<uint8_t[]> data;
186     resourceMgr_->GetMediaDataByName(name.c_str(), len, data);
187     Media::SourceOptions opts;
188     uint32_t errorCode = 0;
189     std::unique_ptr<Media::ImageSource> imageSource =
190         Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
191     Media::DecodeOptions decodeOpts;
192     decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
193     auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
194     mask_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
195     if (errorCode != 0 || !mask_) {
196         HILOG_ERROR("Get mask failed");
197         return false;
198     }
199     return true;
200 }
201 
GetMaskByName(const std::string & name)202 bool LayeredDrawableDescriptor::GetMaskByName(const std::string& name)
203 {
204     size_t len = 0;
205     std::unique_ptr<uint8_t[]> data;
206     resourceMgr_->GetMediaDataByName(name.c_str(), len, data);
207     Media::SourceOptions opts;
208     uint32_t errorCode = 0;
209     std::unique_ptr<Media::ImageSource> imageSource =
210         Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
211     Media::DecodeOptions decodeOpts;
212     decodeOpts.desiredPixelFormat = Media::PixelFormat::BGRA_8888;
213     auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
214     mask_ = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
215     if (errorCode != 0 || !mask_) {
216         HILOG_ERROR("Get mask failed");
217         return false;
218     }
219     return true;
220 }
221 
GetForeground()222 std::unique_ptr<DrawableDescriptor> LayeredDrawableDescriptor::GetForeground()
223 {
224     if (foreground_.has_value()) {
225         return std::make_unique<DrawableDescriptor>(foreground_.value());
226     }
227 
228     if (GetPixelMapFromJsonBuf(false)) {
229         return std::make_unique<DrawableDescriptor>(foreground_.value());
230     }
231 
232     HILOG_ERROR("GetForeground failed");
233     return nullptr;
234 }
235 
GetBackground()236 std::unique_ptr<DrawableDescriptor> LayeredDrawableDescriptor::GetBackground()
237 {
238     if (background_.has_value()) {
239         return std::make_unique<DrawableDescriptor>(background_.value());
240     }
241 
242     if (GetPixelMapFromJsonBuf(true)) {
243         return std::make_unique<DrawableDescriptor>(background_.value());
244     }
245     HILOG_ERROR("GetForeground failed");
246     return nullptr;
247 }
248 
GetMask()249 std::unique_ptr<DrawableDescriptor> LayeredDrawableDescriptor::GetMask()
250 {
251     if (mask_.has_value()) {
252         return std::make_unique<DrawableDescriptor>(mask_.value());
253     }
254 
255     if (GetDefaultMask()) {
256         return std::make_unique<DrawableDescriptor>(mask_.value());
257     }
258 
259     HILOG_ERROR("GetMask failed");
260     return nullptr;
261 }
262 
DrawOntoCanvas(const std::shared_ptr<SkBitmap> & bitMap,float width,float height,SkCanvas & canvas,const SkPaint & paint)263 void LayeredDrawableDescriptor::DrawOntoCanvas(
264     const std::shared_ptr<SkBitmap>& bitMap, float width, float height, SkCanvas& canvas, const SkPaint& paint)
265 {
266     auto x = static_cast<float>((bitMap->width() - static_cast<float>(width)) / 2);
267     auto y = static_cast<float>((bitMap->height() - static_cast<float>(height)) / 2);
268     auto rect1 = SkRect::MakeXYWH(x, y, static_cast<float>(width), static_cast<float>(width));
269     auto rect2 = SkRect::MakeWH(static_cast<float>(width), static_cast<float>(width));
270 #ifndef NEW_SKIA
271     canvas.drawImageRect(SkImage::MakeFromBitmap(*bitMap), rect1, rect2, &paint);
272 #else
273     canvas.drawImageRect(
274         SkImage::MakeFromBitmap(*bitMap), rect1, rect2, SkSamplingOptions(), &paint, SkCanvas::kFast_SrcRectConstraint);
275 #endif
276 }
277 
CreatePixelMap()278 bool LayeredDrawableDescriptor::CreatePixelMap()
279 {
280     std::shared_ptr<SkBitmap> foreground;
281     if (foreground_.has_value()) {
282         foreground = ImageConverter::PixelMapToBitmap(foreground_.value());
283     } else if (GetPixelMapFromJsonBuf(false)) {
284         foreground = ImageConverter::PixelMapToBitmap(foreground_.value());
285     } else {
286         HILOG_INFO("Get pixelMap of foreground failed.");
287         return false;
288     }
289 
290     std::shared_ptr<SkBitmap> background;
291     if (background_.has_value()) {
292         background = ImageConverter::PixelMapToBitmap(background_.value());
293     } else if (GetPixelMapFromJsonBuf(true)) {
294         background = ImageConverter::PixelMapToBitmap(background_.value());
295     } else {
296         HILOG_ERROR("Get pixelMap of background failed.");
297         return false;
298     }
299 
300     std::shared_ptr<SkBitmap> mask;
301     if (mask_.has_value()) {
302         mask = ImageConverter::PixelMapToBitmap(mask_.value());
303     } else if (GetDefaultMask()) {
304         mask = ImageConverter::PixelMapToBitmap(mask_.value());
305     } else {
306         HILOG_ERROR("Get pixelMap of mask failed.");
307         return false;
308     }
309 
310     SkPaint paint;
311     paint.setAntiAlias(true);
312     auto colorType = ImageConverter::PixelFormatToSkColorType(background_.value()->GetPixelFormat());
313     auto alphaType = ImageConverter::AlphaTypeToSkAlphaType(background_.value()->GetAlphaType());
314     auto imageInfo = SkImageInfo::Make(SIDE, SIDE, colorType, alphaType);
315     SkBitmap tempCache;
316     tempCache.allocPixels(imageInfo);
317     SkCanvas bitmapCanvas(tempCache);
318 
319     paint.setBlendMode(SkBlendMode::kSrc);
320     DrawOntoCanvas(background, SIDE, SIDE, bitmapCanvas, paint);
321     paint.setBlendMode(SkBlendMode::kDstATop);
322     DrawOntoCanvas(mask, SIDE, SIDE, bitmapCanvas, paint);
323     paint.setBlendMode(SkBlendMode::kSrcATop);
324     DrawOntoCanvas(foreground, SIDE, SIDE, bitmapCanvas, paint);
325     bitmapCanvas.readPixels(tempCache, 0, 0);
326 
327     // convert bitmap back to pixelMap
328     Media::InitializationOptions opts;
329     opts.alphaType = background_.value()->GetAlphaType();
330     opts.pixelFormat = Media::PixelFormat::BGRA_8888;
331     layeredPixelMap_ = ImageConverter::BitmapToPixelMap(std::make_shared<SkBitmap>(tempCache), opts);
332     return true;
333 }
334 
GetPixelMap()335 std::shared_ptr<Media::PixelMap> LayeredDrawableDescriptor::GetPixelMap()
336 {
337     if (layeredPixelMap_.has_value()) {
338         return layeredPixelMap_.value();
339     }
340 
341     if (CreatePixelMap()) {
342         return layeredPixelMap_.value();
343     }
344 
345     HILOG_ERROR("Failed to GetPixelMap!");
346     return nullptr;
347 }
348 
GetStaticMaskClipPath()349 std::string LayeredDrawableDescriptor::GetStaticMaskClipPath()
350 {
351     std::string data;
352     std::shared_ptr<Global::Resource::ResourceManager> resMgr(Global::Resource::CreateResourceManager());
353 
354 #ifdef PREVIEW
355     std::string pathTmp = "";
356 #ifdef WINDOWS_PLATFORM
357     char pathBuf [MAX_PATH];
358     _getcwd(pathBuf, MAX_PATH);
359     pathTmp = pathBuf;
360 #elif defined(MAC_PLATFORM)
361     uint32_t size = 0;
362     _NSGetExecutablePath(nullptr, &size);
363 
364     char pathBuf [size + 1];
365     if (_NSGetExecutablePath(pathBuf, &size) != 0) {
366         pathBuf[0] = '\0';
367         HILOG_ERROR("Failed, buffer too small!");
368     }
369     pathBuf[size] = '\0';
370 
371     std::string previewFullPath = pathBuf;
372     size_t lastPathIdx = previewFullPath.find_last_of("\\/");
373     pathTmp = (lastPathIdx != std::string::npos) ? previewFullPath.substr(0, lastPathIdx) : "";
374 #else
375     char pathBuf [MAX_PATH_LEN];
376     readlink("/proc/self/exe", pathBuf, MAX_PATH_LEN);
377     pathTmp = pathBuf;
378 #endif
379     size_t lastPathSepLoc = pathTmp.find_last_of("\\/");
380     std::string path = (lastPathSepLoc != std::string::npos) ? pathTmp.substr(0, lastPathSepLoc) : "";
381     path += PREVIEW_LOAD_RESOURCE_PATH;
382     resMgr->AddResource(path.c_str());
383 #endif
384     resMgr->GetStringByName(PREVIEW_LOAD_RESOURCE_ID, data);
385     return data;
386 }
387 } // namespace OHOS::Ace::Napi
388