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