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 "bmp_decoder.h"
17 #include "image_utils.h"
18 #include "media_errors.h"
19 #include "securec.h"
20
21 namespace OHOS {
22 namespace ImagePlugin {
23 using namespace OHOS::HiviewDFX;
24 using namespace Media;
25 using namespace std;
26 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "BmpDecoder" };
27 namespace {
28 constexpr uint32_t BMP_IMAGE_NUM = 1;
29 }
30
SetSource(InputDataStream & sourceStream)31 void BmpDecoder::SetSource(InputDataStream &sourceStream)
32 {
33 stream_ = &sourceStream;
34 state_ = BmpDecodingState::SOURCE_INITED;
35 }
36
Reset()37 void BmpDecoder::Reset()
38 {
39 if (stream_ != nullptr) {
40 stream_->Seek(0);
41 }
42 codec_.release();
43 info_.reset();
44 desireColor_ = kUnknown_SkColorType;
45 }
46
GetImageSize(uint32_t index,PlSize & size)47 uint32_t BmpDecoder::GetImageSize(uint32_t index, PlSize &size)
48 {
49 if (index >= BMP_IMAGE_NUM) {
50 HiLog::Error(LABEL, "GetImageSize failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM);
51 return ERR_IMAGE_INVALID_PARAMETER;
52 }
53 if (state_ < BmpDecodingState::SOURCE_INITED) {
54 HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_);
55 return ERR_MEDIA_INVALID_OPERATION;
56 }
57 if (state_ >= BmpDecodingState::BASE_INFO_PARSED) {
58 size.width = info_.width();
59 size.height = info_.height();
60 return SUCCESS;
61 }
62 if (!DecodeHeader()) {
63 HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_);
64 return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
65 }
66 size.width = info_.width();
67 size.height = info_.height();
68 state_ = BmpDecodingState::BASE_INFO_PARSED;
69 return SUCCESS;
70 }
71
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)72 uint32_t BmpDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
73 {
74 if (index >= BMP_IMAGE_NUM) {
75 HiLog::Error(LABEL, "SetDecodeOptions failed, invalid index:%{public}u, range:%{public}u", index,
76 BMP_IMAGE_NUM);
77 return ERR_IMAGE_INVALID_PARAMETER;
78 }
79 if (state_ < BmpDecodingState::SOURCE_INITED) {
80 HiLog::Error(LABEL, "SetDecodeOptions failed, invalid state %{public}d", state_);
81 return ERR_MEDIA_INVALID_OPERATION;
82 }
83 if (state_ >= BmpDecodingState::IMAGE_DECODING) {
84 Reset();
85 state_ = BmpDecodingState::SOURCE_INITED;
86 }
87 if (state_ < BmpDecodingState::BASE_INFO_PARSED) {
88 if (!DecodeHeader()) {
89 HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_);
90 return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
91 }
92 state_ = BmpDecodingState::BASE_INFO_PARSED;
93 }
94 PlPixelFormat desiredFormat = opts.desiredPixelFormat;
95 desireColor_ = ConvertToColorType(desiredFormat, info.pixelFormat);
96 info.size.width = info_.width();
97 info.size.height = info_.height();
98 info.alphaType = ConvertToAlphaType(info_.alphaType());
99 state_ = BmpDecodingState::IMAGE_DECODING;
100 return SUCCESS;
101 }
102
SetShareMemBuffer(uint64_t byteCount,DecodeContext & context)103 uint32_t BmpDecoder::SetShareMemBuffer(uint64_t byteCount, DecodeContext &context)
104 {
105 int fd = AshmemCreate("BMP RawData", byteCount);
106 if (fd < 0) {
107 return ERR_SHAMEM_DATA_ABNORMAL;
108 }
109 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
110 if (result < 0) {
111 ::close(fd);
112 return ERR_SHAMEM_DATA_ABNORMAL;
113 }
114 void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
115 if (ptr == MAP_FAILED) {
116 ::close(fd);
117 return ERR_SHAMEM_DATA_ABNORMAL;
118 }
119 context.pixelsBuffer.buffer = ptr;
120 void *fdBuffer = new int32_t();
121 if (fdBuffer == nullptr) {
122 ::munmap(ptr, byteCount);
123 ::close(fd);
124 context.pixelsBuffer.buffer = nullptr;
125 return ERR_SHAMEM_DATA_ABNORMAL;
126 }
127 *static_cast<int32_t *>(fdBuffer) = fd;
128 context.pixelsBuffer.context = fdBuffer;
129 context.pixelsBuffer.bufferSize = byteCount;
130 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
131 context.freeFunc = nullptr;
132 return SUCCESS;
133 }
134
SetContextPixelsBuffer(uint64_t byteCount,DecodeContext & context)135 uint32_t BmpDecoder::SetContextPixelsBuffer(uint64_t byteCount, DecodeContext &context)
136 {
137 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
138 #if !defined(_WIN32) && !defined(_APPLE)
139 uint32_t res = SetShareMemBuffer(byteCount, context);
140 if (res != SUCCESS) {
141 return res;
142 }
143 #endif
144 } else {
145 if (byteCount <= 0) {
146 HiLog::Error(LABEL, "Decode failed, byteCount is invalid value");
147 return ERR_MEDIA_INVALID_VALUE;
148 }
149 void *outputBuffer = malloc(byteCount);
150 if (outputBuffer == nullptr) {
151 HiLog::Error(LABEL, "Decode failed, alloc output buffer size:[%{public}llu] error",
152 static_cast<unsigned long long>(byteCount));
153 return ERR_IMAGE_MALLOC_ABNORMAL;
154 }
155 #ifdef _WIN32
156 errno_t backRet = memset_s(outputBuffer, 0, byteCount);
157 if (backRet != EOK) {
158 HiLog::Error(LABEL, "Decode failed, memset buffer failed", backRet);
159 free(outputBuffer);
160 outputBuffer = nullptr;
161 return ERR_IMAGE_DECODE_FAILED;
162 }
163 #else
164 if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
165 HiLog::Error(LABEL, "Decode failed, memset buffer failed");
166 free(outputBuffer);
167 outputBuffer = nullptr;
168 return ERR_IMAGE_DECODE_FAILED;
169 }
170 #endif
171 context.pixelsBuffer.buffer = outputBuffer;
172 context.pixelsBuffer.bufferSize = byteCount;
173 context.pixelsBuffer.context = nullptr;
174 context.allocatorType = AllocatorType::HEAP_ALLOC;
175 context.freeFunc = nullptr;
176 }
177 return SUCCESS;
178 }
179
Decode(uint32_t index,DecodeContext & context)180 uint32_t BmpDecoder::Decode(uint32_t index, DecodeContext &context)
181 {
182 if (index >= BMP_IMAGE_NUM) {
183 HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM);
184 return ERR_IMAGE_INVALID_PARAMETER;
185 }
186 if (codec_ == nullptr) {
187 HiLog::Error(LABEL, "Decode failed, codec is null");
188 return ERR_IMAGE_DECODE_FAILED;
189 }
190 if (state_ != BmpDecodingState::IMAGE_DECODING) {
191 HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_);
192 return ERR_MEDIA_INVALID_OPERATION;
193 }
194
195 SkImageInfo dstInfo = info_.makeColorType(desireColor_);
196 if (ImageUtils::CheckMulOverflow(dstInfo.width(), dstInfo.height(), dstInfo.bytesPerPixel())) {
197 HiLog::Error(LABEL, "Decode failed, width:%{public}d, height:%{public}d is too large",
198 dstInfo.width(), dstInfo.height());
199 return ERR_IMAGE_DECODE_FAILED;
200 }
201 if (context.pixelsBuffer.buffer == nullptr) {
202 uint64_t byteCount = static_cast<uint64_t>(dstInfo.height()) * dstInfo.width() * dstInfo.bytesPerPixel();
203 uint32_t res = SetContextPixelsBuffer(byteCount, context);
204 if (res != SUCCESS) {
205 return res;
206 }
207 }
208 uint8_t *dstBuffer = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
209 size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel();
210 SkCodec::Result ret = codec_->getPixels(dstInfo, dstBuffer, rowBytes);
211 if (ret != SkCodec::kSuccess) {
212 HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret);
213 state_ = BmpDecodingState::IMAGE_ERROR;
214 return ERR_IMAGE_DECODE_ABNORMAL;
215 }
216 state_ = BmpDecodingState::IMAGE_DECODED;
217 return SUCCESS;
218 }
219
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)220 uint32_t BmpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
221 {
222 // currently not support increment decode
223 return ERR_IMAGE_DATA_UNSUPPORT;
224 }
225
DecodeHeader()226 bool BmpDecoder::DecodeHeader()
227 {
228 codec_ = SkCodec::MakeFromStream(make_unique<BmpStream>(stream_));
229 if (codec_ == nullptr) {
230 HiLog::Error(LABEL, "create codec from stream failed");
231 return false;
232 }
233 info_ = codec_->getInfo();
234 return true;
235 }
236
ConvertToAlphaType(SkAlphaType alphaType)237 PlAlphaType BmpDecoder::ConvertToAlphaType(SkAlphaType alphaType)
238 {
239 switch (alphaType) {
240 case kOpaque_SkAlphaType:
241 return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
242 case kPremul_SkAlphaType:
243 return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL;
244 case kUnpremul_SkAlphaType:
245 return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
246 default:
247 HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType);
248 break;
249 }
250 return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
251 }
252
ConvertToColorType(PlPixelFormat format,PlPixelFormat & outputFormat)253 SkColorType BmpDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat)
254 {
255 switch (format) {
256 case PlPixelFormat::UNKNOWN:
257 case PlPixelFormat::RGBA_8888: {
258 outputFormat = PlPixelFormat::RGBA_8888;
259 return kRGBA_8888_SkColorType;
260 }
261 case PlPixelFormat::BGRA_8888: {
262 outputFormat = PlPixelFormat::BGRA_8888;
263 return kBGRA_8888_SkColorType;
264 }
265 case PlPixelFormat::ALPHA_8: {
266 SkColorType colorType = info_.colorType();
267 if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) {
268 outputFormat = PlPixelFormat::ALPHA_8;
269 return kAlpha_8_SkColorType;
270 }
271 break;
272 }
273 case PlPixelFormat::RGB_565: {
274 if (info_.isOpaque()) {
275 outputFormat = PlPixelFormat::RGB_565;
276 return kRGB_565_SkColorType;
277 }
278 break;
279 }
280 default: {
281 break;
282 }
283 }
284 HiLog::Debug(LABEL, "unsupported convert to format:%{public}d, set default RGBA", format);
285 outputFormat = PlPixelFormat::RGBA_8888;
286 return kRGBA_8888_SkColorType;
287 }
288 } // namespace ImagePlugin
289 } // namespace OHOS
290