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 memset(outputBuffer, 0, byteCount);
157 #else
158 if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
159 HiLog::Error(LABEL, "Decode failed, memset buffer failed");
160 free(outputBuffer);
161 outputBuffer = nullptr;
162 return ERR_IMAGE_DECODE_FAILED;
163 }
164 #endif
165 context.pixelsBuffer.buffer = outputBuffer;
166 context.pixelsBuffer.bufferSize = byteCount;
167 context.pixelsBuffer.context = nullptr;
168 context.allocatorType = AllocatorType::HEAP_ALLOC;
169 context.freeFunc = nullptr;
170 }
171 return SUCCESS;
172 }
173
Decode(uint32_t index,DecodeContext & context)174 uint32_t BmpDecoder::Decode(uint32_t index, DecodeContext &context)
175 {
176 if (index >= BMP_IMAGE_NUM) {
177 HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM);
178 return ERR_IMAGE_INVALID_PARAMETER;
179 }
180 if (codec_ == nullptr) {
181 HiLog::Error(LABEL, "Decode failed, codec is null");
182 return ERR_IMAGE_DECODE_FAILED;
183 }
184 if (state_ != BmpDecodingState::IMAGE_DECODING) {
185 HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_);
186 return ERR_MEDIA_INVALID_OPERATION;
187 }
188
189 SkImageInfo dstInfo = info_.makeColorType(desireColor_);
190 if (ImageUtils::CheckMulOverflow(dstInfo.width(), dstInfo.height(), dstInfo.bytesPerPixel())) {
191 HiLog::Error(LABEL, "Decode failed, width:%{public}d, height:%{public}d is too large",
192 dstInfo.width(), dstInfo.height());
193 return ERR_IMAGE_DECODE_FAILED;
194 }
195 if (context.pixelsBuffer.buffer == nullptr) {
196 uint64_t byteCount = static_cast<uint64_t>(dstInfo.height()) * dstInfo.width() * dstInfo.bytesPerPixel();
197 uint32_t res = SetContextPixelsBuffer(byteCount, context);
198 if (res != SUCCESS) {
199 return res;
200 }
201 }
202 uint8_t *dstBuffer = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
203 size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel();
204 SkCodec::Result ret = codec_->getPixels(dstInfo, dstBuffer, rowBytes);
205 if (ret != SkCodec::kSuccess) {
206 HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret);
207 state_ = BmpDecodingState::IMAGE_ERROR;
208 return ERR_IMAGE_DECODE_ABNORMAL;
209 }
210 state_ = BmpDecodingState::IMAGE_DECODED;
211 return SUCCESS;
212 }
213
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)214 uint32_t BmpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
215 {
216 // currently not support increment decode
217 return ERR_IMAGE_DATA_UNSUPPORT;
218 }
219
DecodeHeader()220 bool BmpDecoder::DecodeHeader()
221 {
222 codec_ = SkCodec::MakeFromStream(make_unique<BmpStream>(stream_));
223 if (codec_ == nullptr) {
224 HiLog::Error(LABEL, "create codec from stream failed");
225 return false;
226 }
227 info_ = codec_->getInfo();
228 return true;
229 }
230
ConvertToAlphaType(SkAlphaType alphaType)231 PlAlphaType BmpDecoder::ConvertToAlphaType(SkAlphaType alphaType)
232 {
233 switch (alphaType) {
234 case kOpaque_SkAlphaType:
235 return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
236 case kPremul_SkAlphaType:
237 return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL;
238 case kUnpremul_SkAlphaType:
239 return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
240 default:
241 HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType);
242 break;
243 }
244 return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
245 }
246
ConvertToColorType(PlPixelFormat format,PlPixelFormat & outputFormat)247 SkColorType BmpDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat)
248 {
249 switch (format) {
250 case PlPixelFormat::UNKNOWN:
251 case PlPixelFormat::RGBA_8888: {
252 outputFormat = PlPixelFormat::RGBA_8888;
253 return kRGBA_8888_SkColorType;
254 }
255 case PlPixelFormat::BGRA_8888: {
256 outputFormat = PlPixelFormat::BGRA_8888;
257 return kBGRA_8888_SkColorType;
258 }
259 case PlPixelFormat::ALPHA_8: {
260 SkColorType colorType = info_.colorType();
261 if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) {
262 outputFormat = PlPixelFormat::ALPHA_8;
263 return kAlpha_8_SkColorType;
264 }
265 break;
266 }
267 case PlPixelFormat::RGB_565: {
268 if (info_.isOpaque()) {
269 outputFormat = PlPixelFormat::RGB_565;
270 return kRGB_565_SkColorType;
271 }
272 break;
273 }
274 default: {
275 break;
276 }
277 }
278 HiLog::Debug(LABEL, "unsupported convert to format:%{public}d, set default RGBA", format);
279 outputFormat = PlPixelFormat::RGBA_8888;
280 return kRGBA_8888_SkColorType;
281 }
282 } // namespace ImagePlugin
283 } // namespace OHOS