1/*
2 * Copyright (c) 2021 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 "loadbmp_test.h"
17#include <stdio.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
21#include <limits.h>
22#include <sys/types.h>
23#include <unistd.h>
24#include "securec.h"
25#include "hdf_log.h"
26#include "display_type.h"
27
28#define EOK 0
29
30OsdCompInfo g_osdCompInfo[OSD_COLOR_FMT_BUTT] = {
31    {0, 4, 4, 4},   /* RGB444 */
32    {4, 4, 4, 4},   /* ARGB4444 */
33    {0, 5, 5, 5},   /* RGB555 */
34    {0, 5, 6, 5},   /* RGB565 */
35    {1, 5, 5, 5},   /* ARGB1555 */
36    {0, 0, 0, 0},   /* RESERVED */
37    {0, 8, 8, 8},   /* RGB888 */
38    {8, 8, 8, 8}    /* ARGB8888 */
39};
40
41static uint16_t OsdMakeColorU16(uint8_t r, uint8_t g, uint8_t b, OsdCompInfo compinfo)
42{
43    uint8_t r1;
44    uint8_t g1;
45    uint8_t b1;
46    uint16_t pixel = 0;
47    uint32_t tmp = 15; // 16bit color
48
49    r1 = g1 = b1 = 0;
50    r1 = r >> (EIGHT_BITS_PER_PIXEL - compinfo.rLen);
51    g1 = g >> (EIGHT_BITS_PER_PIXEL - compinfo.gLen);
52    b1 = b >> (EIGHT_BITS_PER_PIXEL - compinfo.bLen);
53    while (compinfo.aLen != 0) {
54        pixel |= (1 << tmp);
55        tmp--;
56        compinfo.aLen--;
57    }
58
59    pixel |= (r1 | (g1 << compinfo.bLen) | (b1 << (compinfo.bLen + compinfo.gLen)));
60    return pixel;
61}
62
63int32_t GetBmpInfo(const int8_t *fileName, OsdBitMapFileHeader *bmpFileHeader, OsdBitMapInfo *bmpInfo)
64{
65    FILE *file = NULL;
66    uint16_t bfType = 0;
67    char realPath[PATH_MAX] = {0};
68
69    if (realpath((char*)fileName, realPath) == NULL) {
70        printf("%s: file %s does not exist\n", __func__, fileName);
71        return DISPLAY_FAILURE;
72    }
73    if ((file = fopen((const char*)realPath, "rb")) == NULL) {
74        HDF_LOGE("%s: Open file failure: %s", __func__, fileName);
75        return DISPLAY_FAILURE;
76    }
77
78    (void)fread(&bfType, 1, sizeof(bfType), file);
79    if (bfType != BITMAP_FILE) {
80        HDF_LOGE("%s: not bitmap file", __func__);
81        fclose(file);
82        return DISPLAY_FAILURE;
83    }
84
85    (void)fread(bmpFileHeader, 1, sizeof(OsdBitMapFileHeader), file);
86    (void)fread(bmpInfo, 1, sizeof(OsdBitMapInfo), file);
87    fclose(file);
88
89    return DISPLAY_SUCCESS;
90}
91
92static int32_t CheckBmpInfo(const OsdBitMapInfo *bmpInfo)
93{
94    uint16_t bpp;
95
96    bpp = bmpInfo->header.bitCnt / EIGHT_BITS_PER_PIXEL;
97    if (bpp < INVALID_BITS) {
98        /* only support 1555.8888  888 bitmap */
99        HDF_LOGE("%s: bitmap format not supported", __func__);
100        return DISPLAY_FAILURE;
101    }
102
103    if (bmpInfo->header.compress != 0) {
104        HDF_LOGE("%s: not support compressed bitmap file", __func__);
105        return DISPLAY_FAILURE;
106    }
107    if (bmpInfo->header.height == 0) {
108        HDF_LOGE("%s: bmpInfo.header.height is 0", __func__);
109        return DISPLAY_FAILURE;
110    }
111    return DISPLAY_SUCCESS;
112}
113
114static FILE * OpenPicFile(const int8_t *fileName, OsdBitMapFileHeader *fileHeader, OsdBitMapInfo *info)
115{
116    char realPath[PATH_MAX] = {0};
117    if (GetBmpInfo(fileName, fileHeader, info) < 0) {
118        return NULL;
119    }
120    if (CheckBmpInfo(info) != DISPLAY_SUCCESS) {
121        /* only support 1555.8888  888 bitmap */
122        HDF_LOGE("%s: bitmap format not supported", __func__);
123        return NULL;
124    }
125    if (realpath((char*)fileName, realPath) == NULL) {
126        printf("%s: file %s does not exist\n", __func__, fileName);
127        return NULL;
128    }
129
130    return fopen((const char*)realPath, "rb");
131}
132
133static int32_t LoadPicToBuffer(const int8_t *fileName, OsdLogo *videoLogo, OsdColorFmt enFmt,
134                               uint8_t **outBuf, uint32_t *stride)
135{
136    FILE *file = NULL;
137    OsdBitMapFileHeader bmpFileHeader;
138    OsdBitMapInfo       bmpInfo;
139    uint64_t byteNum;
140
141    file = OpenPicFile(fileName, &bmpFileHeader, &bmpInfo);
142    if (file == NULL) {
143        HDF_LOGE("%s: Open file failure: %s", __func__, fileName);
144        return DISPLAY_FAILURE;
145    }
146    videoLogo->bpp = bmpInfo.header.bitCnt / EIGHT_BITS_PER_PIXEL;
147    videoLogo->width = bmpInfo.header.width;
148    videoLogo->height = ((bmpInfo.header.height > 0) ? bmpInfo.header.height :
149                        (-bmpInfo.header.height));
150    *stride = videoLogo->width * videoLogo->bpp;
151    if ((*stride % FOUR_BITS_PER_PIXEL) != 0) {
152        *stride = (*stride & 0xfffc) + FOUR_BITS_PER_PIXEL;
153    }
154
155    byteNum = videoLogo->height * (*stride);
156    if (byteNum > UINT32_MAX) {
157        HDF_LOGE("%s: buffer size is beyond param's limit", __func__);
158        fclose(file);
159        return DISPLAY_FAILURE;
160    }
161    /* RGB8888 or RGB1555 */
162    *outBuf = (uint8_t*)malloc(byteNum);
163    if (*outBuf == NULL) {
164        HDF_LOGE("%s: not enough memory to malloc", __func__);
165        fclose(file);
166        return DISPLAY_FAILURE;
167    }
168    fseek(file, bmpFileHeader.offBits, 0);
169    if (fread((*outBuf), 1, byteNum, file) != byteNum) {
170        HDF_LOGE("%s: fread %u*%u error", __func__, videoLogo->height, *stride);
171        fclose(file);
172        free(*outBuf);
173        *outBuf = NULL;
174        return DISPLAY_FAILURE;
175    }
176    if (enFmt >= OSD_COLOR_FMT_RGB888) {
177        videoLogo->stride = videoLogo->width * FOUR_BITS_PER_PIXEL;
178    } else {
179        videoLogo->stride = videoLogo->width * TWO_BITS_PER_PIXEL;
180    }
181    fclose(file);
182    return DISPLAY_SUCCESS;
183}
184
185static void LoadRgbData(OsdLogo *videoLogo, OsdColorFmt enFmt, uint32_t stride, uint8_t *origBuf)
186{
187    uint16_t i;
188    uint16_t j;
189    uint8_t *start = NULL;
190    uint16_t *dst = NULL;
191    uint32_t h;
192    OsdColor c;
193
194    h = videoLogo->height;
195    for (i = 0; i < videoLogo->height; i++) {
196        for (j = 0; j < videoLogo->width; j++) {
197            /* start color convert */
198            start = origBuf + ((h - 1) - i) * stride + j * videoLogo->bpp;
199            dst = (uint16_t*)(videoLogo->picBuffer + i * videoLogo->stride + j * TWO_OFFSET);
200            c.r = *(start);
201            c.g = *(start + ONE_OFFSET);
202            c.b = *(start + TWO_OFFSET);
203            *dst = OsdMakeColorU16(c.r, c.g, c.b, g_osdCompInfo[enFmt]);
204        }
205    }
206}
207
208static int32_t LoadData(OsdLogo *videoLogo, OsdColorFmt enFmt, uint32_t stride, uint8_t *origBuf)
209{
210    int32_t ret;
211    uint16_t i;
212    uint16_t j;
213    uint32_t h;
214
215    (void)enFmt;
216    h = videoLogo->height;
217    for (i = 0; i < videoLogo->height; i++) {
218        for (j = 0; j < videoLogo->width; j++) {
219            ret = memcpy_s((videoLogo->picBuffer + i * videoLogo->stride + j * FOUR_BITS_PER_PIXEL), videoLogo->len,
220                (origBuf + ((h - 1) - i) * stride + j * videoLogo->bpp), videoLogo->bpp);
221            if (ret != EOK) {
222                HDF_LOGE("%s: file: %s, line: %d, memcpy_s failure", __func__, __FILE__, __LINE__);
223                return DISPLAY_FAILURE;
224            }
225            *(videoLogo->picBuffer + i * videoLogo->stride + j * FOUR_BITS_PER_PIXEL + THREE_BITS_PER_PIXEL) = 0xff;
226        }
227    }
228    return DISPLAY_SUCCESS;
229}
230
231static int32_t Copy3BitsByFmt(OsdLogo *videoLogo, OsdColorFmt enFmt, uint32_t stride, uint8_t *origBuf)
232{
233    int32_t ret = DISPLAY_SUCCESS;
234
235    switch (enFmt) {
236        case OSD_COLOR_FMT_RGB444:
237        case OSD_COLOR_FMT_RGB555:
238        case OSD_COLOR_FMT_RGB565:
239        case OSD_COLOR_FMT_RGB1555:
240        case OSD_COLOR_FMT_RGB4444:
241            /* start color convert */
242            LoadRgbData(videoLogo, enFmt, stride, origBuf);
243            break;
244        case OSD_COLOR_FMT_RGB888:
245        case OSD_COLOR_FMT_RGB8888:
246            ret = LoadData(videoLogo, enFmt, stride, origBuf);
247            break;
248        default:
249            HDF_LOGE("%s: file: %s, line: %d, no such format", __func__, __FILE__, __LINE__);
250            return DISPLAY_FAILURE;
251    }
252    return ret;
253}
254
255static int32_t Copy2BitsAnd4Bits(OsdLogo *videoLogo, uint32_t stride, uint8_t *origBuf)
256{
257    int32_t ret;
258    uint16_t i;
259    uint16_t j;
260    uint8_t *pRGBBuf;
261
262    pRGBBuf = videoLogo->picBuffer;
263    for (i = 0; i < videoLogo->height; i++) {
264        for (j = 0; j < videoLogo->width; j++) {
265            ret = memcpy_s((pRGBBuf + i * videoLogo->stride + j * videoLogo->bpp), videoLogo->len,
266                (origBuf + ((videoLogo->height - 1) - i) * stride + j * videoLogo->bpp), videoLogo->bpp);
267            if (ret != EOK) {
268                HDF_LOGE("%s: file: %s, line: %d, memcpy_s failure", __func__, __FILE__, __LINE__);
269                return DISPLAY_FAILURE;
270            }
271        }
272    }
273    return DISPLAY_SUCCESS;
274}
275
276static int32_t LoadBMPEx(const int8_t *fileName, OsdLogo *videoLogo, OsdColorFmt enFmt)
277{
278    int32_t ret;
279    uint32_t stride;
280    uint8_t *origBmpBuf = NULL;
281
282    ret = LoadPicToBuffer(fileName, videoLogo, enFmt, &origBmpBuf, &stride);
283    if (ret != DISPLAY_SUCCESS) {
284        HDF_LOGE("%s: LoadPicToBuffer failure", __func__);
285        return DISPLAY_FAILURE;
286    }
287    if (videoLogo->bpp == THREE_BITS_PER_PIXEL) {
288        ret = Copy3BitsByFmt(videoLogo, enFmt, stride, origBmpBuf);
289        if (ret != DISPLAY_SUCCESS) {
290            HDF_LOGE("%s: Copy3BitsByFmt failure", __func__);
291        }
292    } else if ((videoLogo->bpp == TWO_BITS_PER_PIXEL) || (videoLogo->bpp == FOUR_BITS_PER_PIXEL)) {
293        ret = Copy2BitsAnd4Bits(videoLogo, stride, origBmpBuf);
294        if (ret != DISPLAY_SUCCESS) {
295            HDF_LOGE("%s: Copy2BitsAnd4Bits failure", __func__);
296            free(origBmpBuf);
297            return ret;
298        }
299    }
300    free(origBmpBuf);
301    return DISPLAY_SUCCESS;
302}
303
304static int32_t LoadImageEx(const int8_t *fileName, OsdLogo *videoLogo, OsdColorFmt enFmt)
305{
306    char *ext = strrchr((const char *)fileName, '.');
307
308    if (ext == NULL) {
309        HDF_LOGE("%s: LoadImageEx error", __func__);
310        return DISPLAY_FAILURE;
311    }
312
313    ext = ext + 1;
314    if (strcmp(ext, "bmp") == 0) {
315        if (LoadBMPEx(fileName, videoLogo, enFmt) != 0) {
316            HDF_LOGE("%s: LoadBMPEx error", __func__);
317            return DISPLAY_FAILURE;
318        }
319    } else {
320        HDF_LOGE("%s: not supported image file", __func__);
321        return DISPLAY_FAILURE;
322    }
323
324    return DISPLAY_SUCCESS;
325}
326
327int32_t CreateSurfaceByBitMap(const int8_t *fileName, OsdSurface *pstSurface, uint8_t *virAddr, uint32_t len)
328{
329    OsdLogo stLogo;
330
331    if (fileName == NULL) {
332        HDF_LOGE("%s: fileName is null", __func__);
333        return DISPLAY_FAILURE;
334    }
335    if (pstSurface == NULL) {
336        HDF_LOGE("%s: pstSurface is null", __func__);
337        return DISPLAY_FAILURE;
338    }
339    if (virAddr == NULL) {
340        HDF_LOGE("%s: virAddr is null", __func__);
341        return DISPLAY_FAILURE;
342    }
343    (void)memset_s(&stLogo, sizeof(OsdLogo), 0, sizeof(OsdLogo));
344    stLogo.picBuffer = virAddr;
345    stLogo.len = len;
346    if (LoadImageEx(fileName, &stLogo, pstSurface->colorFmt) < 0) {
347        HDF_LOGE("%s: load bmp error", __func__);
348        return DISPLAY_FAILURE;
349    }
350    pstSurface->height = stLogo.height;
351    pstSurface->width = stLogo.width;
352    pstSurface->stride = stLogo.stride;
353    return DISPLAY_SUCCESS;
354}
355