• 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 #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