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