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 "jpeg_decoder.h"
17 #include <map>
18 #include "jerror.h"
19 #include "media_errors.h"
20 #include "string_ex.h"
21 #ifndef _WIN32
22 #include "securec.h"
23 #else
24 #include "memory.h"
25 #endif
26
27 namespace OHOS {
28 namespace ImagePlugin {
29 using namespace OHOS::HiviewDFX;
30 using namespace MultimediaPlugin;
31 using namespace Media;
32 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegDecoder" };
33 static constexpr uint32_t PL_ICC_MARKER = JPEG_APP0 + 2;
34 static constexpr uint32_t PL_MARKER_LENGTH_LIMIT = 0xFFFF;
35 namespace {
36 constexpr uint32_t NUM_100 = 100;
37 constexpr uint32_t PIXEL_BYTES_RGB_565 = 2;
38 constexpr uint32_t MARKER_SIZE = 2;
39 constexpr uint32_t MARKER_LENGTH = 2;
40 constexpr uint8_t MARKER_LENGTH_0_OFFSET = 0;
41 constexpr uint8_t MARKER_LENGTH_1_OFFSET = 1;
42 constexpr uint32_t MARKER_LENGTH_SHIFT = 8;
43 constexpr uint8_t JPG_MARKER_PREFIX_OFFSET = 0;
44 constexpr uint8_t JPG_MARKER_CODE_OFFSET = 1;
45 constexpr uint8_t JPG_MARKER_PREFIX = 0XFF;
46 constexpr uint8_t JPG_MARKER_SOI = 0XD8;
47 constexpr uint8_t JPG_MARKER_SOS = 0XDA;
48 constexpr uint8_t JPG_MARKER_RST = 0XD0;
49 constexpr uint8_t JPG_MARKER_RST0 = 0XD0;
50 constexpr uint8_t JPG_MARKER_RSTN = 0XD7;
51 constexpr uint8_t JPG_MARKER_APP = 0XE0;
52 constexpr uint8_t JPG_MARKER_APP0 = 0XE0;
53 constexpr uint8_t JPG_MARKER_APPN = 0XEF;
54 constexpr size_t TIMES_LEN = 19;
55 constexpr size_t DATE_LEN = 10;
56 const std::string BITS_PER_SAMPLE = "BitsPerSample";
57 const std::string ORIENTATION = "Orientation";
58 const std::string IMAGE_LENGTH = "ImageLength";
59 const std::string IMAGE_WIDTH = "ImageWidth";
60 const std::string GPS_LATITUDE = "GPSLatitude";
61 const std::string GPS_LONGITUDE = "GPSLongitude";
62 const std::string GPS_LATITUDE_REF = "GPSLatitudeRef";
63 const std::string GPS_LONGITUDE_REF = "GPSLongitudeRef";
64 const std::string DATE_TIME_ORIGINAL = "DateTimeOriginal";
65 const std::string DATE_TIME_ORIGINAL_MEDIA = "DateTimeOriginalForMedia";
66 const std::string EXPOSURE_TIME = "ExposureTime";
67 const std::string F_NUMBER = "FNumber";
68 const std::string ISO_SPEED_RATINGS = "ISOSpeedRatings";
69 const std::string SCENE_TYPE = "SceneType";
70 const std::string COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
71 static const std::map<std::string, uint32_t> PROPERTY_INT = {
72 {"Top-left", 0},
73 {"Bottom-right", 180},
74 {"Right-top", 90},
75 {"Left-bottom", 270},
76 };
77 constexpr uint32_t JPEG_APP1_SIZE = 2;
78 constexpr uint32_t ADDRESS_4 = 4;
79 constexpr int OFFSET_8 = 8;
80 } // namespace
81
82 PluginServer &JpegDecoder::pluginServer_ = DelayedRefSingleton<PluginServer>::GetInstance();
83
JpegSrcMgr(InputDataStream * stream)84 JpegSrcMgr::JpegSrcMgr(InputDataStream *stream) : inputStream(stream)
85 {
86 init_source = InitSrcStream;
87 fill_input_buffer = FillInputBuffer;
88 skip_input_data = SkipInputData;
89 resync_to_restart = jpeg_resync_to_restart;
90 term_source = TermSrcStream;
91 }
92
JpegDecoder()93 JpegDecoder::JpegDecoder() : srcMgr_(nullptr)
94 {
95 CreateDecoder();
96 #if !defined(_WIN32) && !defined(_APPLE) && !defined(_ANDROID) && !defined(_IOS)
97 CreateHwDecompressor();
98 #endif
99 }
100
CreateDecoder()101 void JpegDecoder::CreateDecoder()
102 {
103 // create decompress struct
104 jpeg_create_decompress(&decodeInfo_);
105
106 // set error output
107 decodeInfo_.err = jpeg_std_error(&jerr_);
108 jerr_.error_exit = ErrorExit;
109 if (decodeInfo_.err == nullptr) {
110 HiLog::Error(LABEL, "create jpeg decoder failed.");
111 return;
112 }
113 decodeInfo_.err->output_message = &OutputErrorMessage;
114 }
115
~JpegDecoder()116 JpegDecoder::~JpegDecoder()
117 {
118 jpeg_destroy_decompress(&decodeInfo_);
119 if (hwJpegDecompress_ != nullptr) {
120 delete hwJpegDecompress_;
121 hwJpegDecompress_ = nullptr;
122 }
123 }
124
SetSource(InputDataStream & sourceStream)125 void JpegDecoder::SetSource(InputDataStream &sourceStream)
126 {
127 srcMgr_.inputStream = &sourceStream;
128 state_ = JpegDecodingState::SOURCE_INITED;
129 }
130
GetImageSize(uint32_t index,PlSize & size)131 uint32_t JpegDecoder::GetImageSize(uint32_t index, PlSize &size)
132 {
133 if (index >= JPEG_IMAGE_NUM) {
134 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
135 return ERR_IMAGE_INVALID_PARAMETER;
136 }
137 if (state_ < JpegDecodingState::SOURCE_INITED) {
138 HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_);
139 return ERR_MEDIA_INVALID_OPERATION;
140 }
141 if (state_ >= JpegDecodingState::BASE_INFO_PARSED) {
142 size.width = decodeInfo_.image_width;
143 size.height = decodeInfo_.image_height;
144 return Media::SUCCESS;
145 }
146 // only state JpegDecodingState::SOURCE_INITED and JpegDecodingState::BASE_INFO_PARSING can go here.
147 uint32_t ret = DecodeHeader();
148 if (ret != Media::SUCCESS) {
149 HiLog::Error(LABEL, "decode header error on get image size, ret:%{public}u.", ret);
150 state_ = JpegDecodingState::BASE_INFO_PARSING;
151 return ret;
152 }
153 size.width = decodeInfo_.image_width;
154 size.height = decodeInfo_.image_height;
155 state_ = JpegDecodingState::BASE_INFO_PARSED;
156 return Media::SUCCESS;
157 }
158
GetDecodeFormat(PlPixelFormat format,PlPixelFormat & outputFormat)159 J_COLOR_SPACE JpegDecoder::GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat)
160 {
161 outputFormat = format;
162 J_COLOR_SPACE colorSpace = JCS_UNKNOWN;
163 switch (format) {
164 case PlPixelFormat::UNKNOWN:
165 case PlPixelFormat::RGBA_8888: {
166 colorSpace = JCS_EXT_RGBA;
167 outputFormat = PlPixelFormat::RGBA_8888;
168 break;
169 }
170 case PlPixelFormat::BGRA_8888: {
171 colorSpace = JCS_EXT_BGRA;
172 outputFormat = PlPixelFormat::BGRA_8888;
173 break;
174 }
175 case PlPixelFormat::ARGB_8888: {
176 colorSpace = JCS_EXT_ARGB;
177 break;
178 }
179 case PlPixelFormat::ALPHA_8: {
180 colorSpace = JCS_GRAYSCALE;
181 break;
182 }
183 case PlPixelFormat::RGB_565: {
184 colorSpace = JCS_RGB;
185 outputFormat = PlPixelFormat::RGB_888;
186 break;
187 }
188 case PlPixelFormat::RGB_888: {
189 // NOTICE: libjpeg make BE as default when we are LE
190 colorSpace = JCS_EXT_BGR;
191 break;
192 }
193 default: {
194 colorSpace = JCS_EXT_RGBA;
195 outputFormat = PlPixelFormat::RGBA_8888;
196 break;
197 }
198 }
199 return colorSpace;
200 }
201
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)202 uint32_t JpegDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
203 {
204 if (index >= JPEG_IMAGE_NUM) {
205 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
206 return ERR_IMAGE_INVALID_PARAMETER;
207 }
208 if (state_ < JpegDecodingState::SOURCE_INITED) {
209 HiLog::Error(LABEL, "set decode options failed for state %{public}d.", state_);
210 return ERR_MEDIA_INVALID_OPERATION;
211 }
212 if (state_ >= JpegDecodingState::IMAGE_DECODING) {
213 FinishOldDecompress();
214 state_ = JpegDecodingState::SOURCE_INITED;
215 }
216 if (state_ < JpegDecodingState::BASE_INFO_PARSED) {
217 uint32_t ret = DecodeHeader();
218 if (ret != Media::SUCCESS) {
219 state_ = JpegDecodingState::BASE_INFO_PARSING;
220 HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret);
221 return ret;
222 }
223 state_ = JpegDecodingState::BASE_INFO_PARSED;
224 }
225 // only state JpegDecodingState::BASE_INFO_PARSED can go here.
226 uint32_t ret = StartDecompress(opts);
227 if (ret != Media::SUCCESS) {
228 HiLog::Error(LABEL, "start decompress failed on set decode options:%{public}u.", ret);
229 return ret;
230 }
231 info.pixelFormat = outputFormat_;
232 info.size.width = decodeInfo_.output_width;
233 info.size.height = decodeInfo_.output_height;
234 info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
235 opts_ = opts;
236 state_ = JpegDecodingState::IMAGE_DECODING;
237 return Media::SUCCESS;
238 }
239
GetRowBytes()240 uint32_t JpegDecoder::GetRowBytes()
241 {
242 uint32_t pixelBytes =
243 (decodeInfo_.out_color_space == JCS_RGB565) ? PIXEL_BYTES_RGB_565 : decodeInfo_.out_color_components;
244 return decodeInfo_.output_width * pixelBytes;
245 }
246
DoSwDecode(DecodeContext & context)247 uint32_t JpegDecoder::DoSwDecode(DecodeContext &context) __attribute__((no_sanitize("cfi")))
248 {
249 if (setjmp(jerr_.setjmp_buffer)) {
250 HiLog::Error(LABEL, "decode image failed.");
251 return ERR_IMAGE_DECODE_ABNORMAL;
252 }
253 uint32_t rowStride = GetRowBytes();
254 if (context.pixelsBuffer.buffer == nullptr) {
255 uint64_t byteCount = static_cast<uint64_t>(rowStride) * decodeInfo_.output_height;
256 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
257 #if !defined(_WIN32) && !defined(_APPLE) && !defined(_ANDROID) && !defined(_IOS)
258 int fd = AshmemCreate("JPEG RawData", byteCount);
259 if (fd < 0) {
260 return ERR_SHAMEM_DATA_ABNORMAL;
261 }
262 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
263 if (result < 0) {
264 ::close(fd);
265 return ERR_SHAMEM_DATA_ABNORMAL;
266 }
267 void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
268 if (ptr == MAP_FAILED) {
269 ::close(fd);
270 return ERR_SHAMEM_DATA_ABNORMAL;
271 }
272 context.pixelsBuffer.buffer = ptr;
273 void *fdBuffer = new int32_t();
274 if (fdBuffer == nullptr) {
275 HiLog::Error(LABEL, "new fdBuffer fail");
276 ::munmap(ptr, byteCount);
277 ::close(fd);
278 context.pixelsBuffer.buffer = nullptr;
279 return ERR_SHAMEM_DATA_ABNORMAL;
280 }
281 *static_cast<int32_t *>(fdBuffer) = fd;
282 context.pixelsBuffer.context = fdBuffer;
283 context.pixelsBuffer.bufferSize = byteCount;
284 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
285 context.freeFunc = nullptr;
286 #endif
287 } else {
288 void *outputBuffer = malloc(byteCount);
289 if (outputBuffer == nullptr) {
290 HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.",
291 static_cast<unsigned long long>(byteCount));
292 return ERR_IMAGE_MALLOC_ABNORMAL;
293 }
294 context.pixelsBuffer.buffer = outputBuffer;
295 context.pixelsBuffer.context = nullptr;
296 context.pixelsBuffer.bufferSize = byteCount;
297 context.allocatorType = AllocatorType::HEAP_ALLOC;
298 context.freeFunc = nullptr;
299 }
300 }
301 uint8_t *base = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
302 if (base == nullptr) {
303 HiLog::Error(LABEL, "decode image buffer is null.");
304 return ERR_IMAGE_INVALID_PARAMETER;
305 }
306 srcMgr_.inputStream->Seek(streamPosition_);
307 uint8_t *buffer = nullptr;
308 while (decodeInfo_.output_scanline < decodeInfo_.output_height) {
309 buffer = base + rowStride * decodeInfo_.output_scanline;
310 uint32_t readLineNum = jpeg_read_scanlines(&decodeInfo_, &buffer, RW_LINE_NUM);
311 if (readLineNum < RW_LINE_NUM) {
312 streamPosition_ = srcMgr_.inputStream->Tell();
313 HiLog::Error(LABEL, "read line fail, read num:%{public}u, total read num:%{public}u.", readLineNum,
314 decodeInfo_.output_scanline);
315 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
316 }
317 }
318 streamPosition_ = srcMgr_.inputStream->Tell();
319
320 #ifdef IMAGE_COLORSPACE_FLAG
321 // parser icc profile info
322 uint32_t iccPaseredResult = iccProfileInfo_.ParsingICCProfile(&decodeInfo_);
323 if (iccPaseredResult == OHOS::Media::ERR_IMAGE_DENCODE_ICC_FAILED) {
324 HiLog::Error(LABEL, "dencode image icc error.");
325 return iccPaseredResult;
326 }
327 #endif
328
329 return Media::SUCCESS;
330 }
331
Decode(uint32_t index,DecodeContext & context)332 uint32_t JpegDecoder::Decode(uint32_t index, DecodeContext &context)
333 {
334 if (index >= JPEG_IMAGE_NUM) {
335 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
336 return ERR_IMAGE_INVALID_PARAMETER;
337 }
338 if (state_ < JpegDecodingState::IMAGE_DECODING) {
339 HiLog::Error(LABEL, "decode failed for state %{public}d.", state_);
340 return ERR_MEDIA_INVALID_OPERATION;
341 }
342 if (state_ > JpegDecodingState::IMAGE_DECODING) {
343 FinishOldDecompress();
344 state_ = JpegDecodingState::SOURCE_INITED;
345 uint32_t ret = DecodeHeader();
346 if (ret != Media::SUCCESS) {
347 state_ = JpegDecodingState::BASE_INFO_PARSING;
348 HiLog::Error(LABEL, "decode header error on decode:%{public}u.", ret);
349 return ret;
350 }
351 state_ = JpegDecodingState::BASE_INFO_PARSED;
352 ret = StartDecompress(opts_);
353 if (ret != Media::SUCCESS) {
354 HiLog::Error(LABEL, "start decompress failed on decode:%{public}u.", ret);
355 return ret;
356 }
357 state_ = JpegDecodingState::IMAGE_DECODING;
358 }
359 // only state JpegDecodingState::IMAGE_DECODING can go here.
360 if (hwJpegDecompress_ != nullptr) {
361 srcMgr_.inputStream->Seek(streamPosition_);
362 uint32_t ret = hwJpegDecompress_->Decompress(&decodeInfo_, srcMgr_.inputStream, context);
363 if (ret == Media::SUCCESS) {
364 state_ = JpegDecodingState::IMAGE_DECODED;
365 HiLog::Debug(LABEL, "jpeg hardware decode success.");
366 return ret;
367 }
368 }
369 uint32_t ret = DoSwDecode(context);
370 if (ret == Media::SUCCESS) {
371 state_ = JpegDecodingState::IMAGE_DECODED;
372 HiLog::Debug(LABEL, "jpeg software decode success.");
373 return Media::SUCCESS;
374 }
375 if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && opts_.allowPartialImage) {
376 state_ = JpegDecodingState::IMAGE_PARTIAL;
377 context.ifPartialOutput = true;
378 return Media::SUCCESS;
379 }
380 state_ = JpegDecodingState::IMAGE_ERROR;
381 return ret;
382 }
383
Reset()384 void JpegDecoder::Reset()
385 {
386 srcMgr_.inputStream = nullptr;
387 }
388
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & progContext)389 uint32_t JpegDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &progContext)
390 {
391 progContext.totalProcessProgress = 0;
392 if (index >= JPEG_IMAGE_NUM) {
393 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
394 return ERR_IMAGE_INVALID_PARAMETER;
395 }
396 if (state_ != JpegDecodingState::IMAGE_DECODING) {
397 HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_);
398 return ERR_MEDIA_INVALID_OPERATION;
399 }
400
401 uint32_t ret = DoSwDecode(progContext.decodeContext);
402 if (ret == Media::SUCCESS) {
403 state_ = JpegDecodingState::IMAGE_DECODED;
404 }
405 // get promote decode progress, in percentage: 0~100.
406 progContext.totalProcessProgress =
407 decodeInfo_.output_height == 0 ? 0 : (decodeInfo_.output_scanline * NUM_100) / decodeInfo_.output_height;
408 HiLog::Debug(LABEL, "incremental decode progress %{public}u.", progContext.totalProcessProgress);
409 return ret;
410 }
411
CreateHwDecompressor()412 void JpegDecoder::CreateHwDecompressor()
413 {
414 std::map<std::string, AttrData> capabilities;
415 const std::string format = "image/jpeg";
416 capabilities.insert(std::map<std::string, AttrData>::value_type("encodeFormat", AttrData(format)));
417 hwJpegDecompress_ = pluginServer_.CreateObject<AbsImageDecompressComponent>(
418 AbsImageDecompressComponent::SERVICE_DEFAULT, capabilities);
419 if (hwJpegDecompress_ == nullptr) {
420 HiLog::Error(LABEL, "get hardware jpeg decompress component failed.");
421 return;
422 }
423 }
424
FinishOldDecompress()425 void JpegDecoder::FinishOldDecompress()
426 {
427 if (state_ < JpegDecodingState::IMAGE_DECODING) {
428 return;
429 }
430 jpeg_destroy_decompress(&decodeInfo_);
431 CreateDecoder();
432 }
433
IsMarker(uint8_t rawMarkerPrefix,uint8_t rawMarkderCode,uint8_t markerCode)434 bool JpegDecoder::IsMarker(uint8_t rawMarkerPrefix, uint8_t rawMarkderCode, uint8_t markerCode)
435 {
436 if (rawMarkerPrefix != JPG_MARKER_PREFIX) {
437 return false;
438 }
439
440 // RSTn, n from 0 to 7
441 if (rawMarkderCode >= JPG_MARKER_RST0 && rawMarkderCode <= JPG_MARKER_RSTN && markerCode == JPG_MARKER_RST) {
442 return true;
443 }
444
445 // APPn, n from 0 to 15
446 if (rawMarkderCode >= JPG_MARKER_APP0 && rawMarkderCode <= JPG_MARKER_APPN && markerCode == JPG_MARKER_APP) {
447 return true;
448 }
449
450 if (rawMarkderCode == markerCode) {
451 return true;
452 }
453 return false;
454 }
455
FindMarker(InputDataStream & stream,uint8_t marker)456 bool JpegDecoder::FindMarker(InputDataStream &stream, uint8_t marker)
457 {
458 uint8_t buffer[MARKER_SIZE] = { 0 };
459 uint32_t readSize = 0;
460 stream.Seek(0);
461 while (true) {
462 uint32_t cur = stream.Tell();
463 if (!stream.Seek(cur + MARKER_SIZE)) {
464 return false;
465 }
466 stream.Seek(cur);
467
468 // read marker code
469 stream.Read(MARKER_SIZE, buffer, sizeof(buffer), readSize);
470 if (readSize != MARKER_SIZE) {
471 return false;
472 }
473
474 uint8_t markerPrefix = buffer[JPG_MARKER_PREFIX_OFFSET];
475 uint8_t markerCode = buffer[JPG_MARKER_CODE_OFFSET];
476 if (IsMarker(markerPrefix, markerCode, JPG_MARKER_SOS)) {
477 return true;
478 }
479
480 if (IsMarker(markerPrefix, markerCode, JPG_MARKER_SOI) || IsMarker(markerPrefix, markerCode, JPG_MARKER_RST)) {
481 continue;
482 }
483
484 cur = stream.Tell();
485 if (!stream.Seek(cur + MARKER_LENGTH)) {
486 return false;
487 }
488 stream.Seek(cur);
489 // read marker length
490 stream.Read(MARKER_LENGTH, buffer, sizeof(buffer), readSize);
491 if (readSize != MARKER_LENGTH) {
492 return false;
493 }
494 // skip data, length = sizeof(length) + sizeof(data)
495 uint32_t length = (buffer[MARKER_LENGTH_0_OFFSET] << MARKER_LENGTH_SHIFT) + buffer[MARKER_LENGTH_1_OFFSET];
496 if (!stream.Seek(cur + length)) {
497 return false;
498 }
499 }
500 }
501
DecodeHeader()502 uint32_t JpegDecoder::DecodeHeader()
503 {
504 if (setjmp(jerr_.setjmp_buffer)) {
505 HiLog::Error(LABEL, "get image size failed.");
506 return ERR_IMAGE_DECODE_ABNORMAL;
507 }
508 if (state_ == JpegDecodingState::SOURCE_INITED) {
509 srcMgr_.inputStream->Seek(0);
510 } else {
511 srcMgr_.inputStream->Seek(streamPosition_);
512 }
513 decodeInfo_.src = &srcMgr_;
514
515 /**
516 * The function jpeg_read_header() shall read the JPEG datastream until the first SOS marker is encountered
517 * incremental decoding should have enough data(contains SOS marker) before calling jpeg_read_header.
518 */
519 if (!srcMgr_.inputStream->IsStreamCompleted()) {
520 uint32_t curPos = srcMgr_.inputStream->Tell();
521 while (true) {
522 if (!FindMarker(*srcMgr_.inputStream, JPG_MARKER_SOS)) {
523 srcMgr_.inputStream->Seek(curPos);
524 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
525 }
526 srcMgr_.inputStream->Seek(curPos);
527 break;
528 }
529 }
530
531 // call jpeg_save_markers, use to get ICC profile.
532 jpeg_save_markers(&decodeInfo_, PL_ICC_MARKER, PL_MARKER_LENGTH_LIMIT);
533 int32_t ret = jpeg_read_header(&decodeInfo_, false);
534 streamPosition_ = srcMgr_.inputStream->Tell();
535 if (ret == JPEG_SUSPENDED) {
536 HiLog::Debug(LABEL, "image input data incomplete, decode header error:%{public}u.", ret);
537 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
538 } else if (ret != JPEG_HEADER_OK) {
539 HiLog::Error(LABEL, "image type is not jpeg, decode header error:%{public}u.", ret);
540 return ERR_IMAGE_GET_DATA_ABNORMAL;
541 }
542 return Media::SUCCESS;
543 }
544
StartDecompress(const PixelDecodeOptions & opts)545 uint32_t JpegDecoder::StartDecompress(const PixelDecodeOptions &opts)
546 {
547 if (setjmp(jerr_.setjmp_buffer)) {
548 HiLog::Error(LABEL, "set output image info failed.");
549 return ERR_IMAGE_DECODE_ABNORMAL;
550 }
551 // set decode options
552 if (decodeInfo_.jpeg_color_space == JCS_CMYK || decodeInfo_.jpeg_color_space == JCS_YCCK) {
553 // can't support CMYK to alpha8 convert
554 if (opts.desiredPixelFormat == PlPixelFormat::ALPHA_8) {
555 HiLog::Error(LABEL, "can't support colorspace CMYK to alpha convert.");
556 return ERR_IMAGE_UNKNOWN_FORMAT;
557 }
558 HiLog::Debug(LABEL, "jpeg colorspace is CMYK.");
559 decodeInfo_.out_color_space = JCS_CMYK;
560 outputFormat_ = PlPixelFormat::CMYK;
561 } else {
562 decodeInfo_.out_color_space = GetDecodeFormat(opts.desiredPixelFormat, outputFormat_);
563 if (decodeInfo_.out_color_space == JCS_UNKNOWN) {
564 HiLog::Error(LABEL, "set jpeg output color space invalid.");
565 return ERR_IMAGE_UNKNOWN_FORMAT;
566 }
567 }
568 srcMgr_.inputStream->Seek(streamPosition_);
569 if (jpeg_start_decompress(&decodeInfo_) != TRUE) {
570 streamPosition_ = srcMgr_.inputStream->Tell();
571 HiLog::Error(LABEL, "jpeg start decompress failed, invalid input.");
572 return ERR_IMAGE_INVALID_PARAMETER;
573 }
574 streamPosition_ = srcMgr_.inputStream->Tell();
575 return Media::SUCCESS;
576 }
577
ParseExifData()578 bool JpegDecoder::ParseExifData()
579 {
580 HiLog::Debug(LABEL, "ParseExifData enter");
581 uint32_t curPos = srcMgr_.inputStream->Tell();
582 srcMgr_.inputStream->Seek(0);
583 unsigned long fsize = static_cast<unsigned long>(srcMgr_.inputStream->GetStreamSize());
584 if (fsize <= 0) {
585 HiLog::Error(LABEL, "Get stream size failed");
586 return false;
587 }
588 unsigned char *buf = new unsigned char[fsize];
589 uint32_t readSize = 0;
590 srcMgr_.inputStream->Read(fsize, buf, fsize, readSize);
591 HiLog::Debug(LABEL, "parsing EXIF: fsize %{public}lu", fsize);
592
593 int code = exifInfo_.ParseExifData(buf, fsize);
594 delete[] buf;
595 srcMgr_.inputStream->Seek(curPos);
596 if (code) {
597 HiLog::Error(LABEL, "Error parsing EXIF: code %{public}d", code);
598 return false;
599 }
600 return true;
601 }
602
GetImagePropertyInt(uint32_t index,const std::string & key,int32_t & value)603 uint32_t JpegDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value)
604 {
605 HiLog::Debug(LABEL, "[GetImagePropertyInt] enter jpeg plugin, key:%{public}s", key.c_str());
606 if (IsSameTextStr(key, ACTUAL_IMAGE_ENCODED_FORMAT)) {
607 HiLog::Error(LABEL, "[GetImagePropertyInt] this key is used to check the original format of raw image!");
608 return Media::ERR_MEDIA_VALUE_INVALID;
609 }
610
611 if (!exifInfo_.IsExifDataParsed()) {
612 if (!ParseExifData()) {
613 HiLog::Error(LABEL, "[GetImagePropertyInt] Parse exif data failed!");
614 return Media::ERROR;
615 }
616 }
617 if (IsSameTextStr(key, ORIENTATION)) {
618 if (PROPERTY_INT.find(exifInfo_.orientation_) != PROPERTY_INT.end()) {
619 value = PROPERTY_INT.at(exifInfo_.orientation_);
620 } else {
621 HiLog::Error(LABEL, "[GetImagePropertyInt] The ORIENTATION parameter is not supported int32_t");
622 HiLog::Error(LABEL, "[GetImagePropertyInt] The exifinfo:%{public}s is not found",
623 exifInfo_.orientation_.c_str());
624 return Media::ERR_MEDIA_VALUE_INVALID;
625 }
626 } else {
627 HiLog::Error(LABEL, "[GetImagePropertyInt] The key:%{public}s is not supported int32_t", key.c_str());
628 return Media::ERR_MEDIA_VALUE_INVALID;
629 }
630 return Media::SUCCESS;
631 }
632
GetImagePropertyString(uint32_t index,const std::string & key,std::string & value)633 uint32_t JpegDecoder::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value)
634 {
635 HiLog::Debug(LABEL, "[GetImagePropertyString] enter jpeg plugin, key:%{public}s", key.c_str());
636 if (IsSameTextStr(key, ACTUAL_IMAGE_ENCODED_FORMAT)) {
637 HiLog::Error(LABEL, "[GetImagePropertyString] this key is used to check the original format of raw image!");
638 return Media::ERR_MEDIA_VALUE_INVALID;
639 }
640
641 if (!exifInfo_.IsExifDataParsed()) {
642 if (!ParseExifData()) {
643 HiLog::Error(LABEL, "[GetImagePropertyString] Parse exif data failed!");
644 return Media::ERROR;
645 }
646 }
647
648 if (IsSameTextStr(key, BITS_PER_SAMPLE)) {
649 value = exifInfo_.bitsPerSample_;
650 } else if (IsSameTextStr(key, ORIENTATION)) {
651 value = exifInfo_.orientation_;
652 } else if (IsSameTextStr(key, IMAGE_LENGTH)) {
653 value = exifInfo_.imageLength_;
654 } else if (IsSameTextStr(key, IMAGE_WIDTH)) {
655 value = exifInfo_.imageWidth_;
656 } else if (IsSameTextStr(key, GPS_LATITUDE)) {
657 value = exifInfo_.gpsLatitude_;
658 } else if (IsSameTextStr(key, GPS_LONGITUDE)) {
659 value = exifInfo_.gpsLongitude_;
660 } else if (IsSameTextStr(key, GPS_LATITUDE_REF)) {
661 value = exifInfo_.gpsLatitudeRef_;
662 } else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) {
663 value = exifInfo_.gpsLongitudeRef_;
664 } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) {
665 value = exifInfo_.dateTimeOriginal_;
666 } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL_MEDIA)) {
667 FormatTimeStamp(value, exifInfo_.dateTimeOriginal_);
668 } else if (IsSameTextStr(key, EXPOSURE_TIME)) {
669 value = exifInfo_.exposureTime_;
670 } else if (IsSameTextStr(key, F_NUMBER)) {
671 value = exifInfo_.fNumber_;
672 } else if (IsSameTextStr(key, ISO_SPEED_RATINGS)) {
673 value = exifInfo_.isoSpeedRatings_;
674 } else if (IsSameTextStr(key, SCENE_TYPE)) {
675 value = exifInfo_.sceneType_;
676 } else if (IsSameTextStr(key, COMPRESSED_BITS_PER_PIXEL)) {
677 value = exifInfo_.compressedBitsPerPixel_;
678 } else {
679 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
680 }
681
682 if (IsSameTextStr(value, EXIFInfo::DEFAULT_EXIF_VALUE)) {
683 HiLog::Error(LABEL, "[GetImagePropertyString] enter jpeg plugin, ifd and entry are not matched!");
684 return Media::ERR_MEDIA_VALUE_INVALID;
685 }
686 HiLog::Debug(LABEL, "[GetImagePropertyString] enter jpeg plugin, value:%{public}s", value.c_str());
687 return Media::SUCCESS;
688 }
689
InitOriginalTimes(std::string & dataTime)690 void InitOriginalTimes(std::string &dataTime)
691 {
692 for (size_t i = 0; i < dataTime.size() && i < TIMES_LEN; i++) {
693 if ((dataTime[i] < '0' || dataTime[i] > '9') && dataTime[i] != ' ') {
694 if (i < DATE_LEN) {
695 dataTime[i] = '-';
696 } else {
697 dataTime[i] = ':';
698 }
699 }
700 }
701 }
702
SetOriginalTimes(std::string & dataTime)703 std::string SetOriginalTimes(std::string &dataTime)
704 {
705 InitOriginalTimes(dataTime);
706 std::string data = "";
707 std::string time = "";
708 std::string::size_type position = dataTime.find(" ");
709 if (position == dataTime.npos) {
710 data = dataTime;
711 if (data.find("-") == data.npos) {
712 data += "-01-01";
713 } else if (data.find_first_of("-") == data.find_last_of("-")) {
714 data += "-01";
715 }
716 time += " 00:00:00";
717 } else {
718 data = dataTime.substr(0, position);
719 time = dataTime.substr(position);
720 if (data.find("-") == data.npos) {
721 data += "-01-01";
722 } else if (data.find_first_of("-") == data.find_last_of("-")) {
723 data += "-01";
724 }
725 if (time.find(":") == data.npos) {
726 time += ":00:00";
727 } else if (time.find_first_of(":") == time.find_last_of(":")) {
728 time += ":00";
729 } else {
730 std::string timeTmp = time;
731 time = timeTmp.substr(0, time.find("."));
732 }
733 }
734 return data + time;
735 }
736
FormatTimeStamp(std::string & value,std::string & src)737 void JpegDecoder::FormatTimeStamp(std::string &value, std::string &src)
738 {
739 value = "";
740 if (!IsSameTextStr(src, "")) {
741 value = SetOriginalTimes(src);
742 }
743 }
744
getExifTagFromKey(const std::string & key)745 ExifTag JpegDecoder::getExifTagFromKey(const std::string &key)
746 {
747 if (IsSameTextStr(key, BITS_PER_SAMPLE)) {
748 return EXIF_TAG_BITS_PER_SAMPLE;
749 } else if (IsSameTextStr(key, ORIENTATION)) {
750 return EXIF_TAG_ORIENTATION;
751 } else if (IsSameTextStr(key, IMAGE_LENGTH)) {
752 return EXIF_TAG_IMAGE_LENGTH;
753 } else if (IsSameTextStr(key, IMAGE_WIDTH)) {
754 return EXIF_TAG_IMAGE_WIDTH;
755 } else if (IsSameTextStr(key, GPS_LATITUDE)) {
756 return EXIF_TAG_GPS_LATITUDE;
757 } else if (IsSameTextStr(key, GPS_LONGITUDE)) {
758 return EXIF_TAG_GPS_LONGITUDE;
759 } else if (IsSameTextStr(key, GPS_LATITUDE_REF)) {
760 return EXIF_TAG_GPS_LATITUDE_REF;
761 } else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) {
762 return EXIF_TAG_GPS_LONGITUDE_REF;
763 } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) {
764 return EXIF_TAG_DATE_TIME_ORIGINAL;
765 } else if (IsSameTextStr(key, EXPOSURE_TIME)) {
766 return EXIF_TAG_EXPOSURE_TIME;
767 } else if (IsSameTextStr(key, F_NUMBER)) {
768 return EXIF_TAG_FNUMBER;
769 } else if (IsSameTextStr(key, ISO_SPEED_RATINGS)) {
770 return EXIF_TAG_ISO_SPEED_RATINGS;
771 } else if (IsSameTextStr(key, SCENE_TYPE)) {
772 return EXIF_TAG_SCENE_TYPE;
773 } else if (IsSameTextStr(key, COMPRESSED_BITS_PER_PIXEL)) {
774 return EXIF_TAG_COMPRESSED_BITS_PER_PIXEL;
775 } else {
776 return EXIF_TAG_PRINT_IMAGE_MATCHING;
777 }
778 }
779
ModifyImageProperty(uint32_t index,const std::string & key,const std::string & value,const std::string & path)780 uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
781 const std::string &value, const std::string &path)
782 {
783 HiLog::Debug(LABEL, "[ModifyImageProperty] with path:%{public}s, key:%{public}s, value:%{public}s",
784 path.c_str(), key.c_str(), value.c_str());
785 ExifTag tag = getExifTagFromKey(key);
786 if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
787 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
788 }
789
790 uint32_t ret = exifInfo_.ModifyExifData(tag, value, path);
791 if (ret != Media::SUCCESS) {
792 return ret;
793 }
794 return Media::SUCCESS;
795 }
796
ModifyImageProperty(uint32_t index,const std::string & key,const std::string & value,const int fd)797 uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
798 const std::string &value, const int fd)
799 {
800 HiLog::Debug(LABEL, "[ModifyImageProperty] with fd:%{public}d, key:%{public}s, value:%{public}s",
801 fd, key.c_str(), value.c_str());
802 ExifTag tag = getExifTagFromKey(key);
803 if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
804 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
805 }
806
807 uint32_t ret = exifInfo_.ModifyExifData(tag, value, fd);
808 if (ret != Media::SUCCESS) {
809 return ret;
810 }
811 return Media::SUCCESS;
812 }
813
ModifyImageProperty(uint32_t index,const std::string & key,const std::string & value,uint8_t * data,uint32_t size)814 uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
815 const std::string &value, uint8_t *data, uint32_t size)
816 {
817 HiLog::Debug(LABEL, "[ModifyImageProperty] with key:%{public}s, value:%{public}s",
818 key.c_str(), value.c_str());
819 ExifTag tag = getExifTagFromKey(key);
820 if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
821 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
822 }
823
824 uint32_t ret = exifInfo_.ModifyExifData(tag, value, data, size);
825 if (ret != Media::SUCCESS) {
826 return ret;
827 }
828 return Media::SUCCESS;
829 }
830
GetFilterArea(const int & privacyType,std::vector<std::pair<uint32_t,uint32_t>> & ranges)831 uint32_t JpegDecoder::GetFilterArea(const int &privacyType, std::vector<std::pair<uint32_t, uint32_t>> &ranges)
832 {
833 HiLog::Debug(LABEL, "[GetFilterArea] with privacyType:%{public}d ", privacyType);
834 if (srcMgr_.inputStream == nullptr) {
835 HiLog::Error(LABEL, "[GetFilterArea] srcMgr_.inputStream is nullptr.");
836 return Media::ERR_MEDIA_INVALID_OPERATION;
837 }
838 uint32_t curPos = srcMgr_.inputStream->Tell();
839 srcMgr_.inputStream->Seek(ADDRESS_4);
840 // app1SizeBuf is used to get value of EXIF data size
841 uint8_t *app1SizeBuf = new uint8_t[JPEG_APP1_SIZE];
842 uint32_t readSize = 0;
843 if (!srcMgr_.inputStream->Read(JPEG_APP1_SIZE, app1SizeBuf, JPEG_APP1_SIZE, readSize)) {
844 HiLog::Error(LABEL, "[GetFilterArea] get app1 size failed.");
845 return Media::ERR_MEDIA_INVALID_OPERATION;
846 }
847 uint32_t app1Size =
848 static_cast<unsigned int>(app1SizeBuf[1]) | static_cast<unsigned int>(app1SizeBuf[0] << OFFSET_8);
849 delete[] app1SizeBuf;
850 uint32_t fsize = static_cast<uint32_t>(srcMgr_.inputStream->GetStreamSize());
851 if (app1Size > fsize) {
852 HiLog::Error(LABEL, "[GetFilterArea] file format is illegal.");
853 return Media::ERR_MEDIA_INVALID_OPERATION;
854 }
855
856 srcMgr_.inputStream->Seek(0);
857 uint32_t bufSize = app1Size + ADDRESS_4;
858 // buf is from image file head to exif data end
859 uint8_t *buf = new uint8_t[bufSize];
860 srcMgr_.inputStream->Read(bufSize, buf, bufSize, readSize);
861 uint32_t ret = exifInfo_.GetFilterArea(buf, bufSize, privacyType, ranges);
862 delete[] buf;
863 srcMgr_.inputStream->Seek(curPos);
864 if (ret != Media::SUCCESS) {
865 HiLog::Error(LABEL, "[GetFilterArea]: failed to get area, errno %{public}d", ret);
866 return ret;
867 }
868 return Media::SUCCESS;
869 }
870
871 #ifdef IMAGE_COLORSPACE_FLAG
getGrColorSpace()872 OHOS::ColorManager::ColorSpace JpegDecoder::getGrColorSpace()
873 {
874 OHOS::ColorManager::ColorSpace grColorSpace = iccProfileInfo_.getGrColorSpace();
875 return grColorSpace;
876 }
877
IsSupportICCProfile()878 bool JpegDecoder::IsSupportICCProfile()
879 {
880 bool isSupportICCProfile = iccProfileInfo_.IsSupportICCProfile();
881 return isSupportICCProfile;
882 }
883 #endif
884 } // namespace ImagePlugin
885 } // namespace OHOS
886