• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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