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 #include "jpeg_decoder.h"
16
17 #include "jerror.h"
18 #include "media_errors.h"
19 #include "string_ex.h"
20 #ifndef _WIN32
21 #include "securec.h"
22 #else
23 #include "memory.h"
24 #endif
25
26 namespace OHOS {
27 namespace ImagePlugin {
28 using namespace OHOS::HiviewDFX;
29 using namespace MultimediaPlugin;
30 using namespace Media;
31 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegDecoder" };
32 namespace {
33 constexpr uint32_t NUM_100 = 100;
34 constexpr uint32_t PIXEL_BYTES_RGB_565 = 2;
35 constexpr uint32_t MARKER_SIZE = 2;
36 constexpr uint32_t MARKER_LENGTH = 2;
37 constexpr uint8_t MARKER_LENGTH_0_OFFSET = 0;
38 constexpr uint8_t MARKER_LENGTH_1_OFFSET = 1;
39 constexpr uint32_t MARKER_LENGTH_SHIFT = 8;
40 constexpr uint8_t JPG_MARKER_PREFIX_OFFSET = 0;
41 constexpr uint8_t JPG_MARKER_CODE_OFFSET = 1;
42 constexpr uint8_t JPG_MARKER_PREFIX = 0XFF;
43 constexpr uint8_t JPG_MARKER_SOI = 0XD8;
44 constexpr uint8_t JPG_MARKER_SOS = 0XDA;
45 constexpr uint8_t JPG_MARKER_RST = 0XD0;
46 constexpr uint8_t JPG_MARKER_RST0 = 0XD0;
47 constexpr uint8_t JPG_MARKER_RSTN = 0XD7;
48 constexpr uint8_t JPG_MARKER_APP = 0XE0;
49 constexpr uint8_t JPG_MARKER_APP0 = 0XE0;
50 constexpr uint8_t JPG_MARKER_APPN = 0XEF;
51 const std::string BITS_PER_SAMPLE = "BitsPerSample";
52 const std::string ORIENTATION = "Orientation";
53 const std::string IMAGE_LENGTH = "ImageLength";
54 const std::string IMAGE_WIDTH = "ImageWidth";
55 const std::string GPS_LATITUDE = "GPSLatitude";
56 const std::string GPS_LONGITUDE = "GPSLongitude";
57 const std::string GPS_LATITUDE_REF = "GPSLatitudeRef";
58 const std::string GPS_LONGITUDE_REF = "GPSLongitudeRef";
59 const std::string DATE_TIME_ORIGINAL = "DateTimeOriginal";
60 } // namespace
61
62 PluginServer &JpegDecoder::pluginServer_ = DelayedRefSingleton<PluginServer>::GetInstance();
63
JpegSrcMgr(InputDataStream * stream)64 JpegSrcMgr::JpegSrcMgr(InputDataStream *stream) : inputStream(stream)
65 {
66 init_source = InitSrcStream;
67 fill_input_buffer = FillInputBuffer;
68 skip_input_data = SkipInputData;
69 resync_to_restart = jpeg_resync_to_restart;
70 term_source = TermSrcStream;
71 }
72
JpegDecoder()73 JpegDecoder::JpegDecoder() : srcMgr_(nullptr)
74 {
75 CreateDecoder();
76 #if !defined(_WIN32) && !defined(_APPLE)
77 CreateHwDecompressor();
78 #endif
79 }
80
CreateDecoder()81 void JpegDecoder::CreateDecoder()
82 {
83 // create decompress struct
84 jpeg_create_decompress(&decodeInfo_);
85
86 // set error output
87 decodeInfo_.err = jpeg_std_error(&jerr_);
88 jerr_.error_exit = ErrorExit;
89 if (decodeInfo_.err == nullptr) {
90 HiLog::Error(LABEL, "create jpeg decoder failed.");
91 return;
92 }
93 decodeInfo_.err->output_message = &OutputErrorMessage;
94 }
95
~JpegDecoder()96 JpegDecoder::~JpegDecoder()
97 {
98 jpeg_destroy_decompress(&decodeInfo_);
99 if (hwJpegDecompress_ != nullptr) {
100 delete hwJpegDecompress_;
101 hwJpegDecompress_ = nullptr;
102 }
103 }
104
SetSource(InputDataStream & sourceStream)105 void JpegDecoder::SetSource(InputDataStream &sourceStream)
106 {
107 srcMgr_.inputStream = &sourceStream;
108 state_ = JpegDecodingState::SOURCE_INITED;
109 HiLog::Error(LABEL, "SetSource ExifPrintMethod");
110 ExifPrintMethod();
111 }
112
ExifPrintMethod()113 int JpegDecoder::ExifPrintMethod()
114 {
115 HiLog::Debug(LABEL, "ExifPrintMethod enter");
116 srcMgr_.inputStream->Seek(0);
117 unsigned long fsize = 0;
118 fsize = static_cast<unsigned long>(srcMgr_.inputStream->GetStreamSize());
119 unsigned char *buf = new unsigned char[fsize];
120 uint32_t readSize = 0;
121 srcMgr_.inputStream->Read(fsize, buf, fsize, readSize);
122 HiLog::Debug(LABEL, "parsing EXIF: fsize %{public}lu", fsize);
123 HiLog::Debug(LABEL, "parsing EXIF: readSize %{public}u", readSize);
124
125 int code = exifInfo_.ParseExifData(buf, fsize);
126 delete[] buf;
127 if (code) {
128 HiLog::Error(LABEL, "Error parsing EXIF: code %{public}d", code);
129 return ERR_MEDIA_VALUE_INVALID;
130 }
131
132 return Media::SUCCESS;
133 }
134
GetImageSize(uint32_t index,PlSize & size)135 uint32_t JpegDecoder::GetImageSize(uint32_t index, PlSize &size)
136 {
137 if (index >= JPEG_IMAGE_NUM) {
138 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
139 return ERR_IMAGE_INVALID_PARAMETER;
140 }
141 if (state_ < JpegDecodingState::SOURCE_INITED) {
142 HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_);
143 return ERR_MEDIA_INVALID_OPERATION;
144 }
145 if (state_ >= JpegDecodingState::BASE_INFO_PARSED) {
146 size.width = decodeInfo_.image_width;
147 size.height = decodeInfo_.image_height;
148 return Media::SUCCESS;
149 }
150 // only state JpegDecodingState::SOURCE_INITED and JpegDecodingState::BASE_INFO_PARSING can go here.
151 uint32_t ret = DecodeHeader();
152 if (ret != Media::SUCCESS) {
153 HiLog::Error(LABEL, "decode header error on get image size, ret:%{public}u.", ret);
154 state_ = JpegDecodingState::BASE_INFO_PARSING;
155 return ret;
156 }
157 size.width = decodeInfo_.image_width;
158 size.height = decodeInfo_.image_height;
159 state_ = JpegDecodingState::BASE_INFO_PARSED;
160 return Media::SUCCESS;
161 }
162
GetDecodeFormat(PlPixelFormat format,PlPixelFormat & outputFormat)163 J_COLOR_SPACE JpegDecoder::GetDecodeFormat(PlPixelFormat format, PlPixelFormat &outputFormat)
164 {
165 outputFormat = format;
166 J_COLOR_SPACE colorSpace = JCS_UNKNOWN;
167 switch (format) {
168 case PlPixelFormat::UNKNOWN:
169 case PlPixelFormat::RGBA_8888: {
170 colorSpace = JCS_EXT_RGBA;
171 outputFormat = PlPixelFormat::RGBA_8888;
172 break;
173 }
174 case PlPixelFormat::BGRA_8888: {
175 colorSpace = JCS_EXT_BGRA;
176 outputFormat = PlPixelFormat::BGRA_8888;
177 break;
178 }
179 case PlPixelFormat::ARGB_8888: {
180 colorSpace = JCS_EXT_ARGB;
181 break;
182 }
183 case PlPixelFormat::ALPHA_8: {
184 colorSpace = JCS_GRAYSCALE;
185 break;
186 }
187 case PlPixelFormat::RGB_565: {
188 colorSpace = JCS_RGB565;
189 break;
190 }
191 case PlPixelFormat::RGB_888: {
192 colorSpace = JCS_RGB;
193 break;
194 }
195 default: {
196 colorSpace = JCS_EXT_RGBA;
197 outputFormat = PlPixelFormat::RGBA_8888;
198 break;
199 }
200 }
201 return colorSpace;
202 }
203
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)204 uint32_t JpegDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
205 {
206 if (index >= JPEG_IMAGE_NUM) {
207 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
208 return ERR_IMAGE_INVALID_PARAMETER;
209 }
210 if (state_ < JpegDecodingState::SOURCE_INITED) {
211 HiLog::Error(LABEL, "set decode options failed for state %{public}d.", state_);
212 return ERR_MEDIA_INVALID_OPERATION;
213 }
214 if (state_ >= JpegDecodingState::IMAGE_DECODING) {
215 FinishOldDecompress();
216 state_ = JpegDecodingState::SOURCE_INITED;
217 }
218 if (state_ < JpegDecodingState::BASE_INFO_PARSED) {
219 uint32_t ret = DecodeHeader();
220 if (ret != Media::SUCCESS) {
221 state_ = JpegDecodingState::BASE_INFO_PARSING;
222 HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret);
223 return ret;
224 }
225 state_ = JpegDecodingState::BASE_INFO_PARSED;
226 }
227 // only state JpegDecodingState::BASE_INFO_PARSED can go here.
228 uint32_t ret = StartDecompress(opts);
229 if (ret != Media::SUCCESS) {
230 HiLog::Error(LABEL, "start decompress failed on set decode options:%{public}u.", ret);
231 return ret;
232 }
233 info.pixelFormat = outputFormat_;
234 info.size.width = decodeInfo_.output_width;
235 info.size.height = decodeInfo_.output_height;
236 info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
237 opts_ = opts;
238 state_ = JpegDecodingState::IMAGE_DECODING;
239 return Media::SUCCESS;
240 }
241
GetRowBytes()242 uint32_t JpegDecoder::GetRowBytes()
243 {
244 uint32_t pixelBytes =
245 (decodeInfo_.out_color_space == JCS_RGB565) ? PIXEL_BYTES_RGB_565 : decodeInfo_.out_color_components;
246 return decodeInfo_.output_width * pixelBytes;
247 }
248
DoSwDecode(DecodeContext & context)249 uint32_t JpegDecoder::DoSwDecode(DecodeContext &context)
250 {
251 if (setjmp(jerr_.setjmp_buffer)) {
252 HiLog::Error(LABEL, "decode image failed.");
253 return ERR_IMAGE_DECODE_ABNORMAL;
254 }
255 uint32_t rowStride = GetRowBytes();
256 if (context.pixelsBuffer.buffer == nullptr) {
257 uint64_t byteCount = static_cast<uint64_t>(rowStride) * decodeInfo_.output_height;
258 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
259 #if !defined(_WIN32) && !defined(_APPLE)
260 int fd = AshmemCreate("JPEG RawData", byteCount);
261 if (fd < 0) {
262 return ERR_SHAMEM_DATA_ABNORMAL;
263 }
264 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
265 if (result < 0) {
266 ::close(fd);
267 return ERR_SHAMEM_DATA_ABNORMAL;
268 }
269 void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
270 if (ptr == MAP_FAILED) {
271 ::close(fd);
272 return ERR_SHAMEM_DATA_ABNORMAL;
273 }
274 context.pixelsBuffer.buffer = ptr;
275 void *fdBuffer = new int32_t();
276 if (fdBuffer == nullptr) {
277 HiLog::Error(LABEL, "new fdBuffer fail");
278 ::munmap(ptr, byteCount);
279 ::close(fd);
280 context.pixelsBuffer.buffer = nullptr;
281 return ERR_SHAMEM_DATA_ABNORMAL;
282 }
283 *static_cast<int32_t *>(fdBuffer) = fd;
284 context.pixelsBuffer.context = fdBuffer;
285 context.pixelsBuffer.bufferSize = byteCount;
286 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
287 context.freeFunc = nullptr;
288 #endif
289 } else {
290 void *outputBuffer = malloc(byteCount);
291 if (outputBuffer == nullptr) {
292 HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.",
293 static_cast<unsigned long long>(byteCount));
294 return ERR_IMAGE_MALLOC_ABNORMAL;
295 }
296 context.pixelsBuffer.buffer = outputBuffer;
297 context.pixelsBuffer.context = nullptr;
298 context.pixelsBuffer.bufferSize = byteCount;
299 context.allocatorType = AllocatorType::HEAP_ALLOC;
300 context.freeFunc = nullptr;
301 }
302 }
303 uint8_t *base = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
304 if (base == nullptr) {
305 HiLog::Error(LABEL, "decode image buffer is null.");
306 return ERR_IMAGE_INVALID_PARAMETER;
307 }
308 srcMgr_.inputStream->Seek(streamPosition_);
309 uint8_t *buffer = nullptr;
310 while (decodeInfo_.output_scanline < decodeInfo_.output_height) {
311 buffer = base + rowStride * decodeInfo_.output_scanline;
312 uint32_t readLineNum = jpeg_read_scanlines(&decodeInfo_, &buffer, RW_LINE_NUM);
313 if (readLineNum < RW_LINE_NUM) {
314 streamPosition_ = srcMgr_.inputStream->Tell();
315 HiLog::Error(LABEL, "read line fail, read num:%{public}u, total read num:%{public}u.", readLineNum,
316 decodeInfo_.output_scanline);
317 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
318 }
319 }
320 streamPosition_ = srcMgr_.inputStream->Tell();
321 return Media::SUCCESS;
322 }
323
Decode(uint32_t index,DecodeContext & context)324 uint32_t JpegDecoder::Decode(uint32_t index, DecodeContext &context)
325 {
326 if (index >= JPEG_IMAGE_NUM) {
327 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
328 return ERR_IMAGE_INVALID_PARAMETER;
329 }
330 if (state_ < JpegDecodingState::IMAGE_DECODING) {
331 HiLog::Error(LABEL, "decode failed for state %{public}d.", state_);
332 return ERR_MEDIA_INVALID_OPERATION;
333 }
334 if (state_ > JpegDecodingState::IMAGE_DECODING) {
335 FinishOldDecompress();
336 state_ = JpegDecodingState::SOURCE_INITED;
337 uint32_t ret = DecodeHeader();
338 if (ret != Media::SUCCESS) {
339 state_ = JpegDecodingState::BASE_INFO_PARSING;
340 HiLog::Error(LABEL, "decode header error on decode:%{public}u.", ret);
341 return ret;
342 }
343 state_ = JpegDecodingState::BASE_INFO_PARSED;
344 ret = StartDecompress(opts_);
345 if (ret != Media::SUCCESS) {
346 HiLog::Error(LABEL, "start decompress failed on decode:%{public}u.", ret);
347 return ret;
348 }
349 state_ = JpegDecodingState::IMAGE_DECODING;
350 }
351 // only state JpegDecodingState::IMAGE_DECODING can go here.
352 if (hwJpegDecompress_ != nullptr) {
353 srcMgr_.inputStream->Seek(streamPosition_);
354 uint32_t ret = hwJpegDecompress_->Decompress(&decodeInfo_, srcMgr_.inputStream, context);
355 if (ret == Media::SUCCESS) {
356 state_ = JpegDecodingState::IMAGE_DECODED;
357 HiLog::Debug(LABEL, "jpeg hardware decode success.");
358 return ret;
359 }
360 }
361 uint32_t ret = DoSwDecode(context);
362 if (ret == Media::SUCCESS) {
363 state_ = JpegDecodingState::IMAGE_DECODED;
364 HiLog::Debug(LABEL, "jpeg software decode success.");
365 return Media::SUCCESS;
366 }
367 if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && opts_.allowPartialImage) {
368 state_ = JpegDecodingState::IMAGE_PARTIAL;
369 context.ifPartialOutput = true;
370 return Media::SUCCESS;
371 }
372 state_ = JpegDecodingState::IMAGE_ERROR;
373 return ret;
374 }
375
Reset()376 void JpegDecoder::Reset()
377 {
378 srcMgr_.inputStream = nullptr;
379 }
380
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & progContext)381 uint32_t JpegDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &progContext)
382 {
383 progContext.totalProcessProgress = 0;
384 if (index >= JPEG_IMAGE_NUM) {
385 HiLog::Error(LABEL, "decode image index:[%{public}u] out of range:[%{public}u].", index, JPEG_IMAGE_NUM);
386 return ERR_IMAGE_INVALID_PARAMETER;
387 }
388 if (state_ != JpegDecodingState::IMAGE_DECODING) {
389 HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_);
390 return ERR_MEDIA_INVALID_OPERATION;
391 }
392
393 uint32_t ret = DoSwDecode(progContext.decodeContext);
394 if (ret == Media::SUCCESS) {
395 state_ = JpegDecodingState::IMAGE_DECODED;
396 }
397 // get promote decode progress, in percentage: 0~100.
398 progContext.totalProcessProgress =
399 decodeInfo_.output_height == 0 ? 0 : (decodeInfo_.output_scanline * NUM_100) / decodeInfo_.output_height;
400 HiLog::Debug(LABEL, "incremental decode progress %{public}u.", progContext.totalProcessProgress);
401 return ret;
402 }
403
CreateHwDecompressor()404 void JpegDecoder::CreateHwDecompressor()
405 {
406 std::map<std::string, AttrData> capabilities;
407 const std::string format = "image/jpeg";
408 capabilities.insert(std::map<std::string, AttrData>::value_type("encodeFormat", AttrData(format)));
409 hwJpegDecompress_ = pluginServer_.CreateObject<AbsImageDecompressComponent>(
410 AbsImageDecompressComponent::SERVICE_DEFAULT, capabilities);
411 if (hwJpegDecompress_ == nullptr) {
412 HiLog::Error(LABEL, "get hardware jpeg decompress component failed.");
413 return;
414 }
415 }
416
FinishOldDecompress()417 void JpegDecoder::FinishOldDecompress()
418 {
419 if (state_ < JpegDecodingState::IMAGE_DECODING) {
420 return;
421 }
422 jpeg_destroy_decompress(&decodeInfo_);
423 CreateDecoder();
424 }
425
IsMarker(uint8_t rawMarkerPrefix,uint8_t rawMarkderCode,uint8_t markerCode)426 bool JpegDecoder::IsMarker(uint8_t rawMarkerPrefix, uint8_t rawMarkderCode, uint8_t markerCode)
427 {
428 if (rawMarkerPrefix != JPG_MARKER_PREFIX) {
429 return false;
430 }
431
432 // RSTn, n from 0 to 7
433 if (rawMarkderCode >= JPG_MARKER_RST0 && rawMarkderCode <= JPG_MARKER_RSTN && markerCode == JPG_MARKER_RST) {
434 return true;
435 }
436
437 // APPn, n from 0 to 15
438 if (rawMarkderCode >= JPG_MARKER_APP0 && rawMarkderCode <= JPG_MARKER_APPN && markerCode == JPG_MARKER_APP) {
439 return true;
440 }
441
442 if (rawMarkderCode == markerCode) {
443 return true;
444 }
445 return false;
446 }
447
FindMarker(InputDataStream & stream,uint8_t marker)448 bool JpegDecoder::FindMarker(InputDataStream &stream, uint8_t marker)
449 {
450 uint8_t buffer[MARKER_SIZE] = { 0 };
451 uint32_t readSize = 0;
452 stream.Seek(0);
453 while (true) {
454 uint32_t cur = stream.Tell();
455 if (!stream.Seek(cur + MARKER_SIZE)) {
456 return false;
457 }
458 stream.Seek(cur);
459
460 // read marker code
461 stream.Read(MARKER_SIZE, buffer, sizeof(buffer), readSize);
462 if (readSize != MARKER_SIZE) {
463 return false;
464 }
465
466 uint8_t markerPrefix = buffer[JPG_MARKER_PREFIX_OFFSET];
467 uint8_t markerCode = buffer[JPG_MARKER_CODE_OFFSET];
468 if (IsMarker(markerPrefix, markerCode, JPG_MARKER_SOS)) {
469 return true;
470 }
471
472 if (IsMarker(markerPrefix, markerCode, JPG_MARKER_SOI) || IsMarker(markerPrefix, markerCode, JPG_MARKER_RST)) {
473 continue;
474 }
475
476 cur = stream.Tell();
477 if (!stream.Seek(cur + MARKER_LENGTH)) {
478 return false;
479 }
480 stream.Seek(cur);
481 // read marker length
482 stream.Read(MARKER_LENGTH, buffer, sizeof(buffer), readSize);
483 if (readSize != MARKER_LENGTH) {
484 return false;
485 }
486 // skip data, length = sizeof(length) + sizeof(data)
487 uint32_t length = (buffer[MARKER_LENGTH_0_OFFSET] << MARKER_LENGTH_SHIFT) + buffer[MARKER_LENGTH_1_OFFSET];
488 if (!stream.Seek(cur + length)) {
489 return false;
490 }
491 }
492 }
493
DecodeHeader()494 uint32_t JpegDecoder::DecodeHeader()
495 {
496 if (setjmp(jerr_.setjmp_buffer)) {
497 HiLog::Error(LABEL, "get image size failed.");
498 return ERR_IMAGE_DECODE_ABNORMAL;
499 }
500 if (state_ == JpegDecodingState::SOURCE_INITED) {
501 srcMgr_.inputStream->Seek(0);
502 } else {
503 srcMgr_.inputStream->Seek(streamPosition_);
504 }
505 decodeInfo_.src = &srcMgr_;
506
507 /**
508 * The function jpeg_read_header() shall read the JPEG datastream until the first SOS marker is encountered
509 * incremental decoding should have enough data(contains SOS marker) before calling jpeg_read_header.
510 */
511 if (!srcMgr_.inputStream->IsStreamCompleted()) {
512 uint32_t curPos = srcMgr_.inputStream->Tell();
513 while (true) {
514 if (!FindMarker(*srcMgr_.inputStream, JPG_MARKER_SOS)) {
515 srcMgr_.inputStream->Seek(curPos);
516 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
517 }
518 srcMgr_.inputStream->Seek(curPos);
519 break;
520 }
521 }
522
523 int32_t ret = jpeg_read_header(&decodeInfo_, false);
524 streamPosition_ = srcMgr_.inputStream->Tell();
525 if (ret == JPEG_SUSPENDED) {
526 HiLog::Debug(LABEL, "image input data incomplete, decode header error:%{public}u.", ret);
527 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
528 } else if (ret != JPEG_HEADER_OK) {
529 HiLog::Error(LABEL, "image type is not jpeg, decode header error:%{public}u.", ret);
530 return ERR_IMAGE_GET_DATA_ABNORMAL;
531 }
532 return Media::SUCCESS;
533 }
534
StartDecompress(const PixelDecodeOptions & opts)535 uint32_t JpegDecoder::StartDecompress(const PixelDecodeOptions &opts)
536 {
537 if (setjmp(jerr_.setjmp_buffer)) {
538 HiLog::Error(LABEL, "set output image info failed.");
539 return ERR_IMAGE_DECODE_ABNORMAL;
540 }
541 // set decode options
542 if (decodeInfo_.jpeg_color_space == JCS_CMYK || decodeInfo_.jpeg_color_space == JCS_YCCK) {
543 // can't support CMYK to alpha8 convert
544 if (opts.desiredPixelFormat == PlPixelFormat::ALPHA_8) {
545 HiLog::Error(LABEL, "can't support colorspace CMYK to alpha convert.");
546 return ERR_IMAGE_UNKNOWN_FORMAT;
547 }
548 HiLog::Debug(LABEL, "jpeg colorspace is CMYK.");
549 decodeInfo_.out_color_space = JCS_CMYK;
550 outputFormat_ = PlPixelFormat::CMYK;
551 } else {
552 decodeInfo_.out_color_space = GetDecodeFormat(opts.desiredPixelFormat, outputFormat_);
553 if (decodeInfo_.out_color_space == JCS_UNKNOWN) {
554 HiLog::Error(LABEL, "set jpeg output color space invalid.");
555 return ERR_IMAGE_UNKNOWN_FORMAT;
556 }
557 }
558 srcMgr_.inputStream->Seek(streamPosition_);
559 if (jpeg_start_decompress(&decodeInfo_) != TRUE) {
560 streamPosition_ = srcMgr_.inputStream->Tell();
561 HiLog::Error(LABEL, "jpeg start decompress failed, invalid input.");
562 return ERR_IMAGE_INVALID_PARAMETER;
563 }
564 streamPosition_ = srcMgr_.inputStream->Tell();
565 return Media::SUCCESS;
566 }
567
GetImagePropertyInt(uint32_t index,const std::string & key,int32_t & value)568 uint32_t JpegDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value)
569 {
570 HiLog::Error(LABEL, "[GetImagePropertyInt] enter jped plugin, key:%{public}s", key.c_str());
571 return Media::SUCCESS;
572 }
573
GetImagePropertyString(uint32_t index,const std::string & key,std::string & value)574 uint32_t JpegDecoder::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value)
575 {
576 HiLog::Error(LABEL, "[GetImagePropertyString] enter jped plugin, key:%{public}s", key.c_str());
577 if (IsSameTextStr(key, BITS_PER_SAMPLE)) {
578 value = exifInfo_.bitsPerSample_;
579 } else if (IsSameTextStr(key, ORIENTATION)) {
580 value = exifInfo_.orientation_;
581 } else if (IsSameTextStr(key, IMAGE_LENGTH)) {
582 value = exifInfo_.imageLength_;
583 } else if (IsSameTextStr(key, IMAGE_WIDTH)) {
584 value = exifInfo_.imageWidth_;
585 } else if (IsSameTextStr(key, GPS_LATITUDE)) {
586 value = exifInfo_.gpsLatitude_;
587 } else if (IsSameTextStr(key, GPS_LONGITUDE)) {
588 value = exifInfo_.gpsLongitude_;
589 } else if (IsSameTextStr(key, GPS_LATITUDE_REF)) {
590 value = exifInfo_.gpsLatitudeRef_;
591 } else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) {
592 value = exifInfo_.gpsLongitudeRef_;
593 } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) {
594 value = exifInfo_.dateTimeOriginal_;
595 } else {
596 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
597 }
598 HiLog::Error(LABEL, "[GetImagePropertyString] enter jped plugin, value:%{public}s", value.c_str());
599 return Media::SUCCESS;
600 }
601
getExifTagFromKey(const std::string & key,const std::string & value)602 ExifTag JpegDecoder::getExifTagFromKey(const std::string &key, const std::string &value)
603 {
604 if (IsSameTextStr(key, BITS_PER_SAMPLE)) {
605 exifInfo_.bitsPerSample_ = value;
606 return EXIF_TAG_BITS_PER_SAMPLE;
607 } else if (IsSameTextStr(key, ORIENTATION)) {
608 exifInfo_.orientation_ = value;
609 return EXIF_TAG_ORIENTATION;
610 } else if (IsSameTextStr(key, IMAGE_LENGTH)) {
611 exifInfo_.imageLength_ = value;
612 return EXIF_TAG_IMAGE_LENGTH;
613 } else if (IsSameTextStr(key, IMAGE_WIDTH)) {
614 exifInfo_.imageWidth_ = value;
615 return EXIF_TAG_IMAGE_WIDTH;
616 } else if (IsSameTextStr(key, GPS_LATITUDE)) {
617 exifInfo_.gpsLatitude_ = value;
618 return EXIF_TAG_GPS_LATITUDE;
619 } else if (IsSameTextStr(key, GPS_LONGITUDE)) {
620 exifInfo_.gpsLongitude_ = value;
621 return EXIF_TAG_GPS_LONGITUDE;
622 } else if (IsSameTextStr(key, GPS_LATITUDE_REF)) {
623 exifInfo_.gpsLatitudeRef_ = value;
624 return EXIF_TAG_GPS_LATITUDE_REF;
625 } else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) {
626 exifInfo_.gpsLongitudeRef_ = value;
627 return EXIF_TAG_GPS_LONGITUDE_REF;
628 } else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) {
629 exifInfo_.dateTimeOriginal_ = value;
630 return EXIF_TAG_DATE_TIME_ORIGINAL;
631 } else {
632 return EXIF_TAG_PRINT_IMAGE_MATCHING;
633 }
634 }
635
ModifyImageProperty(uint32_t index,const std::string & key,const std::string & value,const std::string & path)636 uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
637 const std::string &value, const std::string &path)
638 {
639 HiLog::Error(LABEL, "[ModifyImageProperty] enter jped plugin, key:%{public}s, value:%{public}s",
640 key.c_str(), value.c_str());
641 ExifTag tag = getExifTagFromKey(key, value);
642 if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
643 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
644 }
645
646 if (!exifInfo_.ModifyExifData(tag, value, path)) {
647 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
648 }
649 return Media::SUCCESS;
650 }
651 } // namespace ImagePlugin
652 } // namespace OHOS
653