1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "imgdecode/image_load.h"
17a3e0fd82Sopenharmony_ci#include "gfx_utils/file.h"
18a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h"
19a3e0fd82Sopenharmony_ci#include "gfx_utils/mem_api.h"
20a3e0fd82Sopenharmony_ci
21a3e0fd82Sopenharmony_cinamespace {
22a3e0fd82Sopenharmony_ciconst uint8_t BITMAP_ZIP_LEN = 3;
23a3e0fd82Sopenharmony_ciconst uint8_t BITMAP_MID_BIT = 1;
24a3e0fd82Sopenharmony_ciconst uint8_t BITMAP_LOW_BIT = 2;
25a3e0fd82Sopenharmony_ciconst uint32_t BITMAP_ZIP24_FLAG = 0x456789;
26a3e0fd82Sopenharmony_ciconst uint32_t BITMAP_ZIP_FLAG = 0x23456789;
27a3e0fd82Sopenharmony_ciconst uint32_t BITMAP_ALPHA_MASK = 0xFF000000;
28a3e0fd82Sopenharmony_ciconst uint32_t BITMAP_MAXCON_PIXNUM = 0xCB100;
29a3e0fd82Sopenharmony_ciconst uint32_t MOVE_HIGH = 16;
30a3e0fd82Sopenharmony_ciconst uint32_t MOVE_LOW = 8;
31a3e0fd82Sopenharmony_ci} // namespace
32a3e0fd82Sopenharmony_ci
33a3e0fd82Sopenharmony_cinamespace OHOS {
34a3e0fd82Sopenharmony_cibool ImageLoad::CreateImage(ImageInfo& imageInfo)
35a3e0fd82Sopenharmony_ci{
36a3e0fd82Sopenharmony_ci    uint32_t bytePerPixel = 4;
37a3e0fd82Sopenharmony_ci    ImageHeader& imageHeader = imageInfo.header;
38a3e0fd82Sopenharmony_ci
39a3e0fd82Sopenharmony_ci    switch (imageHeader.colorMode) {
40a3e0fd82Sopenharmony_ci        case ARGB8888:
41a3e0fd82Sopenharmony_ci            bytePerPixel = 4; // 4 bytes per pixel
42a3e0fd82Sopenharmony_ci            break;
43a3e0fd82Sopenharmony_ci        case RGB888:
44a3e0fd82Sopenharmony_ci            bytePerPixel = 3; // 3 bytes per pixel
45a3e0fd82Sopenharmony_ci            break;
46a3e0fd82Sopenharmony_ci        case RGB565:
47a3e0fd82Sopenharmony_ci            bytePerPixel = 2; // 2 bytes per pixel
48a3e0fd82Sopenharmony_ci            break;
49a3e0fd82Sopenharmony_ci        default:
50a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("CreateImage invalid colorMode.");
51a3e0fd82Sopenharmony_ci            return false;
52a3e0fd82Sopenharmony_ci    }
53a3e0fd82Sopenharmony_ci
54a3e0fd82Sopenharmony_ci    imageInfo.dataSize = imageHeader.width * imageHeader.height * bytePerPixel;
55a3e0fd82Sopenharmony_ci    imageInfo.data = static_cast<uint8_t*>(ImageCacheMalloc(imageInfo));
56a3e0fd82Sopenharmony_ci    if (imageInfo.data == nullptr) {
57a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("ImageCacheMalloc error.");
58a3e0fd82Sopenharmony_ci        return false;
59a3e0fd82Sopenharmony_ci    }
60a3e0fd82Sopenharmony_ci
61a3e0fd82Sopenharmony_ci    return true;
62a3e0fd82Sopenharmony_ci}
63a3e0fd82Sopenharmony_ci
64a3e0fd82Sopenharmony_cibool ImageLoad::UncompressImageInZip(ImageInfo& imageInfo, uint8_t* buffer, uint32_t size)
65a3e0fd82Sopenharmony_ci{
66a3e0fd82Sopenharmony_ci    if (!CreateImage(imageInfo)) {
67a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("Create image error.");
68a3e0fd82Sopenharmony_ci        return false;
69a3e0fd82Sopenharmony_ci    }
70a3e0fd82Sopenharmony_ci
71a3e0fd82Sopenharmony_ci    if (imageInfo.header.colorMode == RGB888) {
72a3e0fd82Sopenharmony_ci        return Unzip24Image(buffer, size, imageInfo);
73a3e0fd82Sopenharmony_ci    } else {
74a3e0fd82Sopenharmony_ci        return UnzipImage(buffer, size, imageInfo);
75a3e0fd82Sopenharmony_ci    }
76a3e0fd82Sopenharmony_ci}
77a3e0fd82Sopenharmony_ci
78a3e0fd82Sopenharmony_cibool ImageLoad::UnzipImage(uint8_t* imageBuffer, uint32_t size, ImageInfo& imageInfo)
79a3e0fd82Sopenharmony_ci{
80a3e0fd82Sopenharmony_ci    if ((imageBuffer == nullptr) || (size == 0)) {
81a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("imageHeader is null.");
82a3e0fd82Sopenharmony_ci        return false;
83a3e0fd82Sopenharmony_ci    }
84a3e0fd82Sopenharmony_ci
85a3e0fd82Sopenharmony_ci    uint32_t* source = reinterpret_cast<uint32_t*>(imageBuffer);
86a3e0fd82Sopenharmony_ci    uint32_t* sourceEnd = reinterpret_cast<uint32_t*>(imageBuffer + size);
87a3e0fd82Sopenharmony_ci    uint32_t* dest = nullptr;
88a3e0fd82Sopenharmony_ci    uint32_t* destEnd = nullptr;
89a3e0fd82Sopenharmony_ci
90a3e0fd82Sopenharmony_ci    dest = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data));
91a3e0fd82Sopenharmony_ci    destEnd = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data) + imageInfo.dataSize);
92a3e0fd82Sopenharmony_ci
93a3e0fd82Sopenharmony_ci    while ((source < sourceEnd) && (dest < destEnd)) {
94a3e0fd82Sopenharmony_ci        if (*source != BITMAP_ZIP_FLAG) {
95a3e0fd82Sopenharmony_ci            *dest++ = *source++;
96a3e0fd82Sopenharmony_ci        } else {
97a3e0fd82Sopenharmony_ci            source++;
98a3e0fd82Sopenharmony_ci            uint32_t value = *source++;
99a3e0fd82Sopenharmony_ci            uint32_t count = *source++;
100a3e0fd82Sopenharmony_ci            if (destEnd < count + dest) {
101a3e0fd82Sopenharmony_ci                break;
102a3e0fd82Sopenharmony_ci            }
103a3e0fd82Sopenharmony_ci
104a3e0fd82Sopenharmony_ci            while (count--) {
105a3e0fd82Sopenharmony_ci                *dest++ = value;
106a3e0fd82Sopenharmony_ci            }
107a3e0fd82Sopenharmony_ci        }
108a3e0fd82Sopenharmony_ci    }
109a3e0fd82Sopenharmony_ci
110a3e0fd82Sopenharmony_ci    if (dest == destEnd) {
111a3e0fd82Sopenharmony_ci        return true;
112a3e0fd82Sopenharmony_ci    }
113a3e0fd82Sopenharmony_ci    ImageCacheFree(imageInfo);
114a3e0fd82Sopenharmony_ci    imageInfo.data = nullptr;
115a3e0fd82Sopenharmony_ci    return false;
116a3e0fd82Sopenharmony_ci}
117a3e0fd82Sopenharmony_ci
118a3e0fd82Sopenharmony_cibool ImageLoad::Unzip24Image(uint8_t* imageBuffer, uint32_t size, ImageInfo& imageInfo)
119a3e0fd82Sopenharmony_ci{
120a3e0fd82Sopenharmony_ci    if ((imageBuffer == nullptr) || (size == 0)) {
121a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("imageHeader is null.");
122a3e0fd82Sopenharmony_ci        return false;
123a3e0fd82Sopenharmony_ci    }
124a3e0fd82Sopenharmony_ci
125a3e0fd82Sopenharmony_ci    uint8_t* source = reinterpret_cast<uint8_t*>(imageBuffer);
126a3e0fd82Sopenharmony_ci    uint8_t* sourceEnd = reinterpret_cast<uint8_t*>(imageBuffer + size);
127a3e0fd82Sopenharmony_ci    uint32_t* dest = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data));
128a3e0fd82Sopenharmony_ci    uint32_t* destEnd = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data) + imageInfo.dataSize);
129a3e0fd82Sopenharmony_ci    while ((source < sourceEnd) && (dest < destEnd)) {
130a3e0fd82Sopenharmony_ci        // Little endian
131a3e0fd82Sopenharmony_ci        uint32_t value = ((*source)) + (*(source + BITMAP_MID_BIT) << MOVE_LOW)
132a3e0fd82Sopenharmony_ci                         + (*(source + BITMAP_LOW_BIT) << MOVE_HIGH);
133a3e0fd82Sopenharmony_ci        source = source + BITMAP_ZIP_LEN;
134a3e0fd82Sopenharmony_ci        if (value != BITMAP_ZIP24_FLAG) {
135a3e0fd82Sopenharmony_ci            *dest = value | BITMAP_ALPHA_MASK;
136a3e0fd82Sopenharmony_ci            dest++;
137a3e0fd82Sopenharmony_ci        } else {
138a3e0fd82Sopenharmony_ci            value = ((*source)) + (*(source + BITMAP_MID_BIT) << MOVE_LOW) + (*(source + BITMAP_LOW_BIT) << MOVE_HIGH);
139a3e0fd82Sopenharmony_ci            source = source + BITMAP_ZIP_LEN;
140a3e0fd82Sopenharmony_ci
141a3e0fd82Sopenharmony_ci            uint32_t count = ((*source)) + (*(source + BITMAP_MID_BIT) << MOVE_LOW)
142a3e0fd82Sopenharmony_ci                             + (*(source + BITMAP_LOW_BIT) << MOVE_HIGH);
143a3e0fd82Sopenharmony_ci            source = source + BITMAP_ZIP_LEN;
144a3e0fd82Sopenharmony_ci
145a3e0fd82Sopenharmony_ci            if (count > BITMAP_MAXCON_PIXNUM) {
146a3e0fd82Sopenharmony_ci                *dest = BITMAP_ZIP24_FLAG | BITMAP_ALPHA_MASK;
147a3e0fd82Sopenharmony_ci                dest++;
148a3e0fd82Sopenharmony_ci                *dest = value | BITMAP_ALPHA_MASK;
149a3e0fd82Sopenharmony_ci                dest++;
150a3e0fd82Sopenharmony_ci                *dest = count | BITMAP_ALPHA_MASK;
151a3e0fd82Sopenharmony_ci                dest++;
152a3e0fd82Sopenharmony_ci                continue;
153a3e0fd82Sopenharmony_ci            }
154a3e0fd82Sopenharmony_ci            if (static_cast<uintptr_t>(destEnd - dest) < static_cast<uintptr_t>(count)) {
155a3e0fd82Sopenharmony_ci                break;
156a3e0fd82Sopenharmony_ci            }
157a3e0fd82Sopenharmony_ci            while (count--) {
158a3e0fd82Sopenharmony_ci                *dest = value | BITMAP_ALPHA_MASK;
159a3e0fd82Sopenharmony_ci                dest++;
160a3e0fd82Sopenharmony_ci            }
161a3e0fd82Sopenharmony_ci        }
162a3e0fd82Sopenharmony_ci    }
163a3e0fd82Sopenharmony_ci
164a3e0fd82Sopenharmony_ci    if (dest == destEnd) {
165a3e0fd82Sopenharmony_ci        return true;
166a3e0fd82Sopenharmony_ci    }
167a3e0fd82Sopenharmony_ci    ImageCacheFree(imageInfo);
168a3e0fd82Sopenharmony_ci    imageInfo.data = nullptr;
169a3e0fd82Sopenharmony_ci    return false;
170a3e0fd82Sopenharmony_ci}
171a3e0fd82Sopenharmony_ci
172a3e0fd82Sopenharmony_cibool ImageLoad::UnZip2ImageInfo(ImageInfo& imageInfo, uint8_t* buffer, uint32_t size)
173a3e0fd82Sopenharmony_ci{
174a3e0fd82Sopenharmony_ci    switch (imageInfo.header.compressMode) {
175a3e0fd82Sopenharmony_ci        case COMPRESS_MODE__ZIP_ALG:
176a3e0fd82Sopenharmony_ci            return UncompressImageInZip(imageInfo, buffer, size);
177a3e0fd82Sopenharmony_ci        default:
178a3e0fd82Sopenharmony_ci            return false;
179a3e0fd82Sopenharmony_ci    }
180a3e0fd82Sopenharmony_ci}
181a3e0fd82Sopenharmony_ci
182a3e0fd82Sopenharmony_cibool ImageLoad::GetImageInfo(int32_t fd, uint32_t size, ImageInfo& imageInfo)
183a3e0fd82Sopenharmony_ci{
184a3e0fd82Sopenharmony_ci    if (size == 0) {
185a3e0fd82Sopenharmony_ci        return false;
186a3e0fd82Sopenharmony_ci    }
187a3e0fd82Sopenharmony_ci
188a3e0fd82Sopenharmony_ci    uint8_t* buffer = reinterpret_cast<uint8_t*>(UIMalloc(size));
189a3e0fd82Sopenharmony_ci    if (buffer == nullptr) {
190a3e0fd82Sopenharmony_ci        return false;
191a3e0fd82Sopenharmony_ci    }
192a3e0fd82Sopenharmony_ci
193a3e0fd82Sopenharmony_ci    if (read(fd, buffer, size) != static_cast<int32_t>(size)) {
194a3e0fd82Sopenharmony_ci        UIFree(buffer);
195a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("SeekImageFile error.");
196a3e0fd82Sopenharmony_ci        return false;
197a3e0fd82Sopenharmony_ci    }
198a3e0fd82Sopenharmony_ci    bool ret = UnZip2ImageInfo(imageInfo, buffer, size);
199a3e0fd82Sopenharmony_ci    UIFree(buffer);
200a3e0fd82Sopenharmony_ci    return ret;
201a3e0fd82Sopenharmony_ci}
202a3e0fd82Sopenharmony_ci} // namespace OHOS
203