• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 "heif_parser.h"
17 #include "box/item_property_aux_box.h"
18 #include "box/item_property_basic_box.h"
19 #include "box/item_property_display_box.h"
20 #include "box/item_property_transform_box.h"
21 #include "securec.h"
22 
23 #include <algorithm>
24 #include <limits>
25 #include <cstring>
26 #include <set>
27 
28 namespace OHOS {
29 namespace ImagePlugin {
30 
31 const auto EXIF_ID = "Exif\0\0";
32 const auto HEIF_AUXTTYPE_ID_FRAGMENT_MAP = "urn:com:huawei:photo:5:0:0:aux:fragmentmap";
33 const std::set<std::string> INFE_ITEM_TYPE = {
34     "hvc1", "grid", "tmap", "iden", "mime"
35 };
36 const static uint32_t HEIF_MAX_EXIF_SIZE = 128 * 1024;
37 
38 HeifParser::HeifParser() = default;
39 
40 HeifParser::~HeifParser() = default;
41 
MakeFromMemory(const void * data,size_t size,bool isNeedCopy,std::shared_ptr<HeifParser> * out)42 heif_error HeifParser::MakeFromMemory(const void *data, size_t size, bool isNeedCopy, std::shared_ptr<HeifParser> *out)
43 {
44     if (data == nullptr) {
45         return heif_error_no_data;
46     }
47     auto input_stream = std::make_shared<HeifBufferInputStream>((const uint8_t *) data, size, isNeedCopy);
48     return MakeFromStream(input_stream, out);
49 }
50 
MakeFromStream(const std::shared_ptr<HeifInputStream> & stream,std::shared_ptr<HeifParser> * out)51 heif_error HeifParser::MakeFromStream(const std::shared_ptr<HeifInputStream> &stream, std::shared_ptr<HeifParser> *out)
52 {
53     if (stream == nullptr) {
54         return heif_error_no_data;
55     }
56     std::shared_ptr<HeifParser> file = std::make_shared<HeifParser>(stream);
57 
58     auto maxSize = static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
59     HeifStreamReader reader(stream, 0, maxSize);
60 
61     heif_error errorBox = file->AssembleBoxes(reader);
62     if (errorBox != heif_error_ok) {
63         return errorBox;
64     }
65 
66     heif_error errorImage = file->AssembleImages();
67     if (errorImage != heif_error_ok) {
68         return errorImage;
69     }
70 
71     *out = std::move(file);
72     return errorBox;
73 }
74 
Write(HeifStreamWriter & writer)75 void HeifParser::Write(HeifStreamWriter &writer)
76 {
77     CheckExtentData();
78     for (auto &box: topBoxes_) {
79         box->InferAllFullBoxVersion();
80         box->Write(writer);
81     }
82 
83     ilocBox_->WriteMdatBox(writer);
84 }
85 
GetPrimaryItemId() const86 heif_item_id HeifParser::GetPrimaryItemId() const
87 {
88     return pitmBox_->GetItemId();
89 }
90 
GetAllItemId(std::vector<heif_item_id> & itemIdList) const91 void HeifParser::GetAllItemId(std::vector<heif_item_id> &itemIdList) const
92 {
93     for (const auto &infeBox: infeBoxes_) {
94         itemIdList.push_back(infeBox.second->GetItemId());
95     }
96 }
97 
AssembleBoxes(HeifStreamReader & reader)98 heif_error HeifParser::AssembleBoxes(HeifStreamReader &reader)
99 {
100     while (true) {
101         std::shared_ptr<HeifBox> box;
102         uint32_t recursionCount = 0;
103         heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
104         if (reader.IsAtEnd() || error == heif_error_eof) {
105             break;
106         }
107         if (error != heif_error_ok) {
108             return error;
109         }
110         if (box == nullptr) {
111             return heif_error_no_meta;
112         }
113         topBoxes_.push_back(box);
114         if (box->GetBoxType() == BOX_TYPE_META) {
115             metaBox_ = std::dynamic_pointer_cast<HeifMetaBox>(box);
116         }
117         if (box->GetBoxType() == BOX_TYPE_FTYP) {
118             ftypBox_ = std::dynamic_pointer_cast<HeifFtypBox>(box);
119         }
120     }
121 
122     if (!ftypBox_) {
123         return heif_error_no_ftyp;
124     }
125 
126     if (!metaBox_) {
127         return heif_error_no_meta;
128     }
129 
130     hdlrBox_ = metaBox_->GetChild<HeifHdlrBox>(BOX_TYPE_HDLR);
131     if (!hdlrBox_ || (hdlrBox_ && hdlrBox_->GetHandlerType() != HANDLER_TYPE_PICT)) {
132         return heif_error_invalid_handler;
133     }
134 
135     pitmBox_ = metaBox_->GetChild<HeifPtimBox>(BOX_TYPE_PITM);
136     if (!pitmBox_) {
137         return heif_error_no_pitm;
138     }
139 
140     iinfBox_ = metaBox_->GetChild<HeifIinfBox>(BOX_TYPE_IINF);
141     if (!iinfBox_) {
142         return heif_error_no_iinf;
143     }
144     std::vector<std::shared_ptr<HeifInfeBox>> infes = iinfBox_->GetChildren<HeifInfeBox>(BOX_TYPE_INFE);
145     for (auto &infe: infes) {
146         infeBoxes_.insert(std::make_pair(infe->GetItemId(), infe));
147     }
148 
149     irefBox_ = metaBox_->GetChild<HeifIrefBox>(BOX_TYPE_IREF);
150 
151     iprpBox_ = metaBox_->GetChild<HeifIprpBox>(BOX_TYPE_IPRP);
152     if (!iprpBox_) {
153         return heif_error_no_iprp;
154     }
155 
156     ipcoBox_ = iprpBox_->GetChild<HeifIpcoBox>(BOX_TYPE_IPCO);
157     if (!ipcoBox_) {
158         return heif_error_no_ipco;
159     }
160 
161     std::vector<std::shared_ptr<HeifIpmaBox>> ipmas = iprpBox_->GetChildren<HeifIpmaBox>(BOX_TYPE_IPMA);
162     if (ipmas.empty()) {
163         return heif_error_no_ipma;
164     }
165     ipmaBox_ = std::make_shared<HeifIpmaBox>();
166     for (auto &ipma : ipmas) {
167         ipmaBox_->MergeImpaBoxes(*ipma);
168     }
169     idatBox_ = metaBox_->GetChild<HeifIdatBox>(BOX_TYPE_IDAT);
170 
171     ilocBox_ = metaBox_->GetChild<HeifIlocBox>(BOX_TYPE_ILOC);
172     if (!ilocBox_) {
173         return heif_error_no_iloc;
174     }
175     return heif_error_ok;
176 }
177 
HasItemId(heif_item_id itemId) const178 bool HeifParser::HasItemId(heif_item_id itemId) const
179 {
180     return infeBoxes_.find(itemId) != infeBoxes_.end();
181 }
182 
GetItemType(heif_item_id itemId) const183 std::string HeifParser::GetItemType(heif_item_id itemId) const
184 {
185     auto infe_box = GetInfeBox(itemId);
186     if (!infe_box) {
187         return "";
188     }
189     return infe_box->GetItemType();
190 }
191 
GetItemContentType(heif_item_id itemId) const192 std::string HeifParser::GetItemContentType(heif_item_id itemId) const
193 {
194     auto infe_box = GetInfeBox(itemId);
195     if (!infe_box) {
196         return "";
197     }
198     return infe_box->GetContentType();
199 }
200 
GetItemUriType(heif_item_id itemId) const201 std::string HeifParser::GetItemUriType(heif_item_id itemId) const
202 {
203     auto infe_box = GetInfeBox(itemId);
204     if (!infe_box) {
205         return "";
206     }
207     return infe_box->GetItemUriType();
208 }
209 
210 
GetAllProperties(heif_item_id itemId,std::vector<std::shared_ptr<HeifBox>> & properties) const211 heif_error HeifParser::GetAllProperties(heif_item_id itemId, std::vector<std::shared_ptr<HeifBox>> &properties) const
212 {
213     if (!ipcoBox_) {
214         return heif_error_no_ipco;
215     }
216     if (!ipmaBox_) {
217         return heif_error_no_ipma;
218     }
219     return ipcoBox_->GetProperties(itemId, ipmaBox_, properties);
220 }
221 
GetGridLength(heif_item_id itemId,size_t & length)222 heif_error HeifParser::GetGridLength(heif_item_id itemId, size_t &length)
223 {
224     if (!HasItemId(itemId)) {
225         return heif_error_item_not_found;
226     }
227     auto items = ilocBox_->GetItems();
228     const HeifIlocBox::Item *ilocItem = nullptr;
229     auto iter = std::find_if(items.begin(), items.end(), [&itemId](const auto &item) {
230         return item.itemId == itemId;
231     });
232     if (iter != items.end()) {
233         ilocItem = &*iter;
234     } else {
235         return heif_error_item_data_not_found;
236     }
237     return ilocBox_->GetIlocDataLength(*ilocItem, length);
238 }
239 
GetItemData(heif_item_id itemId,std::vector<uint8_t> * out,heif_header_option option) const240 heif_error HeifParser::GetItemData(heif_item_id itemId, std::vector<uint8_t> *out, heif_header_option option) const
241 {
242     if (!HasItemId(itemId)) {
243         return heif_error_item_not_found;
244     }
245 
246     auto infe_box = GetInfeBox(itemId);
247     if (!infe_box) {
248         return heif_error_item_not_found;
249     }
250 
251     std::string item_type = infe_box->GetItemType();
252     const auto& items = ilocBox_->GetItems();
253     const HeifIlocBox::Item *ilocItem = nullptr;
254     for (const auto &item: items) {
255         if (item.itemId == itemId) {
256             ilocItem = &item;
257             break;
258         }
259     }
260     if (!ilocItem) {
261         return heif_error_item_data_not_found;
262     }
263 
264     heif_error error;
265     if (item_type == "hvc1") {
266         auto hvcc = GetProperty<HeifHvccBox>(itemId);
267         if (!hvcc) {
268             return heif_error_no_hvcc;
269         }
270         if (option != heif_no_header && !hvcc->GetHeaders(out)) {
271             return heif_error_item_data_not_found;
272         }
273         if (option != heif_only_header) {
274             error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
275         } else {
276             error = heif_error_ok;
277         }
278     } else {
279         error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
280     }
281 
282     return error;
283 }
284 
GetTileImages(heif_item_id gridItemId,std::vector<std::shared_ptr<HeifImage>> & out)285 void HeifParser::GetTileImages(heif_item_id gridItemId, std::vector<std::shared_ptr<HeifImage>> &out)
286 {
287     auto infe = GetInfeBox(gridItemId);
288     if (!infe || infe->GetItemType() != "grid") {
289         return;
290     }
291     if (!irefBox_) {
292         return;
293     }
294     auto toItemIds = irefBox_->GetReferences(gridItemId, BOX_TYPE_DIMG);
295     for (heif_item_id toItemId: toItemIds) {
296         auto tileImage = GetImage(toItemId);
297         if (tileImage) {
298             out.push_back(tileImage);
299         }
300     }
301 }
302 
GetIdenImage(heif_item_id itemId,std::shared_ptr<HeifImage> & out)303 void HeifParser::GetIdenImage(heif_item_id itemId, std::shared_ptr<HeifImage> &out)
304 {
305     auto infe = GetInfeBox(itemId);
306     if (!infe || infe->GetItemType() != "iden") {
307         return;
308     }
309     if (!irefBox_) {
310         return;
311     }
312     auto toItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
313     for (heif_item_id toItemId: toItemIds) {
314         auto idenImage = GetImage(toItemId);
315         if (idenImage) {
316             out = idenImage;
317             return;
318         }
319     }
320 }
321 
GetInfeBox(heif_item_id itemId) const322 std::shared_ptr<HeifInfeBox> HeifParser::GetInfeBox(heif_item_id itemId) const
323 {
324     auto iter = infeBoxes_.find(itemId);
325     if (iter == infeBoxes_.end()) {
326         return nullptr;
327     }
328     return iter->second;
329 }
330 
AssembleImages()331 heif_error HeifParser::AssembleImages()
332 {
333     images_.clear();
334     primaryImage_.reset();
335 
336     std::vector<heif_item_id> allItemIds;
337     GetAllItemId(allItemIds);
338 
339     for (heif_item_id itemId: allItemIds) {
340         // extract Image Item
341         auto infe = GetInfeBox(itemId);
342         if (!infe) {
343             continue;
344         }
345         const std::string& itemType = infe->GetItemType();
346         if (INFE_ITEM_TYPE.find(itemType) == INFE_ITEM_TYPE.end()) {
347             continue;
348         }
349         auto image = std::make_shared<HeifImage>(itemId);
350         if (itemType == "tmap") {
351             tmapImage_ = image;
352             ExtractImageProperties(tmapImage_);
353             continue;
354         }
355         images_.insert(std::make_pair(itemId, image));
356         if (!infe->IsHidden() && itemId == GetPrimaryItemId()) {
357             image->SetPrimaryImage(true);
358             primaryImage_ = image;
359         }
360 
361         ExtractImageProperties(image);
362     }
363 
364     if (!primaryImage_) {
365         return heif_error_primary_item_not_found;
366     }
367 
368     ExtractGainmap(allItemIds);
369     ExtractDerivedImageProperties();
370     ExtractNonMasterImages();
371     ExtractMetadata(allItemIds);
372     return heif_error_ok;
373 }
374 
ExtractIT35Metadata(const heif_item_id & metadataItemId)375 void HeifParser::ExtractIT35Metadata(const heif_item_id& metadataItemId)
376 {
377     if (GetItemType(metadataItemId) != "it35") {
378         return;
379     }
380     std::vector<uint8_t> extendInfo;
381     heif_error err = GetItemData(metadataItemId, &(extendInfo));
382     if (err != heif_error_ok || extendInfo.empty()) {
383         return;
384     }
385     primaryImage_->SetUWAInfo(extendInfo);
386 }
387 
ExtractISOMetadata(const heif_item_id & itemId)388 void HeifParser::ExtractISOMetadata(const heif_item_id& itemId)
389 {
390     if (GetItemType(itemId) != "tmap") {
391         return;
392     }
393     std::vector<uint8_t> extendInfo;
394     heif_error err = GetItemData(itemId, &extendInfo);
395     if (err != heif_error_ok || extendInfo.empty()) {
396         return ;
397     }
398     primaryImage_->SetISOMetadata(extendInfo);
399 }
400 
ExtractFragmentMetadata(const heif_item_id & itemId)401 void HeifParser::ExtractFragmentMetadata(const heif_item_id& itemId)
402 {
403     HeifFragmentMetadata extendInfo;
404     auto ispe = GetProperty<HeifIspeBox>(itemId);
405     if (ispe) {
406         extendInfo.width = ispe->GetWidth();
407         extendInfo.height = ispe->GetHeight();
408     }
409     auto rloc = GetProperty<HeifRlocBox>(itemId);
410     if (rloc) {
411         extendInfo.horizontalOffset = rloc->GetX();
412         extendInfo.verticalOffset = rloc->GetY();
413     }
414     primaryImage_->SetFragmentMetadata(extendInfo);
415 }
416 
ExtractDisplayData(std::shared_ptr<HeifImage> & image,heif_item_id & itemId)417 void HeifParser::ExtractDisplayData(std::shared_ptr<HeifImage>& image, heif_item_id& itemId)
418 {
419     auto mdcv = GetProperty<HeifMdcvBox>(itemId);
420     auto clli = GetProperty<HeifClliBox>(itemId);
421     if (mdcv == nullptr && clli == nullptr) {
422         return;
423     }
424     DisplayColourVolume displayColourVolume{};
425     ContentLightLevelInfo lightInfo{};
426     uint32_t displaySize = sizeof(DisplayColourVolume);
427     std::vector<uint8_t> displayVec(displaySize);
428     if (mdcv) {
429         displayColourVolume = mdcv->GetColourVolume();
430         if (memcpy_s(displayVec.data(), displaySize, &displayColourVolume, displaySize) != EOK) {
431             displayVec.resize(0);
432         }
433     }
434 
435     uint32_t lightInfoSize = sizeof(ContentLightLevelInfo);
436     std::vector<uint8_t> lightInfoVec(lightInfoSize);
437     if (clli) {
438         lightInfo = clli->GetLightLevel();
439         if (memcpy_s(lightInfoVec.data(), lightInfoSize, &lightInfo, lightInfoSize) != EOK) {
440             lightInfoVec.resize(0);
441         }
442     }
443 
444     image->SetStaticMetadata(displayVec, lightInfoVec);
445 }
446 
ExtractGainmap(const std::vector<heif_item_id> & allItemIds)447 void HeifParser::ExtractGainmap(const std::vector<heif_item_id>& allItemIds)
448 {
449     for (heif_item_id itemId: allItemIds) {
450         // extract Image Item
451         auto infe = GetInfeBox(itemId);
452         if (!infe) {
453             continue;
454         }
455         const std::string& itemType = infe->GetItemType();
456         if (itemType == "it35") {
457             ExtractIT35Metadata(itemId);
458         }
459         if (itemType == "tmap") {
460             ExtractISOMetadata(itemId);
461             ExtractGainmapImage(itemId);
462         }
463     }
464 }
465 
ExtractImageProperties(std::shared_ptr<HeifImage> & image)466 void HeifParser::ExtractImageProperties(std::shared_ptr<HeifImage> &image)
467 {
468     heif_item_id itemId = image->GetItemId();
469 
470     auto ispe = GetProperty<HeifIspeBox>(itemId);
471     if (ispe) {
472         uint32_t width = ispe->GetWidth();
473         uint32_t height = ispe->GetHeight();
474         image->SetOriginalSize(width, height);
475     }
476 
477     auto irot = GetProperty<HeifIrotBox>(itemId);
478     if (irot) {
479         image->SetRotateDegrees(irot->GetRotDegree());
480     }
481 
482     auto imir = GetProperty<HeifImirBox>(itemId);
483     if (imir) {
484         image->SetMirrorDirection(imir->GetDirection());
485     }
486 
487     auto colr = GetProperty<HeifColrBox>(itemId);
488     if (colr) {
489         auto profile = colr->GetColorProfile();
490         image->SetColorProfile(profile);
491     }
492 
493     auto pixi = GetProperty<HeifPixiBox>(itemId);
494     if (pixi && pixi->GetChannelNum() == 1) {
495         image->SetDefaultColorFormat(HeifColorFormat::MONOCHROME);
496         image->SetDefaultPixelFormat(HeifPixelFormat::MONOCHROME);
497     } else {
498         image->SetDefaultColorFormat(HeifColorFormat::YCBCR);
499         image->SetDefaultPixelFormat(HeifPixelFormat::UNDEFINED);
500     }
501 
502     auto hvcc = GetProperty<HeifHvccBox>(itemId);
503     if (hvcc) {
504         auto hvccConfig = hvcc->GetConfig();
505         image->SetLumaBitNum(hvccConfig.bitDepthLuma);
506         image->SetChromaBitNum(hvccConfig.bitDepthChroma);
507         image->SetDefaultPixelFormat((HeifPixelFormat) hvccConfig.chromaFormat);
508 
509         auto nalArrays = hvcc->GetNalArrays();
510         bool isGetFlag = hvcc->ParserHvccColorRangeFlag(nalArrays);
511         if (isGetFlag) {
512             auto spsConfig = hvcc->GetSpsConfig();
513             image->SetColorRangeFlag(static_cast<int>(spsConfig.videoRangeFlag));
514         }
515     }
516     ExtractDisplayData(image, itemId);
517 }
518 
ExtractDerivedImageProperties()519 void HeifParser::ExtractDerivedImageProperties()
520 {
521     for (auto &pair: images_) {
522         heif_item_id itemId = pair.first;
523         auto infe = GetInfeBox(itemId);
524         if (!infe || (infe->GetItemType() != "grid" && infe->GetItemType() != "iden")) {
525             continue;
526         }
527         auto &image = pair.second;
528         if (!irefBox_) {
529             return;
530         }
531         auto tileItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
532         if (tileItemIds.empty()) {
533             continue;
534         }
535         auto tileImage = GetImage(tileItemIds[0]);
536         if (tileImage == nullptr) {
537             continue;
538         }
539         if (image->GetLumaBitNum() < 0) {
540             image->SetLumaBitNum(tileImage->GetLumaBitNum());
541         }
542         if (image->GetChromaBitNum() < 0) {
543             image->SetChromaBitNum(tileImage->GetChromaBitNum());
544         }
545         if (image->GetDefaultPixelFormat() == HeifPixelFormat::UNDEFINED) {
546             image->SetDefaultPixelFormat(tileImage->GetDefaultPixelFormat());
547         }
548         if (image->GetDefaultColorFormat() == HeifColorFormat::UNDEDEFINED) {
549             image->SetDefaultColorFormat(tileImage->GetDefaultColorFormat());
550         }
551     }
552 }
553 
ExtractThumbnailImage(std::shared_ptr<HeifImage> & thumbnailImage,const HeifIrefBox::Reference & ref)554 void HeifParser::ExtractThumbnailImage(std::shared_ptr<HeifImage> &thumbnailImage, const HeifIrefBox::Reference &ref)
555 {
556     std::vector<heif_item_id> toItemIds = ref.toItemIds;
557     if (toItemIds.empty()) {
558         return;
559     }
560     heif_item_id masterItemId = toItemIds[0];
561     if (masterItemId == thumbnailImage->GetItemId()) {
562         return;
563     }
564     auto masterImage = GetImage(masterItemId);
565     if (!masterImage) {
566         return;
567     }
568 
569     thumbnailImage->SetThumbnailImage(masterItemId);
570     masterImage->AddThumbnailImage(thumbnailImage);
571 }
572 
ExtractAuxImage(std::shared_ptr<HeifImage> & auxImage,const HeifIrefBox::Reference & ref)573 void HeifParser::ExtractAuxImage(std::shared_ptr<HeifImage> &auxImage, const HeifIrefBox::Reference &ref)
574 {
575     std::vector<heif_item_id> toItemIds = ref.toItemIds;
576     if (toItemIds.empty()) {
577         return;
578     }
579     heif_item_id masterItemId = toItemIds[0];
580     heif_item_id auxItemId = auxImage->GetItemId();
581     if (masterItemId == auxItemId) {
582         return;
583     }
584     auto masterImage = GetImage(masterItemId);
585     if (!masterImage) {
586         return;
587     }
588     std::shared_ptr<HeifAuxcBox> auxc = GetProperty<HeifAuxcBox>(auxItemId);
589     if (!auxc) {
590         return;
591     }
592 
593     if (auxc->GetAuxType() == HEIF_AUXTTYPE_ID_FRAGMENT_MAP) {
594         ExtractFragmentMetadata(auxItemId);
595     }
596     auxImage->SetAuxImage(masterItemId, auxc->GetAuxType());
597     masterImage->AddAuxImage(auxImage);
598 }
599 
ExtractGainmapImage(const heif_item_id & tmapId)600 void HeifParser::ExtractGainmapImage(const heif_item_id& tmapId)
601 {
602     if (!irefBox_) {
603         return;
604     }
605     std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(tmapId);
606     for (const HeifIrefBox::Reference &ref : references) {
607         uint32_t type = ref.box.GetBoxType();
608         if (type != BOX_TYPE_DIMG) {
609             continue;
610         }
611         heif_item_id fromItemId = ref.fromItemId;
612         auto fromItemInfeBox = GetInfeBox(fromItemId);
613         if (fromItemInfeBox == nullptr) {
614             continue;
615         }
616         if (fromItemInfeBox->GetItemType() != "tmap") {
617             return;
618         }
619         std::vector<heif_item_id> toItemIds = ref.toItemIds;
620         const size_t tmapToItemSize = 2;
621         if (toItemIds.size() != tmapToItemSize) {
622             return;
623         }
624         const uint8_t baseIndex = 0;
625         const uint8_t gainmapIndex = 1;
626         heif_item_id baseId = toItemIds[baseIndex];
627         if (baseId != primaryImage_->GetItemId()) {
628             return;
629         }
630         heif_item_id gainmapId = toItemIds[gainmapIndex];
631         auto gainmapImage = GetImage(gainmapId);
632         if (gainmapImage == nullptr) {
633             return;
634         }
635         gainmapImage->SetGainmapMasterImage(baseId);
636         gainmapImage->SetTmapBoxId(tmapId);
637         primaryImage_->AddGainmapImage(gainmapImage);
638         primaryImage_->SetTmapBoxId(tmapId);
639     }
640 }
641 
ExtractNonMasterImages()642 void HeifParser::ExtractNonMasterImages()
643 {
644     if (!irefBox_) {
645         return;
646     }
647     for (auto &pair: images_) {
648         auto &image = pair.second;
649         std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(image->GetItemId());
650         for (const HeifIrefBox::Reference &ref: references) {
651             uint32_t type = ref.box.GetBoxType();
652             if (type == BOX_TYPE_THMB) {
653                 ExtractThumbnailImage(image, ref);
654             } else if (type == BOX_TYPE_AUXL) {
655                 ExtractAuxImage(image, ref);
656             }
657         }
658     }
659 }
660 
ExtractMetadata(const std::vector<heif_item_id> & allItemIds)661 void HeifParser::ExtractMetadata(const std::vector<heif_item_id> &allItemIds)
662 {
663     if (!irefBox_) {
664         return;
665     }
666 
667     for (heif_item_id metadataItemId: allItemIds) {
668         std::vector<heif_item_id> toItemIds = irefBox_->GetReferences(metadataItemId, BOX_TYPE_CDSC);
669         if (toItemIds.empty()) {
670             continue;
671         }
672         heif_item_id masterImageId = toItemIds[0];
673         if (masterImageId == metadataItemId) {
674             continue;
675         }
676         auto masterImage = GetImage(masterImageId);
677         if (!masterImage) {
678             continue;
679         }
680 
681         std::shared_ptr<HeifMetadata> metadata = std::make_shared<HeifMetadata>();
682         metadata->itemId = metadataItemId;
683         metadata->itemType = GetItemType(metadataItemId);
684         metadata->contentType = GetItemContentType(metadataItemId);
685         metadata->itemUriType = GetItemUriType(metadataItemId);
686         heif_error err = GetItemData(metadataItemId, &(metadata->mData));
687         if (err != heif_error_ok) {
688             metadata.reset();
689             continue;
690         }
691         masterImage->AddMetadata(metadata);
692     }
693 }
694 
GetImage(heif_item_id itemId)695 std::shared_ptr<HeifImage> HeifParser::GetImage(heif_item_id itemId)
696 {
697     auto iter = images_.find(itemId);
698     if (iter == images_.end()) {
699         return nullptr;
700     }
701     return iter->second;
702 }
703 
GetPrimaryImage()704 std::shared_ptr<HeifImage> HeifParser::GetPrimaryImage()
705 {
706     return primaryImage_;
707 }
708 
GetGainmapImage()709 std::shared_ptr<HeifImage> HeifParser::GetGainmapImage()
710 {
711     return primaryImage_ != nullptr ? primaryImage_->GetGainmapImage() : nullptr;
712 }
713 
GetAuxiliaryMapImage(const std::string type)714 std::shared_ptr<HeifImage> HeifParser::GetAuxiliaryMapImage(const std::string type)
715 {
716     auto auxImages = primaryImage_->GetAuxImages();
717     for (auto image : auxImages) {
718         if (image->GetAuxImageType() == type) {
719             return image;
720         }
721     }
722     return nullptr;
723 }
724 
GetTmapImage()725 std::shared_ptr<HeifImage> HeifParser::GetTmapImage()
726 {
727     return tmapImage_;
728 }
729 
GetNextItemId() const730 heif_item_id HeifParser::GetNextItemId() const
731 {
732     heif_item_id max_id = 0;
733     for (const auto& infe: infeBoxes_) {
734         max_id = std::max(max_id, infe.second->GetItemId());
735     }
736     return max_id + 1;
737 }
738 
AddItem(const char * itemType,bool hidden)739 std::shared_ptr<HeifInfeBox> HeifParser::AddItem(const char *itemType, bool hidden)
740 {
741     heif_item_id newItemId = GetNextItemId();
742     auto newInfe = std::make_shared<HeifInfeBox>(newItemId, itemType, false);
743     newInfe->SetHidden(hidden);
744     infeBoxes_[newItemId] = newInfe;
745     if (iinfBox_ == nullptr) {
746         return nullptr;
747     }
748     iinfBox_->AddChild(newInfe);
749     return newInfe;
750 }
751 
AddIspeProperty(heif_item_id itemId,uint32_t width,uint32_t height)752 void HeifParser::AddIspeProperty(heif_item_id itemId, uint32_t width, uint32_t height)
753 {
754     auto ispe = std::make_shared<HeifIspeBox>();
755     ispe->SetDimension(width, height);
756     AddProperty(itemId, ispe, false);
757 }
758 
AddProperty(heif_item_id itemId,const std::shared_ptr<HeifBox> & property,bool essential)759 heif_property_id HeifParser::AddProperty(heif_item_id itemId, const std::shared_ptr<HeifBox>& property, bool essential)
760 {
761     int index = ipcoBox_->AddChild(property);
762     ipmaBox_->AddProperty(itemId, PropertyAssociation{essential, uint16_t(index + 1)});
763     return index + 1;
764 }
765 
AddPixiProperty(heif_item_id itemId,uint8_t c1,uint8_t c2,uint8_t c3)766 void HeifParser::AddPixiProperty(heif_item_id itemId, uint8_t c1, uint8_t c2, uint8_t c3)
767 {
768     auto pixi = std::make_shared<HeifPixiBox>();
769     pixi->AddBitNum(c1);
770     pixi->AddBitNum(c2);
771     pixi->AddBitNum(c3);
772     AddProperty(itemId, pixi, false);
773 }
774 
775 
AddHvccProperty(heif_item_id itemId)776 void HeifParser::AddHvccProperty(heif_item_id itemId)
777 {
778     auto hvcC = std::make_shared<HeifHvccBox>();
779     AddProperty(itemId, hvcC, true);
780 }
781 
AppendHvccNalData(heif_item_id itemId,const std::vector<uint8_t> & data)782 heif_error HeifParser::AppendHvccNalData(heif_item_id itemId, const std::vector<uint8_t> &data)
783 {
784     auto hvcc = GetProperty<HeifHvccBox>(itemId);
785     if (!hvcc) {
786         return heif_error_no_hvcc;
787     }
788     hvcc->AppendNalData(data);
789     return heif_error_ok;
790 }
791 
SetHvccConfig(heif_item_id itemId,const HvccConfig & config)792 heif_error HeifParser::SetHvccConfig(heif_item_id itemId, const HvccConfig &config)
793 {
794     auto hvcc = GetProperty<HeifHvccBox>(itemId);
795     if (!hvcc) {
796         return heif_error_no_hvcc;
797     }
798     hvcc->SetConfig(config);
799     return heif_error_ok;
800 }
801 
AppendIlocData(heif_item_id itemId,const std::vector<uint8_t> & data,uint8_t construction_method)802 void HeifParser::AppendIlocData(heif_item_id itemId, const std::vector<uint8_t> &data, uint8_t construction_method)
803 {
804     if (!ilocBox_) {
805         return;
806     }
807     ilocBox_->AppendData(itemId, data, construction_method);
808 }
809 
SetPrimaryItemId(heif_item_id itemId)810 void HeifParser::SetPrimaryItemId(heif_item_id itemId)
811 {
812     if (!pitmBox_) {
813         return;
814     }
815     pitmBox_->SetItemId(itemId);
816 }
817 
AddReference(heif_item_id fromItemId,uint32_t type,const std::vector<heif_item_id> & toItemIds)818 void HeifParser::AddReference(heif_item_id fromItemId, uint32_t type, const std::vector<heif_item_id> &toItemIds)
819 {
820     if (!irefBox_) {
821         irefBox_ = std::make_shared<HeifIrefBox>();
822         metaBox_->AddChild(irefBox_);
823     }
824     irefBox_->AddReferences(fromItemId, type, toItemIds);
825 }
826 
SetAuxcProperty(heif_item_id itemId,const std::string & type)827 void HeifParser::SetAuxcProperty(heif_item_id itemId, const std::string &type)
828 {
829     auto auxC = std::make_shared<HeifAuxcBox>();
830     auxC->SetAuxType(type);
831     AddProperty(itemId, auxC, true);
832 }
833 
SetColorProfile(heif_item_id itemId,const std::shared_ptr<const HeifColorProfile> & profile)834 void HeifParser::SetColorProfile(heif_item_id itemId, const std::shared_ptr<const HeifColorProfile> &profile)
835 {
836     auto colr = std::make_shared<HeifColrBox>();
837     colr->SetColorProfile(profile);
838     AddProperty(itemId, colr, false);
839 }
840 
CheckExtentData()841 void HeifParser::CheckExtentData()
842 {
843     const std::vector<HeifIlocBox::Item>& items = ilocBox_->GetItems();
844     for (const HeifIlocBox::Item& item: items) {
845         ilocBox_->ReadToExtentData(const_cast<HeifIlocBox::Item &>(item), inputStream_, idatBox_);
846     }
847 }
848 
SetPrimaryImage(const std::shared_ptr<HeifImage> & image)849 void HeifParser::SetPrimaryImage(const std::shared_ptr<HeifImage> &image)
850 {
851     if (primaryImage_) {
852         if (primaryImage_->GetItemId() == image->GetItemId()) {
853             return;
854         }
855         primaryImage_->SetPrimaryImage(false);
856     }
857     primaryImage_ = image;
858     image->SetPrimaryImage(true);
859     SetPrimaryItemId(image->GetItemId());
860 }
861 
GetExifHeaderOffset(const uint8_t * data,uint32_t size)862 uint32_t HeifParser::GetExifHeaderOffset(const uint8_t *data, uint32_t size)
863 {
864     uint32_t offset = 0;
865     const int endianSize = 4;
866     while (offset + endianSize < static_cast<unsigned int>(size)) {
867         if (!memcmp(data + offset, "MM\0*", endianSize) || !memcmp(data + offset, "II*\0", endianSize)) {
868             return offset;
869         }
870         offset++;
871     }
872     return offset;
873 }
874 
SetExifMetadata(const std::shared_ptr<HeifImage> & image,const uint8_t * data,uint32_t size)875 heif_error HeifParser::SetExifMetadata(const std::shared_ptr<HeifImage> &image, const uint8_t *data, uint32_t size)
876 {
877     if (size > HEIF_MAX_EXIF_SIZE) {
878         return heif_invalid_exif_data;
879     }
880     uint32_t offset = GetExifHeaderOffset(data, size);
881     if (offset >= size) {
882         return heif_invalid_exif_data;
883     }
884 
885     std::vector<uint8_t> content;
886     content.resize(size + UINT32_BYTES_NUM);
887     std::string offsetFourcc = code_to_fourcc(offset);
888     for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
889         content[index] = (uint8_t)offsetFourcc[index];
890     }
891     if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != EOK) {
892         return heif_invalid_exif_data;
893     }
894     return SetMetadata(image, content, "Exif", nullptr);
895 }
896 
UpdateExifMetadata(const std::shared_ptr<HeifImage> & master_image,const uint8_t * data,uint32_t size,heif_item_id itemId)897 heif_error HeifParser::UpdateExifMetadata(const std::shared_ptr<HeifImage> &master_image, const uint8_t *data,
898                                           uint32_t size, heif_item_id itemId)
899 {
900     if (size > HEIF_MAX_EXIF_SIZE) {
901         return heif_invalid_exif_data;
902     }
903     uint32_t offset = GetExifHeaderOffset(data, size);
904     if (offset >= static_cast<unsigned int>(size)) {
905         return heif_invalid_exif_data;
906     }
907 
908     std::vector<uint8_t> content;
909     content.resize(size + UINT32_BYTES_NUM);
910     std::string offsetFourcc = code_to_fourcc(offset);
911     for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
912         content[index] = (uint8_t)offsetFourcc[index];
913     }
914 
915     if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != 0) {
916         return heif_invalid_exif_data;
917     }
918 
919     uint8_t construction_method = GetConstructMethod(itemId);
920 
921     return ilocBox_->UpdateData(itemId, content, construction_method);
922 }
923 
SetMetadata(const std::shared_ptr<HeifImage> & image,const std::vector<uint8_t> & data,const char * item_type,const char * content_type)924 heif_error HeifParser::SetMetadata(const std::shared_ptr<HeifImage> &image, const std::vector<uint8_t> &data,
925                                    const char *item_type, const char *content_type)
926 {
927     auto metadataInfe = AddItem(item_type, true);
928     if (content_type != nullptr) {
929         metadataInfe->SetContentType(content_type);
930     }
931 
932     heif_item_id metadataItemId = metadataInfe->GetItemId();
933     heif_item_id imageItemId = image->GetItemId();
934     AddReference(metadataItemId, BOX_TYPE_CDSC, {imageItemId});
935 
936     // store metadata in mdat
937     AppendIlocData(metadataItemId, data, 0);
938     return heif_error_ok;
939 }
940 
GetConstructMethod(const heif_item_id & id)941 uint8_t HeifParser::GetConstructMethod(const heif_item_id &id)
942 {
943     auto items = ilocBox_->GetItems();
944     for (const auto &item: items) {
945         if (item.itemId == id) {
946             return item.constructionMethod;
947         }
948     }
949 
950     // CONSTRUCTION_METHOD_FILE_OFFSET 0
951     return 0;
952 }
953 
SetTiffOffset()954 void HeifParser::SetTiffOffset()
955 {
956     if (tiffOffset_ != 0) {
957         return;
958     }
959     if (GetPrimaryImage() == nullptr) {
960         return;
961     }
962     auto metadataList = GetPrimaryImage()->GetAllMetadata();
963     heif_item_id exifId = 0;
964     for (auto metadata : metadataList) {
965         if (metadata && metadata->itemType == EXIF_ID) {
966             exifId = metadata->itemId;
967             break;
968         }
969     }
970     if (exifId == 0) {
971         return;
972     }
973 
974     if (!HasItemId(exifId)) {
975         return;
976     }
977 
978     auto items = ilocBox_->GetItems();
979     const HeifIlocBox::Item *ilocItem = nullptr;
980     for (const auto &item: items) {
981         if (item.itemId == exifId) {
982             ilocItem = &item;
983             break;
984         }
985     }
986     if (!ilocItem) {
987         return;
988     }
989 
990     tiffOffset_ = ilocItem->baseOffset;
991     if (!ilocItem->extents.empty()) {
992         tiffOffset_ += ilocItem->extents[0].offset;
993     }
994 }
995 } // namespace ImagePlugin
996 } // namespace OHOS
997