1/*
2 * Copyright (c) 2021-2022 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 "pixel_map_ohos.h"
17
18#include "drawable_descriptor.h"
19#include "pixel_map_manager.h"
20
21#include "core/image/image_file_cache.h"
22
23namespace OHOS::Ace {
24
25PixelFormat PixelMapOhos::PixelFormatConverter(Media::PixelFormat pixelFormat)
26{
27    switch (pixelFormat) {
28        case Media::PixelFormat::RGB_565:
29            return PixelFormat::RGB_565;
30        case Media::PixelFormat::RGBA_8888:
31            return PixelFormat::RGBA_8888;
32        case Media::PixelFormat::RGBA_1010102:
33            return PixelFormat::RGBA_1010102;
34        case Media::PixelFormat::BGRA_8888:
35            return PixelFormat::BGRA_8888;
36        case Media::PixelFormat::ALPHA_8:
37            return PixelFormat::ALPHA_8;
38        case Media::PixelFormat::RGBA_F16:
39            return PixelFormat::RGBA_F16;
40        case Media::PixelFormat::UNKNOWN:
41            return PixelFormat::UNKNOWN;
42        case Media::PixelFormat::ARGB_8888:
43            return PixelFormat::ARGB_8888;
44        case Media::PixelFormat::RGB_888:
45            return PixelFormat::RGB_888;
46        case Media::PixelFormat::NV21:
47            return PixelFormat::NV21;
48        case Media::PixelFormat::NV12:
49            return PixelFormat::NV12;
50        case Media::PixelFormat::CMYK:
51            return PixelFormat::CMYK;
52        default:
53            return PixelFormat::UNKNOWN;
54    }
55}
56
57AlphaType PixelMapOhos::AlphaTypeConverter(Media::AlphaType alphaType)
58{
59    switch (alphaType) {
60        case Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
61            return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
62        case Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
63            return AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
64        case Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
65            return AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
66        case Media::AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
67            return AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
68        default:
69            return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
70    }
71}
72
73RefPtr<PixelMap> PixelMap::Create(std::unique_ptr<Media::PixelMap>&& pixmap)
74{
75    return AceType::MakeRefPtr<PixelMapOhos>(std::move(pixmap));
76}
77
78RefPtr<PixelMap> PixelMap::CreatePixelMap(void* rawPtr)
79{
80    auto* pixmapPtr = reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(rawPtr);
81    if (pixmapPtr == nullptr || *pixmapPtr == nullptr) {
82        TAG_LOGW(AceLogTag::ACE_IMAGE, "pixmap pointer is nullptr when CreatePixelMap.");
83        return nullptr;
84    }
85    return AceType::MakeRefPtr<PixelMapOhos>(*pixmapPtr);
86}
87
88RefPtr<PixelMap> PixelMap::CopyPixelMap(const RefPtr<PixelMap>& pixelMap)
89{
90    CHECK_NULL_RETURN(pixelMap, nullptr);
91    OHOS::Media::InitializationOptions opts;
92    auto mediaPixelMap = pixelMap->GetPixelMapSharedPtr();
93    std::unique_ptr<Media::PixelMap> uniquePixelMap = Media::PixelMap::Create(*mediaPixelMap, opts);
94    CHECK_NULL_RETURN(uniquePixelMap, nullptr);
95    Media::PixelMap* pixelMapRelease = uniquePixelMap.release();
96    CHECK_NULL_RETURN(pixelMapRelease, nullptr);
97    std::shared_ptr<Media::PixelMap> newPixelMap(pixelMapRelease);
98    CHECK_NULL_RETURN(newPixelMap, nullptr);
99    return AceType::MakeRefPtr<PixelMapOhos>(newPixelMap);
100}
101
102RefPtr<PixelMap> PixelMap::DecodeTlv(std::vector<uint8_t>& buff)
103{
104    Media::PixelMap* pixelMapRelease = OHOS::Media::PixelMap::DecodeTlv(buff);
105    CHECK_NULL_RETURN(pixelMapRelease, nullptr);
106    std::shared_ptr<Media::PixelMap> newPixelMap(pixelMapRelease);
107    CHECK_NULL_RETURN(newPixelMap, nullptr);
108    return AceType::MakeRefPtr<PixelMapOhos>(newPixelMap);
109}
110
111bool PixelMapOhos::EncodeTlv(std::vector<uint8_t>& buff)
112{
113    CHECK_NULL_RETURN(pixmap_, false);
114    return pixmap_->EncodeTlv(buff);
115}
116
117RefPtr<PixelMap> PixelMap::GetFromDrawable(void* ptr)
118{
119    CHECK_NULL_RETURN(ptr, nullptr);
120    auto* drawable = reinterpret_cast<Napi::DrawableDescriptor*>(ptr);
121    return AceType::MakeRefPtr<PixelMapOhos>(drawable->GetPixelMap());
122}
123
124bool PixelMap::GetPxielMapListFromAnimatedDrawable(void* ptr, std::vector<RefPtr<PixelMap>>& pixelMaps,
125    int32_t& duration, int32_t& iterations)
126{
127    CHECK_NULL_RETURN(ptr, false);
128    auto* drawable = reinterpret_cast<Napi::DrawableDescriptor*>(ptr);
129    auto drawableType = drawable->GetDrawableType();
130    if (drawableType != Napi::DrawableDescriptor::DrawableType::ANIMATED) {
131        return false;
132    }
133    auto* animatedDrawable = static_cast<Napi::AnimatedDrawableDescriptor*>(drawable);
134    std::vector<std::shared_ptr<Media::PixelMap>> pixelMapList = animatedDrawable->GetPixelMapList();
135    for (uint32_t i = 0; i < pixelMapList.size(); i++) {
136        pixelMaps.push_back(AceType::MakeRefPtr<PixelMapOhos>(std::move(pixelMapList[i])));
137    }
138    duration = animatedDrawable->GetDuration();
139    iterations = animatedDrawable->GetIterations();
140    return true;
141}
142
143RefPtr<PixelMap> PixelMap::CreatePixelMapFromDataAbility(void* ptr)
144{
145    auto* pixmap = reinterpret_cast<Media::PixelMap*>(ptr);
146    CHECK_NULL_RETURN(pixmap, nullptr);
147    return AceType::MakeRefPtr<PixelMapOhos>(std::shared_ptr<Media::PixelMap>(pixmap));
148}
149
150int32_t PixelMapOhos::GetWidth() const
151{
152    CHECK_NULL_RETURN(pixmap_, 0);
153    return pixmap_->GetWidth();
154}
155
156int32_t PixelMapOhos::GetHeight() const
157{
158    CHECK_NULL_RETURN(pixmap_, 0);
159    return pixmap_->GetHeight();
160}
161
162const uint8_t* PixelMapOhos::GetPixels() const
163{
164    CHECK_NULL_RETURN(pixmap_, nullptr);
165    return pixmap_->GetPixels();
166}
167
168PixelFormat PixelMapOhos::GetPixelFormat() const
169{
170    CHECK_NULL_RETURN(pixmap_, PixelFormat::UNKNOWN);
171    return PixelFormatConverter(pixmap_->GetPixelFormat());
172}
173
174AlphaType PixelMapOhos::GetAlphaType() const
175{
176    CHECK_NULL_RETURN(pixmap_, AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN);
177    return AlphaTypeConverter(pixmap_->GetAlphaType());
178}
179
180int32_t PixelMapOhos::GetRowStride() const
181{
182    CHECK_NULL_RETURN(pixmap_, 0);
183    return pixmap_->GetRowStride();
184}
185
186int32_t PixelMapOhos::GetRowBytes() const
187{
188    CHECK_NULL_RETURN(pixmap_, 0);
189    return pixmap_->GetRowBytes();
190}
191
192int32_t PixelMapOhos::GetByteCount() const
193{
194    CHECK_NULL_RETURN(pixmap_, 0);
195    return pixmap_->GetByteCount();
196}
197
198void* PixelMapOhos::GetPixelManager() const
199{
200    Media::InitializationOptions opts;
201    CHECK_NULL_RETURN(pixmap_, nullptr);
202    auto newPixelMap = Media::PixelMap::Create(*pixmap_, opts);
203    return reinterpret_cast<void*>(new Media::PixelMapManager(newPixelMap.release()));
204}
205
206void* PixelMapOhos::GetRawPixelMapPtr() const
207{
208    CHECK_NULL_RETURN(pixmap_, nullptr);
209    return pixmap_.get();
210}
211
212void PixelMapOhos::Scale(float xAxis, float yAxis)
213{
214    CHECK_NULL_VOID(pixmap_);
215    pixmap_->scale(xAxis, yAxis);
216}
217
218void PixelMapOhos::Scale(float xAxis, float yAxis, const AceAntiAliasingOption &option)
219{
220    CHECK_NULL_VOID(pixmap_);
221    switch (option) {
222        case AceAntiAliasingOption::NONE:
223            pixmap_->scale(xAxis, yAxis, Media::AntiAliasingOption::NONE);
224            break;
225        case AceAntiAliasingOption::LOW:
226            pixmap_->scale(xAxis, yAxis, Media::AntiAliasingOption::LOW);
227            break;
228        case AceAntiAliasingOption::MEDIUM:
229            pixmap_->scale(xAxis, yAxis, Media::AntiAliasingOption::MEDIUM);
230            break;
231        case AceAntiAliasingOption::HIGH:
232            pixmap_->scale(xAxis, yAxis, Media::AntiAliasingOption::HIGH);
233            break;
234        default:
235            pixmap_->scale(xAxis, yAxis, Media::AntiAliasingOption::NONE);
236            break;
237    }
238}
239
240std::string PixelMapOhos::GetId()
241{
242    // using pixmap addr
243    CHECK_NULL_RETURN(pixmap_, "nullptr");
244    std::stringstream strm;
245    strm << pixmap_.get();
246    return strm.str();
247}
248
249std::string PixelMapOhos::GetModifyId()
250{
251    return {};
252}
253
254std::shared_ptr<Media::PixelMap> PixelMapOhos::GetPixelMapSharedPtr()
255{
256    return pixmap_;
257}
258
259void* PixelMapOhos::GetWritablePixels() const
260{
261    CHECK_NULL_RETURN(pixmap_, nullptr);
262    return pixmap_->GetWritablePixels();
263}
264
265bool PixelMapOhos::GetPixelsVec(std::vector<uint8_t>& data) const
266{
267    CHECK_NULL_RETURN(pixmap_, false);
268    data.resize(pixmap_->GetByteCount());
269    uint8_t* dst = data.data();
270    uint32_t errCode = pixmap_->ReadPixels(pixmap_->GetByteCount(), dst);
271    if (errCode) {
272        TAG_LOGW(AceLogTag::ACE_IMAGE, "GetPixelsVec error, errCode=%{public}d", errCode);
273        return false;
274    }
275    return true;
276}
277
278RefPtr<PixelMap> PixelMap::ConvertSkImageToPixmap(
279    const uint32_t* colors, uint32_t colorLength, int32_t width, int32_t height)
280{
281    Media::InitializationOptions opts;
282    opts.size.width = width;
283    opts.size.height = height;
284    opts.editable = true;
285    std::unique_ptr<Media::PixelMap> pixmap = Media::PixelMap::Create(colors, colorLength, opts);
286    CHECK_NULL_RETURN(pixmap, nullptr);
287    std::shared_ptr<Media::PixelMap> sharedPixelmap(pixmap.release());
288    return AceType::MakeRefPtr<PixelMapOhos>(sharedPixelmap);
289}
290
291void PixelMapOhos::SavePixelMapToFile(const std::string& dst) const
292{
293    int32_t w = pixmap_->GetWidth();
294    int32_t h = pixmap_->GetHeight();
295    int32_t totalSize = static_cast<int32_t>(pixmap_->GetCapacity());
296    auto rowStride = pixmap_->GetRowStride();
297    uint64_t nowTime = static_cast<uint64_t>(
298        std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
299            .count());
300    std::string filename = std::to_string(nowTime) + "_w" + std::to_string(w) + "_h" + std::to_string(h) +
301                           "_rowStride" + std::to_string(rowStride) + "_byteCount" + std::to_string(totalSize) + dst +
302                           ".dat";
303    auto path = ImageFileCache::GetInstance().ConstructCacheFilePath(filename);
304    std::ofstream outFile(path, std::fstream::out);
305    if (!outFile.is_open()) {
306        TAG_LOGW(AceLogTag::ACE_IMAGE, "write error, path=%{public}s", path.c_str());
307    }
308    outFile.write(reinterpret_cast<const char*>(pixmap_->GetPixels()), totalSize);
309    TAG_LOGI(AceLogTag::ACE_IMAGE, "write success, path=%{public}s", path.c_str());
310}
311
312RefPtr<PixelMap> PixelMapOhos::GetCropPixelMap(const Rect& srcRect)
313{
314    Media::InitializationOptions options;
315    options.size.width = static_cast<int32_t>(srcRect.Width());
316    options.size.height = static_cast<int32_t>(srcRect.Height());
317    options.pixelFormat = Media::PixelFormat::RGBA_8888;
318    options.alphaType = Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
319    options.scaleMode = Media::ScaleMode::FIT_TARGET_SIZE;
320
321    Media::Rect rect {srcRect.Left(), srcRect.Top(), srcRect.Width(), srcRect.Height()};
322    auto resPixelmap = OHOS::Media::PixelMap::Create(*pixmap_, rect, options);
323    return AceType::MakeRefPtr<PixelMapOhos>(std::move(resPixelmap));
324}
325
326} // namespace OHOS::Ace
327