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