1 /*
2  * Copyright (C) 2023-2024 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 "image/loaders/image_loader_common.h"
17 
18 CORE_BEGIN_NAMESPACE()
19 using BASE_NS::array_view;
20 using BASE_NS::Format;
21 using BASE_NS::make_unique;
22 using BASE_NS::move;
23 using BASE_NS::string;
24 using BASE_NS::string_view;
25 using BASE_NS::unique_ptr;
26 
GetInstance()27 ImageLoaderCommon &ImageLoaderCommon::GetInstance()
28 {
29     static ImageLoaderCommon single;
30     return single;
31 }
32 
InitializeSRGBTable()33 void ImageLoaderCommon::InitializeSRGBTable()
34 {
35     // Generate lookup table to premultiply sRGB encoded image in linear space and reencoding it to sRGB
36     // Formulas from https://en.wikipedia.org/wiki/SRGB
37     for (uint32_t a = 0; a < 256u; a++) {
38         const float alpha = a / 255.f;
39         for (uint32_t sRGB = 0; sRGB < 256u; sRGB++) {
40             float color = sRGB / 255.f;
41             if (color <= 0.04045f) {
42                 color *= (1.f / 12.92f);
43             } else {
44                 color = pow((color + 0.055f) * (1.f / 1.055f), 2.4f);
45             }
46             float premultiplied = color * alpha;
47             if (premultiplied <= 0.0031308f) {
48                 premultiplied *= 12.92f;
49             } else {
50                 premultiplied = 1.055f * pow(premultiplied, 1.f / 2.4f) - 0.055f;
51             }
52             SRGBPremultiplyLookup[a * 256u + sRGB] = static_cast<uint8_t>(round(premultiplied * 255.f));
53         }
54     }
55 }
56 
PremultiplyAlpha(uint8_t * imageBytes,uint32_t width,uint32_t height,uint32_t channelCount,uint32_t bytesPerChannel,bool linear)57 bool ImageLoaderCommon::PremultiplyAlpha(
58     uint8_t *imageBytes, uint32_t width, uint32_t height, uint32_t channelCount, uint32_t bytesPerChannel, bool linear)
59 {
60     // Only need to process images with color and alpha data. I.e. RGBA or grayscale + alpha.
61     if (channelCount != 4u && channelCount != 2u) {
62         return true;
63     }
64 
65     const uint32_t pixelCount = width * height;
66 
67     if (bytesPerChannel == 1 && linear) {
68         uint8_t *img = imageBytes;
69         for (uint32_t i = 0; i < pixelCount; i++) {
70             // We know the alpha value is always last.
71             uint32_t alpha = img[channelCount - 1];
72             for (uint32_t j = 0; j < channelCount - 1; j++) {
73                 *img = static_cast<uint8_t>(*img * alpha / 0xff);
74                 img++;
75             }
76             img++;  // Skip over the alpha value.
77         }
78     } else if (bytesPerChannel == 1) {
79         if (SRGBPremultiplyLookup[256u * 256u - 1] == 0) {
80             InitializeSRGBTable();
81         }
82         uint8_t *img = imageBytes;
83         for (uint32_t i = 0; i < pixelCount; i++) {
84             uint8_t *p = &SRGBPremultiplyLookup[img[channelCount - 1] * 256u];
85             for (uint32_t j = 0; j < channelCount - 1; j++) {
86                 *img = p[*img];
87                 img++;
88             }
89             img++;
90         }
91     } else if (bytesPerChannel == 2u) {
92         // Same for 16 bits per channel images.
93         uint16_t *img = reinterpret_cast<uint16_t *>(imageBytes);
94         for (uint32_t i = 0; i < pixelCount; i++) {
95             uint32_t alpha = img[channelCount - 1];
96             for (uint32_t j = 0; j < channelCount - 1; j++) {
97                 *img = static_cast<uint16_t>(*img * alpha / 0xffff);
98                 img++;
99             }
100             img++;
101         }
102     } else {
103         CORE_LOG_E("Format not supported.");
104         return false;
105     }
106     return true;
107 }
108 
FreeLibBaseImageBytes(void * imageBytes)109 void FreeLibBaseImageBytes(void *imageBytes)
110 {
111     free(imageBytes);
112 }
113 
LibBaseImage()114 LibBaseImage::LibBaseImage() : IImageContainer(), imageDesc_(), imageBuffer_()
115 {}
116 
GetImageDesc() const117 const IImageContainer::ImageDesc &LibBaseImage::GetImageDesc() const
118 {
119     return imageDesc_;
120 }
121 
GetData() const122 array_view<const uint8_t> LibBaseImage::GetData() const
123 {
124     return array_view<const uint8_t>(static_cast<const uint8_t *>(imageBytes_.get()), imageBytesLength_);
125 }
126 
GetBufferImageCopies() const127 array_view<const IImageContainer::SubImageDesc> LibBaseImage::GetBufferImageCopies() const
128 {
129     return array_view<const IImageContainer::SubImageDesc>(&imageBuffer_, 1);
130 }
131 
ResolveFormat(uint32_t loadFlags,uint32_t componentCount,bool is16bpc)132 constexpr Format LibBaseImage::ResolveFormat(uint32_t loadFlags, uint32_t componentCount, bool is16bpc)
133 {
134     Format format{};
135     const bool forceLinear = (loadFlags & IImageLoaderManager::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT) != 0;
136 
137     switch (componentCount) {
138         case 1u:
139             format = is16bpc ? Format::BASE_FORMAT_R16_UNORM
140                              : (forceLinear ? Format::BASE_FORMAT_R8_UNORM : Format::BASE_FORMAT_R8_SRGB);
141             break;
142         case 2u:
143             format = is16bpc ? Format::BASE_FORMAT_R16G16_UNORM
144                              : (forceLinear ? Format::BASE_FORMAT_R8G8_UNORM : Format::BASE_FORMAT_R8G8_SRGB);
145             break;
146         case 3u:
147             format = is16bpc ? Format::BASE_FORMAT_R16G16B16_UNORM
148                              : (forceLinear ? Format::BASE_FORMAT_R8G8B8_UNORM : Format::BASE_FORMAT_R8G8B8_SRGB);
149             break;
150         case 4u:
151             format = is16bpc ? Format::BASE_FORMAT_R16G16B16A16_UNORM
152                              : (forceLinear ? Format::BASE_FORMAT_R8G8B8A8_UNORM : Format::BASE_FORMAT_R8G8B8A8_SRGB);
153             break;
154         default:
155             format = Format::BASE_FORMAT_UNDEFINED;
156             break;
157     }
158 
159     return format;
160 }
161 
ResolveImageDesc(Format format,uint32_t imageWidth,uint32_t imageHeight,uint32_t bitsPerPixel,bool generateMips,bool isPremultiplied)162 constexpr IImageContainer::ImageDesc LibBaseImage::ResolveImageDesc(Format format, uint32_t imageWidth,
163     uint32_t imageHeight, uint32_t bitsPerPixel, bool generateMips, bool isPremultiplied)
164 {
165     uint32_t mipCount = 1;
166 
167     // 1D images not supported with img loader
168     constexpr ImageType imageType = ImageType::TYPE_2D;
169     constexpr ImageViewType imageViewType = ImageViewType::VIEW_TYPE_2D;
170 
171     uint32_t imageFlags = isPremultiplied ? ImageFlags::FLAGS_PREMULTIPLIED_ALPHA_BIT : 0;
172     if (generateMips) {
173         imageFlags |= ImageFlags::FLAGS_REQUESTING_MIPMAPS_BIT;
174         uint32_t mipsize = (imageWidth > imageHeight) ? imageWidth : imageHeight;
175         mipCount = 0;
176         while (mipsize > 0) {
177             mipCount++;
178             mipsize >>= 1;
179         }
180     }
181 
182     return ImageDesc{
183         imageFlags,    // imageFlags
184         1,             // blockPixelWidth
185         1,             // blockPixelHeight
186         1,             // blockPixelDepth
187         bitsPerPixel,  // bitsPerBlock
188 
189         imageType,      // imageType
190         imageViewType,  // imageViewType
191         format,         // format
192 
193         static_cast<uint32_t>(imageWidth),   // width
194         static_cast<uint32_t>(imageHeight),  // height
195         1,                                   // depth
196 
197         mipCount,  // mipCount
198         1,         // layerCount
199     };
200 }
201 
CreateImage(LibBaseImagePtr imageBytes,uint32_t imageWidth,uint32_t imageHeight,uint32_t componentCount,uint32_t loadFlags,bool is16bpc)202 ImageLoaderManager::LoadResult LibBaseImage::CreateImage(LibBaseImagePtr imageBytes, uint32_t imageWidth,
203     uint32_t imageHeight, uint32_t componentCount, uint32_t loadFlags, bool is16bpc)
204 {
205     auto image = LibBaseImage::Ptr(new LibBaseImage);
206     if (!image) {
207         return ImageLoaderManager::ResultFailure("Loading image failed.");
208     }
209 
210     // Premultiply alpha if requested.
211     bool isPremultiplied = false;
212     if ((loadFlags & IImageLoaderManager::IMAGE_LOADER_METADATA_ONLY) == 0) {
213         if ((loadFlags & IImageLoaderManager::IMAGE_LOADER_PREMULTIPLY_ALPHA) != 0) {
214             const uint32_t bytesPerChannel = is16bpc ? 2u : 1u;
215             const bool forceLinear = (loadFlags & IImageLoaderManager::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT) != 0;
216             isPremultiplied =
217                 ImageLoaderCommon::GetInstance().PremultiplyAlpha(static_cast<uint8_t *>(imageBytes.get()),
218                     imageWidth,
219                     imageHeight,
220                     componentCount,
221                     bytesPerChannel,
222                     forceLinear);
223         }
224     }
225 
226     const Format format = ResolveFormat(loadFlags, componentCount, is16bpc);
227 
228     const bool generateMips = (loadFlags & IImageLoaderManager::IMAGE_LOADER_GENERATE_MIPS) != 0;
229     const uint32_t bytesPerComponent = is16bpc ? 2u : 1u;
230     const uint32_t bitsPerPixel = bytesPerComponent * componentCount * 8u;
231 
232     image->imageDesc_ = ResolveImageDesc(format, imageWidth, imageHeight, bitsPerPixel, generateMips, isPremultiplied);
233     image->imageBytes_ = BASE_NS::move(imageBytes);
234     image->imageBytesLength_ = static_cast<size_t>(imageWidth * imageHeight * componentCount * bytesPerComponent);
235 
236     image->imageBuffer_ = SubImageDesc{
237         0,            // uint32_t bufferOffset
238         imageWidth,   // uint32_t bufferRowLength
239         imageHeight,  // uint32_t bufferImageHeight
240 
241         0,  // uint32_t mipLevel
242         1,  // uint32_t layerCount
243 
244         static_cast<uint32_t>(imageWidth),
245         static_cast<uint32_t>(imageHeight),
246         1,
247     };
248     return ImageLoaderManager::ResultSuccess(CORE_NS::move(image));
249 }
250 
Destroy()251 void LibBaseImage::Destroy()
252 {
253     delete this;
254 }
255 CORE_END_NAMESPACE()
256